033c8c1240b853b705020e01449b30471a8e4322
[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             valid = false;
7802
7803             if(!target && f.el.isVisible(true)){
7804                 target = f;
7805             }
7806            
7807         });
7808         
7809         if(this.errorMask && !valid){
7810             Roo.bootstrap.Form.popover.mask(this, target);
7811         }
7812         
7813         return valid;
7814     },
7815     
7816     /**
7817      * Returns true if any fields in this form have changed since their original load.
7818      * @return Boolean
7819      */
7820     isDirty : function(){
7821         var dirty = false;
7822         var items = this.getItems();
7823         items.each(function(f){
7824            if(f.isDirty()){
7825                dirty = true;
7826                return false;
7827            }
7828            return true;
7829         });
7830         return dirty;
7831     },
7832      /**
7833      * Performs a predefined action (submit or load) or custom actions you define on this form.
7834      * @param {String} actionName The name of the action type
7835      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
7836      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7837      * accept other config options):
7838      * <pre>
7839 Property          Type             Description
7840 ----------------  ---------------  ----------------------------------------------------------------------------------
7841 url               String           The url for the action (defaults to the form's url)
7842 method            String           The form method to use (defaults to the form's method, or POST if not defined)
7843 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
7844 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
7845                                    validate the form on the client (defaults to false)
7846      * </pre>
7847      * @return {BasicForm} this
7848      */
7849     doAction : function(action, options){
7850         if(typeof action == 'string'){
7851             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7852         }
7853         if(this.fireEvent('beforeaction', this, action) !== false){
7854             this.beforeAction(action);
7855             action.run.defer(100, action);
7856         }
7857         return this;
7858     },
7859
7860     // private
7861     beforeAction : function(action){
7862         var o = action.options;
7863         
7864         if(this.loadMask){
7865             
7866             if(this.maskBody){
7867                 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7868             } else {
7869                 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7870             }
7871         }
7872         // not really supported yet.. ??
7873
7874         //if(this.waitMsgTarget === true){
7875         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7876         //}else if(this.waitMsgTarget){
7877         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7878         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7879         //}else {
7880         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7881        // }
7882
7883     },
7884
7885     // private
7886     afterAction : function(action, success){
7887         this.activeAction = null;
7888         var o = action.options;
7889
7890         if(this.loadMask){
7891             
7892             if(this.maskBody){
7893                 Roo.get(document.body).unmask();
7894             } else {
7895                 this.el.unmask();
7896             }
7897         }
7898         
7899         //if(this.waitMsgTarget === true){
7900 //            this.el.unmask();
7901         //}else if(this.waitMsgTarget){
7902         //    this.waitMsgTarget.unmask();
7903         //}else{
7904         //    Roo.MessageBox.updateProgress(1);
7905         //    Roo.MessageBox.hide();
7906        // }
7907         //
7908         if(success){
7909             if(o.reset){
7910                 this.reset();
7911             }
7912             Roo.callback(o.success, o.scope, [this, action]);
7913             this.fireEvent('actioncomplete', this, action);
7914
7915         }else{
7916
7917             // failure condition..
7918             // we have a scenario where updates need confirming.
7919             // eg. if a locking scenario exists..
7920             // we look for { errors : { needs_confirm : true }} in the response.
7921             if (
7922                 (typeof(action.result) != 'undefined')  &&
7923                 (typeof(action.result.errors) != 'undefined')  &&
7924                 (typeof(action.result.errors.needs_confirm) != 'undefined')
7925            ){
7926                 var _t = this;
7927                 Roo.log("not supported yet");
7928                  /*
7929
7930                 Roo.MessageBox.confirm(
7931                     "Change requires confirmation",
7932                     action.result.errorMsg,
7933                     function(r) {
7934                         if (r != 'yes') {
7935                             return;
7936                         }
7937                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
7938                     }
7939
7940                 );
7941                 */
7942
7943
7944                 return;
7945             }
7946
7947             Roo.callback(o.failure, o.scope, [this, action]);
7948             // show an error message if no failed handler is set..
7949             if (!this.hasListener('actionfailed')) {
7950                 Roo.log("need to add dialog support");
7951                 /*
7952                 Roo.MessageBox.alert("Error",
7953                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7954                         action.result.errorMsg :
7955                         "Saving Failed, please check your entries or try again"
7956                 );
7957                 */
7958             }
7959
7960             this.fireEvent('actionfailed', this, action);
7961         }
7962
7963     },
7964     /**
7965      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7966      * @param {String} id The value to search for
7967      * @return Field
7968      */
7969     findField : function(id){
7970         var items = this.getItems();
7971         var field = items.get(id);
7972         if(!field){
7973              items.each(function(f){
7974                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7975                     field = f;
7976                     return false;
7977                 }
7978                 return true;
7979             });
7980         }
7981         return field || null;
7982     },
7983      /**
7984      * Mark fields in this form invalid in bulk.
7985      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7986      * @return {BasicForm} this
7987      */
7988     markInvalid : function(errors){
7989         if(errors instanceof Array){
7990             for(var i = 0, len = errors.length; i < len; i++){
7991                 var fieldError = errors[i];
7992                 var f = this.findField(fieldError.id);
7993                 if(f){
7994                     f.markInvalid(fieldError.msg);
7995                 }
7996             }
7997         }else{
7998             var field, id;
7999             for(id in errors){
8000                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8001                     field.markInvalid(errors[id]);
8002                 }
8003             }
8004         }
8005         //Roo.each(this.childForms || [], function (f) {
8006         //    f.markInvalid(errors);
8007         //});
8008
8009         return this;
8010     },
8011
8012     /**
8013      * Set values for fields in this form in bulk.
8014      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8015      * @return {BasicForm} this
8016      */
8017     setValues : function(values){
8018         if(values instanceof Array){ // array of objects
8019             for(var i = 0, len = values.length; i < len; i++){
8020                 var v = values[i];
8021                 var f = this.findField(v.id);
8022                 if(f){
8023                     f.setValue(v.value);
8024                     if(this.trackResetOnLoad){
8025                         f.originalValue = f.getValue();
8026                     }
8027                 }
8028             }
8029         }else{ // object hash
8030             var field, id;
8031             for(id in values){
8032                 if(typeof values[id] != 'function' && (field = this.findField(id))){
8033
8034                     if (field.setFromData &&
8035                         field.valueField &&
8036                         field.displayField &&
8037                         // combos' with local stores can
8038                         // be queried via setValue()
8039                         // to set their value..
8040                         (field.store && !field.store.isLocal)
8041                         ) {
8042                         // it's a combo
8043                         var sd = { };
8044                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8045                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8046                         field.setFromData(sd);
8047
8048                     } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8049                         
8050                         field.setFromData(values);
8051                         
8052                     } else {
8053                         field.setValue(values[id]);
8054                     }
8055
8056
8057                     if(this.trackResetOnLoad){
8058                         field.originalValue = field.getValue();
8059                     }
8060                 }
8061             }
8062         }
8063
8064         //Roo.each(this.childForms || [], function (f) {
8065         //    f.setValues(values);
8066         //});
8067
8068         return this;
8069     },
8070
8071     /**
8072      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8073      * they are returned as an array.
8074      * @param {Boolean} asString
8075      * @return {Object}
8076      */
8077     getValues : function(asString){
8078         //if (this.childForms) {
8079             // copy values from the child forms
8080         //    Roo.each(this.childForms, function (f) {
8081         //        this.setValues(f.getValues());
8082         //    }, this);
8083         //}
8084
8085
8086
8087         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8088         if(asString === true){
8089             return fs;
8090         }
8091         return Roo.urlDecode(fs);
8092     },
8093
8094     /**
8095      * Returns the fields in this form as an object with key/value pairs.
8096      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8097      * @return {Object}
8098      */
8099     getFieldValues : function(with_hidden)
8100     {
8101         var items = this.getItems();
8102         var ret = {};
8103         items.each(function(f){
8104             
8105             if (!f.getName()) {
8106                 return;
8107             }
8108             
8109             var v = f.getValue();
8110             
8111             if (f.inputType =='radio') {
8112                 if (typeof(ret[f.getName()]) == 'undefined') {
8113                     ret[f.getName()] = ''; // empty..
8114                 }
8115
8116                 if (!f.el.dom.checked) {
8117                     return;
8118
8119                 }
8120                 v = f.el.dom.value;
8121
8122             }
8123             
8124             if(f.xtype == 'MoneyField'){
8125                 ret[f.currencyName] = f.getCurrency();
8126             }
8127
8128             // not sure if this supported any more..
8129             if ((typeof(v) == 'object') && f.getRawValue) {
8130                 v = f.getRawValue() ; // dates..
8131             }
8132             // combo boxes where name != hiddenName...
8133             if (f.name !== false && f.name != '' && f.name != f.getName()) {
8134                 ret[f.name] = f.getRawValue();
8135             }
8136             ret[f.getName()] = v;
8137         });
8138
8139         return ret;
8140     },
8141
8142     /**
8143      * Clears all invalid messages in this form.
8144      * @return {BasicForm} this
8145      */
8146     clearInvalid : function(){
8147         var items = this.getItems();
8148
8149         items.each(function(f){
8150            f.clearInvalid();
8151         });
8152
8153         return this;
8154     },
8155
8156     /**
8157      * Resets this form.
8158      * @return {BasicForm} this
8159      */
8160     reset : function(){
8161         var items = this.getItems();
8162         items.each(function(f){
8163             f.reset();
8164         });
8165
8166         Roo.each(this.childForms || [], function (f) {
8167             f.reset();
8168         });
8169
8170
8171         return this;
8172     },
8173     
8174     getItems : function()
8175     {
8176         var r=new Roo.util.MixedCollection(false, function(o){
8177             return o.id || (o.id = Roo.id());
8178         });
8179         var iter = function(el) {
8180             if (el.inputEl) {
8181                 r.add(el);
8182             }
8183             if (!el.items) {
8184                 return;
8185             }
8186             Roo.each(el.items,function(e) {
8187                 iter(e);
8188             });
8189         };
8190
8191         iter(this);
8192         return r;
8193     },
8194     
8195     hideFields : function(items)
8196     {
8197         Roo.each(items, function(i){
8198             
8199             var f = this.findField(i);
8200             
8201             if(!f){
8202                 return;
8203             }
8204             
8205             if(f.xtype == 'DateField'){
8206                 f.setVisible(false);
8207                 return;
8208             }
8209             
8210             f.hide();
8211             
8212         }, this);
8213     },
8214     
8215     showFields : function(items)
8216     {
8217         Roo.each(items, function(i){
8218             
8219             var f = this.findField(i);
8220             
8221             if(!f){
8222                 return;
8223             }
8224             
8225             if(f.xtype == 'DateField'){
8226                 f.setVisible(true);
8227                 return;
8228             }
8229             
8230             f.show();
8231             
8232         }, this);
8233     }
8234
8235 });
8236
8237 Roo.apply(Roo.bootstrap.Form, {
8238     
8239     popover : {
8240         
8241         padding : 5,
8242         
8243         isApplied : false,
8244         
8245         isMasked : false,
8246         
8247         form : false,
8248         
8249         target : false,
8250         
8251         toolTip : false,
8252         
8253         intervalID : false,
8254         
8255         maskEl : false,
8256         
8257         apply : function()
8258         {
8259             if(this.isApplied){
8260                 return;
8261             }
8262             
8263             this.maskEl = {
8264                 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8265                 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8266                 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8267                 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8268             };
8269             
8270             this.maskEl.top.enableDisplayMode("block");
8271             this.maskEl.left.enableDisplayMode("block");
8272             this.maskEl.bottom.enableDisplayMode("block");
8273             this.maskEl.right.enableDisplayMode("block");
8274             
8275             this.toolTip = new Roo.bootstrap.Tooltip({
8276                 cls : 'roo-form-error-popover',
8277                 alignment : {
8278                     'left' : ['r-l', [-2,0], 'right'],
8279                     'right' : ['l-r', [2,0], 'left'],
8280                     'bottom' : ['tl-bl', [0,2], 'top'],
8281                     'top' : [ 'bl-tl', [0,-2], 'bottom']
8282                 }
8283             });
8284             
8285             this.toolTip.render(Roo.get(document.body));
8286
8287             this.toolTip.el.enableDisplayMode("block");
8288             
8289             Roo.get(document.body).on('click', function(){
8290                 this.unmask();
8291             }, this);
8292             
8293             Roo.get(document.body).on('touchstart', function(){
8294                 this.unmask();
8295             }, this);
8296             
8297             this.isApplied = true
8298         },
8299         
8300         mask : function(form, target)
8301         {
8302             this.form = form;
8303             
8304             this.target = target;
8305             
8306             if(!this.form.errorMask || !target.el){
8307                 return;
8308             }
8309             
8310             var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8311             
8312             Roo.log(scrollable);
8313             
8314             var ot = this.target.el.calcOffsetsTo(scrollable);
8315             
8316             var scrollTo = ot[1] - this.form.maskOffset;
8317             
8318             scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8319             
8320             scrollable.scrollTo('top', scrollTo);
8321             
8322             var box = this.target.el.getBox();
8323             Roo.log(box);
8324             var zIndex = Roo.bootstrap.Modal.zIndex++;
8325
8326             
8327             this.maskEl.top.setStyle('position', 'absolute');
8328             this.maskEl.top.setStyle('z-index', zIndex);
8329             this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8330             this.maskEl.top.setLeft(0);
8331             this.maskEl.top.setTop(0);
8332             this.maskEl.top.show();
8333             
8334             this.maskEl.left.setStyle('position', 'absolute');
8335             this.maskEl.left.setStyle('z-index', zIndex);
8336             this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8337             this.maskEl.left.setLeft(0);
8338             this.maskEl.left.setTop(box.y - this.padding);
8339             this.maskEl.left.show();
8340
8341             this.maskEl.bottom.setStyle('position', 'absolute');
8342             this.maskEl.bottom.setStyle('z-index', zIndex);
8343             this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8344             this.maskEl.bottom.setLeft(0);
8345             this.maskEl.bottom.setTop(box.bottom + this.padding);
8346             this.maskEl.bottom.show();
8347
8348             this.maskEl.right.setStyle('position', 'absolute');
8349             this.maskEl.right.setStyle('z-index', zIndex);
8350             this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8351             this.maskEl.right.setLeft(box.right + this.padding);
8352             this.maskEl.right.setTop(box.y - this.padding);
8353             this.maskEl.right.show();
8354
8355             this.toolTip.bindEl = this.target.el;
8356
8357             this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8358
8359             var tip = this.target.blankText;
8360
8361             if(this.target.getValue() !== '' ) {
8362                 
8363                 if (this.target.invalidText.length) {
8364                     tip = this.target.invalidText;
8365                 } else if (this.target.regexText.length){
8366                     tip = this.target.regexText;
8367                 }
8368             }
8369
8370             this.toolTip.show(tip);
8371
8372             this.intervalID = window.setInterval(function() {
8373                 Roo.bootstrap.Form.popover.unmask();
8374             }, 10000);
8375
8376             window.onwheel = function(){ return false;};
8377             
8378             (function(){ this.isMasked = true; }).defer(500, this);
8379             
8380         },
8381         
8382         unmask : function()
8383         {
8384             if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8385                 return;
8386             }
8387             
8388             this.maskEl.top.setStyle('position', 'absolute');
8389             this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8390             this.maskEl.top.hide();
8391
8392             this.maskEl.left.setStyle('position', 'absolute');
8393             this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8394             this.maskEl.left.hide();
8395
8396             this.maskEl.bottom.setStyle('position', 'absolute');
8397             this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8398             this.maskEl.bottom.hide();
8399
8400             this.maskEl.right.setStyle('position', 'absolute');
8401             this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8402             this.maskEl.right.hide();
8403             
8404             this.toolTip.hide();
8405             
8406             this.toolTip.el.hide();
8407             
8408             window.onwheel = function(){ return true;};
8409             
8410             if(this.intervalID){
8411                 window.clearInterval(this.intervalID);
8412                 this.intervalID = false;
8413             }
8414             
8415             this.isMasked = false;
8416             
8417         }
8418         
8419     }
8420     
8421 });
8422
8423 /*
8424  * Based on:
8425  * Ext JS Library 1.1.1
8426  * Copyright(c) 2006-2007, Ext JS, LLC.
8427  *
8428  * Originally Released Under LGPL - original licence link has changed is not relivant.
8429  *
8430  * Fork - LGPL
8431  * <script type="text/javascript">
8432  */
8433 /**
8434  * @class Roo.form.VTypes
8435  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8436  * @singleton
8437  */
8438 Roo.form.VTypes = function(){
8439     // closure these in so they are only created once.
8440     var alpha = /^[a-zA-Z_]+$/;
8441     var alphanum = /^[a-zA-Z0-9_]+$/;
8442     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8443     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8444
8445     // All these messages and functions are configurable
8446     return {
8447         /**
8448          * The function used to validate email addresses
8449          * @param {String} value The email address
8450          */
8451         'email' : function(v){
8452             return email.test(v);
8453         },
8454         /**
8455          * The error text to display when the email validation function returns false
8456          * @type String
8457          */
8458         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8459         /**
8460          * The keystroke filter mask to be applied on email input
8461          * @type RegExp
8462          */
8463         'emailMask' : /[a-z0-9_\.\-@]/i,
8464
8465         /**
8466          * The function used to validate URLs
8467          * @param {String} value The URL
8468          */
8469         'url' : function(v){
8470             return url.test(v);
8471         },
8472         /**
8473          * The error text to display when the url validation function returns false
8474          * @type String
8475          */
8476         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8477         
8478         /**
8479          * The function used to validate alpha values
8480          * @param {String} value The value
8481          */
8482         'alpha' : function(v){
8483             return alpha.test(v);
8484         },
8485         /**
8486          * The error text to display when the alpha validation function returns false
8487          * @type String
8488          */
8489         'alphaText' : 'This field should only contain letters and _',
8490         /**
8491          * The keystroke filter mask to be applied on alpha input
8492          * @type RegExp
8493          */
8494         'alphaMask' : /[a-z_]/i,
8495
8496         /**
8497          * The function used to validate alphanumeric values
8498          * @param {String} value The value
8499          */
8500         'alphanum' : function(v){
8501             return alphanum.test(v);
8502         },
8503         /**
8504          * The error text to display when the alphanumeric validation function returns false
8505          * @type String
8506          */
8507         'alphanumText' : 'This field should only contain letters, numbers and _',
8508         /**
8509          * The keystroke filter mask to be applied on alphanumeric input
8510          * @type RegExp
8511          */
8512         'alphanumMask' : /[a-z0-9_]/i
8513     };
8514 }();/*
8515  * - LGPL
8516  *
8517  * Input
8518  * 
8519  */
8520
8521 /**
8522  * @class Roo.bootstrap.Input
8523  * @extends Roo.bootstrap.Component
8524  * Bootstrap Input class
8525  * @cfg {Boolean} disabled is it disabled
8526  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8527  * @cfg {String} name name of the input
8528  * @cfg {string} fieldLabel - the label associated
8529  * @cfg {string} placeholder - placeholder to put in text.
8530  * @cfg {string}  before - input group add on before
8531  * @cfg {string} after - input group add on after
8532  * @cfg {string} size - (lg|sm) or leave empty..
8533  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8534  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8535  * @cfg {Number} md colspan out of 12 for computer-sized screens
8536  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8537  * @cfg {string} value default value of the input
8538  * @cfg {Number} labelWidth set the width of label 
8539  * @cfg {Number} labellg set the width of label (1-12)
8540  * @cfg {Number} labelmd set the width of label (1-12)
8541  * @cfg {Number} labelsm set the width of label (1-12)
8542  * @cfg {Number} labelxs set the width of label (1-12)
8543  * @cfg {String} labelAlign (top|left)
8544  * @cfg {Boolean} readOnly Specifies that the field should be read-only
8545  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8546  * @cfg {String} indicatorpos (left|right) default left
8547  * @cfg {String} capture (user|camera) use for file input only. (default empty)
8548  * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8549
8550  * @cfg {String} align (left|center|right) Default left
8551  * @cfg {Boolean} forceFeedback (true|false) Default false
8552  * 
8553  * @constructor
8554  * Create a new Input
8555  * @param {Object} config The config object
8556  */
8557
8558 Roo.bootstrap.Input = function(config){
8559     
8560     Roo.bootstrap.Input.superclass.constructor.call(this, config);
8561     
8562     this.addEvents({
8563         /**
8564          * @event focus
8565          * Fires when this field receives input focus.
8566          * @param {Roo.form.Field} this
8567          */
8568         focus : true,
8569         /**
8570          * @event blur
8571          * Fires when this field loses input focus.
8572          * @param {Roo.form.Field} this
8573          */
8574         blur : true,
8575         /**
8576          * @event specialkey
8577          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
8578          * {@link Roo.EventObject#getKey} to determine which key was pressed.
8579          * @param {Roo.form.Field} this
8580          * @param {Roo.EventObject} e The event object
8581          */
8582         specialkey : true,
8583         /**
8584          * @event change
8585          * Fires just before the field blurs if the field value has changed.
8586          * @param {Roo.form.Field} this
8587          * @param {Mixed} newValue The new value
8588          * @param {Mixed} oldValue The original value
8589          */
8590         change : true,
8591         /**
8592          * @event invalid
8593          * Fires after the field has been marked as invalid.
8594          * @param {Roo.form.Field} this
8595          * @param {String} msg The validation message
8596          */
8597         invalid : true,
8598         /**
8599          * @event valid
8600          * Fires after the field has been validated with no errors.
8601          * @param {Roo.form.Field} this
8602          */
8603         valid : true,
8604          /**
8605          * @event keyup
8606          * Fires after the key up
8607          * @param {Roo.form.Field} this
8608          * @param {Roo.EventObject}  e The event Object
8609          */
8610         keyup : true
8611     });
8612 };
8613
8614 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
8615      /**
8616      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8617       automatic validation (defaults to "keyup").
8618      */
8619     validationEvent : "keyup",
8620      /**
8621      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8622      */
8623     validateOnBlur : true,
8624     /**
8625      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8626      */
8627     validationDelay : 250,
8628      /**
8629      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8630      */
8631     focusClass : "x-form-focus",  // not needed???
8632     
8633        
8634     /**
8635      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8636      */
8637     invalidClass : "has-warning",
8638     
8639     /**
8640      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8641      */
8642     validClass : "has-success",
8643     
8644     /**
8645      * @cfg {Boolean} hasFeedback (true|false) default true
8646      */
8647     hasFeedback : true,
8648     
8649     /**
8650      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8651      */
8652     invalidFeedbackClass : "glyphicon-warning-sign",
8653     
8654     /**
8655      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8656      */
8657     validFeedbackClass : "glyphicon-ok",
8658     
8659     /**
8660      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8661      */
8662     selectOnFocus : false,
8663     
8664      /**
8665      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8666      */
8667     maskRe : null,
8668        /**
8669      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8670      */
8671     vtype : null,
8672     
8673       /**
8674      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8675      */
8676     disableKeyFilter : false,
8677     
8678        /**
8679      * @cfg {Boolean} disabled True to disable the field (defaults to false).
8680      */
8681     disabled : false,
8682      /**
8683      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8684      */
8685     allowBlank : true,
8686     /**
8687      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8688      */
8689     blankText : "Please complete this mandatory field",
8690     
8691      /**
8692      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8693      */
8694     minLength : 0,
8695     /**
8696      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8697      */
8698     maxLength : Number.MAX_VALUE,
8699     /**
8700      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8701      */
8702     minLengthText : "The minimum length for this field is {0}",
8703     /**
8704      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8705      */
8706     maxLengthText : "The maximum length for this field is {0}",
8707   
8708     
8709     /**
8710      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8711      * If available, this function will be called only after the basic validators all return true, and will be passed the
8712      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8713      */
8714     validator : null,
8715     /**
8716      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8717      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8718      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
8719      */
8720     regex : null,
8721     /**
8722      * @cfg {String} regexText -- Depricated - use Invalid Text
8723      */
8724     regexText : "",
8725     
8726     /**
8727      * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8728      */
8729     invalidText : "",
8730     
8731     
8732     
8733     autocomplete: false,
8734     
8735     
8736     fieldLabel : '',
8737     inputType : 'text',
8738     
8739     name : false,
8740     placeholder: false,
8741     before : false,
8742     after : false,
8743     size : false,
8744     hasFocus : false,
8745     preventMark: false,
8746     isFormField : true,
8747     value : '',
8748     labelWidth : 2,
8749     labelAlign : false,
8750     readOnly : false,
8751     align : false,
8752     formatedValue : false,
8753     forceFeedback : false,
8754     
8755     indicatorpos : 'left',
8756     
8757     labellg : 0,
8758     labelmd : 0,
8759     labelsm : 0,
8760     labelxs : 0,
8761     
8762     capture : '',
8763     accept : '',
8764     
8765     parentLabelAlign : function()
8766     {
8767         var parent = this;
8768         while (parent.parent()) {
8769             parent = parent.parent();
8770             if (typeof(parent.labelAlign) !='undefined') {
8771                 return parent.labelAlign;
8772             }
8773         }
8774         return 'left';
8775         
8776     },
8777     
8778     getAutoCreate : function()
8779     {
8780         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8781         
8782         var id = Roo.id();
8783         
8784         var cfg = {};
8785         
8786         if(this.inputType != 'hidden'){
8787             cfg.cls = 'form-group' //input-group
8788         }
8789         
8790         var input =  {
8791             tag: 'input',
8792             id : id,
8793             type : this.inputType,
8794             value : this.value,
8795             cls : 'form-control',
8796             placeholder : this.placeholder || '',
8797             autocomplete : this.autocomplete || 'new-password'
8798         };
8799         
8800         if(this.capture.length){
8801             input.capture = this.capture;
8802         }
8803         
8804         if(this.accept.length){
8805             input.accept = this.accept + "/*";
8806         }
8807         
8808         if(this.align){
8809             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8810         }
8811         
8812         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8813             input.maxLength = this.maxLength;
8814         }
8815         
8816         if (this.disabled) {
8817             input.disabled=true;
8818         }
8819         
8820         if (this.readOnly) {
8821             input.readonly=true;
8822         }
8823         
8824         if (this.name) {
8825             input.name = this.name;
8826         }
8827         
8828         if (this.size) {
8829             input.cls += ' input-' + this.size;
8830         }
8831         
8832         var settings=this;
8833         ['xs','sm','md','lg'].map(function(size){
8834             if (settings[size]) {
8835                 cfg.cls += ' col-' + size + '-' + settings[size];
8836             }
8837         });
8838         
8839         var inputblock = input;
8840         
8841         var feedback = {
8842             tag: 'span',
8843             cls: 'glyphicon form-control-feedback'
8844         };
8845             
8846         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8847             
8848             inputblock = {
8849                 cls : 'has-feedback',
8850                 cn :  [
8851                     input,
8852                     feedback
8853                 ] 
8854             };  
8855         }
8856         
8857         if (this.before || this.after) {
8858             
8859             inputblock = {
8860                 cls : 'input-group',
8861                 cn :  [] 
8862             };
8863             
8864             if (this.before && typeof(this.before) == 'string') {
8865                 
8866                 inputblock.cn.push({
8867                     tag :'span',
8868                     cls : 'roo-input-before input-group-addon',
8869                     html : this.before
8870                 });
8871             }
8872             if (this.before && typeof(this.before) == 'object') {
8873                 this.before = Roo.factory(this.before);
8874                 
8875                 inputblock.cn.push({
8876                     tag :'span',
8877                     cls : 'roo-input-before input-group-' +
8878                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8879                 });
8880             }
8881             
8882             inputblock.cn.push(input);
8883             
8884             if (this.after && typeof(this.after) == 'string') {
8885                 inputblock.cn.push({
8886                     tag :'span',
8887                     cls : 'roo-input-after input-group-addon',
8888                     html : this.after
8889                 });
8890             }
8891             if (this.after && typeof(this.after) == 'object') {
8892                 this.after = Roo.factory(this.after);
8893                 
8894                 inputblock.cn.push({
8895                     tag :'span',
8896                     cls : 'roo-input-after input-group-' +
8897                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8898                 });
8899             }
8900             
8901             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8902                 inputblock.cls += ' has-feedback';
8903                 inputblock.cn.push(feedback);
8904             }
8905         };
8906         
8907         if (align ==='left' && this.fieldLabel.length) {
8908             
8909             cfg.cls += ' roo-form-group-label-left';
8910             
8911             cfg.cn = [
8912                 {
8913                     tag : 'i',
8914                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8915                     tooltip : 'This field is required'
8916                 },
8917                 {
8918                     tag: 'label',
8919                     'for' :  id,
8920                     cls : 'control-label',
8921                     html : this.fieldLabel
8922
8923                 },
8924                 {
8925                     cls : "", 
8926                     cn: [
8927                         inputblock
8928                     ]
8929                 }
8930             ];
8931             
8932             var labelCfg = cfg.cn[1];
8933             var contentCfg = cfg.cn[2];
8934             
8935             if(this.indicatorpos == 'right'){
8936                 cfg.cn = [
8937                     {
8938                         tag: 'label',
8939                         'for' :  id,
8940                         cls : 'control-label',
8941                         cn : [
8942                             {
8943                                 tag : 'span',
8944                                 html : this.fieldLabel
8945                             },
8946                             {
8947                                 tag : 'i',
8948                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8949                                 tooltip : 'This field is required'
8950                             }
8951                         ]
8952                     },
8953                     {
8954                         cls : "",
8955                         cn: [
8956                             inputblock
8957                         ]
8958                     }
8959
8960                 ];
8961                 
8962                 labelCfg = cfg.cn[0];
8963                 contentCfg = cfg.cn[1];
8964             
8965             }
8966             
8967             if(this.labelWidth > 12){
8968                 labelCfg.style = "width: " + this.labelWidth + 'px';
8969             }
8970             
8971             if(this.labelWidth < 13 && this.labelmd == 0){
8972                 this.labelmd = this.labelWidth;
8973             }
8974             
8975             if(this.labellg > 0){
8976                 labelCfg.cls += ' col-lg-' + this.labellg;
8977                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8978             }
8979             
8980             if(this.labelmd > 0){
8981                 labelCfg.cls += ' col-md-' + this.labelmd;
8982                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8983             }
8984             
8985             if(this.labelsm > 0){
8986                 labelCfg.cls += ' col-sm-' + this.labelsm;
8987                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8988             }
8989             
8990             if(this.labelxs > 0){
8991                 labelCfg.cls += ' col-xs-' + this.labelxs;
8992                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8993             }
8994             
8995             
8996         } else if ( this.fieldLabel.length) {
8997                 
8998             cfg.cn = [
8999                 {
9000                     tag : 'i',
9001                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9002                     tooltip : 'This field is required'
9003                 },
9004                 {
9005                     tag: 'label',
9006                    //cls : 'input-group-addon',
9007                     html : this.fieldLabel
9008
9009                 },
9010
9011                inputblock
9012
9013            ];
9014            
9015            if(this.indicatorpos == 'right'){
9016                 
9017                 cfg.cn = [
9018                     {
9019                         tag: 'label',
9020                        //cls : 'input-group-addon',
9021                         html : this.fieldLabel
9022
9023                     },
9024                     {
9025                         tag : 'i',
9026                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9027                         tooltip : 'This field is required'
9028                     },
9029
9030                    inputblock
9031
9032                ];
9033
9034             }
9035
9036         } else {
9037             
9038             cfg.cn = [
9039
9040                     inputblock
9041
9042             ];
9043                 
9044                 
9045         };
9046         
9047         if (this.parentType === 'Navbar' &&  this.parent().bar) {
9048            cfg.cls += ' navbar-form';
9049         }
9050         
9051         if (this.parentType === 'NavGroup') {
9052            cfg.cls += ' navbar-form';
9053            cfg.tag = 'li';
9054         }
9055         
9056         return cfg;
9057         
9058     },
9059     /**
9060      * return the real input element.
9061      */
9062     inputEl: function ()
9063     {
9064         return this.el.select('input.form-control',true).first();
9065     },
9066     
9067     tooltipEl : function()
9068     {
9069         return this.inputEl();
9070     },
9071     
9072     indicatorEl : function()
9073     {
9074         var indicator = this.el.select('i.roo-required-indicator',true).first();
9075         
9076         if(!indicator){
9077             return false;
9078         }
9079         
9080         return indicator;
9081         
9082     },
9083     
9084     setDisabled : function(v)
9085     {
9086         var i  = this.inputEl().dom;
9087         if (!v) {
9088             i.removeAttribute('disabled');
9089             return;
9090             
9091         }
9092         i.setAttribute('disabled','true');
9093     },
9094     initEvents : function()
9095     {
9096           
9097         this.inputEl().on("keydown" , this.fireKey,  this);
9098         this.inputEl().on("focus", this.onFocus,  this);
9099         this.inputEl().on("blur", this.onBlur,  this);
9100         
9101         this.inputEl().relayEvent('keyup', this);
9102         
9103         this.indicator = this.indicatorEl();
9104         
9105         if(this.indicator){
9106             this.indicator.addClass('invisible');
9107         }
9108  
9109         // reference to original value for reset
9110         this.originalValue = this.getValue();
9111         //Roo.form.TextField.superclass.initEvents.call(this);
9112         if(this.validationEvent == 'keyup'){
9113             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9114             this.inputEl().on('keyup', this.filterValidation, this);
9115         }
9116         else if(this.validationEvent !== false){
9117             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9118         }
9119         
9120         if(this.selectOnFocus){
9121             this.on("focus", this.preFocus, this);
9122             
9123         }
9124         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9125             this.inputEl().on("keypress", this.filterKeys, this);
9126         } else {
9127             this.inputEl().relayEvent('keypress', this);
9128         }
9129        /* if(this.grow){
9130             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
9131             this.el.on("click", this.autoSize,  this);
9132         }
9133         */
9134         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9135             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9136         }
9137         
9138         if (typeof(this.before) == 'object') {
9139             this.before.render(this.el.select('.roo-input-before',true).first());
9140         }
9141         if (typeof(this.after) == 'object') {
9142             this.after.render(this.el.select('.roo-input-after',true).first());
9143         }
9144         
9145         this.inputEl().on('change', this.onChange, this);
9146         
9147     },
9148     filterValidation : function(e){
9149         if(!e.isNavKeyPress()){
9150             this.validationTask.delay(this.validationDelay);
9151         }
9152     },
9153      /**
9154      * Validates the field value
9155      * @return {Boolean} True if the value is valid, else false
9156      */
9157     validate : function(){
9158         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9159         if(this.disabled || this.validateValue(this.getRawValue())){
9160             this.markValid();
9161             return true;
9162         }
9163         
9164         this.markInvalid();
9165         return false;
9166     },
9167     
9168     
9169     /**
9170      * Validates a value according to the field's validation rules and marks the field as invalid
9171      * if the validation fails
9172      * @param {Mixed} value The value to validate
9173      * @return {Boolean} True if the value is valid, else false
9174      */
9175     validateValue : function(value)
9176     {
9177         if(this.getVisibilityEl().hasClass('hidden')){
9178             return true;
9179         }
9180         
9181         if(value.length < 1)  { // if it's blank
9182             if(this.allowBlank){
9183                 return true;
9184             }
9185             return false;
9186         }
9187         
9188         if(value.length < this.minLength){
9189             return false;
9190         }
9191         if(value.length > this.maxLength){
9192             return false;
9193         }
9194         if(this.vtype){
9195             var vt = Roo.form.VTypes;
9196             if(!vt[this.vtype](value, this)){
9197                 return false;
9198             }
9199         }
9200         if(typeof this.validator == "function"){
9201             var msg = this.validator(value);
9202             if(msg !== true){
9203                 return false;
9204             }
9205             if (typeof(msg) == 'string') {
9206                 this.invalidText = msg;
9207             }
9208         }
9209         
9210         if(this.regex && !this.regex.test(value)){
9211             return false;
9212         }
9213         
9214         return true;
9215     },
9216     
9217      // private
9218     fireKey : function(e){
9219         //Roo.log('field ' + e.getKey());
9220         if(e.isNavKeyPress()){
9221             this.fireEvent("specialkey", this, e);
9222         }
9223     },
9224     focus : function (selectText){
9225         if(this.rendered){
9226             this.inputEl().focus();
9227             if(selectText === true){
9228                 this.inputEl().dom.select();
9229             }
9230         }
9231         return this;
9232     } ,
9233     
9234     onFocus : function(){
9235         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9236            // this.el.addClass(this.focusClass);
9237         }
9238         if(!this.hasFocus){
9239             this.hasFocus = true;
9240             this.startValue = this.getValue();
9241             this.fireEvent("focus", this);
9242         }
9243     },
9244     
9245     beforeBlur : Roo.emptyFn,
9246
9247     
9248     // private
9249     onBlur : function(){
9250         this.beforeBlur();
9251         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9252             //this.el.removeClass(this.focusClass);
9253         }
9254         this.hasFocus = false;
9255         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9256             this.validate();
9257         }
9258         var v = this.getValue();
9259         if(String(v) !== String(this.startValue)){
9260             this.fireEvent('change', this, v, this.startValue);
9261         }
9262         this.fireEvent("blur", this);
9263     },
9264     
9265     onChange : function(e)
9266     {
9267         var v = this.getValue();
9268         if(String(v) !== String(this.startValue)){
9269             this.fireEvent('change', this, v, this.startValue);
9270         }
9271         
9272     },
9273     
9274     /**
9275      * Resets the current field value to the originally loaded value and clears any validation messages
9276      */
9277     reset : function(){
9278         this.setValue(this.originalValue);
9279         this.validate();
9280     },
9281      /**
9282      * Returns the name of the field
9283      * @return {Mixed} name The name field
9284      */
9285     getName: function(){
9286         return this.name;
9287     },
9288      /**
9289      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
9290      * @return {Mixed} value The field value
9291      */
9292     getValue : function(){
9293         
9294         var v = this.inputEl().getValue();
9295         
9296         return v;
9297     },
9298     /**
9299      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
9300      * @return {Mixed} value The field value
9301      */
9302     getRawValue : function(){
9303         var v = this.inputEl().getValue();
9304         
9305         return v;
9306     },
9307     
9308     /**
9309      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
9310      * @param {Mixed} value The value to set
9311      */
9312     setRawValue : function(v){
9313         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9314     },
9315     
9316     selectText : function(start, end){
9317         var v = this.getRawValue();
9318         if(v.length > 0){
9319             start = start === undefined ? 0 : start;
9320             end = end === undefined ? v.length : end;
9321             var d = this.inputEl().dom;
9322             if(d.setSelectionRange){
9323                 d.setSelectionRange(start, end);
9324             }else if(d.createTextRange){
9325                 var range = d.createTextRange();
9326                 range.moveStart("character", start);
9327                 range.moveEnd("character", v.length-end);
9328                 range.select();
9329             }
9330         }
9331     },
9332     
9333     /**
9334      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
9335      * @param {Mixed} value The value to set
9336      */
9337     setValue : function(v){
9338         this.value = v;
9339         if(this.rendered){
9340             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9341             this.validate();
9342         }
9343     },
9344     
9345     /*
9346     processValue : function(value){
9347         if(this.stripCharsRe){
9348             var newValue = value.replace(this.stripCharsRe, '');
9349             if(newValue !== value){
9350                 this.setRawValue(newValue);
9351                 return newValue;
9352             }
9353         }
9354         return value;
9355     },
9356   */
9357     preFocus : function(){
9358         
9359         if(this.selectOnFocus){
9360             this.inputEl().dom.select();
9361         }
9362     },
9363     filterKeys : function(e){
9364         var k = e.getKey();
9365         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9366             return;
9367         }
9368         var c = e.getCharCode(), cc = String.fromCharCode(c);
9369         if(Roo.isIE && (e.isSpecialKey() || !cc)){
9370             return;
9371         }
9372         if(!this.maskRe.test(cc)){
9373             e.stopEvent();
9374         }
9375     },
9376      /**
9377      * Clear any invalid styles/messages for this field
9378      */
9379     clearInvalid : function(){
9380         
9381         if(!this.el || this.preventMark){ // not rendered
9382             return;
9383         }
9384         
9385      
9386         this.el.removeClass(this.invalidClass);
9387         
9388         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9389             
9390             var feedback = this.el.select('.form-control-feedback', true).first();
9391             
9392             if(feedback){
9393                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9394             }
9395             
9396         }
9397         
9398         this.fireEvent('valid', this);
9399     },
9400     
9401      /**
9402      * Mark this field as valid
9403      */
9404     markValid : function()
9405     {
9406         if(!this.el  || this.preventMark){ // not rendered...
9407             return;
9408         }
9409         
9410         this.el.removeClass([this.invalidClass, this.validClass]);
9411         
9412         var feedback = this.el.select('.form-control-feedback', true).first();
9413             
9414         if(feedback){
9415             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9416         }
9417         
9418         if(this.indicator){
9419             this.indicator.removeClass('visible');
9420             this.indicator.addClass('invisible');
9421         }
9422         
9423         if(this.disabled){
9424             return;
9425         }
9426         
9427         if(this.allowBlank && !this.getRawValue().length){
9428             return;
9429         }
9430         
9431         this.el.addClass(this.validClass);
9432         
9433         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9434             
9435             var feedback = this.el.select('.form-control-feedback', true).first();
9436             
9437             if(feedback){
9438                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9439                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9440             }
9441             
9442         }
9443         
9444         this.fireEvent('valid', this);
9445     },
9446     
9447      /**
9448      * Mark this field as invalid
9449      * @param {String} msg The validation message
9450      */
9451     markInvalid : function(msg)
9452     {
9453         if(!this.el  || this.preventMark){ // not rendered
9454             return;
9455         }
9456         
9457         this.el.removeClass([this.invalidClass, this.validClass]);
9458         
9459         var feedback = this.el.select('.form-control-feedback', true).first();
9460             
9461         if(feedback){
9462             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9463         }
9464
9465         if(this.disabled){
9466             return;
9467         }
9468         
9469         if(this.allowBlank && !this.getRawValue().length){
9470             return;
9471         }
9472         
9473         if(this.indicator){
9474             this.indicator.removeClass('invisible');
9475             this.indicator.addClass('visible');
9476         }
9477         
9478         this.el.addClass(this.invalidClass);
9479         
9480         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9481             
9482             var feedback = this.el.select('.form-control-feedback', true).first();
9483             
9484             if(feedback){
9485                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9486                 
9487                 if(this.getValue().length || this.forceFeedback){
9488                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9489                 }
9490                 
9491             }
9492             
9493         }
9494         
9495         this.fireEvent('invalid', this, msg);
9496     },
9497     // private
9498     SafariOnKeyDown : function(event)
9499     {
9500         // this is a workaround for a password hang bug on chrome/ webkit.
9501         if (this.inputEl().dom.type != 'password') {
9502             return;
9503         }
9504         
9505         var isSelectAll = false;
9506         
9507         if(this.inputEl().dom.selectionEnd > 0){
9508             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9509         }
9510         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9511             event.preventDefault();
9512             this.setValue('');
9513             return;
9514         }
9515         
9516         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9517             
9518             event.preventDefault();
9519             // this is very hacky as keydown always get's upper case.
9520             //
9521             var cc = String.fromCharCode(event.getCharCode());
9522             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
9523             
9524         }
9525     },
9526     adjustWidth : function(tag, w){
9527         tag = tag.toLowerCase();
9528         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9529             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9530                 if(tag == 'input'){
9531                     return w + 2;
9532                 }
9533                 if(tag == 'textarea'){
9534                     return w-2;
9535                 }
9536             }else if(Roo.isOpera){
9537                 if(tag == 'input'){
9538                     return w + 2;
9539                 }
9540                 if(tag == 'textarea'){
9541                     return w-2;
9542                 }
9543             }
9544         }
9545         return w;
9546     },
9547     
9548     setFieldLabel : function(v)
9549     {
9550         if(!this.rendered){
9551             return;
9552         }
9553         
9554         if(this.indicator){
9555             var ar = this.el.select('label > span',true);
9556             
9557             if (ar.elements.length) {
9558                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9559                 this.fieldLabel = v;
9560                 return;
9561             }
9562             
9563             var br = this.el.select('label',true);
9564             
9565             if(br.elements.length) {
9566                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9567                 this.fieldLabel = v;
9568                 return;
9569             }
9570             
9571             Roo.log('Cannot Found any of label > span || label in input');
9572             return;
9573         }
9574         
9575         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9576         this.fieldLabel = v;
9577         
9578         
9579     }
9580 });
9581
9582  
9583 /*
9584  * - LGPL
9585  *
9586  * Input
9587  * 
9588  */
9589
9590 /**
9591  * @class Roo.bootstrap.TextArea
9592  * @extends Roo.bootstrap.Input
9593  * Bootstrap TextArea class
9594  * @cfg {Number} cols Specifies the visible width of a text area
9595  * @cfg {Number} rows Specifies the visible number of lines in a text area
9596  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9597  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9598  * @cfg {string} html text
9599  * 
9600  * @constructor
9601  * Create a new TextArea
9602  * @param {Object} config The config object
9603  */
9604
9605 Roo.bootstrap.TextArea = function(config){
9606     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9607    
9608 };
9609
9610 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
9611      
9612     cols : false,
9613     rows : 5,
9614     readOnly : false,
9615     warp : 'soft',
9616     resize : false,
9617     value: false,
9618     html: false,
9619     
9620     getAutoCreate : function(){
9621         
9622         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9623         
9624         var id = Roo.id();
9625         
9626         var cfg = {};
9627         
9628         if(this.inputType != 'hidden'){
9629             cfg.cls = 'form-group' //input-group
9630         }
9631         
9632         var input =  {
9633             tag: 'textarea',
9634             id : id,
9635             warp : this.warp,
9636             rows : this.rows,
9637             value : this.value || '',
9638             html: this.html || '',
9639             cls : 'form-control',
9640             placeholder : this.placeholder || '' 
9641             
9642         };
9643         
9644         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9645             input.maxLength = this.maxLength;
9646         }
9647         
9648         if(this.resize){
9649             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9650         }
9651         
9652         if(this.cols){
9653             input.cols = this.cols;
9654         }
9655         
9656         if (this.readOnly) {
9657             input.readonly = true;
9658         }
9659         
9660         if (this.name) {
9661             input.name = this.name;
9662         }
9663         
9664         if (this.size) {
9665             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9666         }
9667         
9668         var settings=this;
9669         ['xs','sm','md','lg'].map(function(size){
9670             if (settings[size]) {
9671                 cfg.cls += ' col-' + size + '-' + settings[size];
9672             }
9673         });
9674         
9675         var inputblock = input;
9676         
9677         if(this.hasFeedback && !this.allowBlank){
9678             
9679             var feedback = {
9680                 tag: 'span',
9681                 cls: 'glyphicon form-control-feedback'
9682             };
9683
9684             inputblock = {
9685                 cls : 'has-feedback',
9686                 cn :  [
9687                     input,
9688                     feedback
9689                 ] 
9690             };  
9691         }
9692         
9693         
9694         if (this.before || this.after) {
9695             
9696             inputblock = {
9697                 cls : 'input-group',
9698                 cn :  [] 
9699             };
9700             if (this.before) {
9701                 inputblock.cn.push({
9702                     tag :'span',
9703                     cls : 'input-group-addon',
9704                     html : this.before
9705                 });
9706             }
9707             
9708             inputblock.cn.push(input);
9709             
9710             if(this.hasFeedback && !this.allowBlank){
9711                 inputblock.cls += ' has-feedback';
9712                 inputblock.cn.push(feedback);
9713             }
9714             
9715             if (this.after) {
9716                 inputblock.cn.push({
9717                     tag :'span',
9718                     cls : 'input-group-addon',
9719                     html : this.after
9720                 });
9721             }
9722             
9723         }
9724         
9725         if (align ==='left' && this.fieldLabel.length) {
9726             cfg.cn = [
9727                 {
9728                     tag: 'label',
9729                     'for' :  id,
9730                     cls : 'control-label',
9731                     html : this.fieldLabel
9732                 },
9733                 {
9734                     cls : "",
9735                     cn: [
9736                         inputblock
9737                     ]
9738                 }
9739
9740             ];
9741             
9742             if(this.labelWidth > 12){
9743                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9744             }
9745
9746             if(this.labelWidth < 13 && this.labelmd == 0){
9747                 this.labelmd = this.labelWidth;
9748             }
9749
9750             if(this.labellg > 0){
9751                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9752                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9753             }
9754
9755             if(this.labelmd > 0){
9756                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9757                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9758             }
9759
9760             if(this.labelsm > 0){
9761                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9762                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9763             }
9764
9765             if(this.labelxs > 0){
9766                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9767                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9768             }
9769             
9770         } else if ( this.fieldLabel.length) {
9771             cfg.cn = [
9772
9773                {
9774                    tag: 'label',
9775                    //cls : 'input-group-addon',
9776                    html : this.fieldLabel
9777
9778                },
9779
9780                inputblock
9781
9782            ];
9783
9784         } else {
9785
9786             cfg.cn = [
9787
9788                 inputblock
9789
9790             ];
9791                 
9792         }
9793         
9794         if (this.disabled) {
9795             input.disabled=true;
9796         }
9797         
9798         return cfg;
9799         
9800     },
9801     /**
9802      * return the real textarea element.
9803      */
9804     inputEl: function ()
9805     {
9806         return this.el.select('textarea.form-control',true).first();
9807     },
9808     
9809     /**
9810      * Clear any invalid styles/messages for this field
9811      */
9812     clearInvalid : function()
9813     {
9814         
9815         if(!this.el || this.preventMark){ // not rendered
9816             return;
9817         }
9818         
9819         var label = this.el.select('label', true).first();
9820         var icon = this.el.select('i.fa-star', true).first();
9821         
9822         if(label && icon){
9823             icon.remove();
9824         }
9825         
9826         this.el.removeClass(this.invalidClass);
9827         
9828         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9829             
9830             var feedback = this.el.select('.form-control-feedback', true).first();
9831             
9832             if(feedback){
9833                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9834             }
9835             
9836         }
9837         
9838         this.fireEvent('valid', this);
9839     },
9840     
9841      /**
9842      * Mark this field as valid
9843      */
9844     markValid : function()
9845     {
9846         if(!this.el  || this.preventMark){ // not rendered
9847             return;
9848         }
9849         
9850         this.el.removeClass([this.invalidClass, this.validClass]);
9851         
9852         var feedback = this.el.select('.form-control-feedback', true).first();
9853             
9854         if(feedback){
9855             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9856         }
9857
9858         if(this.disabled || this.allowBlank){
9859             return;
9860         }
9861         
9862         var label = this.el.select('label', true).first();
9863         var icon = this.el.select('i.fa-star', true).first();
9864         
9865         if(label && icon){
9866             icon.remove();
9867         }
9868         
9869         this.el.addClass(this.validClass);
9870         
9871         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9872             
9873             var feedback = this.el.select('.form-control-feedback', true).first();
9874             
9875             if(feedback){
9876                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9877                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9878             }
9879             
9880         }
9881         
9882         this.fireEvent('valid', this);
9883     },
9884     
9885      /**
9886      * Mark this field as invalid
9887      * @param {String} msg The validation message
9888      */
9889     markInvalid : function(msg)
9890     {
9891         if(!this.el  || this.preventMark){ // not rendered
9892             return;
9893         }
9894         
9895         this.el.removeClass([this.invalidClass, this.validClass]);
9896         
9897         var feedback = this.el.select('.form-control-feedback', true).first();
9898             
9899         if(feedback){
9900             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9901         }
9902
9903         if(this.disabled || this.allowBlank){
9904             return;
9905         }
9906         
9907         var label = this.el.select('label', true).first();
9908         var icon = this.el.select('i.fa-star', true).first();
9909         
9910         if(!this.getValue().length && label && !icon){
9911             this.el.createChild({
9912                 tag : 'i',
9913                 cls : 'text-danger fa fa-lg fa-star',
9914                 tooltip : 'This field is required',
9915                 style : 'margin-right:5px;'
9916             }, label, true);
9917         }
9918
9919         this.el.addClass(this.invalidClass);
9920         
9921         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9922             
9923             var feedback = this.el.select('.form-control-feedback', true).first();
9924             
9925             if(feedback){
9926                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9927                 
9928                 if(this.getValue().length || this.forceFeedback){
9929                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9930                 }
9931                 
9932             }
9933             
9934         }
9935         
9936         this.fireEvent('invalid', this, msg);
9937     }
9938 });
9939
9940  
9941 /*
9942  * - LGPL
9943  *
9944  * trigger field - base class for combo..
9945  * 
9946  */
9947  
9948 /**
9949  * @class Roo.bootstrap.TriggerField
9950  * @extends Roo.bootstrap.Input
9951  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9952  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9953  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9954  * for which you can provide a custom implementation.  For example:
9955  * <pre><code>
9956 var trigger = new Roo.bootstrap.TriggerField();
9957 trigger.onTriggerClick = myTriggerFn;
9958 trigger.applyTo('my-field');
9959 </code></pre>
9960  *
9961  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9962  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9963  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
9964  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9965  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9966
9967  * @constructor
9968  * Create a new TriggerField.
9969  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9970  * to the base TextField)
9971  */
9972 Roo.bootstrap.TriggerField = function(config){
9973     this.mimicing = false;
9974     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9975 };
9976
9977 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
9978     /**
9979      * @cfg {String} triggerClass A CSS class to apply to the trigger
9980      */
9981      /**
9982      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9983      */
9984     hideTrigger:false,
9985
9986     /**
9987      * @cfg {Boolean} removable (true|false) special filter default false
9988      */
9989     removable : false,
9990     
9991     /** @cfg {Boolean} grow @hide */
9992     /** @cfg {Number} growMin @hide */
9993     /** @cfg {Number} growMax @hide */
9994
9995     /**
9996      * @hide 
9997      * @method
9998      */
9999     autoSize: Roo.emptyFn,
10000     // private
10001     monitorTab : true,
10002     // private
10003     deferHeight : true,
10004
10005     
10006     actionMode : 'wrap',
10007     
10008     caret : false,
10009     
10010     
10011     getAutoCreate : function(){
10012        
10013         var align = this.labelAlign || this.parentLabelAlign();
10014         
10015         var id = Roo.id();
10016         
10017         var cfg = {
10018             cls: 'form-group' //input-group
10019         };
10020         
10021         
10022         var input =  {
10023             tag: 'input',
10024             id : id,
10025             type : this.inputType,
10026             cls : 'form-control',
10027             autocomplete: 'new-password',
10028             placeholder : this.placeholder || '' 
10029             
10030         };
10031         if (this.name) {
10032             input.name = this.name;
10033         }
10034         if (this.size) {
10035             input.cls += ' input-' + this.size;
10036         }
10037         
10038         if (this.disabled) {
10039             input.disabled=true;
10040         }
10041         
10042         var inputblock = input;
10043         
10044         if(this.hasFeedback && !this.allowBlank){
10045             
10046             var feedback = {
10047                 tag: 'span',
10048                 cls: 'glyphicon form-control-feedback'
10049             };
10050             
10051             if(this.removable && !this.editable && !this.tickable){
10052                 inputblock = {
10053                     cls : 'has-feedback',
10054                     cn :  [
10055                         inputblock,
10056                         {
10057                             tag: 'button',
10058                             html : 'x',
10059                             cls : 'roo-combo-removable-btn close'
10060                         },
10061                         feedback
10062                     ] 
10063                 };
10064             } else {
10065                 inputblock = {
10066                     cls : 'has-feedback',
10067                     cn :  [
10068                         inputblock,
10069                         feedback
10070                     ] 
10071                 };
10072             }
10073
10074         } else {
10075             if(this.removable && !this.editable && !this.tickable){
10076                 inputblock = {
10077                     cls : 'roo-removable',
10078                     cn :  [
10079                         inputblock,
10080                         {
10081                             tag: 'button',
10082                             html : 'x',
10083                             cls : 'roo-combo-removable-btn close'
10084                         }
10085                     ] 
10086                 };
10087             }
10088         }
10089         
10090         if (this.before || this.after) {
10091             
10092             inputblock = {
10093                 cls : 'input-group',
10094                 cn :  [] 
10095             };
10096             if (this.before) {
10097                 inputblock.cn.push({
10098                     tag :'span',
10099                     cls : 'input-group-addon',
10100                     html : this.before
10101                 });
10102             }
10103             
10104             inputblock.cn.push(input);
10105             
10106             if(this.hasFeedback && !this.allowBlank){
10107                 inputblock.cls += ' has-feedback';
10108                 inputblock.cn.push(feedback);
10109             }
10110             
10111             if (this.after) {
10112                 inputblock.cn.push({
10113                     tag :'span',
10114                     cls : 'input-group-addon',
10115                     html : this.after
10116                 });
10117             }
10118             
10119         };
10120         
10121         var box = {
10122             tag: 'div',
10123             cn: [
10124                 {
10125                     tag: 'input',
10126                     type : 'hidden',
10127                     cls: 'form-hidden-field'
10128                 },
10129                 inputblock
10130             ]
10131             
10132         };
10133         
10134         if(this.multiple){
10135             box = {
10136                 tag: 'div',
10137                 cn: [
10138                     {
10139                         tag: 'input',
10140                         type : 'hidden',
10141                         cls: 'form-hidden-field'
10142                     },
10143                     {
10144                         tag: 'ul',
10145                         cls: 'roo-select2-choices',
10146                         cn:[
10147                             {
10148                                 tag: 'li',
10149                                 cls: 'roo-select2-search-field',
10150                                 cn: [
10151
10152                                     inputblock
10153                                 ]
10154                             }
10155                         ]
10156                     }
10157                 ]
10158             }
10159         };
10160         
10161         var combobox = {
10162             cls: 'roo-select2-container input-group',
10163             cn: [
10164                 box
10165 //                {
10166 //                    tag: 'ul',
10167 //                    cls: 'typeahead typeahead-long dropdown-menu',
10168 //                    style: 'display:none'
10169 //                }
10170             ]
10171         };
10172         
10173         if(!this.multiple && this.showToggleBtn){
10174             
10175             var caret = {
10176                         tag: 'span',
10177                         cls: 'caret'
10178              };
10179             if (this.caret != false) {
10180                 caret = {
10181                      tag: 'i',
10182                      cls: 'fa fa-' + this.caret
10183                 };
10184                 
10185             }
10186             
10187             combobox.cn.push({
10188                 tag :'span',
10189                 cls : 'input-group-addon btn dropdown-toggle',
10190                 cn : [
10191                     caret,
10192                     {
10193                         tag: 'span',
10194                         cls: 'combobox-clear',
10195                         cn  : [
10196                             {
10197                                 tag : 'i',
10198                                 cls: 'icon-remove'
10199                             }
10200                         ]
10201                     }
10202                 ]
10203
10204             })
10205         }
10206         
10207         if(this.multiple){
10208             combobox.cls += ' roo-select2-container-multi';
10209         }
10210         
10211         if (align ==='left' && this.fieldLabel.length) {
10212             
10213             cfg.cls += ' roo-form-group-label-left';
10214
10215             cfg.cn = [
10216                 {
10217                     tag : 'i',
10218                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10219                     tooltip : 'This field is required'
10220                 },
10221                 {
10222                     tag: 'label',
10223                     'for' :  id,
10224                     cls : 'control-label',
10225                     html : this.fieldLabel
10226
10227                 },
10228                 {
10229                     cls : "", 
10230                     cn: [
10231                         combobox
10232                     ]
10233                 }
10234
10235             ];
10236             
10237             var labelCfg = cfg.cn[1];
10238             var contentCfg = cfg.cn[2];
10239             
10240             if(this.indicatorpos == 'right'){
10241                 cfg.cn = [
10242                     {
10243                         tag: 'label',
10244                         'for' :  id,
10245                         cls : 'control-label',
10246                         cn : [
10247                             {
10248                                 tag : 'span',
10249                                 html : this.fieldLabel
10250                             },
10251                             {
10252                                 tag : 'i',
10253                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10254                                 tooltip : 'This field is required'
10255                             }
10256                         ]
10257                     },
10258                     {
10259                         cls : "", 
10260                         cn: [
10261                             combobox
10262                         ]
10263                     }
10264
10265                 ];
10266                 
10267                 labelCfg = cfg.cn[0];
10268                 contentCfg = cfg.cn[1];
10269             }
10270             
10271             if(this.labelWidth > 12){
10272                 labelCfg.style = "width: " + this.labelWidth + 'px';
10273             }
10274             
10275             if(this.labelWidth < 13 && this.labelmd == 0){
10276                 this.labelmd = this.labelWidth;
10277             }
10278             
10279             if(this.labellg > 0){
10280                 labelCfg.cls += ' col-lg-' + this.labellg;
10281                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10282             }
10283             
10284             if(this.labelmd > 0){
10285                 labelCfg.cls += ' col-md-' + this.labelmd;
10286                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10287             }
10288             
10289             if(this.labelsm > 0){
10290                 labelCfg.cls += ' col-sm-' + this.labelsm;
10291                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10292             }
10293             
10294             if(this.labelxs > 0){
10295                 labelCfg.cls += ' col-xs-' + this.labelxs;
10296                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10297             }
10298             
10299         } else if ( this.fieldLabel.length) {
10300 //                Roo.log(" label");
10301             cfg.cn = [
10302                 {
10303                    tag : 'i',
10304                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10305                    tooltip : 'This field is required'
10306                },
10307                {
10308                    tag: 'label',
10309                    //cls : 'input-group-addon',
10310                    html : this.fieldLabel
10311
10312                },
10313
10314                combobox
10315
10316             ];
10317             
10318             if(this.indicatorpos == 'right'){
10319                 
10320                 cfg.cn = [
10321                     {
10322                        tag: 'label',
10323                        cn : [
10324                            {
10325                                tag : 'span',
10326                                html : this.fieldLabel
10327                            },
10328                            {
10329                               tag : 'i',
10330                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10331                               tooltip : 'This field is required'
10332                            }
10333                        ]
10334
10335                     },
10336                     combobox
10337
10338                 ];
10339
10340             }
10341
10342         } else {
10343             
10344 //                Roo.log(" no label && no align");
10345                 cfg = combobox
10346                      
10347                 
10348         }
10349         
10350         var settings=this;
10351         ['xs','sm','md','lg'].map(function(size){
10352             if (settings[size]) {
10353                 cfg.cls += ' col-' + size + '-' + settings[size];
10354             }
10355         });
10356         
10357         return cfg;
10358         
10359     },
10360     
10361     
10362     
10363     // private
10364     onResize : function(w, h){
10365 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10366 //        if(typeof w == 'number'){
10367 //            var x = w - this.trigger.getWidth();
10368 //            this.inputEl().setWidth(this.adjustWidth('input', x));
10369 //            this.trigger.setStyle('left', x+'px');
10370 //        }
10371     },
10372
10373     // private
10374     adjustSize : Roo.BoxComponent.prototype.adjustSize,
10375
10376     // private
10377     getResizeEl : function(){
10378         return this.inputEl();
10379     },
10380
10381     // private
10382     getPositionEl : function(){
10383         return this.inputEl();
10384     },
10385
10386     // private
10387     alignErrorIcon : function(){
10388         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10389     },
10390
10391     // private
10392     initEvents : function(){
10393         
10394         this.createList();
10395         
10396         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10397         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10398         if(!this.multiple && this.showToggleBtn){
10399             this.trigger = this.el.select('span.dropdown-toggle',true).first();
10400             if(this.hideTrigger){
10401                 this.trigger.setDisplayed(false);
10402             }
10403             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10404         }
10405         
10406         if(this.multiple){
10407             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10408         }
10409         
10410         if(this.removable && !this.editable && !this.tickable){
10411             var close = this.closeTriggerEl();
10412             
10413             if(close){
10414                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10415                 close.on('click', this.removeBtnClick, this, close);
10416             }
10417         }
10418         
10419         //this.trigger.addClassOnOver('x-form-trigger-over');
10420         //this.trigger.addClassOnClick('x-form-trigger-click');
10421         
10422         //if(!this.width){
10423         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10424         //}
10425     },
10426     
10427     closeTriggerEl : function()
10428     {
10429         var close = this.el.select('.roo-combo-removable-btn', true).first();
10430         return close ? close : false;
10431     },
10432     
10433     removeBtnClick : function(e, h, el)
10434     {
10435         e.preventDefault();
10436         
10437         if(this.fireEvent("remove", this) !== false){
10438             this.reset();
10439             this.fireEvent("afterremove", this)
10440         }
10441     },
10442     
10443     createList : function()
10444     {
10445         this.list = Roo.get(document.body).createChild({
10446             tag: 'ul',
10447             cls: 'typeahead typeahead-long dropdown-menu',
10448             style: 'display:none'
10449         });
10450         
10451         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10452         
10453     },
10454
10455     // private
10456     initTrigger : function(){
10457        
10458     },
10459
10460     // private
10461     onDestroy : function(){
10462         if(this.trigger){
10463             this.trigger.removeAllListeners();
10464           //  this.trigger.remove();
10465         }
10466         //if(this.wrap){
10467         //    this.wrap.remove();
10468         //}
10469         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10470     },
10471
10472     // private
10473     onFocus : function(){
10474         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10475         /*
10476         if(!this.mimicing){
10477             this.wrap.addClass('x-trigger-wrap-focus');
10478             this.mimicing = true;
10479             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10480             if(this.monitorTab){
10481                 this.el.on("keydown", this.checkTab, this);
10482             }
10483         }
10484         */
10485     },
10486
10487     // private
10488     checkTab : function(e){
10489         if(e.getKey() == e.TAB){
10490             this.triggerBlur();
10491         }
10492     },
10493
10494     // private
10495     onBlur : function(){
10496         // do nothing
10497     },
10498
10499     // private
10500     mimicBlur : function(e, t){
10501         /*
10502         if(!this.wrap.contains(t) && this.validateBlur()){
10503             this.triggerBlur();
10504         }
10505         */
10506     },
10507
10508     // private
10509     triggerBlur : function(){
10510         this.mimicing = false;
10511         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10512         if(this.monitorTab){
10513             this.el.un("keydown", this.checkTab, this);
10514         }
10515         //this.wrap.removeClass('x-trigger-wrap-focus');
10516         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10517     },
10518
10519     // private
10520     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10521     validateBlur : function(e, t){
10522         return true;
10523     },
10524
10525     // private
10526     onDisable : function(){
10527         this.inputEl().dom.disabled = true;
10528         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10529         //if(this.wrap){
10530         //    this.wrap.addClass('x-item-disabled');
10531         //}
10532     },
10533
10534     // private
10535     onEnable : function(){
10536         this.inputEl().dom.disabled = false;
10537         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10538         //if(this.wrap){
10539         //    this.el.removeClass('x-item-disabled');
10540         //}
10541     },
10542
10543     // private
10544     onShow : function(){
10545         var ae = this.getActionEl();
10546         
10547         if(ae){
10548             ae.dom.style.display = '';
10549             ae.dom.style.visibility = 'visible';
10550         }
10551     },
10552
10553     // private
10554     
10555     onHide : function(){
10556         var ae = this.getActionEl();
10557         ae.dom.style.display = 'none';
10558     },
10559
10560     /**
10561      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
10562      * by an implementing function.
10563      * @method
10564      * @param {EventObject} e
10565      */
10566     onTriggerClick : Roo.emptyFn
10567 });
10568  /*
10569  * Based on:
10570  * Ext JS Library 1.1.1
10571  * Copyright(c) 2006-2007, Ext JS, LLC.
10572  *
10573  * Originally Released Under LGPL - original licence link has changed is not relivant.
10574  *
10575  * Fork - LGPL
10576  * <script type="text/javascript">
10577  */
10578
10579
10580 /**
10581  * @class Roo.data.SortTypes
10582  * @singleton
10583  * Defines the default sorting (casting?) comparison functions used when sorting data.
10584  */
10585 Roo.data.SortTypes = {
10586     /**
10587      * Default sort that does nothing
10588      * @param {Mixed} s The value being converted
10589      * @return {Mixed} The comparison value
10590      */
10591     none : function(s){
10592         return s;
10593     },
10594     
10595     /**
10596      * The regular expression used to strip tags
10597      * @type {RegExp}
10598      * @property
10599      */
10600     stripTagsRE : /<\/?[^>]+>/gi,
10601     
10602     /**
10603      * Strips all HTML tags to sort on text only
10604      * @param {Mixed} s The value being converted
10605      * @return {String} The comparison value
10606      */
10607     asText : function(s){
10608         return String(s).replace(this.stripTagsRE, "");
10609     },
10610     
10611     /**
10612      * Strips all HTML tags to sort on text only - Case insensitive
10613      * @param {Mixed} s The value being converted
10614      * @return {String} The comparison value
10615      */
10616     asUCText : function(s){
10617         return String(s).toUpperCase().replace(this.stripTagsRE, "");
10618     },
10619     
10620     /**
10621      * Case insensitive string
10622      * @param {Mixed} s The value being converted
10623      * @return {String} The comparison value
10624      */
10625     asUCString : function(s) {
10626         return String(s).toUpperCase();
10627     },
10628     
10629     /**
10630      * Date sorting
10631      * @param {Mixed} s The value being converted
10632      * @return {Number} The comparison value
10633      */
10634     asDate : function(s) {
10635         if(!s){
10636             return 0;
10637         }
10638         if(s instanceof Date){
10639             return s.getTime();
10640         }
10641         return Date.parse(String(s));
10642     },
10643     
10644     /**
10645      * Float sorting
10646      * @param {Mixed} s The value being converted
10647      * @return {Float} The comparison value
10648      */
10649     asFloat : function(s) {
10650         var val = parseFloat(String(s).replace(/,/g, ""));
10651         if(isNaN(val)) {
10652             val = 0;
10653         }
10654         return val;
10655     },
10656     
10657     /**
10658      * Integer sorting
10659      * @param {Mixed} s The value being converted
10660      * @return {Number} The comparison value
10661      */
10662     asInt : function(s) {
10663         var val = parseInt(String(s).replace(/,/g, ""));
10664         if(isNaN(val)) {
10665             val = 0;
10666         }
10667         return val;
10668     }
10669 };/*
10670  * Based on:
10671  * Ext JS Library 1.1.1
10672  * Copyright(c) 2006-2007, Ext JS, LLC.
10673  *
10674  * Originally Released Under LGPL - original licence link has changed is not relivant.
10675  *
10676  * Fork - LGPL
10677  * <script type="text/javascript">
10678  */
10679
10680 /**
10681 * @class Roo.data.Record
10682  * Instances of this class encapsulate both record <em>definition</em> information, and record
10683  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10684  * to access Records cached in an {@link Roo.data.Store} object.<br>
10685  * <p>
10686  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10687  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10688  * objects.<br>
10689  * <p>
10690  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10691  * @constructor
10692  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10693  * {@link #create}. The parameters are the same.
10694  * @param {Array} data An associative Array of data values keyed by the field name.
10695  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10696  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10697  * not specified an integer id is generated.
10698  */
10699 Roo.data.Record = function(data, id){
10700     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10701     this.data = data;
10702 };
10703
10704 /**
10705  * Generate a constructor for a specific record layout.
10706  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10707  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10708  * Each field definition object may contain the following properties: <ul>
10709  * <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,
10710  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10711  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10712  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10713  * is being used, then this is a string containing the javascript expression to reference the data relative to 
10714  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10715  * to the data item relative to the record element. If the mapping expression is the same as the field name,
10716  * this may be omitted.</p></li>
10717  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10718  * <ul><li>auto (Default, implies no conversion)</li>
10719  * <li>string</li>
10720  * <li>int</li>
10721  * <li>float</li>
10722  * <li>boolean</li>
10723  * <li>date</li></ul></p></li>
10724  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10725  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10726  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10727  * by the Reader into an object that will be stored in the Record. It is passed the
10728  * following parameters:<ul>
10729  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10730  * </ul></p></li>
10731  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10732  * </ul>
10733  * <br>usage:<br><pre><code>
10734 var TopicRecord = Roo.data.Record.create(
10735     {name: 'title', mapping: 'topic_title'},
10736     {name: 'author', mapping: 'username'},
10737     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10738     {name: 'lastPost', mapping: 'post_time', type: 'date'},
10739     {name: 'lastPoster', mapping: 'user2'},
10740     {name: 'excerpt', mapping: 'post_text'}
10741 );
10742
10743 var myNewRecord = new TopicRecord({
10744     title: 'Do my job please',
10745     author: 'noobie',
10746     totalPosts: 1,
10747     lastPost: new Date(),
10748     lastPoster: 'Animal',
10749     excerpt: 'No way dude!'
10750 });
10751 myStore.add(myNewRecord);
10752 </code></pre>
10753  * @method create
10754  * @static
10755  */
10756 Roo.data.Record.create = function(o){
10757     var f = function(){
10758         f.superclass.constructor.apply(this, arguments);
10759     };
10760     Roo.extend(f, Roo.data.Record);
10761     var p = f.prototype;
10762     p.fields = new Roo.util.MixedCollection(false, function(field){
10763         return field.name;
10764     });
10765     for(var i = 0, len = o.length; i < len; i++){
10766         p.fields.add(new Roo.data.Field(o[i]));
10767     }
10768     f.getField = function(name){
10769         return p.fields.get(name);  
10770     };
10771     return f;
10772 };
10773
10774 Roo.data.Record.AUTO_ID = 1000;
10775 Roo.data.Record.EDIT = 'edit';
10776 Roo.data.Record.REJECT = 'reject';
10777 Roo.data.Record.COMMIT = 'commit';
10778
10779 Roo.data.Record.prototype = {
10780     /**
10781      * Readonly flag - true if this record has been modified.
10782      * @type Boolean
10783      */
10784     dirty : false,
10785     editing : false,
10786     error: null,
10787     modified: null,
10788
10789     // private
10790     join : function(store){
10791         this.store = store;
10792     },
10793
10794     /**
10795      * Set the named field to the specified value.
10796      * @param {String} name The name of the field to set.
10797      * @param {Object} value The value to set the field to.
10798      */
10799     set : function(name, value){
10800         if(this.data[name] == value){
10801             return;
10802         }
10803         this.dirty = true;
10804         if(!this.modified){
10805             this.modified = {};
10806         }
10807         if(typeof this.modified[name] == 'undefined'){
10808             this.modified[name] = this.data[name];
10809         }
10810         this.data[name] = value;
10811         if(!this.editing && this.store){
10812             this.store.afterEdit(this);
10813         }       
10814     },
10815
10816     /**
10817      * Get the value of the named field.
10818      * @param {String} name The name of the field to get the value of.
10819      * @return {Object} The value of the field.
10820      */
10821     get : function(name){
10822         return this.data[name]; 
10823     },
10824
10825     // private
10826     beginEdit : function(){
10827         this.editing = true;
10828         this.modified = {}; 
10829     },
10830
10831     // private
10832     cancelEdit : function(){
10833         this.editing = false;
10834         delete this.modified;
10835     },
10836
10837     // private
10838     endEdit : function(){
10839         this.editing = false;
10840         if(this.dirty && this.store){
10841             this.store.afterEdit(this);
10842         }
10843     },
10844
10845     /**
10846      * Usually called by the {@link Roo.data.Store} which owns the Record.
10847      * Rejects all changes made to the Record since either creation, or the last commit operation.
10848      * Modified fields are reverted to their original values.
10849      * <p>
10850      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10851      * of reject operations.
10852      */
10853     reject : function(){
10854         var m = this.modified;
10855         for(var n in m){
10856             if(typeof m[n] != "function"){
10857                 this.data[n] = m[n];
10858             }
10859         }
10860         this.dirty = false;
10861         delete this.modified;
10862         this.editing = false;
10863         if(this.store){
10864             this.store.afterReject(this);
10865         }
10866     },
10867
10868     /**
10869      * Usually called by the {@link Roo.data.Store} which owns the Record.
10870      * Commits all changes made to the Record since either creation, or the last commit operation.
10871      * <p>
10872      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10873      * of commit operations.
10874      */
10875     commit : function(){
10876         this.dirty = false;
10877         delete this.modified;
10878         this.editing = false;
10879         if(this.store){
10880             this.store.afterCommit(this);
10881         }
10882     },
10883
10884     // private
10885     hasError : function(){
10886         return this.error != null;
10887     },
10888
10889     // private
10890     clearError : function(){
10891         this.error = null;
10892     },
10893
10894     /**
10895      * Creates a copy of this record.
10896      * @param {String} id (optional) A new record id if you don't want to use this record's id
10897      * @return {Record}
10898      */
10899     copy : function(newId) {
10900         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10901     }
10902 };/*
10903  * Based on:
10904  * Ext JS Library 1.1.1
10905  * Copyright(c) 2006-2007, Ext JS, LLC.
10906  *
10907  * Originally Released Under LGPL - original licence link has changed is not relivant.
10908  *
10909  * Fork - LGPL
10910  * <script type="text/javascript">
10911  */
10912
10913
10914
10915 /**
10916  * @class Roo.data.Store
10917  * @extends Roo.util.Observable
10918  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10919  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10920  * <p>
10921  * 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
10922  * has no knowledge of the format of the data returned by the Proxy.<br>
10923  * <p>
10924  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10925  * instances from the data object. These records are cached and made available through accessor functions.
10926  * @constructor
10927  * Creates a new Store.
10928  * @param {Object} config A config object containing the objects needed for the Store to access data,
10929  * and read the data into Records.
10930  */
10931 Roo.data.Store = function(config){
10932     this.data = new Roo.util.MixedCollection(false);
10933     this.data.getKey = function(o){
10934         return o.id;
10935     };
10936     this.baseParams = {};
10937     // private
10938     this.paramNames = {
10939         "start" : "start",
10940         "limit" : "limit",
10941         "sort" : "sort",
10942         "dir" : "dir",
10943         "multisort" : "_multisort"
10944     };
10945
10946     if(config && config.data){
10947         this.inlineData = config.data;
10948         delete config.data;
10949     }
10950
10951     Roo.apply(this, config);
10952     
10953     if(this.reader){ // reader passed
10954         this.reader = Roo.factory(this.reader, Roo.data);
10955         this.reader.xmodule = this.xmodule || false;
10956         if(!this.recordType){
10957             this.recordType = this.reader.recordType;
10958         }
10959         if(this.reader.onMetaChange){
10960             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10961         }
10962     }
10963
10964     if(this.recordType){
10965         this.fields = this.recordType.prototype.fields;
10966     }
10967     this.modified = [];
10968
10969     this.addEvents({
10970         /**
10971          * @event datachanged
10972          * Fires when the data cache has changed, and a widget which is using this Store
10973          * as a Record cache should refresh its view.
10974          * @param {Store} this
10975          */
10976         datachanged : true,
10977         /**
10978          * @event metachange
10979          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10980          * @param {Store} this
10981          * @param {Object} meta The JSON metadata
10982          */
10983         metachange : true,
10984         /**
10985          * @event add
10986          * Fires when Records have been added to the Store
10987          * @param {Store} this
10988          * @param {Roo.data.Record[]} records The array of Records added
10989          * @param {Number} index The index at which the record(s) were added
10990          */
10991         add : true,
10992         /**
10993          * @event remove
10994          * Fires when a Record has been removed from the Store
10995          * @param {Store} this
10996          * @param {Roo.data.Record} record The Record that was removed
10997          * @param {Number} index The index at which the record was removed
10998          */
10999         remove : true,
11000         /**
11001          * @event update
11002          * Fires when a Record has been updated
11003          * @param {Store} this
11004          * @param {Roo.data.Record} record The Record that was updated
11005          * @param {String} operation The update operation being performed.  Value may be one of:
11006          * <pre><code>
11007  Roo.data.Record.EDIT
11008  Roo.data.Record.REJECT
11009  Roo.data.Record.COMMIT
11010          * </code></pre>
11011          */
11012         update : true,
11013         /**
11014          * @event clear
11015          * Fires when the data cache has been cleared.
11016          * @param {Store} this
11017          */
11018         clear : true,
11019         /**
11020          * @event beforeload
11021          * Fires before a request is made for a new data object.  If the beforeload handler returns false
11022          * the load action will be canceled.
11023          * @param {Store} this
11024          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11025          */
11026         beforeload : true,
11027         /**
11028          * @event beforeloadadd
11029          * Fires after a new set of Records has been loaded.
11030          * @param {Store} this
11031          * @param {Roo.data.Record[]} records The Records that were loaded
11032          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11033          */
11034         beforeloadadd : true,
11035         /**
11036          * @event load
11037          * Fires after a new set of Records has been loaded, before they are added to the store.
11038          * @param {Store} this
11039          * @param {Roo.data.Record[]} records The Records that were loaded
11040          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11041          * @params {Object} return from reader
11042          */
11043         load : true,
11044         /**
11045          * @event loadexception
11046          * Fires if an exception occurs in the Proxy during loading.
11047          * Called with the signature of the Proxy's "loadexception" event.
11048          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11049          * 
11050          * @param {Proxy} 
11051          * @param {Object} return from JsonData.reader() - success, totalRecords, records
11052          * @param {Object} load options 
11053          * @param {Object} jsonData from your request (normally this contains the Exception)
11054          */
11055         loadexception : true
11056     });
11057     
11058     if(this.proxy){
11059         this.proxy = Roo.factory(this.proxy, Roo.data);
11060         this.proxy.xmodule = this.xmodule || false;
11061         this.relayEvents(this.proxy,  ["loadexception"]);
11062     }
11063     this.sortToggle = {};
11064     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11065
11066     Roo.data.Store.superclass.constructor.call(this);
11067
11068     if(this.inlineData){
11069         this.loadData(this.inlineData);
11070         delete this.inlineData;
11071     }
11072 };
11073
11074 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11075      /**
11076     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
11077     * without a remote query - used by combo/forms at present.
11078     */
11079     
11080     /**
11081     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11082     */
11083     /**
11084     * @cfg {Array} data Inline data to be loaded when the store is initialized.
11085     */
11086     /**
11087     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11088     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11089     */
11090     /**
11091     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11092     * on any HTTP request
11093     */
11094     /**
11095     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11096     */
11097     /**
11098     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11099     */
11100     multiSort: false,
11101     /**
11102     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11103     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11104     */
11105     remoteSort : false,
11106
11107     /**
11108     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11109      * loaded or when a record is removed. (defaults to false).
11110     */
11111     pruneModifiedRecords : false,
11112
11113     // private
11114     lastOptions : null,
11115
11116     /**
11117      * Add Records to the Store and fires the add event.
11118      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11119      */
11120     add : function(records){
11121         records = [].concat(records);
11122         for(var i = 0, len = records.length; i < len; i++){
11123             records[i].join(this);
11124         }
11125         var index = this.data.length;
11126         this.data.addAll(records);
11127         this.fireEvent("add", this, records, index);
11128     },
11129
11130     /**
11131      * Remove a Record from the Store and fires the remove event.
11132      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11133      */
11134     remove : function(record){
11135         var index = this.data.indexOf(record);
11136         this.data.removeAt(index);
11137  
11138         if(this.pruneModifiedRecords){
11139             this.modified.remove(record);
11140         }
11141         this.fireEvent("remove", this, record, index);
11142     },
11143
11144     /**
11145      * Remove all Records from the Store and fires the clear event.
11146      */
11147     removeAll : function(){
11148         this.data.clear();
11149         if(this.pruneModifiedRecords){
11150             this.modified = [];
11151         }
11152         this.fireEvent("clear", this);
11153     },
11154
11155     /**
11156      * Inserts Records to the Store at the given index and fires the add event.
11157      * @param {Number} index The start index at which to insert the passed Records.
11158      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11159      */
11160     insert : function(index, records){
11161         records = [].concat(records);
11162         for(var i = 0, len = records.length; i < len; i++){
11163             this.data.insert(index, records[i]);
11164             records[i].join(this);
11165         }
11166         this.fireEvent("add", this, records, index);
11167     },
11168
11169     /**
11170      * Get the index within the cache of the passed Record.
11171      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11172      * @return {Number} The index of the passed Record. Returns -1 if not found.
11173      */
11174     indexOf : function(record){
11175         return this.data.indexOf(record);
11176     },
11177
11178     /**
11179      * Get the index within the cache of the Record with the passed id.
11180      * @param {String} id The id of the Record to find.
11181      * @return {Number} The index of the Record. Returns -1 if not found.
11182      */
11183     indexOfId : function(id){
11184         return this.data.indexOfKey(id);
11185     },
11186
11187     /**
11188      * Get the Record with the specified id.
11189      * @param {String} id The id of the Record to find.
11190      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11191      */
11192     getById : function(id){
11193         return this.data.key(id);
11194     },
11195
11196     /**
11197      * Get the Record at the specified index.
11198      * @param {Number} index The index of the Record to find.
11199      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11200      */
11201     getAt : function(index){
11202         return this.data.itemAt(index);
11203     },
11204
11205     /**
11206      * Returns a range of Records between specified indices.
11207      * @param {Number} startIndex (optional) The starting index (defaults to 0)
11208      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11209      * @return {Roo.data.Record[]} An array of Records
11210      */
11211     getRange : function(start, end){
11212         return this.data.getRange(start, end);
11213     },
11214
11215     // private
11216     storeOptions : function(o){
11217         o = Roo.apply({}, o);
11218         delete o.callback;
11219         delete o.scope;
11220         this.lastOptions = o;
11221     },
11222
11223     /**
11224      * Loads the Record cache from the configured Proxy using the configured Reader.
11225      * <p>
11226      * If using remote paging, then the first load call must specify the <em>start</em>
11227      * and <em>limit</em> properties in the options.params property to establish the initial
11228      * position within the dataset, and the number of Records to cache on each read from the Proxy.
11229      * <p>
11230      * <strong>It is important to note that for remote data sources, loading is asynchronous,
11231      * and this call will return before the new data has been loaded. Perform any post-processing
11232      * in a callback function, or in a "load" event handler.</strong>
11233      * <p>
11234      * @param {Object} options An object containing properties which control loading options:<ul>
11235      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11236      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11237      * passed the following arguments:<ul>
11238      * <li>r : Roo.data.Record[]</li>
11239      * <li>options: Options object from the load call</li>
11240      * <li>success: Boolean success indicator</li></ul></li>
11241      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11242      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11243      * </ul>
11244      */
11245     load : function(options){
11246         options = options || {};
11247         if(this.fireEvent("beforeload", this, options) !== false){
11248             this.storeOptions(options);
11249             var p = Roo.apply(options.params || {}, this.baseParams);
11250             // if meta was not loaded from remote source.. try requesting it.
11251             if (!this.reader.metaFromRemote) {
11252                 p._requestMeta = 1;
11253             }
11254             if(this.sortInfo && this.remoteSort){
11255                 var pn = this.paramNames;
11256                 p[pn["sort"]] = this.sortInfo.field;
11257                 p[pn["dir"]] = this.sortInfo.direction;
11258             }
11259             if (this.multiSort) {
11260                 var pn = this.paramNames;
11261                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11262             }
11263             
11264             this.proxy.load(p, this.reader, this.loadRecords, this, options);
11265         }
11266     },
11267
11268     /**
11269      * Reloads the Record cache from the configured Proxy using the configured Reader and
11270      * the options from the last load operation performed.
11271      * @param {Object} options (optional) An object containing properties which may override the options
11272      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11273      * the most recently used options are reused).
11274      */
11275     reload : function(options){
11276         this.load(Roo.applyIf(options||{}, this.lastOptions));
11277     },
11278
11279     // private
11280     // Called as a callback by the Reader during a load operation.
11281     loadRecords : function(o, options, success){
11282         if(!o || success === false){
11283             if(success !== false){
11284                 this.fireEvent("load", this, [], options, o);
11285             }
11286             if(options.callback){
11287                 options.callback.call(options.scope || this, [], options, false);
11288             }
11289             return;
11290         }
11291         // if data returned failure - throw an exception.
11292         if (o.success === false) {
11293             // show a message if no listener is registered.
11294             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11295                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11296             }
11297             // loadmask wil be hooked into this..
11298             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11299             return;
11300         }
11301         var r = o.records, t = o.totalRecords || r.length;
11302         
11303         this.fireEvent("beforeloadadd", this, r, options, o);
11304         
11305         if(!options || options.add !== true){
11306             if(this.pruneModifiedRecords){
11307                 this.modified = [];
11308             }
11309             for(var i = 0, len = r.length; i < len; i++){
11310                 r[i].join(this);
11311             }
11312             if(this.snapshot){
11313                 this.data = this.snapshot;
11314                 delete this.snapshot;
11315             }
11316             this.data.clear();
11317             this.data.addAll(r);
11318             this.totalLength = t;
11319             this.applySort();
11320             this.fireEvent("datachanged", this);
11321         }else{
11322             this.totalLength = Math.max(t, this.data.length+r.length);
11323             this.add(r);
11324         }
11325         
11326         if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11327                 
11328             var e = new Roo.data.Record({});
11329
11330             e.set(this.parent.displayField, this.parent.emptyTitle);
11331             e.set(this.parent.valueField, '');
11332
11333             this.insert(0, e);
11334         }
11335             
11336         this.fireEvent("load", this, r, options, o);
11337         if(options.callback){
11338             options.callback.call(options.scope || this, r, options, true);
11339         }
11340     },
11341
11342
11343     /**
11344      * Loads data from a passed data block. A Reader which understands the format of the data
11345      * must have been configured in the constructor.
11346      * @param {Object} data The data block from which to read the Records.  The format of the data expected
11347      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11348      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11349      */
11350     loadData : function(o, append){
11351         var r = this.reader.readRecords(o);
11352         this.loadRecords(r, {add: append}, true);
11353     },
11354
11355     /**
11356      * Gets the number of cached records.
11357      * <p>
11358      * <em>If using paging, this may not be the total size of the dataset. If the data object
11359      * used by the Reader contains the dataset size, then the getTotalCount() function returns
11360      * the data set size</em>
11361      */
11362     getCount : function(){
11363         return this.data.length || 0;
11364     },
11365
11366     /**
11367      * Gets the total number of records in the dataset as returned by the server.
11368      * <p>
11369      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11370      * the dataset size</em>
11371      */
11372     getTotalCount : function(){
11373         return this.totalLength || 0;
11374     },
11375
11376     /**
11377      * Returns the sort state of the Store as an object with two properties:
11378      * <pre><code>
11379  field {String} The name of the field by which the Records are sorted
11380  direction {String} The sort order, "ASC" or "DESC"
11381      * </code></pre>
11382      */
11383     getSortState : function(){
11384         return this.sortInfo;
11385     },
11386
11387     // private
11388     applySort : function(){
11389         if(this.sortInfo && !this.remoteSort){
11390             var s = this.sortInfo, f = s.field;
11391             var st = this.fields.get(f).sortType;
11392             var fn = function(r1, r2){
11393                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11394                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11395             };
11396             this.data.sort(s.direction, fn);
11397             if(this.snapshot && this.snapshot != this.data){
11398                 this.snapshot.sort(s.direction, fn);
11399             }
11400         }
11401     },
11402
11403     /**
11404      * Sets the default sort column and order to be used by the next load operation.
11405      * @param {String} fieldName The name of the field to sort by.
11406      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11407      */
11408     setDefaultSort : function(field, dir){
11409         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11410     },
11411
11412     /**
11413      * Sort the Records.
11414      * If remote sorting is used, the sort is performed on the server, and the cache is
11415      * reloaded. If local sorting is used, the cache is sorted internally.
11416      * @param {String} fieldName The name of the field to sort by.
11417      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11418      */
11419     sort : function(fieldName, dir){
11420         var f = this.fields.get(fieldName);
11421         if(!dir){
11422             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11423             
11424             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11425                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11426             }else{
11427                 dir = f.sortDir;
11428             }
11429         }
11430         this.sortToggle[f.name] = dir;
11431         this.sortInfo = {field: f.name, direction: dir};
11432         if(!this.remoteSort){
11433             this.applySort();
11434             this.fireEvent("datachanged", this);
11435         }else{
11436             this.load(this.lastOptions);
11437         }
11438     },
11439
11440     /**
11441      * Calls the specified function for each of the Records in the cache.
11442      * @param {Function} fn The function to call. The Record is passed as the first parameter.
11443      * Returning <em>false</em> aborts and exits the iteration.
11444      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11445      */
11446     each : function(fn, scope){
11447         this.data.each(fn, scope);
11448     },
11449
11450     /**
11451      * Gets all records modified since the last commit.  Modified records are persisted across load operations
11452      * (e.g., during paging).
11453      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11454      */
11455     getModifiedRecords : function(){
11456         return this.modified;
11457     },
11458
11459     // private
11460     createFilterFn : function(property, value, anyMatch){
11461         if(!value.exec){ // not a regex
11462             value = String(value);
11463             if(value.length == 0){
11464                 return false;
11465             }
11466             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11467         }
11468         return function(r){
11469             return value.test(r.data[property]);
11470         };
11471     },
11472
11473     /**
11474      * Sums the value of <i>property</i> for each record between start and end and returns the result.
11475      * @param {String} property A field on your records
11476      * @param {Number} start The record index to start at (defaults to 0)
11477      * @param {Number} end The last record index to include (defaults to length - 1)
11478      * @return {Number} The sum
11479      */
11480     sum : function(property, start, end){
11481         var rs = this.data.items, v = 0;
11482         start = start || 0;
11483         end = (end || end === 0) ? end : rs.length-1;
11484
11485         for(var i = start; i <= end; i++){
11486             v += (rs[i].data[property] || 0);
11487         }
11488         return v;
11489     },
11490
11491     /**
11492      * Filter the records by a specified property.
11493      * @param {String} field A field on your records
11494      * @param {String/RegExp} value Either a string that the field
11495      * should start with or a RegExp to test against the field
11496      * @param {Boolean} anyMatch True to match any part not just the beginning
11497      */
11498     filter : function(property, value, anyMatch){
11499         var fn = this.createFilterFn(property, value, anyMatch);
11500         return fn ? this.filterBy(fn) : this.clearFilter();
11501     },
11502
11503     /**
11504      * Filter by a function. The specified function will be called with each
11505      * record in this data source. If the function returns true the record is included,
11506      * otherwise it is filtered.
11507      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11508      * @param {Object} scope (optional) The scope of the function (defaults to this)
11509      */
11510     filterBy : function(fn, scope){
11511         this.snapshot = this.snapshot || this.data;
11512         this.data = this.queryBy(fn, scope||this);
11513         this.fireEvent("datachanged", this);
11514     },
11515
11516     /**
11517      * Query the records by a specified property.
11518      * @param {String} field A field on your records
11519      * @param {String/RegExp} value Either a string that the field
11520      * should start with or a RegExp to test against the field
11521      * @param {Boolean} anyMatch True to match any part not just the beginning
11522      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11523      */
11524     query : function(property, value, anyMatch){
11525         var fn = this.createFilterFn(property, value, anyMatch);
11526         return fn ? this.queryBy(fn) : this.data.clone();
11527     },
11528
11529     /**
11530      * Query by a function. The specified function will be called with each
11531      * record in this data source. If the function returns true the record is included
11532      * in the results.
11533      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11534      * @param {Object} scope (optional) The scope of the function (defaults to this)
11535       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11536      **/
11537     queryBy : function(fn, scope){
11538         var data = this.snapshot || this.data;
11539         return data.filterBy(fn, scope||this);
11540     },
11541
11542     /**
11543      * Collects unique values for a particular dataIndex from this store.
11544      * @param {String} dataIndex The property to collect
11545      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11546      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11547      * @return {Array} An array of the unique values
11548      **/
11549     collect : function(dataIndex, allowNull, bypassFilter){
11550         var d = (bypassFilter === true && this.snapshot) ?
11551                 this.snapshot.items : this.data.items;
11552         var v, sv, r = [], l = {};
11553         for(var i = 0, len = d.length; i < len; i++){
11554             v = d[i].data[dataIndex];
11555             sv = String(v);
11556             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11557                 l[sv] = true;
11558                 r[r.length] = v;
11559             }
11560         }
11561         return r;
11562     },
11563
11564     /**
11565      * Revert to a view of the Record cache with no filtering applied.
11566      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11567      */
11568     clearFilter : function(suppressEvent){
11569         if(this.snapshot && this.snapshot != this.data){
11570             this.data = this.snapshot;
11571             delete this.snapshot;
11572             if(suppressEvent !== true){
11573                 this.fireEvent("datachanged", this);
11574             }
11575         }
11576     },
11577
11578     // private
11579     afterEdit : function(record){
11580         if(this.modified.indexOf(record) == -1){
11581             this.modified.push(record);
11582         }
11583         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11584     },
11585     
11586     // private
11587     afterReject : function(record){
11588         this.modified.remove(record);
11589         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11590     },
11591
11592     // private
11593     afterCommit : function(record){
11594         this.modified.remove(record);
11595         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11596     },
11597
11598     /**
11599      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11600      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11601      */
11602     commitChanges : function(){
11603         var m = this.modified.slice(0);
11604         this.modified = [];
11605         for(var i = 0, len = m.length; i < len; i++){
11606             m[i].commit();
11607         }
11608     },
11609
11610     /**
11611      * Cancel outstanding changes on all changed records.
11612      */
11613     rejectChanges : function(){
11614         var m = this.modified.slice(0);
11615         this.modified = [];
11616         for(var i = 0, len = m.length; i < len; i++){
11617             m[i].reject();
11618         }
11619     },
11620
11621     onMetaChange : function(meta, rtype, o){
11622         this.recordType = rtype;
11623         this.fields = rtype.prototype.fields;
11624         delete this.snapshot;
11625         this.sortInfo = meta.sortInfo || this.sortInfo;
11626         this.modified = [];
11627         this.fireEvent('metachange', this, this.reader.meta);
11628     },
11629     
11630     moveIndex : function(data, type)
11631     {
11632         var index = this.indexOf(data);
11633         
11634         var newIndex = index + type;
11635         
11636         this.remove(data);
11637         
11638         this.insert(newIndex, data);
11639         
11640     }
11641 });/*
11642  * Based on:
11643  * Ext JS Library 1.1.1
11644  * Copyright(c) 2006-2007, Ext JS, LLC.
11645  *
11646  * Originally Released Under LGPL - original licence link has changed is not relivant.
11647  *
11648  * Fork - LGPL
11649  * <script type="text/javascript">
11650  */
11651
11652 /**
11653  * @class Roo.data.SimpleStore
11654  * @extends Roo.data.Store
11655  * Small helper class to make creating Stores from Array data easier.
11656  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11657  * @cfg {Array} fields An array of field definition objects, or field name strings.
11658  * @cfg {Array} data The multi-dimensional array of data
11659  * @constructor
11660  * @param {Object} config
11661  */
11662 Roo.data.SimpleStore = function(config){
11663     Roo.data.SimpleStore.superclass.constructor.call(this, {
11664         isLocal : true,
11665         reader: new Roo.data.ArrayReader({
11666                 id: config.id
11667             },
11668             Roo.data.Record.create(config.fields)
11669         ),
11670         proxy : new Roo.data.MemoryProxy(config.data)
11671     });
11672     this.load();
11673 };
11674 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11675  * Based on:
11676  * Ext JS Library 1.1.1
11677  * Copyright(c) 2006-2007, Ext JS, LLC.
11678  *
11679  * Originally Released Under LGPL - original licence link has changed is not relivant.
11680  *
11681  * Fork - LGPL
11682  * <script type="text/javascript">
11683  */
11684
11685 /**
11686 /**
11687  * @extends Roo.data.Store
11688  * @class Roo.data.JsonStore
11689  * Small helper class to make creating Stores for JSON data easier. <br/>
11690 <pre><code>
11691 var store = new Roo.data.JsonStore({
11692     url: 'get-images.php',
11693     root: 'images',
11694     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11695 });
11696 </code></pre>
11697  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11698  * JsonReader and HttpProxy (unless inline data is provided).</b>
11699  * @cfg {Array} fields An array of field definition objects, or field name strings.
11700  * @constructor
11701  * @param {Object} config
11702  */
11703 Roo.data.JsonStore = function(c){
11704     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11705         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11706         reader: new Roo.data.JsonReader(c, c.fields)
11707     }));
11708 };
11709 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11710  * Based on:
11711  * Ext JS Library 1.1.1
11712  * Copyright(c) 2006-2007, Ext JS, LLC.
11713  *
11714  * Originally Released Under LGPL - original licence link has changed is not relivant.
11715  *
11716  * Fork - LGPL
11717  * <script type="text/javascript">
11718  */
11719
11720  
11721 Roo.data.Field = function(config){
11722     if(typeof config == "string"){
11723         config = {name: config};
11724     }
11725     Roo.apply(this, config);
11726     
11727     if(!this.type){
11728         this.type = "auto";
11729     }
11730     
11731     var st = Roo.data.SortTypes;
11732     // named sortTypes are supported, here we look them up
11733     if(typeof this.sortType == "string"){
11734         this.sortType = st[this.sortType];
11735     }
11736     
11737     // set default sortType for strings and dates
11738     if(!this.sortType){
11739         switch(this.type){
11740             case "string":
11741                 this.sortType = st.asUCString;
11742                 break;
11743             case "date":
11744                 this.sortType = st.asDate;
11745                 break;
11746             default:
11747                 this.sortType = st.none;
11748         }
11749     }
11750
11751     // define once
11752     var stripRe = /[\$,%]/g;
11753
11754     // prebuilt conversion function for this field, instead of
11755     // switching every time we're reading a value
11756     if(!this.convert){
11757         var cv, dateFormat = this.dateFormat;
11758         switch(this.type){
11759             case "":
11760             case "auto":
11761             case undefined:
11762                 cv = function(v){ return v; };
11763                 break;
11764             case "string":
11765                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11766                 break;
11767             case "int":
11768                 cv = function(v){
11769                     return v !== undefined && v !== null && v !== '' ?
11770                            parseInt(String(v).replace(stripRe, ""), 10) : '';
11771                     };
11772                 break;
11773             case "float":
11774                 cv = function(v){
11775                     return v !== undefined && v !== null && v !== '' ?
11776                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
11777                     };
11778                 break;
11779             case "bool":
11780             case "boolean":
11781                 cv = function(v){ return v === true || v === "true" || v == 1; };
11782                 break;
11783             case "date":
11784                 cv = function(v){
11785                     if(!v){
11786                         return '';
11787                     }
11788                     if(v instanceof Date){
11789                         return v;
11790                     }
11791                     if(dateFormat){
11792                         if(dateFormat == "timestamp"){
11793                             return new Date(v*1000);
11794                         }
11795                         return Date.parseDate(v, dateFormat);
11796                     }
11797                     var parsed = Date.parse(v);
11798                     return parsed ? new Date(parsed) : null;
11799                 };
11800              break;
11801             
11802         }
11803         this.convert = cv;
11804     }
11805 };
11806
11807 Roo.data.Field.prototype = {
11808     dateFormat: null,
11809     defaultValue: "",
11810     mapping: null,
11811     sortType : null,
11812     sortDir : "ASC"
11813 };/*
11814  * Based on:
11815  * Ext JS Library 1.1.1
11816  * Copyright(c) 2006-2007, Ext JS, LLC.
11817  *
11818  * Originally Released Under LGPL - original licence link has changed is not relivant.
11819  *
11820  * Fork - LGPL
11821  * <script type="text/javascript">
11822  */
11823  
11824 // Base class for reading structured data from a data source.  This class is intended to be
11825 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11826
11827 /**
11828  * @class Roo.data.DataReader
11829  * Base class for reading structured data from a data source.  This class is intended to be
11830  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11831  */
11832
11833 Roo.data.DataReader = function(meta, recordType){
11834     
11835     this.meta = meta;
11836     
11837     this.recordType = recordType instanceof Array ? 
11838         Roo.data.Record.create(recordType) : recordType;
11839 };
11840
11841 Roo.data.DataReader.prototype = {
11842      /**
11843      * Create an empty record
11844      * @param {Object} data (optional) - overlay some values
11845      * @return {Roo.data.Record} record created.
11846      */
11847     newRow :  function(d) {
11848         var da =  {};
11849         this.recordType.prototype.fields.each(function(c) {
11850             switch( c.type) {
11851                 case 'int' : da[c.name] = 0; break;
11852                 case 'date' : da[c.name] = new Date(); break;
11853                 case 'float' : da[c.name] = 0.0; break;
11854                 case 'boolean' : da[c.name] = false; break;
11855                 default : da[c.name] = ""; break;
11856             }
11857             
11858         });
11859         return new this.recordType(Roo.apply(da, d));
11860     }
11861     
11862 };/*
11863  * Based on:
11864  * Ext JS Library 1.1.1
11865  * Copyright(c) 2006-2007, Ext JS, LLC.
11866  *
11867  * Originally Released Under LGPL - original licence link has changed is not relivant.
11868  *
11869  * Fork - LGPL
11870  * <script type="text/javascript">
11871  */
11872
11873 /**
11874  * @class Roo.data.DataProxy
11875  * @extends Roo.data.Observable
11876  * This class is an abstract base class for implementations which provide retrieval of
11877  * unformatted data objects.<br>
11878  * <p>
11879  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11880  * (of the appropriate type which knows how to parse the data object) to provide a block of
11881  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11882  * <p>
11883  * Custom implementations must implement the load method as described in
11884  * {@link Roo.data.HttpProxy#load}.
11885  */
11886 Roo.data.DataProxy = function(){
11887     this.addEvents({
11888         /**
11889          * @event beforeload
11890          * Fires before a network request is made to retrieve a data object.
11891          * @param {Object} This DataProxy object.
11892          * @param {Object} params The params parameter to the load function.
11893          */
11894         beforeload : true,
11895         /**
11896          * @event load
11897          * Fires before the load method's callback is called.
11898          * @param {Object} This DataProxy object.
11899          * @param {Object} o The data object.
11900          * @param {Object} arg The callback argument object passed to the load function.
11901          */
11902         load : true,
11903         /**
11904          * @event loadexception
11905          * Fires if an Exception occurs during data retrieval.
11906          * @param {Object} This DataProxy object.
11907          * @param {Object} o The data object.
11908          * @param {Object} arg The callback argument object passed to the load function.
11909          * @param {Object} e The Exception.
11910          */
11911         loadexception : true
11912     });
11913     Roo.data.DataProxy.superclass.constructor.call(this);
11914 };
11915
11916 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11917
11918     /**
11919      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11920      */
11921 /*
11922  * Based on:
11923  * Ext JS Library 1.1.1
11924  * Copyright(c) 2006-2007, Ext JS, LLC.
11925  *
11926  * Originally Released Under LGPL - original licence link has changed is not relivant.
11927  *
11928  * Fork - LGPL
11929  * <script type="text/javascript">
11930  */
11931 /**
11932  * @class Roo.data.MemoryProxy
11933  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11934  * to the Reader when its load method is called.
11935  * @constructor
11936  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11937  */
11938 Roo.data.MemoryProxy = function(data){
11939     if (data.data) {
11940         data = data.data;
11941     }
11942     Roo.data.MemoryProxy.superclass.constructor.call(this);
11943     this.data = data;
11944 };
11945
11946 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11947     
11948     /**
11949      * Load data from the requested source (in this case an in-memory
11950      * data object passed to the constructor), read the data object into
11951      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11952      * process that block using the passed callback.
11953      * @param {Object} params This parameter is not used by the MemoryProxy class.
11954      * @param {Roo.data.DataReader} reader The Reader object which converts the data
11955      * object into a block of Roo.data.Records.
11956      * @param {Function} callback The function into which to pass the block of Roo.data.records.
11957      * The function must be passed <ul>
11958      * <li>The Record block object</li>
11959      * <li>The "arg" argument from the load function</li>
11960      * <li>A boolean success indicator</li>
11961      * </ul>
11962      * @param {Object} scope The scope in which to call the callback
11963      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11964      */
11965     load : function(params, reader, callback, scope, arg){
11966         params = params || {};
11967         var result;
11968         try {
11969             result = reader.readRecords(this.data);
11970         }catch(e){
11971             this.fireEvent("loadexception", this, arg, null, e);
11972             callback.call(scope, null, arg, false);
11973             return;
11974         }
11975         callback.call(scope, result, arg, true);
11976     },
11977     
11978     // private
11979     update : function(params, records){
11980         
11981     }
11982 });/*
11983  * Based on:
11984  * Ext JS Library 1.1.1
11985  * Copyright(c) 2006-2007, Ext JS, LLC.
11986  *
11987  * Originally Released Under LGPL - original licence link has changed is not relivant.
11988  *
11989  * Fork - LGPL
11990  * <script type="text/javascript">
11991  */
11992 /**
11993  * @class Roo.data.HttpProxy
11994  * @extends Roo.data.DataProxy
11995  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11996  * configured to reference a certain URL.<br><br>
11997  * <p>
11998  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11999  * from which the running page was served.<br><br>
12000  * <p>
12001  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12002  * <p>
12003  * Be aware that to enable the browser to parse an XML document, the server must set
12004  * the Content-Type header in the HTTP response to "text/xml".
12005  * @constructor
12006  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12007  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
12008  * will be used to make the request.
12009  */
12010 Roo.data.HttpProxy = function(conn){
12011     Roo.data.HttpProxy.superclass.constructor.call(this);
12012     // is conn a conn config or a real conn?
12013     this.conn = conn;
12014     this.useAjax = !conn || !conn.events;
12015   
12016 };
12017
12018 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12019     // thse are take from connection...
12020     
12021     /**
12022      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12023      */
12024     /**
12025      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12026      * extra parameters to each request made by this object. (defaults to undefined)
12027      */
12028     /**
12029      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12030      *  to each request made by this object. (defaults to undefined)
12031      */
12032     /**
12033      * @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)
12034      */
12035     /**
12036      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12037      */
12038      /**
12039      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12040      * @type Boolean
12041      */
12042   
12043
12044     /**
12045      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12046      * @type Boolean
12047      */
12048     /**
12049      * Return the {@link Roo.data.Connection} object being used by this Proxy.
12050      * @return {Connection} The Connection object. This object may be used to subscribe to events on
12051      * a finer-grained basis than the DataProxy events.
12052      */
12053     getConnection : function(){
12054         return this.useAjax ? Roo.Ajax : this.conn;
12055     },
12056
12057     /**
12058      * Load data from the configured {@link Roo.data.Connection}, read the data object into
12059      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12060      * process that block using the passed callback.
12061      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12062      * for the request to the remote server.
12063      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12064      * object into a block of Roo.data.Records.
12065      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12066      * The function must be passed <ul>
12067      * <li>The Record block object</li>
12068      * <li>The "arg" argument from the load function</li>
12069      * <li>A boolean success indicator</li>
12070      * </ul>
12071      * @param {Object} scope The scope in which to call the callback
12072      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12073      */
12074     load : function(params, reader, callback, scope, arg){
12075         if(this.fireEvent("beforeload", this, params) !== false){
12076             var  o = {
12077                 params : params || {},
12078                 request: {
12079                     callback : callback,
12080                     scope : scope,
12081                     arg : arg
12082                 },
12083                 reader: reader,
12084                 callback : this.loadResponse,
12085                 scope: this
12086             };
12087             if(this.useAjax){
12088                 Roo.applyIf(o, this.conn);
12089                 if(this.activeRequest){
12090                     Roo.Ajax.abort(this.activeRequest);
12091                 }
12092                 this.activeRequest = Roo.Ajax.request(o);
12093             }else{
12094                 this.conn.request(o);
12095             }
12096         }else{
12097             callback.call(scope||this, null, arg, false);
12098         }
12099     },
12100
12101     // private
12102     loadResponse : function(o, success, response){
12103         delete this.activeRequest;
12104         if(!success){
12105             this.fireEvent("loadexception", this, o, response);
12106             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12107             return;
12108         }
12109         var result;
12110         try {
12111             result = o.reader.read(response);
12112         }catch(e){
12113             this.fireEvent("loadexception", this, o, response, e);
12114             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12115             return;
12116         }
12117         
12118         this.fireEvent("load", this, o, o.request.arg);
12119         o.request.callback.call(o.request.scope, result, o.request.arg, true);
12120     },
12121
12122     // private
12123     update : function(dataSet){
12124
12125     },
12126
12127     // private
12128     updateResponse : function(dataSet){
12129
12130     }
12131 });/*
12132  * Based on:
12133  * Ext JS Library 1.1.1
12134  * Copyright(c) 2006-2007, Ext JS, LLC.
12135  *
12136  * Originally Released Under LGPL - original licence link has changed is not relivant.
12137  *
12138  * Fork - LGPL
12139  * <script type="text/javascript">
12140  */
12141
12142 /**
12143  * @class Roo.data.ScriptTagProxy
12144  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12145  * other than the originating domain of the running page.<br><br>
12146  * <p>
12147  * <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
12148  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12149  * <p>
12150  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12151  * source code that is used as the source inside a &lt;script> tag.<br><br>
12152  * <p>
12153  * In order for the browser to process the returned data, the server must wrap the data object
12154  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12155  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12156  * depending on whether the callback name was passed:
12157  * <p>
12158  * <pre><code>
12159 boolean scriptTag = false;
12160 String cb = request.getParameter("callback");
12161 if (cb != null) {
12162     scriptTag = true;
12163     response.setContentType("text/javascript");
12164 } else {
12165     response.setContentType("application/x-json");
12166 }
12167 Writer out = response.getWriter();
12168 if (scriptTag) {
12169     out.write(cb + "(");
12170 }
12171 out.print(dataBlock.toJsonString());
12172 if (scriptTag) {
12173     out.write(");");
12174 }
12175 </pre></code>
12176  *
12177  * @constructor
12178  * @param {Object} config A configuration object.
12179  */
12180 Roo.data.ScriptTagProxy = function(config){
12181     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12182     Roo.apply(this, config);
12183     this.head = document.getElementsByTagName("head")[0];
12184 };
12185
12186 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12187
12188 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12189     /**
12190      * @cfg {String} url The URL from which to request the data object.
12191      */
12192     /**
12193      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12194      */
12195     timeout : 30000,
12196     /**
12197      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12198      * the server the name of the callback function set up by the load call to process the returned data object.
12199      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12200      * javascript output which calls this named function passing the data object as its only parameter.
12201      */
12202     callbackParam : "callback",
12203     /**
12204      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12205      * name to the request.
12206      */
12207     nocache : true,
12208
12209     /**
12210      * Load data from the configured URL, read the data object into
12211      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12212      * process that block using the passed callback.
12213      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12214      * for the request to the remote server.
12215      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12216      * object into a block of Roo.data.Records.
12217      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12218      * The function must be passed <ul>
12219      * <li>The Record block object</li>
12220      * <li>The "arg" argument from the load function</li>
12221      * <li>A boolean success indicator</li>
12222      * </ul>
12223      * @param {Object} scope The scope in which to call the callback
12224      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12225      */
12226     load : function(params, reader, callback, scope, arg){
12227         if(this.fireEvent("beforeload", this, params) !== false){
12228
12229             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12230
12231             var url = this.url;
12232             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12233             if(this.nocache){
12234                 url += "&_dc=" + (new Date().getTime());
12235             }
12236             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12237             var trans = {
12238                 id : transId,
12239                 cb : "stcCallback"+transId,
12240                 scriptId : "stcScript"+transId,
12241                 params : params,
12242                 arg : arg,
12243                 url : url,
12244                 callback : callback,
12245                 scope : scope,
12246                 reader : reader
12247             };
12248             var conn = this;
12249
12250             window[trans.cb] = function(o){
12251                 conn.handleResponse(o, trans);
12252             };
12253
12254             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12255
12256             if(this.autoAbort !== false){
12257                 this.abort();
12258             }
12259
12260             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12261
12262             var script = document.createElement("script");
12263             script.setAttribute("src", url);
12264             script.setAttribute("type", "text/javascript");
12265             script.setAttribute("id", trans.scriptId);
12266             this.head.appendChild(script);
12267
12268             this.trans = trans;
12269         }else{
12270             callback.call(scope||this, null, arg, false);
12271         }
12272     },
12273
12274     // private
12275     isLoading : function(){
12276         return this.trans ? true : false;
12277     },
12278
12279     /**
12280      * Abort the current server request.
12281      */
12282     abort : function(){
12283         if(this.isLoading()){
12284             this.destroyTrans(this.trans);
12285         }
12286     },
12287
12288     // private
12289     destroyTrans : function(trans, isLoaded){
12290         this.head.removeChild(document.getElementById(trans.scriptId));
12291         clearTimeout(trans.timeoutId);
12292         if(isLoaded){
12293             window[trans.cb] = undefined;
12294             try{
12295                 delete window[trans.cb];
12296             }catch(e){}
12297         }else{
12298             // if hasn't been loaded, wait for load to remove it to prevent script error
12299             window[trans.cb] = function(){
12300                 window[trans.cb] = undefined;
12301                 try{
12302                     delete window[trans.cb];
12303                 }catch(e){}
12304             };
12305         }
12306     },
12307
12308     // private
12309     handleResponse : function(o, trans){
12310         this.trans = false;
12311         this.destroyTrans(trans, true);
12312         var result;
12313         try {
12314             result = trans.reader.readRecords(o);
12315         }catch(e){
12316             this.fireEvent("loadexception", this, o, trans.arg, e);
12317             trans.callback.call(trans.scope||window, null, trans.arg, false);
12318             return;
12319         }
12320         this.fireEvent("load", this, o, trans.arg);
12321         trans.callback.call(trans.scope||window, result, trans.arg, true);
12322     },
12323
12324     // private
12325     handleFailure : function(trans){
12326         this.trans = false;
12327         this.destroyTrans(trans, false);
12328         this.fireEvent("loadexception", this, null, trans.arg);
12329         trans.callback.call(trans.scope||window, null, trans.arg, false);
12330     }
12331 });/*
12332  * Based on:
12333  * Ext JS Library 1.1.1
12334  * Copyright(c) 2006-2007, Ext JS, LLC.
12335  *
12336  * Originally Released Under LGPL - original licence link has changed is not relivant.
12337  *
12338  * Fork - LGPL
12339  * <script type="text/javascript">
12340  */
12341
12342 /**
12343  * @class Roo.data.JsonReader
12344  * @extends Roo.data.DataReader
12345  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12346  * based on mappings in a provided Roo.data.Record constructor.
12347  * 
12348  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12349  * in the reply previously. 
12350  * 
12351  * <p>
12352  * Example code:
12353  * <pre><code>
12354 var RecordDef = Roo.data.Record.create([
12355     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
12356     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
12357 ]);
12358 var myReader = new Roo.data.JsonReader({
12359     totalProperty: "results",    // The property which contains the total dataset size (optional)
12360     root: "rows",                // The property which contains an Array of row objects
12361     id: "id"                     // The property within each row object that provides an ID for the record (optional)
12362 }, RecordDef);
12363 </code></pre>
12364  * <p>
12365  * This would consume a JSON file like this:
12366  * <pre><code>
12367 { 'results': 2, 'rows': [
12368     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12369     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12370 }
12371 </code></pre>
12372  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12373  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12374  * paged from the remote server.
12375  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12376  * @cfg {String} root name of the property which contains the Array of row objects.
12377  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12378  * @cfg {Array} fields Array of field definition objects
12379  * @constructor
12380  * Create a new JsonReader
12381  * @param {Object} meta Metadata configuration options
12382  * @param {Object} recordType Either an Array of field definition objects,
12383  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12384  */
12385 Roo.data.JsonReader = function(meta, recordType){
12386     
12387     meta = meta || {};
12388     // set some defaults:
12389     Roo.applyIf(meta, {
12390         totalProperty: 'total',
12391         successProperty : 'success',
12392         root : 'data',
12393         id : 'id'
12394     });
12395     
12396     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12397 };
12398 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12399     
12400     /**
12401      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
12402      * Used by Store query builder to append _requestMeta to params.
12403      * 
12404      */
12405     metaFromRemote : false,
12406     /**
12407      * This method is only used by a DataProxy which has retrieved data from a remote server.
12408      * @param {Object} response The XHR object which contains the JSON data in its responseText.
12409      * @return {Object} data A data block which is used by an Roo.data.Store object as
12410      * a cache of Roo.data.Records.
12411      */
12412     read : function(response){
12413         var json = response.responseText;
12414        
12415         var o = /* eval:var:o */ eval("("+json+")");
12416         if(!o) {
12417             throw {message: "JsonReader.read: Json object not found"};
12418         }
12419         
12420         if(o.metaData){
12421             
12422             delete this.ef;
12423             this.metaFromRemote = true;
12424             this.meta = o.metaData;
12425             this.recordType = Roo.data.Record.create(o.metaData.fields);
12426             this.onMetaChange(this.meta, this.recordType, o);
12427         }
12428         return this.readRecords(o);
12429     },
12430
12431     // private function a store will implement
12432     onMetaChange : function(meta, recordType, o){
12433
12434     },
12435
12436     /**
12437          * @ignore
12438          */
12439     simpleAccess: function(obj, subsc) {
12440         return obj[subsc];
12441     },
12442
12443         /**
12444          * @ignore
12445          */
12446     getJsonAccessor: function(){
12447         var re = /[\[\.]/;
12448         return function(expr) {
12449             try {
12450                 return(re.test(expr))
12451                     ? new Function("obj", "return obj." + expr)
12452                     : function(obj){
12453                         return obj[expr];
12454                     };
12455             } catch(e){}
12456             return Roo.emptyFn;
12457         };
12458     }(),
12459
12460     /**
12461      * Create a data block containing Roo.data.Records from an XML document.
12462      * @param {Object} o An object which contains an Array of row objects in the property specified
12463      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12464      * which contains the total size of the dataset.
12465      * @return {Object} data A data block which is used by an Roo.data.Store object as
12466      * a cache of Roo.data.Records.
12467      */
12468     readRecords : function(o){
12469         /**
12470          * After any data loads, the raw JSON data is available for further custom processing.
12471          * @type Object
12472          */
12473         this.o = o;
12474         var s = this.meta, Record = this.recordType,
12475             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12476
12477 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
12478         if (!this.ef) {
12479             if(s.totalProperty) {
12480                     this.getTotal = this.getJsonAccessor(s.totalProperty);
12481                 }
12482                 if(s.successProperty) {
12483                     this.getSuccess = this.getJsonAccessor(s.successProperty);
12484                 }
12485                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12486                 if (s.id) {
12487                         var g = this.getJsonAccessor(s.id);
12488                         this.getId = function(rec) {
12489                                 var r = g(rec);  
12490                                 return (r === undefined || r === "") ? null : r;
12491                         };
12492                 } else {
12493                         this.getId = function(){return null;};
12494                 }
12495             this.ef = [];
12496             for(var jj = 0; jj < fl; jj++){
12497                 f = fi[jj];
12498                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12499                 this.ef[jj] = this.getJsonAccessor(map);
12500             }
12501         }
12502
12503         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12504         if(s.totalProperty){
12505             var vt = parseInt(this.getTotal(o), 10);
12506             if(!isNaN(vt)){
12507                 totalRecords = vt;
12508             }
12509         }
12510         if(s.successProperty){
12511             var vs = this.getSuccess(o);
12512             if(vs === false || vs === 'false'){
12513                 success = false;
12514             }
12515         }
12516         var records = [];
12517         for(var i = 0; i < c; i++){
12518                 var n = root[i];
12519             var values = {};
12520             var id = this.getId(n);
12521             for(var j = 0; j < fl; j++){
12522                 f = fi[j];
12523             var v = this.ef[j](n);
12524             if (!f.convert) {
12525                 Roo.log('missing convert for ' + f.name);
12526                 Roo.log(f);
12527                 continue;
12528             }
12529             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12530             }
12531             var record = new Record(values, id);
12532             record.json = n;
12533             records[i] = record;
12534         }
12535         return {
12536             raw : o,
12537             success : success,
12538             records : records,
12539             totalRecords : totalRecords
12540         };
12541     }
12542 });/*
12543  * Based on:
12544  * Ext JS Library 1.1.1
12545  * Copyright(c) 2006-2007, Ext JS, LLC.
12546  *
12547  * Originally Released Under LGPL - original licence link has changed is not relivant.
12548  *
12549  * Fork - LGPL
12550  * <script type="text/javascript">
12551  */
12552
12553 /**
12554  * @class Roo.data.ArrayReader
12555  * @extends Roo.data.DataReader
12556  * Data reader class to create an Array of Roo.data.Record objects from an Array.
12557  * Each element of that Array represents a row of data fields. The
12558  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12559  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12560  * <p>
12561  * Example code:.
12562  * <pre><code>
12563 var RecordDef = Roo.data.Record.create([
12564     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
12565     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
12566 ]);
12567 var myReader = new Roo.data.ArrayReader({
12568     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
12569 }, RecordDef);
12570 </code></pre>
12571  * <p>
12572  * This would consume an Array like this:
12573  * <pre><code>
12574 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12575   </code></pre>
12576  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12577  * @constructor
12578  * Create a new JsonReader
12579  * @param {Object} meta Metadata configuration options.
12580  * @param {Object} recordType Either an Array of field definition objects
12581  * as specified to {@link Roo.data.Record#create},
12582  * or an {@link Roo.data.Record} object
12583  * created using {@link Roo.data.Record#create}.
12584  */
12585 Roo.data.ArrayReader = function(meta, recordType){
12586     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12587 };
12588
12589 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12590     /**
12591      * Create a data block containing Roo.data.Records from an XML document.
12592      * @param {Object} o An Array of row objects which represents the dataset.
12593      * @return {Object} data A data block which is used by an Roo.data.Store object as
12594      * a cache of Roo.data.Records.
12595      */
12596     readRecords : function(o){
12597         var sid = this.meta ? this.meta.id : null;
12598         var recordType = this.recordType, fields = recordType.prototype.fields;
12599         var records = [];
12600         var root = o;
12601             for(var i = 0; i < root.length; i++){
12602                     var n = root[i];
12603                 var values = {};
12604                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12605                 for(var j = 0, jlen = fields.length; j < jlen; j++){
12606                 var f = fields.items[j];
12607                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12608                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12609                 v = f.convert(v);
12610                 values[f.name] = v;
12611             }
12612                 var record = new recordType(values, id);
12613                 record.json = n;
12614                 records[records.length] = record;
12615             }
12616             return {
12617                 records : records,
12618                 totalRecords : records.length
12619             };
12620     }
12621 });/*
12622  * - LGPL
12623  * * 
12624  */
12625
12626 /**
12627  * @class Roo.bootstrap.ComboBox
12628  * @extends Roo.bootstrap.TriggerField
12629  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12630  * @cfg {Boolean} append (true|false) default false
12631  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12632  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12633  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12634  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12635  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12636  * @cfg {Boolean} animate default true
12637  * @cfg {Boolean} emptyResultText only for touch device
12638  * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12639  * @cfg {String} emptyTitle default ''
12640  * @constructor
12641  * Create a new ComboBox.
12642  * @param {Object} config Configuration options
12643  */
12644 Roo.bootstrap.ComboBox = function(config){
12645     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12646     this.addEvents({
12647         /**
12648          * @event expand
12649          * Fires when the dropdown list is expanded
12650         * @param {Roo.bootstrap.ComboBox} combo This combo box
12651         */
12652         'expand' : true,
12653         /**
12654          * @event collapse
12655          * Fires when the dropdown list is collapsed
12656         * @param {Roo.bootstrap.ComboBox} combo This combo box
12657         */
12658         'collapse' : true,
12659         /**
12660          * @event beforeselect
12661          * Fires before a list item is selected. Return false to cancel the selection.
12662         * @param {Roo.bootstrap.ComboBox} combo This combo box
12663         * @param {Roo.data.Record} record The data record returned from the underlying store
12664         * @param {Number} index The index of the selected item in the dropdown list
12665         */
12666         'beforeselect' : true,
12667         /**
12668          * @event select
12669          * Fires when a list item is selected
12670         * @param {Roo.bootstrap.ComboBox} combo This combo box
12671         * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12672         * @param {Number} index The index of the selected item in the dropdown list
12673         */
12674         'select' : true,
12675         /**
12676          * @event beforequery
12677          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12678          * The event object passed has these properties:
12679         * @param {Roo.bootstrap.ComboBox} combo This combo box
12680         * @param {String} query The query
12681         * @param {Boolean} forceAll true to force "all" query
12682         * @param {Boolean} cancel true to cancel the query
12683         * @param {Object} e The query event object
12684         */
12685         'beforequery': true,
12686          /**
12687          * @event add
12688          * Fires when the 'add' icon is pressed (add a listener to enable add button)
12689         * @param {Roo.bootstrap.ComboBox} combo This combo box
12690         */
12691         'add' : true,
12692         /**
12693          * @event edit
12694          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12695         * @param {Roo.bootstrap.ComboBox} combo This combo box
12696         * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12697         */
12698         'edit' : true,
12699         /**
12700          * @event remove
12701          * Fires when the remove value from the combobox array
12702         * @param {Roo.bootstrap.ComboBox} combo This combo box
12703         */
12704         'remove' : true,
12705         /**
12706          * @event afterremove
12707          * Fires when the remove value from the combobox array
12708         * @param {Roo.bootstrap.ComboBox} combo This combo box
12709         */
12710         'afterremove' : true,
12711         /**
12712          * @event specialfilter
12713          * Fires when specialfilter
12714             * @param {Roo.bootstrap.ComboBox} combo This combo box
12715             */
12716         'specialfilter' : true,
12717         /**
12718          * @event tick
12719          * Fires when tick the element
12720             * @param {Roo.bootstrap.ComboBox} combo This combo box
12721             */
12722         'tick' : true,
12723         /**
12724          * @event touchviewdisplay
12725          * Fires when touch view require special display (default is using displayField)
12726             * @param {Roo.bootstrap.ComboBox} combo This combo box
12727             * @param {Object} cfg set html .
12728             */
12729         'touchviewdisplay' : true
12730         
12731     });
12732     
12733     this.item = [];
12734     this.tickItems = [];
12735     
12736     this.selectedIndex = -1;
12737     if(this.mode == 'local'){
12738         if(config.queryDelay === undefined){
12739             this.queryDelay = 10;
12740         }
12741         if(config.minChars === undefined){
12742             this.minChars = 0;
12743         }
12744     }
12745 };
12746
12747 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12748      
12749     /**
12750      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12751      * rendering into an Roo.Editor, defaults to false)
12752      */
12753     /**
12754      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12755      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12756      */
12757     /**
12758      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12759      */
12760     /**
12761      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12762      * the dropdown list (defaults to undefined, with no header element)
12763      */
12764
12765      /**
12766      * @cfg {String/Roo.Template} tpl The template to use to render the output
12767      */
12768      
12769      /**
12770      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12771      */
12772     listWidth: undefined,
12773     /**
12774      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12775      * mode = 'remote' or 'text' if mode = 'local')
12776      */
12777     displayField: undefined,
12778     
12779     /**
12780      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12781      * mode = 'remote' or 'value' if mode = 'local'). 
12782      * Note: use of a valueField requires the user make a selection
12783      * in order for a value to be mapped.
12784      */
12785     valueField: undefined,
12786     /**
12787      * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12788      */
12789     modalTitle : '',
12790     
12791     /**
12792      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12793      * field's data value (defaults to the underlying DOM element's name)
12794      */
12795     hiddenName: undefined,
12796     /**
12797      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12798      */
12799     listClass: '',
12800     /**
12801      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12802      */
12803     selectedClass: 'active',
12804     
12805     /**
12806      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12807      */
12808     shadow:'sides',
12809     /**
12810      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12811      * anchor positions (defaults to 'tl-bl')
12812      */
12813     listAlign: 'tl-bl?',
12814     /**
12815      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12816      */
12817     maxHeight: 300,
12818     /**
12819      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
12820      * query specified by the allQuery config option (defaults to 'query')
12821      */
12822     triggerAction: 'query',
12823     /**
12824      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12825      * (defaults to 4, does not apply if editable = false)
12826      */
12827     minChars : 4,
12828     /**
12829      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12830      * delay (typeAheadDelay) if it matches a known value (defaults to false)
12831      */
12832     typeAhead: false,
12833     /**
12834      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12835      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12836      */
12837     queryDelay: 500,
12838     /**
12839      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12840      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
12841      */
12842     pageSize: 0,
12843     /**
12844      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
12845      * when editable = true (defaults to false)
12846      */
12847     selectOnFocus:false,
12848     /**
12849      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12850      */
12851     queryParam: 'query',
12852     /**
12853      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
12854      * when mode = 'remote' (defaults to 'Loading...')
12855      */
12856     loadingText: 'Loading...',
12857     /**
12858      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12859      */
12860     resizable: false,
12861     /**
12862      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12863      */
12864     handleHeight : 8,
12865     /**
12866      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12867      * traditional select (defaults to true)
12868      */
12869     editable: true,
12870     /**
12871      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12872      */
12873     allQuery: '',
12874     /**
12875      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12876      */
12877     mode: 'remote',
12878     /**
12879      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12880      * listWidth has a higher value)
12881      */
12882     minListWidth : 70,
12883     /**
12884      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12885      * allow the user to set arbitrary text into the field (defaults to false)
12886      */
12887     forceSelection:false,
12888     /**
12889      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12890      * if typeAhead = true (defaults to 250)
12891      */
12892     typeAheadDelay : 250,
12893     /**
12894      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12895      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12896      */
12897     valueNotFoundText : undefined,
12898     /**
12899      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12900      */
12901     blockFocus : false,
12902     
12903     /**
12904      * @cfg {Boolean} disableClear Disable showing of clear button.
12905      */
12906     disableClear : false,
12907     /**
12908      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
12909      */
12910     alwaysQuery : false,
12911     
12912     /**
12913      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
12914      */
12915     multiple : false,
12916     
12917     /**
12918      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12919      */
12920     invalidClass : "has-warning",
12921     
12922     /**
12923      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12924      */
12925     validClass : "has-success",
12926     
12927     /**
12928      * @cfg {Boolean} specialFilter (true|false) special filter default false
12929      */
12930     specialFilter : false,
12931     
12932     /**
12933      * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12934      */
12935     mobileTouchView : true,
12936     
12937     /**
12938      * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12939      */
12940     useNativeIOS : false,
12941     
12942     ios_options : false,
12943     
12944     //private
12945     addicon : false,
12946     editicon: false,
12947     
12948     page: 0,
12949     hasQuery: false,
12950     append: false,
12951     loadNext: false,
12952     autoFocus : true,
12953     tickable : false,
12954     btnPosition : 'right',
12955     triggerList : true,
12956     showToggleBtn : true,
12957     animate : true,
12958     emptyResultText: 'Empty',
12959     triggerText : 'Select',
12960     emptyTitle : '',
12961     
12962     // element that contains real text value.. (when hidden is used..)
12963     
12964     getAutoCreate : function()
12965     {   
12966         var cfg = false;
12967         //render
12968         /*
12969          * Render classic select for iso
12970          */
12971         
12972         if(Roo.isIOS && this.useNativeIOS){
12973             cfg = this.getAutoCreateNativeIOS();
12974             return cfg;
12975         }
12976         
12977         /*
12978          * Touch Devices
12979          */
12980         
12981         if(Roo.isTouch && this.mobileTouchView){
12982             cfg = this.getAutoCreateTouchView();
12983             return cfg;;
12984         }
12985         
12986         /*
12987          *  Normal ComboBox
12988          */
12989         if(!this.tickable){
12990             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12991             return cfg;
12992         }
12993         
12994         /*
12995          *  ComboBox with tickable selections
12996          */
12997              
12998         var align = this.labelAlign || this.parentLabelAlign();
12999         
13000         cfg = {
13001             cls : 'form-group roo-combobox-tickable' //input-group
13002         };
13003         
13004         var btn_text_select = '';
13005         var btn_text_done = '';
13006         var btn_text_cancel = '';
13007         
13008         if (this.btn_text_show) {
13009             btn_text_select = 'Select';
13010             btn_text_done = 'Done';
13011             btn_text_cancel = 'Cancel'; 
13012         }
13013         
13014         var buttons = {
13015             tag : 'div',
13016             cls : 'tickable-buttons',
13017             cn : [
13018                 {
13019                     tag : 'button',
13020                     type : 'button',
13021                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13022                     //html : this.triggerText
13023                     html: btn_text_select
13024                 },
13025                 {
13026                     tag : 'button',
13027                     type : 'button',
13028                     name : 'ok',
13029                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13030                     //html : 'Done'
13031                     html: btn_text_done
13032                 },
13033                 {
13034                     tag : 'button',
13035                     type : 'button',
13036                     name : 'cancel',
13037                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13038                     //html : 'Cancel'
13039                     html: btn_text_cancel
13040                 }
13041             ]
13042         };
13043         
13044         if(this.editable){
13045             buttons.cn.unshift({
13046                 tag: 'input',
13047                 cls: 'roo-select2-search-field-input'
13048             });
13049         }
13050         
13051         var _this = this;
13052         
13053         Roo.each(buttons.cn, function(c){
13054             if (_this.size) {
13055                 c.cls += ' btn-' + _this.size;
13056             }
13057
13058             if (_this.disabled) {
13059                 c.disabled = true;
13060             }
13061         });
13062         
13063         var box = {
13064             tag: 'div',
13065             cn: [
13066                 {
13067                     tag: 'input',
13068                     type : 'hidden',
13069                     cls: 'form-hidden-field'
13070                 },
13071                 {
13072                     tag: 'ul',
13073                     cls: 'roo-select2-choices',
13074                     cn:[
13075                         {
13076                             tag: 'li',
13077                             cls: 'roo-select2-search-field',
13078                             cn: [
13079                                 buttons
13080                             ]
13081                         }
13082                     ]
13083                 }
13084             ]
13085         };
13086         
13087         var combobox = {
13088             cls: 'roo-select2-container input-group roo-select2-container-multi',
13089             cn: [
13090                 box
13091 //                {
13092 //                    tag: 'ul',
13093 //                    cls: 'typeahead typeahead-long dropdown-menu',
13094 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
13095 //                }
13096             ]
13097         };
13098         
13099         if(this.hasFeedback && !this.allowBlank){
13100             
13101             var feedback = {
13102                 tag: 'span',
13103                 cls: 'glyphicon form-control-feedback'
13104             };
13105
13106             combobox.cn.push(feedback);
13107         }
13108         
13109         
13110         if (align ==='left' && this.fieldLabel.length) {
13111             
13112             cfg.cls += ' roo-form-group-label-left';
13113             
13114             cfg.cn = [
13115                 {
13116                     tag : 'i',
13117                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13118                     tooltip : 'This field is required'
13119                 },
13120                 {
13121                     tag: 'label',
13122                     'for' :  id,
13123                     cls : 'control-label',
13124                     html : this.fieldLabel
13125
13126                 },
13127                 {
13128                     cls : "", 
13129                     cn: [
13130                         combobox
13131                     ]
13132                 }
13133
13134             ];
13135             
13136             var labelCfg = cfg.cn[1];
13137             var contentCfg = cfg.cn[2];
13138             
13139
13140             if(this.indicatorpos == 'right'){
13141                 
13142                 cfg.cn = [
13143                     {
13144                         tag: 'label',
13145                         'for' :  id,
13146                         cls : 'control-label',
13147                         cn : [
13148                             {
13149                                 tag : 'span',
13150                                 html : this.fieldLabel
13151                             },
13152                             {
13153                                 tag : 'i',
13154                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13155                                 tooltip : 'This field is required'
13156                             }
13157                         ]
13158                     },
13159                     {
13160                         cls : "",
13161                         cn: [
13162                             combobox
13163                         ]
13164                     }
13165
13166                 ];
13167                 
13168                 
13169                 
13170                 labelCfg = cfg.cn[0];
13171                 contentCfg = cfg.cn[1];
13172             
13173             }
13174             
13175             if(this.labelWidth > 12){
13176                 labelCfg.style = "width: " + this.labelWidth + 'px';
13177             }
13178             
13179             if(this.labelWidth < 13 && this.labelmd == 0){
13180                 this.labelmd = this.labelWidth;
13181             }
13182             
13183             if(this.labellg > 0){
13184                 labelCfg.cls += ' col-lg-' + this.labellg;
13185                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13186             }
13187             
13188             if(this.labelmd > 0){
13189                 labelCfg.cls += ' col-md-' + this.labelmd;
13190                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13191             }
13192             
13193             if(this.labelsm > 0){
13194                 labelCfg.cls += ' col-sm-' + this.labelsm;
13195                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13196             }
13197             
13198             if(this.labelxs > 0){
13199                 labelCfg.cls += ' col-xs-' + this.labelxs;
13200                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13201             }
13202                 
13203                 
13204         } else if ( this.fieldLabel.length) {
13205 //                Roo.log(" label");
13206                  cfg.cn = [
13207                     {
13208                         tag : 'i',
13209                         cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13210                         tooltip : 'This field is required'
13211                     },
13212                     {
13213                         tag: 'label',
13214                         //cls : 'input-group-addon',
13215                         html : this.fieldLabel
13216                     },
13217                     combobox
13218                 ];
13219                 
13220                 if(this.indicatorpos == 'right'){
13221                     cfg.cn = [
13222                         {
13223                             tag: 'label',
13224                             //cls : 'input-group-addon',
13225                             html : this.fieldLabel
13226                         },
13227                         {
13228                             tag : 'i',
13229                             cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13230                             tooltip : 'This field is required'
13231                         },
13232                         combobox
13233                     ];
13234                     
13235                 }
13236
13237         } else {
13238             
13239 //                Roo.log(" no label && no align");
13240                 cfg = combobox
13241                      
13242                 
13243         }
13244          
13245         var settings=this;
13246         ['xs','sm','md','lg'].map(function(size){
13247             if (settings[size]) {
13248                 cfg.cls += ' col-' + size + '-' + settings[size];
13249             }
13250         });
13251         
13252         return cfg;
13253         
13254     },
13255     
13256     _initEventsCalled : false,
13257     
13258     // private
13259     initEvents: function()
13260     {   
13261         if (this._initEventsCalled) { // as we call render... prevent looping...
13262             return;
13263         }
13264         this._initEventsCalled = true;
13265         
13266         if (!this.store) {
13267             throw "can not find store for combo";
13268         }
13269         
13270         this.indicator = this.indicatorEl();
13271         
13272         this.store = Roo.factory(this.store, Roo.data);
13273         this.store.parent = this;
13274         
13275         // if we are building from html. then this element is so complex, that we can not really
13276         // use the rendered HTML.
13277         // so we have to trash and replace the previous code.
13278         if (Roo.XComponent.build_from_html) {
13279             // remove this element....
13280             var e = this.el.dom, k=0;
13281             while (e ) { e = e.previousSibling;  ++k;}
13282
13283             this.el.remove();
13284             
13285             this.el=false;
13286             this.rendered = false;
13287             
13288             this.render(this.parent().getChildContainer(true), k);
13289         }
13290         
13291         if(Roo.isIOS && this.useNativeIOS){
13292             this.initIOSView();
13293             return;
13294         }
13295         
13296         /*
13297          * Touch Devices
13298          */
13299         
13300         if(Roo.isTouch && this.mobileTouchView){
13301             this.initTouchView();
13302             return;
13303         }
13304         
13305         if(this.tickable){
13306             this.initTickableEvents();
13307             return;
13308         }
13309         
13310         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13311         
13312         if(this.hiddenName){
13313             
13314             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13315             
13316             this.hiddenField.dom.value =
13317                 this.hiddenValue !== undefined ? this.hiddenValue :
13318                 this.value !== undefined ? this.value : '';
13319
13320             // prevent input submission
13321             this.el.dom.removeAttribute('name');
13322             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13323              
13324              
13325         }
13326         //if(Roo.isGecko){
13327         //    this.el.dom.setAttribute('autocomplete', 'off');
13328         //}
13329         
13330         var cls = 'x-combo-list';
13331         
13332         //this.list = new Roo.Layer({
13333         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13334         //});
13335         
13336         var _this = this;
13337         
13338         (function(){
13339             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13340             _this.list.setWidth(lw);
13341         }).defer(100);
13342         
13343         this.list.on('mouseover', this.onViewOver, this);
13344         this.list.on('mousemove', this.onViewMove, this);
13345         this.list.on('scroll', this.onViewScroll, this);
13346         
13347         /*
13348         this.list.swallowEvent('mousewheel');
13349         this.assetHeight = 0;
13350
13351         if(this.title){
13352             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13353             this.assetHeight += this.header.getHeight();
13354         }
13355
13356         this.innerList = this.list.createChild({cls:cls+'-inner'});
13357         this.innerList.on('mouseover', this.onViewOver, this);
13358         this.innerList.on('mousemove', this.onViewMove, this);
13359         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13360         
13361         if(this.allowBlank && !this.pageSize && !this.disableClear){
13362             this.footer = this.list.createChild({cls:cls+'-ft'});
13363             this.pageTb = new Roo.Toolbar(this.footer);
13364            
13365         }
13366         if(this.pageSize){
13367             this.footer = this.list.createChild({cls:cls+'-ft'});
13368             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13369                     {pageSize: this.pageSize});
13370             
13371         }
13372         
13373         if (this.pageTb && this.allowBlank && !this.disableClear) {
13374             var _this = this;
13375             this.pageTb.add(new Roo.Toolbar.Fill(), {
13376                 cls: 'x-btn-icon x-btn-clear',
13377                 text: '&#160;',
13378                 handler: function()
13379                 {
13380                     _this.collapse();
13381                     _this.clearValue();
13382                     _this.onSelect(false, -1);
13383                 }
13384             });
13385         }
13386         if (this.footer) {
13387             this.assetHeight += this.footer.getHeight();
13388         }
13389         */
13390             
13391         if(!this.tpl){
13392             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13393         }
13394
13395         this.view = new Roo.View(this.list, this.tpl, {
13396             singleSelect:true, store: this.store, selectedClass: this.selectedClass
13397         });
13398         //this.view.wrapEl.setDisplayed(false);
13399         this.view.on('click', this.onViewClick, this);
13400         
13401         
13402         this.store.on('beforeload', this.onBeforeLoad, this);
13403         this.store.on('load', this.onLoad, this);
13404         this.store.on('loadexception', this.onLoadException, this);
13405         /*
13406         if(this.resizable){
13407             this.resizer = new Roo.Resizable(this.list,  {
13408                pinned:true, handles:'se'
13409             });
13410             this.resizer.on('resize', function(r, w, h){
13411                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13412                 this.listWidth = w;
13413                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13414                 this.restrictHeight();
13415             }, this);
13416             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13417         }
13418         */
13419         if(!this.editable){
13420             this.editable = true;
13421             this.setEditable(false);
13422         }
13423         
13424         /*
13425         
13426         if (typeof(this.events.add.listeners) != 'undefined') {
13427             
13428             this.addicon = this.wrap.createChild(
13429                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
13430        
13431             this.addicon.on('click', function(e) {
13432                 this.fireEvent('add', this);
13433             }, this);
13434         }
13435         if (typeof(this.events.edit.listeners) != 'undefined') {
13436             
13437             this.editicon = this.wrap.createChild(
13438                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
13439             if (this.addicon) {
13440                 this.editicon.setStyle('margin-left', '40px');
13441             }
13442             this.editicon.on('click', function(e) {
13443                 
13444                 // we fire even  if inothing is selected..
13445                 this.fireEvent('edit', this, this.lastData );
13446                 
13447             }, this);
13448         }
13449         */
13450         
13451         this.keyNav = new Roo.KeyNav(this.inputEl(), {
13452             "up" : function(e){
13453                 this.inKeyMode = true;
13454                 this.selectPrev();
13455             },
13456
13457             "down" : function(e){
13458                 if(!this.isExpanded()){
13459                     this.onTriggerClick();
13460                 }else{
13461                     this.inKeyMode = true;
13462                     this.selectNext();
13463                 }
13464             },
13465
13466             "enter" : function(e){
13467 //                this.onViewClick();
13468                 //return true;
13469                 this.collapse();
13470                 
13471                 if(this.fireEvent("specialkey", this, e)){
13472                     this.onViewClick(false);
13473                 }
13474                 
13475                 return true;
13476             },
13477
13478             "esc" : function(e){
13479                 this.collapse();
13480             },
13481
13482             "tab" : function(e){
13483                 this.collapse();
13484                 
13485                 if(this.fireEvent("specialkey", this, e)){
13486                     this.onViewClick(false);
13487                 }
13488                 
13489                 return true;
13490             },
13491
13492             scope : this,
13493
13494             doRelay : function(foo, bar, hname){
13495                 if(hname == 'down' || this.scope.isExpanded()){
13496                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13497                 }
13498                 return true;
13499             },
13500
13501             forceKeyDown: true
13502         });
13503         
13504         
13505         this.queryDelay = Math.max(this.queryDelay || 10,
13506                 this.mode == 'local' ? 10 : 250);
13507         
13508         
13509         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13510         
13511         if(this.typeAhead){
13512             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13513         }
13514         if(this.editable !== false){
13515             this.inputEl().on("keyup", this.onKeyUp, this);
13516         }
13517         if(this.forceSelection){
13518             this.inputEl().on('blur', this.doForce, this);
13519         }
13520         
13521         if(this.multiple){
13522             this.choices = this.el.select('ul.roo-select2-choices', true).first();
13523             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13524         }
13525     },
13526     
13527     initTickableEvents: function()
13528     {   
13529         this.createList();
13530         
13531         if(this.hiddenName){
13532             
13533             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13534             
13535             this.hiddenField.dom.value =
13536                 this.hiddenValue !== undefined ? this.hiddenValue :
13537                 this.value !== undefined ? this.value : '';
13538
13539             // prevent input submission
13540             this.el.dom.removeAttribute('name');
13541             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13542              
13543              
13544         }
13545         
13546 //        this.list = this.el.select('ul.dropdown-menu',true).first();
13547         
13548         this.choices = this.el.select('ul.roo-select2-choices', true).first();
13549         this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13550         if(this.triggerList){
13551             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13552         }
13553          
13554         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13555         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13556         
13557         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13558         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13559         
13560         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13561         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13562         
13563         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13564         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13565         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13566         
13567         this.okBtn.hide();
13568         this.cancelBtn.hide();
13569         
13570         var _this = this;
13571         
13572         (function(){
13573             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13574             _this.list.setWidth(lw);
13575         }).defer(100);
13576         
13577         this.list.on('mouseover', this.onViewOver, this);
13578         this.list.on('mousemove', this.onViewMove, this);
13579         
13580         this.list.on('scroll', this.onViewScroll, this);
13581         
13582         if(!this.tpl){
13583             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>';
13584         }
13585
13586         this.view = new Roo.View(this.list, this.tpl, {
13587             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13588         });
13589         
13590         //this.view.wrapEl.setDisplayed(false);
13591         this.view.on('click', this.onViewClick, this);
13592         
13593         
13594         
13595         this.store.on('beforeload', this.onBeforeLoad, this);
13596         this.store.on('load', this.onLoad, this);
13597         this.store.on('loadexception', this.onLoadException, this);
13598         
13599         if(this.editable){
13600             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13601                 "up" : function(e){
13602                     this.inKeyMode = true;
13603                     this.selectPrev();
13604                 },
13605
13606                 "down" : function(e){
13607                     this.inKeyMode = true;
13608                     this.selectNext();
13609                 },
13610
13611                 "enter" : function(e){
13612                     if(this.fireEvent("specialkey", this, e)){
13613                         this.onViewClick(false);
13614                     }
13615                     
13616                     return true;
13617                 },
13618
13619                 "esc" : function(e){
13620                     this.onTickableFooterButtonClick(e, false, false);
13621                 },
13622
13623                 "tab" : function(e){
13624                     this.fireEvent("specialkey", this, e);
13625                     
13626                     this.onTickableFooterButtonClick(e, false, false);
13627                     
13628                     return true;
13629                 },
13630
13631                 scope : this,
13632
13633                 doRelay : function(e, fn, key){
13634                     if(this.scope.isExpanded()){
13635                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13636                     }
13637                     return true;
13638                 },
13639
13640                 forceKeyDown: true
13641             });
13642         }
13643         
13644         this.queryDelay = Math.max(this.queryDelay || 10,
13645                 this.mode == 'local' ? 10 : 250);
13646         
13647         
13648         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13649         
13650         if(this.typeAhead){
13651             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13652         }
13653         
13654         if(this.editable !== false){
13655             this.tickableInputEl().on("keyup", this.onKeyUp, this);
13656         }
13657         
13658         this.indicator = this.indicatorEl();
13659         
13660         if(this.indicator){
13661             this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13662             this.indicator.hide();
13663         }
13664         
13665     },
13666
13667     onDestroy : function(){
13668         if(this.view){
13669             this.view.setStore(null);
13670             this.view.el.removeAllListeners();
13671             this.view.el.remove();
13672             this.view.purgeListeners();
13673         }
13674         if(this.list){
13675             this.list.dom.innerHTML  = '';
13676         }
13677         
13678         if(this.store){
13679             this.store.un('beforeload', this.onBeforeLoad, this);
13680             this.store.un('load', this.onLoad, this);
13681             this.store.un('loadexception', this.onLoadException, this);
13682         }
13683         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13684     },
13685
13686     // private
13687     fireKey : function(e){
13688         if(e.isNavKeyPress() && !this.list.isVisible()){
13689             this.fireEvent("specialkey", this, e);
13690         }
13691     },
13692
13693     // private
13694     onResize: function(w, h){
13695 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13696 //        
13697 //        if(typeof w != 'number'){
13698 //            // we do not handle it!?!?
13699 //            return;
13700 //        }
13701 //        var tw = this.trigger.getWidth();
13702 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
13703 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
13704 //        var x = w - tw;
13705 //        this.inputEl().setWidth( this.adjustWidth('input', x));
13706 //            
13707 //        //this.trigger.setStyle('left', x+'px');
13708 //        
13709 //        if(this.list && this.listWidth === undefined){
13710 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13711 //            this.list.setWidth(lw);
13712 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13713 //        }
13714         
13715     
13716         
13717     },
13718
13719     /**
13720      * Allow or prevent the user from directly editing the field text.  If false is passed,
13721      * the user will only be able to select from the items defined in the dropdown list.  This method
13722      * is the runtime equivalent of setting the 'editable' config option at config time.
13723      * @param {Boolean} value True to allow the user to directly edit the field text
13724      */
13725     setEditable : function(value){
13726         if(value == this.editable){
13727             return;
13728         }
13729         this.editable = value;
13730         if(!value){
13731             this.inputEl().dom.setAttribute('readOnly', true);
13732             this.inputEl().on('mousedown', this.onTriggerClick,  this);
13733             this.inputEl().addClass('x-combo-noedit');
13734         }else{
13735             this.inputEl().dom.setAttribute('readOnly', false);
13736             this.inputEl().un('mousedown', this.onTriggerClick,  this);
13737             this.inputEl().removeClass('x-combo-noedit');
13738         }
13739     },
13740
13741     // private
13742     
13743     onBeforeLoad : function(combo,opts){
13744         if(!this.hasFocus){
13745             return;
13746         }
13747          if (!opts.add) {
13748             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13749          }
13750         this.restrictHeight();
13751         this.selectedIndex = -1;
13752     },
13753
13754     // private
13755     onLoad : function(){
13756         
13757         this.hasQuery = false;
13758         
13759         if(!this.hasFocus){
13760             return;
13761         }
13762         
13763         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13764             this.loading.hide();
13765         }
13766         
13767         if(this.store.getCount() > 0){
13768             
13769             this.expand();
13770             this.restrictHeight();
13771             if(this.lastQuery == this.allQuery){
13772                 if(this.editable && !this.tickable){
13773                     this.inputEl().dom.select();
13774                 }
13775                 
13776                 if(
13777                     !this.selectByValue(this.value, true) &&
13778                     this.autoFocus && 
13779                     (
13780                         !this.store.lastOptions ||
13781                         typeof(this.store.lastOptions.add) == 'undefined' || 
13782                         this.store.lastOptions.add != true
13783                     )
13784                 ){
13785                     this.select(0, true);
13786                 }
13787             }else{
13788                 if(this.autoFocus){
13789                     this.selectNext();
13790                 }
13791                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13792                     this.taTask.delay(this.typeAheadDelay);
13793                 }
13794             }
13795         }else{
13796             this.onEmptyResults();
13797         }
13798         
13799         //this.el.focus();
13800     },
13801     // private
13802     onLoadException : function()
13803     {
13804         this.hasQuery = false;
13805         
13806         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13807             this.loading.hide();
13808         }
13809         
13810         if(this.tickable && this.editable){
13811             return;
13812         }
13813         
13814         this.collapse();
13815         // only causes errors at present
13816         //Roo.log(this.store.reader.jsonData);
13817         //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13818             // fixme
13819             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13820         //}
13821         
13822         
13823     },
13824     // private
13825     onTypeAhead : function(){
13826         if(this.store.getCount() > 0){
13827             var r = this.store.getAt(0);
13828             var newValue = r.data[this.displayField];
13829             var len = newValue.length;
13830             var selStart = this.getRawValue().length;
13831             
13832             if(selStart != len){
13833                 this.setRawValue(newValue);
13834                 this.selectText(selStart, newValue.length);
13835             }
13836         }
13837     },
13838
13839     // private
13840     onSelect : function(record, index){
13841         
13842         if(this.fireEvent('beforeselect', this, record, index) !== false){
13843         
13844             this.setFromData(index > -1 ? record.data : false);
13845             
13846             this.collapse();
13847             this.fireEvent('select', this, record, index);
13848         }
13849     },
13850
13851     /**
13852      * Returns the currently selected field value or empty string if no value is set.
13853      * @return {String} value The selected value
13854      */
13855     getValue : function()
13856     {
13857         if(Roo.isIOS && this.useNativeIOS){
13858             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13859         }
13860         
13861         if(this.multiple){
13862             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13863         }
13864         
13865         if(this.valueField){
13866             return typeof this.value != 'undefined' ? this.value : '';
13867         }else{
13868             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13869         }
13870     },
13871     
13872     getRawValue : function()
13873     {
13874         if(Roo.isIOS && this.useNativeIOS){
13875             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13876         }
13877         
13878         var v = this.inputEl().getValue();
13879         
13880         return v;
13881     },
13882
13883     /**
13884      * Clears any text/value currently set in the field
13885      */
13886     clearValue : function(){
13887         
13888         if(this.hiddenField){
13889             this.hiddenField.dom.value = '';
13890         }
13891         this.value = '';
13892         this.setRawValue('');
13893         this.lastSelectionText = '';
13894         this.lastData = false;
13895         
13896         var close = this.closeTriggerEl();
13897         
13898         if(close){
13899             close.hide();
13900         }
13901         
13902         this.validate();
13903         
13904     },
13905
13906     /**
13907      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
13908      * will be displayed in the field.  If the value does not match the data value of an existing item,
13909      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13910      * Otherwise the field will be blank (although the value will still be set).
13911      * @param {String} value The value to match
13912      */
13913     setValue : function(v)
13914     {
13915         if(Roo.isIOS && this.useNativeIOS){
13916             this.setIOSValue(v);
13917             return;
13918         }
13919         
13920         if(this.multiple){
13921             this.syncValue();
13922             return;
13923         }
13924         
13925         var text = v;
13926         if(this.valueField){
13927             var r = this.findRecord(this.valueField, v);
13928             if(r){
13929                 text = r.data[this.displayField];
13930             }else if(this.valueNotFoundText !== undefined){
13931                 text = this.valueNotFoundText;
13932             }
13933         }
13934         this.lastSelectionText = text;
13935         if(this.hiddenField){
13936             this.hiddenField.dom.value = v;
13937         }
13938         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13939         this.value = v;
13940         
13941         var close = this.closeTriggerEl();
13942         
13943         if(close){
13944             (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13945         }
13946         
13947         this.validate();
13948     },
13949     /**
13950      * @property {Object} the last set data for the element
13951      */
13952     
13953     lastData : false,
13954     /**
13955      * Sets the value of the field based on a object which is related to the record format for the store.
13956      * @param {Object} value the value to set as. or false on reset?
13957      */
13958     setFromData : function(o){
13959         
13960         if(this.multiple){
13961             this.addItem(o);
13962             return;
13963         }
13964             
13965         var dv = ''; // display value
13966         var vv = ''; // value value..
13967         this.lastData = o;
13968         if (this.displayField) {
13969             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13970         } else {
13971             // this is an error condition!!!
13972             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
13973         }
13974         
13975         if(this.valueField){
13976             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13977         }
13978         
13979         var close = this.closeTriggerEl();
13980         
13981         if(close){
13982             if(dv.length || vv * 1 > 0){
13983                 close.show() ;
13984                 this.blockFocus=true;
13985             } else {
13986                 close.hide();
13987             }             
13988         }
13989         
13990         if(this.hiddenField){
13991             this.hiddenField.dom.value = vv;
13992             
13993             this.lastSelectionText = dv;
13994             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13995             this.value = vv;
13996             return;
13997         }
13998         // no hidden field.. - we store the value in 'value', but still display
13999         // display field!!!!
14000         this.lastSelectionText = dv;
14001         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14002         this.value = vv;
14003         
14004         
14005         
14006     },
14007     // private
14008     reset : function(){
14009         // overridden so that last data is reset..
14010         
14011         if(this.multiple){
14012             this.clearItem();
14013             return;
14014         }
14015         
14016         this.setValue(this.originalValue);
14017         //this.clearInvalid();
14018         this.lastData = false;
14019         if (this.view) {
14020             this.view.clearSelections();
14021         }
14022         
14023         this.validate();
14024     },
14025     // private
14026     findRecord : function(prop, value){
14027         var record;
14028         if(this.store.getCount() > 0){
14029             this.store.each(function(r){
14030                 if(r.data[prop] == value){
14031                     record = r;
14032                     return false;
14033                 }
14034                 return true;
14035             });
14036         }
14037         return record;
14038     },
14039     
14040     getName: function()
14041     {
14042         // returns hidden if it's set..
14043         if (!this.rendered) {return ''};
14044         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
14045         
14046     },
14047     // private
14048     onViewMove : function(e, t){
14049         this.inKeyMode = false;
14050     },
14051
14052     // private
14053     onViewOver : function(e, t){
14054         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14055             return;
14056         }
14057         var item = this.view.findItemFromChild(t);
14058         
14059         if(item){
14060             var index = this.view.indexOf(item);
14061             this.select(index, false);
14062         }
14063     },
14064
14065     // private
14066     onViewClick : function(view, doFocus, el, e)
14067     {
14068         var index = this.view.getSelectedIndexes()[0];
14069         
14070         var r = this.store.getAt(index);
14071         
14072         if(this.tickable){
14073             
14074             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14075                 return;
14076             }
14077             
14078             var rm = false;
14079             var _this = this;
14080             
14081             Roo.each(this.tickItems, function(v,k){
14082                 
14083                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14084                     Roo.log(v);
14085                     _this.tickItems.splice(k, 1);
14086                     
14087                     if(typeof(e) == 'undefined' && view == false){
14088                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14089                     }
14090                     
14091                     rm = true;
14092                     return;
14093                 }
14094             });
14095             
14096             if(rm){
14097                 return;
14098             }
14099             
14100             if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14101                 this.tickItems.push(r.data);
14102             }
14103             
14104             if(typeof(e) == 'undefined' && view == false){
14105                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14106             }
14107                     
14108             return;
14109         }
14110         
14111         if(r){
14112             this.onSelect(r, index);
14113         }
14114         if(doFocus !== false && !this.blockFocus){
14115             this.inputEl().focus();
14116         }
14117     },
14118
14119     // private
14120     restrictHeight : function(){
14121         //this.innerList.dom.style.height = '';
14122         //var inner = this.innerList.dom;
14123         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14124         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14125         //this.list.beginUpdate();
14126         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14127         this.list.alignTo(this.inputEl(), this.listAlign);
14128         this.list.alignTo(this.inputEl(), this.listAlign);
14129         //this.list.endUpdate();
14130     },
14131
14132     // private
14133     onEmptyResults : function(){
14134         
14135         if(this.tickable && this.editable){
14136             this.hasFocus = false;
14137             this.restrictHeight();
14138             return;
14139         }
14140         
14141         this.collapse();
14142     },
14143
14144     /**
14145      * Returns true if the dropdown list is expanded, else false.
14146      */
14147     isExpanded : function(){
14148         return this.list.isVisible();
14149     },
14150
14151     /**
14152      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14153      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14154      * @param {String} value The data value of the item to select
14155      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14156      * selected item if it is not currently in view (defaults to true)
14157      * @return {Boolean} True if the value matched an item in the list, else false
14158      */
14159     selectByValue : function(v, scrollIntoView){
14160         if(v !== undefined && v !== null){
14161             var r = this.findRecord(this.valueField || this.displayField, v);
14162             if(r){
14163                 this.select(this.store.indexOf(r), scrollIntoView);
14164                 return true;
14165             }
14166         }
14167         return false;
14168     },
14169
14170     /**
14171      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14172      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14173      * @param {Number} index The zero-based index of the list item to select
14174      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14175      * selected item if it is not currently in view (defaults to true)
14176      */
14177     select : function(index, scrollIntoView){
14178         this.selectedIndex = index;
14179         this.view.select(index);
14180         if(scrollIntoView !== false){
14181             var el = this.view.getNode(index);
14182             /*
14183              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14184              */
14185             if(el){
14186                 this.list.scrollChildIntoView(el, false);
14187             }
14188         }
14189     },
14190
14191     // private
14192     selectNext : function(){
14193         var ct = this.store.getCount();
14194         if(ct > 0){
14195             if(this.selectedIndex == -1){
14196                 this.select(0);
14197             }else if(this.selectedIndex < ct-1){
14198                 this.select(this.selectedIndex+1);
14199             }
14200         }
14201     },
14202
14203     // private
14204     selectPrev : function(){
14205         var ct = this.store.getCount();
14206         if(ct > 0){
14207             if(this.selectedIndex == -1){
14208                 this.select(0);
14209             }else if(this.selectedIndex != 0){
14210                 this.select(this.selectedIndex-1);
14211             }
14212         }
14213     },
14214
14215     // private
14216     onKeyUp : function(e){
14217         if(this.editable !== false && !e.isSpecialKey()){
14218             this.lastKey = e.getKey();
14219             this.dqTask.delay(this.queryDelay);
14220         }
14221     },
14222
14223     // private
14224     validateBlur : function(){
14225         return !this.list || !this.list.isVisible();   
14226     },
14227
14228     // private
14229     initQuery : function(){
14230         
14231         var v = this.getRawValue();
14232         
14233         if(this.tickable && this.editable){
14234             v = this.tickableInputEl().getValue();
14235         }
14236         
14237         this.doQuery(v);
14238     },
14239
14240     // private
14241     doForce : function(){
14242         if(this.inputEl().dom.value.length > 0){
14243             this.inputEl().dom.value =
14244                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14245              
14246         }
14247     },
14248
14249     /**
14250      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
14251      * query allowing the query action to be canceled if needed.
14252      * @param {String} query The SQL query to execute
14253      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14254      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
14255      * saved in the current store (defaults to false)
14256      */
14257     doQuery : function(q, forceAll){
14258         
14259         if(q === undefined || q === null){
14260             q = '';
14261         }
14262         var qe = {
14263             query: q,
14264             forceAll: forceAll,
14265             combo: this,
14266             cancel:false
14267         };
14268         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14269             return false;
14270         }
14271         q = qe.query;
14272         
14273         forceAll = qe.forceAll;
14274         if(forceAll === true || (q.length >= this.minChars)){
14275             
14276             this.hasQuery = true;
14277             
14278             if(this.lastQuery != q || this.alwaysQuery){
14279                 this.lastQuery = q;
14280                 if(this.mode == 'local'){
14281                     this.selectedIndex = -1;
14282                     if(forceAll){
14283                         this.store.clearFilter();
14284                     }else{
14285                         
14286                         if(this.specialFilter){
14287                             this.fireEvent('specialfilter', this);
14288                             this.onLoad();
14289                             return;
14290                         }
14291                         
14292                         this.store.filter(this.displayField, q);
14293                     }
14294                     
14295                     this.store.fireEvent("datachanged", this.store);
14296                     
14297                     this.onLoad();
14298                     
14299                     
14300                 }else{
14301                     
14302                     this.store.baseParams[this.queryParam] = q;
14303                     
14304                     var options = {params : this.getParams(q)};
14305                     
14306                     if(this.loadNext){
14307                         options.add = true;
14308                         options.params.start = this.page * this.pageSize;
14309                     }
14310                     
14311                     this.store.load(options);
14312                     
14313                     /*
14314                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
14315                      *  we should expand the list on onLoad
14316                      *  so command out it
14317                      */
14318 //                    this.expand();
14319                 }
14320             }else{
14321                 this.selectedIndex = -1;
14322                 this.onLoad();   
14323             }
14324         }
14325         
14326         this.loadNext = false;
14327     },
14328     
14329     // private
14330     getParams : function(q){
14331         var p = {};
14332         //p[this.queryParam] = q;
14333         
14334         if(this.pageSize){
14335             p.start = 0;
14336             p.limit = this.pageSize;
14337         }
14338         return p;
14339     },
14340
14341     /**
14342      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14343      */
14344     collapse : function(){
14345         if(!this.isExpanded()){
14346             return;
14347         }
14348         
14349         this.list.hide();
14350         
14351         this.hasFocus = false;
14352         
14353         if(this.tickable){
14354             this.okBtn.hide();
14355             this.cancelBtn.hide();
14356             this.trigger.show();
14357             
14358             if(this.editable){
14359                 this.tickableInputEl().dom.value = '';
14360                 this.tickableInputEl().blur();
14361             }
14362             
14363         }
14364         
14365         Roo.get(document).un('mousedown', this.collapseIf, this);
14366         Roo.get(document).un('mousewheel', this.collapseIf, this);
14367         if (!this.editable) {
14368             Roo.get(document).un('keydown', this.listKeyPress, this);
14369         }
14370         this.fireEvent('collapse', this);
14371         
14372         this.validate();
14373     },
14374
14375     // private
14376     collapseIf : function(e){
14377         var in_combo  = e.within(this.el);
14378         var in_list =  e.within(this.list);
14379         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14380         
14381         if (in_combo || in_list || is_list) {
14382             //e.stopPropagation();
14383             return;
14384         }
14385         
14386         if(this.tickable){
14387             this.onTickableFooterButtonClick(e, false, false);
14388         }
14389
14390         this.collapse();
14391         
14392     },
14393
14394     /**
14395      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14396      */
14397     expand : function(){
14398        
14399         if(this.isExpanded() || !this.hasFocus){
14400             return;
14401         }
14402         
14403         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14404         this.list.setWidth(lw);
14405         
14406         Roo.log('expand');
14407         
14408         this.list.show();
14409         
14410         this.restrictHeight();
14411         
14412         if(this.tickable){
14413             
14414             this.tickItems = Roo.apply([], this.item);
14415             
14416             this.okBtn.show();
14417             this.cancelBtn.show();
14418             this.trigger.hide();
14419             
14420             if(this.editable){
14421                 this.tickableInputEl().focus();
14422             }
14423             
14424         }
14425         
14426         Roo.get(document).on('mousedown', this.collapseIf, this);
14427         Roo.get(document).on('mousewheel', this.collapseIf, this);
14428         if (!this.editable) {
14429             Roo.get(document).on('keydown', this.listKeyPress, this);
14430         }
14431         
14432         this.fireEvent('expand', this);
14433     },
14434
14435     // private
14436     // Implements the default empty TriggerField.onTriggerClick function
14437     onTriggerClick : function(e)
14438     {
14439         Roo.log('trigger click');
14440         
14441         if(this.disabled || !this.triggerList){
14442             return;
14443         }
14444         
14445         this.page = 0;
14446         this.loadNext = false;
14447         
14448         if(this.isExpanded()){
14449             this.collapse();
14450             if (!this.blockFocus) {
14451                 this.inputEl().focus();
14452             }
14453             
14454         }else {
14455             this.hasFocus = true;
14456             if(this.triggerAction == 'all') {
14457                 this.doQuery(this.allQuery, true);
14458             } else {
14459                 this.doQuery(this.getRawValue());
14460             }
14461             if (!this.blockFocus) {
14462                 this.inputEl().focus();
14463             }
14464         }
14465     },
14466     
14467     onTickableTriggerClick : function(e)
14468     {
14469         if(this.disabled){
14470             return;
14471         }
14472         
14473         this.page = 0;
14474         this.loadNext = false;
14475         this.hasFocus = true;
14476         
14477         if(this.triggerAction == 'all') {
14478             this.doQuery(this.allQuery, true);
14479         } else {
14480             this.doQuery(this.getRawValue());
14481         }
14482     },
14483     
14484     onSearchFieldClick : function(e)
14485     {
14486         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14487             this.onTickableFooterButtonClick(e, false, false);
14488             return;
14489         }
14490         
14491         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14492             return;
14493         }
14494         
14495         this.page = 0;
14496         this.loadNext = false;
14497         this.hasFocus = true;
14498         
14499         if(this.triggerAction == 'all') {
14500             this.doQuery(this.allQuery, true);
14501         } else {
14502             this.doQuery(this.getRawValue());
14503         }
14504     },
14505     
14506     listKeyPress : function(e)
14507     {
14508         //Roo.log('listkeypress');
14509         // scroll to first matching element based on key pres..
14510         if (e.isSpecialKey()) {
14511             return false;
14512         }
14513         var k = String.fromCharCode(e.getKey()).toUpperCase();
14514         //Roo.log(k);
14515         var match  = false;
14516         var csel = this.view.getSelectedNodes();
14517         var cselitem = false;
14518         if (csel.length) {
14519             var ix = this.view.indexOf(csel[0]);
14520             cselitem  = this.store.getAt(ix);
14521             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14522                 cselitem = false;
14523             }
14524             
14525         }
14526         
14527         this.store.each(function(v) { 
14528             if (cselitem) {
14529                 // start at existing selection.
14530                 if (cselitem.id == v.id) {
14531                     cselitem = false;
14532                 }
14533                 return true;
14534             }
14535                 
14536             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14537                 match = this.store.indexOf(v);
14538                 return false;
14539             }
14540             return true;
14541         }, this);
14542         
14543         if (match === false) {
14544             return true; // no more action?
14545         }
14546         // scroll to?
14547         this.view.select(match);
14548         var sn = Roo.get(this.view.getSelectedNodes()[0]);
14549         sn.scrollIntoView(sn.dom.parentNode, false);
14550     },
14551     
14552     onViewScroll : function(e, t){
14553         
14554         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){
14555             return;
14556         }
14557         
14558         this.hasQuery = true;
14559         
14560         this.loading = this.list.select('.loading', true).first();
14561         
14562         if(this.loading === null){
14563             this.list.createChild({
14564                 tag: 'div',
14565                 cls: 'loading roo-select2-more-results roo-select2-active',
14566                 html: 'Loading more results...'
14567             });
14568             
14569             this.loading = this.list.select('.loading', true).first();
14570             
14571             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14572             
14573             this.loading.hide();
14574         }
14575         
14576         this.loading.show();
14577         
14578         var _combo = this;
14579         
14580         this.page++;
14581         this.loadNext = true;
14582         
14583         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14584         
14585         return;
14586     },
14587     
14588     addItem : function(o)
14589     {   
14590         var dv = ''; // display value
14591         
14592         if (this.displayField) {
14593             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14594         } else {
14595             // this is an error condition!!!
14596             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14597         }
14598         
14599         if(!dv.length){
14600             return;
14601         }
14602         
14603         var choice = this.choices.createChild({
14604             tag: 'li',
14605             cls: 'roo-select2-search-choice',
14606             cn: [
14607                 {
14608                     tag: 'div',
14609                     html: dv
14610                 },
14611                 {
14612                     tag: 'a',
14613                     href: '#',
14614                     cls: 'roo-select2-search-choice-close fa fa-times',
14615                     tabindex: '-1'
14616                 }
14617             ]
14618             
14619         }, this.searchField);
14620         
14621         var close = choice.select('a.roo-select2-search-choice-close', true).first();
14622         
14623         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14624         
14625         this.item.push(o);
14626         
14627         this.lastData = o;
14628         
14629         this.syncValue();
14630         
14631         this.inputEl().dom.value = '';
14632         
14633         this.validate();
14634     },
14635     
14636     onRemoveItem : function(e, _self, o)
14637     {
14638         e.preventDefault();
14639         
14640         this.lastItem = Roo.apply([], this.item);
14641         
14642         var index = this.item.indexOf(o.data) * 1;
14643         
14644         if( index < 0){
14645             Roo.log('not this item?!');
14646             return;
14647         }
14648         
14649         this.item.splice(index, 1);
14650         o.item.remove();
14651         
14652         this.syncValue();
14653         
14654         this.fireEvent('remove', this, e);
14655         
14656         this.validate();
14657         
14658     },
14659     
14660     syncValue : function()
14661     {
14662         if(!this.item.length){
14663             this.clearValue();
14664             return;
14665         }
14666             
14667         var value = [];
14668         var _this = this;
14669         Roo.each(this.item, function(i){
14670             if(_this.valueField){
14671                 value.push(i[_this.valueField]);
14672                 return;
14673             }
14674
14675             value.push(i);
14676         });
14677
14678         this.value = value.join(',');
14679
14680         if(this.hiddenField){
14681             this.hiddenField.dom.value = this.value;
14682         }
14683         
14684         this.store.fireEvent("datachanged", this.store);
14685         
14686         this.validate();
14687     },
14688     
14689     clearItem : function()
14690     {
14691         if(!this.multiple){
14692             return;
14693         }
14694         
14695         this.item = [];
14696         
14697         Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14698            c.remove();
14699         });
14700         
14701         this.syncValue();
14702         
14703         this.validate();
14704         
14705         if(this.tickable && !Roo.isTouch){
14706             this.view.refresh();
14707         }
14708     },
14709     
14710     inputEl: function ()
14711     {
14712         if(Roo.isIOS && this.useNativeIOS){
14713             return this.el.select('select.roo-ios-select', true).first();
14714         }
14715         
14716         if(Roo.isTouch && this.mobileTouchView){
14717             return this.el.select('input.form-control',true).first();
14718         }
14719         
14720         if(this.tickable){
14721             return this.searchField;
14722         }
14723         
14724         return this.el.select('input.form-control',true).first();
14725     },
14726     
14727     onTickableFooterButtonClick : function(e, btn, el)
14728     {
14729         e.preventDefault();
14730         
14731         this.lastItem = Roo.apply([], this.item);
14732         
14733         if(btn && btn.name == 'cancel'){
14734             this.tickItems = Roo.apply([], this.item);
14735             this.collapse();
14736             return;
14737         }
14738         
14739         this.clearItem();
14740         
14741         var _this = this;
14742         
14743         Roo.each(this.tickItems, function(o){
14744             _this.addItem(o);
14745         });
14746         
14747         this.collapse();
14748         
14749     },
14750     
14751     validate : function()
14752     {
14753         if(this.getVisibilityEl().hasClass('hidden')){
14754             return true;
14755         }
14756         
14757         var v = this.getRawValue();
14758         
14759         if(this.multiple){
14760             v = this.getValue();
14761         }
14762         
14763         if(this.disabled || this.allowBlank || v.length){
14764             this.markValid();
14765             return true;
14766         }
14767         
14768         this.markInvalid();
14769         return false;
14770     },
14771     
14772     tickableInputEl : function()
14773     {
14774         if(!this.tickable || !this.editable){
14775             return this.inputEl();
14776         }
14777         
14778         return this.inputEl().select('.roo-select2-search-field-input', true).first();
14779     },
14780     
14781     
14782     getAutoCreateTouchView : function()
14783     {
14784         var id = Roo.id();
14785         
14786         var cfg = {
14787             cls: 'form-group' //input-group
14788         };
14789         
14790         var input =  {
14791             tag: 'input',
14792             id : id,
14793             type : this.inputType,
14794             cls : 'form-control x-combo-noedit',
14795             autocomplete: 'new-password',
14796             placeholder : this.placeholder || '',
14797             readonly : true
14798         };
14799         
14800         if (this.name) {
14801             input.name = this.name;
14802         }
14803         
14804         if (this.size) {
14805             input.cls += ' input-' + this.size;
14806         }
14807         
14808         if (this.disabled) {
14809             input.disabled = true;
14810         }
14811         
14812         var inputblock = {
14813             cls : '',
14814             cn : [
14815                 input
14816             ]
14817         };
14818         
14819         if(this.before){
14820             inputblock.cls += ' input-group';
14821             
14822             inputblock.cn.unshift({
14823                 tag :'span',
14824                 cls : 'input-group-addon',
14825                 html : this.before
14826             });
14827         }
14828         
14829         if(this.removable && !this.multiple){
14830             inputblock.cls += ' roo-removable';
14831             
14832             inputblock.cn.push({
14833                 tag: 'button',
14834                 html : 'x',
14835                 cls : 'roo-combo-removable-btn close'
14836             });
14837         }
14838
14839         if(this.hasFeedback && !this.allowBlank){
14840             
14841             inputblock.cls += ' has-feedback';
14842             
14843             inputblock.cn.push({
14844                 tag: 'span',
14845                 cls: 'glyphicon form-control-feedback'
14846             });
14847             
14848         }
14849         
14850         if (this.after) {
14851             
14852             inputblock.cls += (this.before) ? '' : ' input-group';
14853             
14854             inputblock.cn.push({
14855                 tag :'span',
14856                 cls : 'input-group-addon',
14857                 html : this.after
14858             });
14859         }
14860
14861         var box = {
14862             tag: 'div',
14863             cn: [
14864                 {
14865                     tag: 'input',
14866                     type : 'hidden',
14867                     cls: 'form-hidden-field'
14868                 },
14869                 inputblock
14870             ]
14871             
14872         };
14873         
14874         if(this.multiple){
14875             box = {
14876                 tag: 'div',
14877                 cn: [
14878                     {
14879                         tag: 'input',
14880                         type : 'hidden',
14881                         cls: 'form-hidden-field'
14882                     },
14883                     {
14884                         tag: 'ul',
14885                         cls: 'roo-select2-choices',
14886                         cn:[
14887                             {
14888                                 tag: 'li',
14889                                 cls: 'roo-select2-search-field',
14890                                 cn: [
14891
14892                                     inputblock
14893                                 ]
14894                             }
14895                         ]
14896                     }
14897                 ]
14898             }
14899         };
14900         
14901         var combobox = {
14902             cls: 'roo-select2-container input-group roo-touchview-combobox ',
14903             cn: [
14904                 box
14905             ]
14906         };
14907         
14908         if(!this.multiple && this.showToggleBtn){
14909             
14910             var caret = {
14911                         tag: 'span',
14912                         cls: 'caret'
14913             };
14914             
14915             if (this.caret != false) {
14916                 caret = {
14917                      tag: 'i',
14918                      cls: 'fa fa-' + this.caret
14919                 };
14920                 
14921             }
14922             
14923             combobox.cn.push({
14924                 tag :'span',
14925                 cls : 'input-group-addon btn dropdown-toggle',
14926                 cn : [
14927                     caret,
14928                     {
14929                         tag: 'span',
14930                         cls: 'combobox-clear',
14931                         cn  : [
14932                             {
14933                                 tag : 'i',
14934                                 cls: 'icon-remove'
14935                             }
14936                         ]
14937                     }
14938                 ]
14939
14940             })
14941         }
14942         
14943         if(this.multiple){
14944             combobox.cls += ' roo-select2-container-multi';
14945         }
14946         
14947         var align = this.labelAlign || this.parentLabelAlign();
14948         
14949         if (align ==='left' && this.fieldLabel.length) {
14950
14951             cfg.cn = [
14952                 {
14953                    tag : 'i',
14954                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14955                    tooltip : 'This field is required'
14956                 },
14957                 {
14958                     tag: 'label',
14959                     cls : 'control-label',
14960                     html : this.fieldLabel
14961
14962                 },
14963                 {
14964                     cls : '', 
14965                     cn: [
14966                         combobox
14967                     ]
14968                 }
14969             ];
14970             
14971             var labelCfg = cfg.cn[1];
14972             var contentCfg = cfg.cn[2];
14973             
14974
14975             if(this.indicatorpos == 'right'){
14976                 cfg.cn = [
14977                     {
14978                         tag: 'label',
14979                         'for' :  id,
14980                         cls : 'control-label',
14981                         cn : [
14982                             {
14983                                 tag : 'span',
14984                                 html : this.fieldLabel
14985                             },
14986                             {
14987                                 tag : 'i',
14988                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14989                                 tooltip : 'This field is required'
14990                             }
14991                         ]
14992                     },
14993                     {
14994                         cls : "",
14995                         cn: [
14996                             combobox
14997                         ]
14998                     }
14999
15000                 ];
15001                 
15002                 labelCfg = cfg.cn[0];
15003                 contentCfg = cfg.cn[1];
15004             }
15005             
15006            
15007             
15008             if(this.labelWidth > 12){
15009                 labelCfg.style = "width: " + this.labelWidth + 'px';
15010             }
15011             
15012             if(this.labelWidth < 13 && this.labelmd == 0){
15013                 this.labelmd = this.labelWidth;
15014             }
15015             
15016             if(this.labellg > 0){
15017                 labelCfg.cls += ' col-lg-' + this.labellg;
15018                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15019             }
15020             
15021             if(this.labelmd > 0){
15022                 labelCfg.cls += ' col-md-' + this.labelmd;
15023                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15024             }
15025             
15026             if(this.labelsm > 0){
15027                 labelCfg.cls += ' col-sm-' + this.labelsm;
15028                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15029             }
15030             
15031             if(this.labelxs > 0){
15032                 labelCfg.cls += ' col-xs-' + this.labelxs;
15033                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15034             }
15035                 
15036                 
15037         } else if ( this.fieldLabel.length) {
15038             cfg.cn = [
15039                 {
15040                    tag : 'i',
15041                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15042                    tooltip : 'This field is required'
15043                 },
15044                 {
15045                     tag: 'label',
15046                     cls : 'control-label',
15047                     html : this.fieldLabel
15048
15049                 },
15050                 {
15051                     cls : '', 
15052                     cn: [
15053                         combobox
15054                     ]
15055                 }
15056             ];
15057             
15058             if(this.indicatorpos == 'right'){
15059                 cfg.cn = [
15060                     {
15061                         tag: 'label',
15062                         cls : 'control-label',
15063                         html : this.fieldLabel,
15064                         cn : [
15065                             {
15066                                tag : 'i',
15067                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15068                                tooltip : 'This field is required'
15069                             }
15070                         ]
15071                     },
15072                     {
15073                         cls : '', 
15074                         cn: [
15075                             combobox
15076                         ]
15077                     }
15078                 ];
15079             }
15080         } else {
15081             cfg.cn = combobox;    
15082         }
15083         
15084         
15085         var settings = this;
15086         
15087         ['xs','sm','md','lg'].map(function(size){
15088             if (settings[size]) {
15089                 cfg.cls += ' col-' + size + '-' + settings[size];
15090             }
15091         });
15092         
15093         return cfg;
15094     },
15095     
15096     initTouchView : function()
15097     {
15098         this.renderTouchView();
15099         
15100         this.touchViewEl.on('scroll', function(){
15101             this.el.dom.scrollTop = 0;
15102         }, this);
15103         
15104         this.originalValue = this.getValue();
15105         
15106         this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15107         
15108         this.inputEl().on("click", this.showTouchView, this);
15109         if (this.triggerEl) {
15110             this.triggerEl.on("click", this.showTouchView, this);
15111         }
15112         
15113         
15114         this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15115         this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15116         
15117         this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15118         
15119         this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15120         this.store.on('load', this.onTouchViewLoad, this);
15121         this.store.on('loadexception', this.onTouchViewLoadException, this);
15122         
15123         if(this.hiddenName){
15124             
15125             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15126             
15127             this.hiddenField.dom.value =
15128                 this.hiddenValue !== undefined ? this.hiddenValue :
15129                 this.value !== undefined ? this.value : '';
15130         
15131             this.el.dom.removeAttribute('name');
15132             this.hiddenField.dom.setAttribute('name', this.hiddenName);
15133         }
15134         
15135         if(this.multiple){
15136             this.choices = this.el.select('ul.roo-select2-choices', true).first();
15137             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15138         }
15139         
15140         if(this.removable && !this.multiple){
15141             var close = this.closeTriggerEl();
15142             if(close){
15143                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15144                 close.on('click', this.removeBtnClick, this, close);
15145             }
15146         }
15147         /*
15148          * fix the bug in Safari iOS8
15149          */
15150         this.inputEl().on("focus", function(e){
15151             document.activeElement.blur();
15152         }, this);
15153         
15154         return;
15155         
15156         
15157     },
15158     
15159     renderTouchView : function()
15160     {
15161         this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15162         this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15163         
15164         this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15165         this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15166         
15167         this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15168         this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15169         this.touchViewBodyEl.setStyle('overflow', 'auto');
15170         
15171         this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15172         this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15173         
15174         this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15175         this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15176         
15177     },
15178     
15179     showTouchView : function()
15180     {
15181         if(this.disabled){
15182             return;
15183         }
15184         
15185         this.touchViewHeaderEl.hide();
15186
15187         if(this.modalTitle.length){
15188             this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15189             this.touchViewHeaderEl.show();
15190         }
15191
15192         this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15193         this.touchViewEl.show();
15194
15195         this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15196         
15197         //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15198         //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15199
15200         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15201
15202         if(this.modalTitle.length){
15203             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15204         }
15205         
15206         this.touchViewBodyEl.setHeight(bodyHeight);
15207
15208         if(this.animate){
15209             var _this = this;
15210             (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15211         }else{
15212             this.touchViewEl.addClass('in');
15213         }
15214
15215         this.doTouchViewQuery();
15216         
15217     },
15218     
15219     hideTouchView : function()
15220     {
15221         this.touchViewEl.removeClass('in');
15222
15223         if(this.animate){
15224             var _this = this;
15225             (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15226         }else{
15227             this.touchViewEl.setStyle('display', 'none');
15228         }
15229         
15230     },
15231     
15232     setTouchViewValue : function()
15233     {
15234         if(this.multiple){
15235             this.clearItem();
15236         
15237             var _this = this;
15238
15239             Roo.each(this.tickItems, function(o){
15240                 this.addItem(o);
15241             }, this);
15242         }
15243         
15244         this.hideTouchView();
15245     },
15246     
15247     doTouchViewQuery : function()
15248     {
15249         var qe = {
15250             query: '',
15251             forceAll: true,
15252             combo: this,
15253             cancel:false
15254         };
15255         
15256         if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15257             return false;
15258         }
15259         
15260         if(!this.alwaysQuery || this.mode == 'local'){
15261             this.onTouchViewLoad();
15262             return;
15263         }
15264         
15265         this.store.load();
15266     },
15267     
15268     onTouchViewBeforeLoad : function(combo,opts)
15269     {
15270         return;
15271     },
15272
15273     // private
15274     onTouchViewLoad : function()
15275     {
15276         if(this.store.getCount() < 1){
15277             this.onTouchViewEmptyResults();
15278             return;
15279         }
15280         
15281         this.clearTouchView();
15282         
15283         var rawValue = this.getRawValue();
15284         
15285         var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15286         
15287         this.tickItems = [];
15288         
15289         this.store.data.each(function(d, rowIndex){
15290             var row = this.touchViewListGroup.createChild(template);
15291             
15292             if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15293                 row.addClass(d.data.cls);
15294             }
15295             
15296             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15297                 var cfg = {
15298                     data : d.data,
15299                     html : d.data[this.displayField]
15300                 };
15301                 
15302                 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15303                     row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15304                 }
15305             }
15306             row.removeClass('selected');
15307             if(!this.multiple && this.valueField &&
15308                     typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15309             {
15310                 // radio buttons..
15311                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15312                 row.addClass('selected');
15313             }
15314             
15315             if(this.multiple && this.valueField &&
15316                     typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15317             {
15318                 
15319                 // checkboxes...
15320                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15321                 this.tickItems.push(d.data);
15322             }
15323             
15324             row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15325             
15326         }, this);
15327         
15328         var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15329         
15330         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15331
15332         if(this.modalTitle.length){
15333             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15334         }
15335
15336         var listHeight = this.touchViewListGroup.getHeight();
15337         
15338         var _this = this;
15339         
15340         if(firstChecked && listHeight > bodyHeight){
15341             (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15342         }
15343         
15344     },
15345     
15346     onTouchViewLoadException : function()
15347     {
15348         this.hideTouchView();
15349     },
15350     
15351     onTouchViewEmptyResults : function()
15352     {
15353         this.clearTouchView();
15354         
15355         this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15356         
15357         this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15358         
15359     },
15360     
15361     clearTouchView : function()
15362     {
15363         this.touchViewListGroup.dom.innerHTML = '';
15364     },
15365     
15366     onTouchViewClick : function(e, el, o)
15367     {
15368         e.preventDefault();
15369         
15370         var row = o.row;
15371         var rowIndex = o.rowIndex;
15372         
15373         var r = this.store.getAt(rowIndex);
15374         
15375         if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15376             
15377             if(!this.multiple){
15378                 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15379                     c.dom.removeAttribute('checked');
15380                 }, this);
15381
15382                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15383
15384                 this.setFromData(r.data);
15385
15386                 var close = this.closeTriggerEl();
15387
15388                 if(close){
15389                     close.show();
15390                 }
15391
15392                 this.hideTouchView();
15393
15394                 this.fireEvent('select', this, r, rowIndex);
15395
15396                 return;
15397             }
15398
15399             if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15400                 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15401                 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15402                 return;
15403             }
15404
15405             row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15406             this.addItem(r.data);
15407             this.tickItems.push(r.data);
15408         }
15409     },
15410     
15411     getAutoCreateNativeIOS : function()
15412     {
15413         var cfg = {
15414             cls: 'form-group' //input-group,
15415         };
15416         
15417         var combobox =  {
15418             tag: 'select',
15419             cls : 'roo-ios-select'
15420         };
15421         
15422         if (this.name) {
15423             combobox.name = this.name;
15424         }
15425         
15426         if (this.disabled) {
15427             combobox.disabled = true;
15428         }
15429         
15430         var settings = this;
15431         
15432         ['xs','sm','md','lg'].map(function(size){
15433             if (settings[size]) {
15434                 cfg.cls += ' col-' + size + '-' + settings[size];
15435             }
15436         });
15437         
15438         cfg.cn = combobox;
15439         
15440         return cfg;
15441         
15442     },
15443     
15444     initIOSView : function()
15445     {
15446         this.store.on('load', this.onIOSViewLoad, this);
15447         
15448         return;
15449     },
15450     
15451     onIOSViewLoad : function()
15452     {
15453         if(this.store.getCount() < 1){
15454             return;
15455         }
15456         
15457         this.clearIOSView();
15458         
15459         if(this.allowBlank) {
15460             
15461             var default_text = '-- SELECT --';
15462             
15463             if(this.placeholder.length){
15464                 default_text = this.placeholder;
15465             }
15466             
15467             if(this.emptyTitle.length){
15468                 default_text += ' - ' + this.emptyTitle + ' -';
15469             }
15470             
15471             var opt = this.inputEl().createChild({
15472                 tag: 'option',
15473                 value : 0,
15474                 html : default_text
15475             });
15476             
15477             var o = {};
15478             o[this.valueField] = 0;
15479             o[this.displayField] = default_text;
15480             
15481             this.ios_options.push({
15482                 data : o,
15483                 el : opt
15484             });
15485             
15486         }
15487         
15488         this.store.data.each(function(d, rowIndex){
15489             
15490             var html = '';
15491             
15492             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15493                 html = d.data[this.displayField];
15494             }
15495             
15496             var value = '';
15497             
15498             if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15499                 value = d.data[this.valueField];
15500             }
15501             
15502             var option = {
15503                 tag: 'option',
15504                 value : value,
15505                 html : html
15506             };
15507             
15508             if(this.value == d.data[this.valueField]){
15509                 option['selected'] = true;
15510             }
15511             
15512             var opt = this.inputEl().createChild(option);
15513             
15514             this.ios_options.push({
15515                 data : d.data,
15516                 el : opt
15517             });
15518             
15519         }, this);
15520         
15521         this.inputEl().on('change', function(){
15522            this.fireEvent('select', this);
15523         }, this);
15524         
15525     },
15526     
15527     clearIOSView: function()
15528     {
15529         this.inputEl().dom.innerHTML = '';
15530         
15531         this.ios_options = [];
15532     },
15533     
15534     setIOSValue: function(v)
15535     {
15536         this.value = v;
15537         
15538         if(!this.ios_options){
15539             return;
15540         }
15541         
15542         Roo.each(this.ios_options, function(opts){
15543            
15544            opts.el.dom.removeAttribute('selected');
15545            
15546            if(opts.data[this.valueField] != v){
15547                return;
15548            }
15549            
15550            opts.el.dom.setAttribute('selected', true);
15551            
15552         }, this);
15553     }
15554
15555     /** 
15556     * @cfg {Boolean} grow 
15557     * @hide 
15558     */
15559     /** 
15560     * @cfg {Number} growMin 
15561     * @hide 
15562     */
15563     /** 
15564     * @cfg {Number} growMax 
15565     * @hide 
15566     */
15567     /**
15568      * @hide
15569      * @method autoSize
15570      */
15571 });
15572
15573 Roo.apply(Roo.bootstrap.ComboBox,  {
15574     
15575     header : {
15576         tag: 'div',
15577         cls: 'modal-header',
15578         cn: [
15579             {
15580                 tag: 'h4',
15581                 cls: 'modal-title'
15582             }
15583         ]
15584     },
15585     
15586     body : {
15587         tag: 'div',
15588         cls: 'modal-body',
15589         cn: [
15590             {
15591                 tag: 'ul',
15592                 cls: 'list-group'
15593             }
15594         ]
15595     },
15596     
15597     listItemRadio : {
15598         tag: 'li',
15599         cls: 'list-group-item',
15600         cn: [
15601             {
15602                 tag: 'span',
15603                 cls: 'roo-combobox-list-group-item-value'
15604             },
15605             {
15606                 tag: 'div',
15607                 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15608                 cn: [
15609                     {
15610                         tag: 'input',
15611                         type: 'radio'
15612                     },
15613                     {
15614                         tag: 'label'
15615                     }
15616                 ]
15617             }
15618         ]
15619     },
15620     
15621     listItemCheckbox : {
15622         tag: 'li',
15623         cls: 'list-group-item',
15624         cn: [
15625             {
15626                 tag: 'span',
15627                 cls: 'roo-combobox-list-group-item-value'
15628             },
15629             {
15630                 tag: 'div',
15631                 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15632                 cn: [
15633                     {
15634                         tag: 'input',
15635                         type: 'checkbox'
15636                     },
15637                     {
15638                         tag: 'label'
15639                     }
15640                 ]
15641             }
15642         ]
15643     },
15644     
15645     emptyResult : {
15646         tag: 'div',
15647         cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15648     },
15649     
15650     footer : {
15651         tag: 'div',
15652         cls: 'modal-footer',
15653         cn: [
15654             {
15655                 tag: 'div',
15656                 cls: 'row',
15657                 cn: [
15658                     {
15659                         tag: 'div',
15660                         cls: 'col-xs-6 text-left',
15661                         cn: {
15662                             tag: 'button',
15663                             cls: 'btn btn-danger roo-touch-view-cancel',
15664                             html: 'Cancel'
15665                         }
15666                     },
15667                     {
15668                         tag: 'div',
15669                         cls: 'col-xs-6 text-right',
15670                         cn: {
15671                             tag: 'button',
15672                             cls: 'btn btn-success roo-touch-view-ok',
15673                             html: 'OK'
15674                         }
15675                     }
15676                 ]
15677             }
15678         ]
15679         
15680     }
15681 });
15682
15683 Roo.apply(Roo.bootstrap.ComboBox,  {
15684     
15685     touchViewTemplate : {
15686         tag: 'div',
15687         cls: 'modal fade roo-combobox-touch-view',
15688         cn: [
15689             {
15690                 tag: 'div',
15691                 cls: 'modal-dialog',
15692                 style : 'position:fixed', // we have to fix position....
15693                 cn: [
15694                     {
15695                         tag: 'div',
15696                         cls: 'modal-content',
15697                         cn: [
15698                             Roo.bootstrap.ComboBox.header,
15699                             Roo.bootstrap.ComboBox.body,
15700                             Roo.bootstrap.ComboBox.footer
15701                         ]
15702                     }
15703                 ]
15704             }
15705         ]
15706     }
15707 });/*
15708  * Based on:
15709  * Ext JS Library 1.1.1
15710  * Copyright(c) 2006-2007, Ext JS, LLC.
15711  *
15712  * Originally Released Under LGPL - original licence link has changed is not relivant.
15713  *
15714  * Fork - LGPL
15715  * <script type="text/javascript">
15716  */
15717
15718 /**
15719  * @class Roo.View
15720  * @extends Roo.util.Observable
15721  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
15722  * This class also supports single and multi selection modes. <br>
15723  * Create a data model bound view:
15724  <pre><code>
15725  var store = new Roo.data.Store(...);
15726
15727  var view = new Roo.View({
15728     el : "my-element",
15729     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
15730  
15731     singleSelect: true,
15732     selectedClass: "ydataview-selected",
15733     store: store
15734  });
15735
15736  // listen for node click?
15737  view.on("click", function(vw, index, node, e){
15738  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15739  });
15740
15741  // load XML data
15742  dataModel.load("foobar.xml");
15743  </code></pre>
15744  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15745  * <br><br>
15746  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15747  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15748  * 
15749  * Note: old style constructor is still suported (container, template, config)
15750  * 
15751  * @constructor
15752  * Create a new View
15753  * @param {Object} config The config object
15754  * 
15755  */
15756 Roo.View = function(config, depreciated_tpl, depreciated_config){
15757     
15758     this.parent = false;
15759     
15760     if (typeof(depreciated_tpl) == 'undefined') {
15761         // new way.. - universal constructor.
15762         Roo.apply(this, config);
15763         this.el  = Roo.get(this.el);
15764     } else {
15765         // old format..
15766         this.el  = Roo.get(config);
15767         this.tpl = depreciated_tpl;
15768         Roo.apply(this, depreciated_config);
15769     }
15770     this.wrapEl  = this.el.wrap().wrap();
15771     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15772     
15773     
15774     if(typeof(this.tpl) == "string"){
15775         this.tpl = new Roo.Template(this.tpl);
15776     } else {
15777         // support xtype ctors..
15778         this.tpl = new Roo.factory(this.tpl, Roo);
15779     }
15780     
15781     
15782     this.tpl.compile();
15783     
15784     /** @private */
15785     this.addEvents({
15786         /**
15787          * @event beforeclick
15788          * Fires before a click is processed. Returns false to cancel the default action.
15789          * @param {Roo.View} this
15790          * @param {Number} index The index of the target node
15791          * @param {HTMLElement} node The target node
15792          * @param {Roo.EventObject} e The raw event object
15793          */
15794             "beforeclick" : true,
15795         /**
15796          * @event click
15797          * Fires when a template node is clicked.
15798          * @param {Roo.View} this
15799          * @param {Number} index The index of the target node
15800          * @param {HTMLElement} node The target node
15801          * @param {Roo.EventObject} e The raw event object
15802          */
15803             "click" : true,
15804         /**
15805          * @event dblclick
15806          * Fires when a template node is double clicked.
15807          * @param {Roo.View} this
15808          * @param {Number} index The index of the target node
15809          * @param {HTMLElement} node The target node
15810          * @param {Roo.EventObject} e The raw event object
15811          */
15812             "dblclick" : true,
15813         /**
15814          * @event contextmenu
15815          * Fires when a template node is right clicked.
15816          * @param {Roo.View} this
15817          * @param {Number} index The index of the target node
15818          * @param {HTMLElement} node The target node
15819          * @param {Roo.EventObject} e The raw event object
15820          */
15821             "contextmenu" : true,
15822         /**
15823          * @event selectionchange
15824          * Fires when the selected nodes change.
15825          * @param {Roo.View} this
15826          * @param {Array} selections Array of the selected nodes
15827          */
15828             "selectionchange" : true,
15829     
15830         /**
15831          * @event beforeselect
15832          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15833          * @param {Roo.View} this
15834          * @param {HTMLElement} node The node to be selected
15835          * @param {Array} selections Array of currently selected nodes
15836          */
15837             "beforeselect" : true,
15838         /**
15839          * @event preparedata
15840          * Fires on every row to render, to allow you to change the data.
15841          * @param {Roo.View} this
15842          * @param {Object} data to be rendered (change this)
15843          */
15844           "preparedata" : true
15845           
15846           
15847         });
15848
15849
15850
15851     this.el.on({
15852         "click": this.onClick,
15853         "dblclick": this.onDblClick,
15854         "contextmenu": this.onContextMenu,
15855         scope:this
15856     });
15857
15858     this.selections = [];
15859     this.nodes = [];
15860     this.cmp = new Roo.CompositeElementLite([]);
15861     if(this.store){
15862         this.store = Roo.factory(this.store, Roo.data);
15863         this.setStore(this.store, true);
15864     }
15865     
15866     if ( this.footer && this.footer.xtype) {
15867            
15868          var fctr = this.wrapEl.appendChild(document.createElement("div"));
15869         
15870         this.footer.dataSource = this.store;
15871         this.footer.container = fctr;
15872         this.footer = Roo.factory(this.footer, Roo);
15873         fctr.insertFirst(this.el);
15874         
15875         // this is a bit insane - as the paging toolbar seems to detach the el..
15876 //        dom.parentNode.parentNode.parentNode
15877          // they get detached?
15878     }
15879     
15880     
15881     Roo.View.superclass.constructor.call(this);
15882     
15883     
15884 };
15885
15886 Roo.extend(Roo.View, Roo.util.Observable, {
15887     
15888      /**
15889      * @cfg {Roo.data.Store} store Data store to load data from.
15890      */
15891     store : false,
15892     
15893     /**
15894      * @cfg {String|Roo.Element} el The container element.
15895      */
15896     el : '',
15897     
15898     /**
15899      * @cfg {String|Roo.Template} tpl The template used by this View 
15900      */
15901     tpl : false,
15902     /**
15903      * @cfg {String} dataName the named area of the template to use as the data area
15904      *                          Works with domtemplates roo-name="name"
15905      */
15906     dataName: false,
15907     /**
15908      * @cfg {String} selectedClass The css class to add to selected nodes
15909      */
15910     selectedClass : "x-view-selected",
15911      /**
15912      * @cfg {String} emptyText The empty text to show when nothing is loaded.
15913      */
15914     emptyText : "",
15915     
15916     /**
15917      * @cfg {String} text to display on mask (default Loading)
15918      */
15919     mask : false,
15920     /**
15921      * @cfg {Boolean} multiSelect Allow multiple selection
15922      */
15923     multiSelect : false,
15924     /**
15925      * @cfg {Boolean} singleSelect Allow single selection
15926      */
15927     singleSelect:  false,
15928     
15929     /**
15930      * @cfg {Boolean} toggleSelect - selecting 
15931      */
15932     toggleSelect : false,
15933     
15934     /**
15935      * @cfg {Boolean} tickable - selecting 
15936      */
15937     tickable : false,
15938     
15939     /**
15940      * Returns the element this view is bound to.
15941      * @return {Roo.Element}
15942      */
15943     getEl : function(){
15944         return this.wrapEl;
15945     },
15946     
15947     
15948
15949     /**
15950      * Refreshes the view. - called by datachanged on the store. - do not call directly.
15951      */
15952     refresh : function(){
15953         //Roo.log('refresh');
15954         var t = this.tpl;
15955         
15956         // if we are using something like 'domtemplate', then
15957         // the what gets used is:
15958         // t.applySubtemplate(NAME, data, wrapping data..)
15959         // the outer template then get' applied with
15960         //     the store 'extra data'
15961         // and the body get's added to the
15962         //      roo-name="data" node?
15963         //      <span class='roo-tpl-{name}'></span> ?????
15964         
15965         
15966         
15967         this.clearSelections();
15968         this.el.update("");
15969         var html = [];
15970         var records = this.store.getRange();
15971         if(records.length < 1) {
15972             
15973             // is this valid??  = should it render a template??
15974             
15975             this.el.update(this.emptyText);
15976             return;
15977         }
15978         var el = this.el;
15979         if (this.dataName) {
15980             this.el.update(t.apply(this.store.meta)); //????
15981             el = this.el.child('.roo-tpl-' + this.dataName);
15982         }
15983         
15984         for(var i = 0, len = records.length; i < len; i++){
15985             var data = this.prepareData(records[i].data, i, records[i]);
15986             this.fireEvent("preparedata", this, data, i, records[i]);
15987             
15988             var d = Roo.apply({}, data);
15989             
15990             if(this.tickable){
15991                 Roo.apply(d, {'roo-id' : Roo.id()});
15992                 
15993                 var _this = this;
15994             
15995                 Roo.each(this.parent.item, function(item){
15996                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15997                         return;
15998                     }
15999                     Roo.apply(d, {'roo-data-checked' : 'checked'});
16000                 });
16001             }
16002             
16003             html[html.length] = Roo.util.Format.trim(
16004                 this.dataName ?
16005                     t.applySubtemplate(this.dataName, d, this.store.meta) :
16006                     t.apply(d)
16007             );
16008         }
16009         
16010         
16011         
16012         el.update(html.join(""));
16013         this.nodes = el.dom.childNodes;
16014         this.updateIndexes(0);
16015     },
16016     
16017
16018     /**
16019      * Function to override to reformat the data that is sent to
16020      * the template for each node.
16021      * DEPRICATED - use the preparedata event handler.
16022      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16023      * a JSON object for an UpdateManager bound view).
16024      */
16025     prepareData : function(data, index, record)
16026     {
16027         this.fireEvent("preparedata", this, data, index, record);
16028         return data;
16029     },
16030
16031     onUpdate : function(ds, record){
16032         // Roo.log('on update');   
16033         this.clearSelections();
16034         var index = this.store.indexOf(record);
16035         var n = this.nodes[index];
16036         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16037         n.parentNode.removeChild(n);
16038         this.updateIndexes(index, index);
16039     },
16040
16041     
16042     
16043 // --------- FIXME     
16044     onAdd : function(ds, records, index)
16045     {
16046         //Roo.log(['on Add', ds, records, index] );        
16047         this.clearSelections();
16048         if(this.nodes.length == 0){
16049             this.refresh();
16050             return;
16051         }
16052         var n = this.nodes[index];
16053         for(var i = 0, len = records.length; i < len; i++){
16054             var d = this.prepareData(records[i].data, i, records[i]);
16055             if(n){
16056                 this.tpl.insertBefore(n, d);
16057             }else{
16058                 
16059                 this.tpl.append(this.el, d);
16060             }
16061         }
16062         this.updateIndexes(index);
16063     },
16064
16065     onRemove : function(ds, record, index){
16066        // Roo.log('onRemove');
16067         this.clearSelections();
16068         var el = this.dataName  ?
16069             this.el.child('.roo-tpl-' + this.dataName) :
16070             this.el; 
16071         
16072         el.dom.removeChild(this.nodes[index]);
16073         this.updateIndexes(index);
16074     },
16075
16076     /**
16077      * Refresh an individual node.
16078      * @param {Number} index
16079      */
16080     refreshNode : function(index){
16081         this.onUpdate(this.store, this.store.getAt(index));
16082     },
16083
16084     updateIndexes : function(startIndex, endIndex){
16085         var ns = this.nodes;
16086         startIndex = startIndex || 0;
16087         endIndex = endIndex || ns.length - 1;
16088         for(var i = startIndex; i <= endIndex; i++){
16089             ns[i].nodeIndex = i;
16090         }
16091     },
16092
16093     /**
16094      * Changes the data store this view uses and refresh the view.
16095      * @param {Store} store
16096      */
16097     setStore : function(store, initial){
16098         if(!initial && this.store){
16099             this.store.un("datachanged", this.refresh);
16100             this.store.un("add", this.onAdd);
16101             this.store.un("remove", this.onRemove);
16102             this.store.un("update", this.onUpdate);
16103             this.store.un("clear", this.refresh);
16104             this.store.un("beforeload", this.onBeforeLoad);
16105             this.store.un("load", this.onLoad);
16106             this.store.un("loadexception", this.onLoad);
16107         }
16108         if(store){
16109           
16110             store.on("datachanged", this.refresh, this);
16111             store.on("add", this.onAdd, this);
16112             store.on("remove", this.onRemove, this);
16113             store.on("update", this.onUpdate, this);
16114             store.on("clear", this.refresh, this);
16115             store.on("beforeload", this.onBeforeLoad, this);
16116             store.on("load", this.onLoad, this);
16117             store.on("loadexception", this.onLoad, this);
16118         }
16119         
16120         if(store){
16121             this.refresh();
16122         }
16123     },
16124     /**
16125      * onbeforeLoad - masks the loading area.
16126      *
16127      */
16128     onBeforeLoad : function(store,opts)
16129     {
16130          //Roo.log('onBeforeLoad');   
16131         if (!opts.add) {
16132             this.el.update("");
16133         }
16134         this.el.mask(this.mask ? this.mask : "Loading" ); 
16135     },
16136     onLoad : function ()
16137     {
16138         this.el.unmask();
16139     },
16140     
16141
16142     /**
16143      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16144      * @param {HTMLElement} node
16145      * @return {HTMLElement} The template node
16146      */
16147     findItemFromChild : function(node){
16148         var el = this.dataName  ?
16149             this.el.child('.roo-tpl-' + this.dataName,true) :
16150             this.el.dom; 
16151         
16152         if(!node || node.parentNode == el){
16153                     return node;
16154             }
16155             var p = node.parentNode;
16156             while(p && p != el){
16157             if(p.parentNode == el){
16158                 return p;
16159             }
16160             p = p.parentNode;
16161         }
16162             return null;
16163     },
16164
16165     /** @ignore */
16166     onClick : function(e){
16167         var item = this.findItemFromChild(e.getTarget());
16168         if(item){
16169             var index = this.indexOf(item);
16170             if(this.onItemClick(item, index, e) !== false){
16171                 this.fireEvent("click", this, index, item, e);
16172             }
16173         }else{
16174             this.clearSelections();
16175         }
16176     },
16177
16178     /** @ignore */
16179     onContextMenu : function(e){
16180         var item = this.findItemFromChild(e.getTarget());
16181         if(item){
16182             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16183         }
16184     },
16185
16186     /** @ignore */
16187     onDblClick : function(e){
16188         var item = this.findItemFromChild(e.getTarget());
16189         if(item){
16190             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16191         }
16192     },
16193
16194     onItemClick : function(item, index, e)
16195     {
16196         if(this.fireEvent("beforeclick", this, index, item, e) === false){
16197             return false;
16198         }
16199         if (this.toggleSelect) {
16200             var m = this.isSelected(item) ? 'unselect' : 'select';
16201             //Roo.log(m);
16202             var _t = this;
16203             _t[m](item, true, false);
16204             return true;
16205         }
16206         if(this.multiSelect || this.singleSelect){
16207             if(this.multiSelect && e.shiftKey && this.lastSelection){
16208                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16209             }else{
16210                 this.select(item, this.multiSelect && e.ctrlKey);
16211                 this.lastSelection = item;
16212             }
16213             
16214             if(!this.tickable){
16215                 e.preventDefault();
16216             }
16217             
16218         }
16219         return true;
16220     },
16221
16222     /**
16223      * Get the number of selected nodes.
16224      * @return {Number}
16225      */
16226     getSelectionCount : function(){
16227         return this.selections.length;
16228     },
16229
16230     /**
16231      * Get the currently selected nodes.
16232      * @return {Array} An array of HTMLElements
16233      */
16234     getSelectedNodes : function(){
16235         return this.selections;
16236     },
16237
16238     /**
16239      * Get the indexes of the selected nodes.
16240      * @return {Array}
16241      */
16242     getSelectedIndexes : function(){
16243         var indexes = [], s = this.selections;
16244         for(var i = 0, len = s.length; i < len; i++){
16245             indexes.push(s[i].nodeIndex);
16246         }
16247         return indexes;
16248     },
16249
16250     /**
16251      * Clear all selections
16252      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16253      */
16254     clearSelections : function(suppressEvent){
16255         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16256             this.cmp.elements = this.selections;
16257             this.cmp.removeClass(this.selectedClass);
16258             this.selections = [];
16259             if(!suppressEvent){
16260                 this.fireEvent("selectionchange", this, this.selections);
16261             }
16262         }
16263     },
16264
16265     /**
16266      * Returns true if the passed node is selected
16267      * @param {HTMLElement/Number} node The node or node index
16268      * @return {Boolean}
16269      */
16270     isSelected : function(node){
16271         var s = this.selections;
16272         if(s.length < 1){
16273             return false;
16274         }
16275         node = this.getNode(node);
16276         return s.indexOf(node) !== -1;
16277     },
16278
16279     /**
16280      * Selects nodes.
16281      * @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
16282      * @param {Boolean} keepExisting (optional) true to keep existing selections
16283      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16284      */
16285     select : function(nodeInfo, keepExisting, suppressEvent){
16286         if(nodeInfo instanceof Array){
16287             if(!keepExisting){
16288                 this.clearSelections(true);
16289             }
16290             for(var i = 0, len = nodeInfo.length; i < len; i++){
16291                 this.select(nodeInfo[i], true, true);
16292             }
16293             return;
16294         } 
16295         var node = this.getNode(nodeInfo);
16296         if(!node || this.isSelected(node)){
16297             return; // already selected.
16298         }
16299         if(!keepExisting){
16300             this.clearSelections(true);
16301         }
16302         
16303         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16304             Roo.fly(node).addClass(this.selectedClass);
16305             this.selections.push(node);
16306             if(!suppressEvent){
16307                 this.fireEvent("selectionchange", this, this.selections);
16308             }
16309         }
16310         
16311         
16312     },
16313       /**
16314      * Unselects nodes.
16315      * @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
16316      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16317      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16318      */
16319     unselect : function(nodeInfo, keepExisting, suppressEvent)
16320     {
16321         if(nodeInfo instanceof Array){
16322             Roo.each(this.selections, function(s) {
16323                 this.unselect(s, nodeInfo);
16324             }, this);
16325             return;
16326         }
16327         var node = this.getNode(nodeInfo);
16328         if(!node || !this.isSelected(node)){
16329             //Roo.log("not selected");
16330             return; // not selected.
16331         }
16332         // fireevent???
16333         var ns = [];
16334         Roo.each(this.selections, function(s) {
16335             if (s == node ) {
16336                 Roo.fly(node).removeClass(this.selectedClass);
16337
16338                 return;
16339             }
16340             ns.push(s);
16341         },this);
16342         
16343         this.selections= ns;
16344         this.fireEvent("selectionchange", this, this.selections);
16345     },
16346
16347     /**
16348      * Gets a template node.
16349      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16350      * @return {HTMLElement} The node or null if it wasn't found
16351      */
16352     getNode : function(nodeInfo){
16353         if(typeof nodeInfo == "string"){
16354             return document.getElementById(nodeInfo);
16355         }else if(typeof nodeInfo == "number"){
16356             return this.nodes[nodeInfo];
16357         }
16358         return nodeInfo;
16359     },
16360
16361     /**
16362      * Gets a range template nodes.
16363      * @param {Number} startIndex
16364      * @param {Number} endIndex
16365      * @return {Array} An array of nodes
16366      */
16367     getNodes : function(start, end){
16368         var ns = this.nodes;
16369         start = start || 0;
16370         end = typeof end == "undefined" ? ns.length - 1 : end;
16371         var nodes = [];
16372         if(start <= end){
16373             for(var i = start; i <= end; i++){
16374                 nodes.push(ns[i]);
16375             }
16376         } else{
16377             for(var i = start; i >= end; i--){
16378                 nodes.push(ns[i]);
16379             }
16380         }
16381         return nodes;
16382     },
16383
16384     /**
16385      * Finds the index of the passed node
16386      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16387      * @return {Number} The index of the node or -1
16388      */
16389     indexOf : function(node){
16390         node = this.getNode(node);
16391         if(typeof node.nodeIndex == "number"){
16392             return node.nodeIndex;
16393         }
16394         var ns = this.nodes;
16395         for(var i = 0, len = ns.length; i < len; i++){
16396             if(ns[i] == node){
16397                 return i;
16398             }
16399         }
16400         return -1;
16401     }
16402 });
16403 /*
16404  * - LGPL
16405  *
16406  * based on jquery fullcalendar
16407  * 
16408  */
16409
16410 Roo.bootstrap = Roo.bootstrap || {};
16411 /**
16412  * @class Roo.bootstrap.Calendar
16413  * @extends Roo.bootstrap.Component
16414  * Bootstrap Calendar class
16415  * @cfg {Boolean} loadMask (true|false) default false
16416  * @cfg {Object} header generate the user specific header of the calendar, default false
16417
16418  * @constructor
16419  * Create a new Container
16420  * @param {Object} config The config object
16421  */
16422
16423
16424
16425 Roo.bootstrap.Calendar = function(config){
16426     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16427      this.addEvents({
16428         /**
16429              * @event select
16430              * Fires when a date is selected
16431              * @param {DatePicker} this
16432              * @param {Date} date The selected date
16433              */
16434         'select': true,
16435         /**
16436              * @event monthchange
16437              * Fires when the displayed month changes 
16438              * @param {DatePicker} this
16439              * @param {Date} date The selected month
16440              */
16441         'monthchange': true,
16442         /**
16443              * @event evententer
16444              * Fires when mouse over an event
16445              * @param {Calendar} this
16446              * @param {event} Event
16447              */
16448         'evententer': true,
16449         /**
16450              * @event eventleave
16451              * Fires when the mouse leaves an
16452              * @param {Calendar} this
16453              * @param {event}
16454              */
16455         'eventleave': true,
16456         /**
16457              * @event eventclick
16458              * Fires when the mouse click an
16459              * @param {Calendar} this
16460              * @param {event}
16461              */
16462         'eventclick': true
16463         
16464     });
16465
16466 };
16467
16468 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
16469     
16470      /**
16471      * @cfg {Number} startDay
16472      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16473      */
16474     startDay : 0,
16475     
16476     loadMask : false,
16477     
16478     header : false,
16479       
16480     getAutoCreate : function(){
16481         
16482         
16483         var fc_button = function(name, corner, style, content ) {
16484             return Roo.apply({},{
16485                 tag : 'span',
16486                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
16487                          (corner.length ?
16488                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16489                             ''
16490                         ),
16491                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16492                 unselectable: 'on'
16493             });
16494         };
16495         
16496         var header = {};
16497         
16498         if(!this.header){
16499             header = {
16500                 tag : 'table',
16501                 cls : 'fc-header',
16502                 style : 'width:100%',
16503                 cn : [
16504                     {
16505                         tag: 'tr',
16506                         cn : [
16507                             {
16508                                 tag : 'td',
16509                                 cls : 'fc-header-left',
16510                                 cn : [
16511                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
16512                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
16513                                     { tag: 'span', cls: 'fc-header-space' },
16514                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
16515
16516
16517                                 ]
16518                             },
16519
16520                             {
16521                                 tag : 'td',
16522                                 cls : 'fc-header-center',
16523                                 cn : [
16524                                     {
16525                                         tag: 'span',
16526                                         cls: 'fc-header-title',
16527                                         cn : {
16528                                             tag: 'H2',
16529                                             html : 'month / year'
16530                                         }
16531                                     }
16532
16533                                 ]
16534                             },
16535                             {
16536                                 tag : 'td',
16537                                 cls : 'fc-header-right',
16538                                 cn : [
16539                               /*      fc_button('month', 'left', '', 'month' ),
16540                                     fc_button('week', '', '', 'week' ),
16541                                     fc_button('day', 'right', '', 'day' )
16542                                 */    
16543
16544                                 ]
16545                             }
16546
16547                         ]
16548                     }
16549                 ]
16550             };
16551         }
16552         
16553         header = this.header;
16554         
16555        
16556         var cal_heads = function() {
16557             var ret = [];
16558             // fixme - handle this.
16559             
16560             for (var i =0; i < Date.dayNames.length; i++) {
16561                 var d = Date.dayNames[i];
16562                 ret.push({
16563                     tag: 'th',
16564                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16565                     html : d.substring(0,3)
16566                 });
16567                 
16568             }
16569             ret[0].cls += ' fc-first';
16570             ret[6].cls += ' fc-last';
16571             return ret;
16572         };
16573         var cal_cell = function(n) {
16574             return  {
16575                 tag: 'td',
16576                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16577                 cn : [
16578                     {
16579                         cn : [
16580                             {
16581                                 cls: 'fc-day-number',
16582                                 html: 'D'
16583                             },
16584                             {
16585                                 cls: 'fc-day-content',
16586                              
16587                                 cn : [
16588                                      {
16589                                         style: 'position: relative;' // height: 17px;
16590                                     }
16591                                 ]
16592                             }
16593                             
16594                             
16595                         ]
16596                     }
16597                 ]
16598                 
16599             }
16600         };
16601         var cal_rows = function() {
16602             
16603             var ret = [];
16604             for (var r = 0; r < 6; r++) {
16605                 var row= {
16606                     tag : 'tr',
16607                     cls : 'fc-week',
16608                     cn : []
16609                 };
16610                 
16611                 for (var i =0; i < Date.dayNames.length; i++) {
16612                     var d = Date.dayNames[i];
16613                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16614
16615                 }
16616                 row.cn[0].cls+=' fc-first';
16617                 row.cn[0].cn[0].style = 'min-height:90px';
16618                 row.cn[6].cls+=' fc-last';
16619                 ret.push(row);
16620                 
16621             }
16622             ret[0].cls += ' fc-first';
16623             ret[4].cls += ' fc-prev-last';
16624             ret[5].cls += ' fc-last';
16625             return ret;
16626             
16627         };
16628         
16629         var cal_table = {
16630             tag: 'table',
16631             cls: 'fc-border-separate',
16632             style : 'width:100%',
16633             cellspacing  : 0,
16634             cn : [
16635                 { 
16636                     tag: 'thead',
16637                     cn : [
16638                         { 
16639                             tag: 'tr',
16640                             cls : 'fc-first fc-last',
16641                             cn : cal_heads()
16642                         }
16643                     ]
16644                 },
16645                 { 
16646                     tag: 'tbody',
16647                     cn : cal_rows()
16648                 }
16649                   
16650             ]
16651         };
16652          
16653          var cfg = {
16654             cls : 'fc fc-ltr',
16655             cn : [
16656                 header,
16657                 {
16658                     cls : 'fc-content',
16659                     style : "position: relative;",
16660                     cn : [
16661                         {
16662                             cls : 'fc-view fc-view-month fc-grid',
16663                             style : 'position: relative',
16664                             unselectable : 'on',
16665                             cn : [
16666                                 {
16667                                     cls : 'fc-event-container',
16668                                     style : 'position:absolute;z-index:8;top:0;left:0;'
16669                                 },
16670                                 cal_table
16671                             ]
16672                         }
16673                     ]
16674     
16675                 }
16676            ] 
16677             
16678         };
16679         
16680          
16681         
16682         return cfg;
16683     },
16684     
16685     
16686     initEvents : function()
16687     {
16688         if(!this.store){
16689             throw "can not find store for calendar";
16690         }
16691         
16692         var mark = {
16693             tag: "div",
16694             cls:"x-dlg-mask",
16695             style: "text-align:center",
16696             cn: [
16697                 {
16698                     tag: "div",
16699                     style: "background-color:white;width:50%;margin:250 auto",
16700                     cn: [
16701                         {
16702                             tag: "img",
16703                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
16704                         },
16705                         {
16706                             tag: "span",
16707                             html: "Loading"
16708                         }
16709                         
16710                     ]
16711                 }
16712             ]
16713         };
16714         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16715         
16716         var size = this.el.select('.fc-content', true).first().getSize();
16717         this.maskEl.setSize(size.width, size.height);
16718         this.maskEl.enableDisplayMode("block");
16719         if(!this.loadMask){
16720             this.maskEl.hide();
16721         }
16722         
16723         this.store = Roo.factory(this.store, Roo.data);
16724         this.store.on('load', this.onLoad, this);
16725         this.store.on('beforeload', this.onBeforeLoad, this);
16726         
16727         this.resize();
16728         
16729         this.cells = this.el.select('.fc-day',true);
16730         //Roo.log(this.cells);
16731         this.textNodes = this.el.query('.fc-day-number');
16732         this.cells.addClassOnOver('fc-state-hover');
16733         
16734         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16735         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16736         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16737         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16738         
16739         this.on('monthchange', this.onMonthChange, this);
16740         
16741         this.update(new Date().clearTime());
16742     },
16743     
16744     resize : function() {
16745         var sz  = this.el.getSize();
16746         
16747         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16748         this.el.select('.fc-day-content div',true).setHeight(34);
16749     },
16750     
16751     
16752     // private
16753     showPrevMonth : function(e){
16754         this.update(this.activeDate.add("mo", -1));
16755     },
16756     showToday : function(e){
16757         this.update(new Date().clearTime());
16758     },
16759     // private
16760     showNextMonth : function(e){
16761         this.update(this.activeDate.add("mo", 1));
16762     },
16763
16764     // private
16765     showPrevYear : function(){
16766         this.update(this.activeDate.add("y", -1));
16767     },
16768
16769     // private
16770     showNextYear : function(){
16771         this.update(this.activeDate.add("y", 1));
16772     },
16773
16774     
16775    // private
16776     update : function(date)
16777     {
16778         var vd = this.activeDate;
16779         this.activeDate = date;
16780 //        if(vd && this.el){
16781 //            var t = date.getTime();
16782 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16783 //                Roo.log('using add remove');
16784 //                
16785 //                this.fireEvent('monthchange', this, date);
16786 //                
16787 //                this.cells.removeClass("fc-state-highlight");
16788 //                this.cells.each(function(c){
16789 //                   if(c.dateValue == t){
16790 //                       c.addClass("fc-state-highlight");
16791 //                       setTimeout(function(){
16792 //                            try{c.dom.firstChild.focus();}catch(e){}
16793 //                       }, 50);
16794 //                       return false;
16795 //                   }
16796 //                   return true;
16797 //                });
16798 //                return;
16799 //            }
16800 //        }
16801         
16802         var days = date.getDaysInMonth();
16803         
16804         var firstOfMonth = date.getFirstDateOfMonth();
16805         var startingPos = firstOfMonth.getDay()-this.startDay;
16806         
16807         if(startingPos < this.startDay){
16808             startingPos += 7;
16809         }
16810         
16811         var pm = date.add(Date.MONTH, -1);
16812         var prevStart = pm.getDaysInMonth()-startingPos;
16813 //        
16814         this.cells = this.el.select('.fc-day',true);
16815         this.textNodes = this.el.query('.fc-day-number');
16816         this.cells.addClassOnOver('fc-state-hover');
16817         
16818         var cells = this.cells.elements;
16819         var textEls = this.textNodes;
16820         
16821         Roo.each(cells, function(cell){
16822             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16823         });
16824         
16825         days += startingPos;
16826
16827         // convert everything to numbers so it's fast
16828         var day = 86400000;
16829         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16830         //Roo.log(d);
16831         //Roo.log(pm);
16832         //Roo.log(prevStart);
16833         
16834         var today = new Date().clearTime().getTime();
16835         var sel = date.clearTime().getTime();
16836         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16837         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16838         var ddMatch = this.disabledDatesRE;
16839         var ddText = this.disabledDatesText;
16840         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16841         var ddaysText = this.disabledDaysText;
16842         var format = this.format;
16843         
16844         var setCellClass = function(cal, cell){
16845             cell.row = 0;
16846             cell.events = [];
16847             cell.more = [];
16848             //Roo.log('set Cell Class');
16849             cell.title = "";
16850             var t = d.getTime();
16851             
16852             //Roo.log(d);
16853             
16854             cell.dateValue = t;
16855             if(t == today){
16856                 cell.className += " fc-today";
16857                 cell.className += " fc-state-highlight";
16858                 cell.title = cal.todayText;
16859             }
16860             if(t == sel){
16861                 // disable highlight in other month..
16862                 //cell.className += " fc-state-highlight";
16863                 
16864             }
16865             // disabling
16866             if(t < min) {
16867                 cell.className = " fc-state-disabled";
16868                 cell.title = cal.minText;
16869                 return;
16870             }
16871             if(t > max) {
16872                 cell.className = " fc-state-disabled";
16873                 cell.title = cal.maxText;
16874                 return;
16875             }
16876             if(ddays){
16877                 if(ddays.indexOf(d.getDay()) != -1){
16878                     cell.title = ddaysText;
16879                     cell.className = " fc-state-disabled";
16880                 }
16881             }
16882             if(ddMatch && format){
16883                 var fvalue = d.dateFormat(format);
16884                 if(ddMatch.test(fvalue)){
16885                     cell.title = ddText.replace("%0", fvalue);
16886                     cell.className = " fc-state-disabled";
16887                 }
16888             }
16889             
16890             if (!cell.initialClassName) {
16891                 cell.initialClassName = cell.dom.className;
16892             }
16893             
16894             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
16895         };
16896
16897         var i = 0;
16898         
16899         for(; i < startingPos; i++) {
16900             textEls[i].innerHTML = (++prevStart);
16901             d.setDate(d.getDate()+1);
16902             
16903             cells[i].className = "fc-past fc-other-month";
16904             setCellClass(this, cells[i]);
16905         }
16906         
16907         var intDay = 0;
16908         
16909         for(; i < days; i++){
16910             intDay = i - startingPos + 1;
16911             textEls[i].innerHTML = (intDay);
16912             d.setDate(d.getDate()+1);
16913             
16914             cells[i].className = ''; // "x-date-active";
16915             setCellClass(this, cells[i]);
16916         }
16917         var extraDays = 0;
16918         
16919         for(; i < 42; i++) {
16920             textEls[i].innerHTML = (++extraDays);
16921             d.setDate(d.getDate()+1);
16922             
16923             cells[i].className = "fc-future fc-other-month";
16924             setCellClass(this, cells[i]);
16925         }
16926         
16927         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16928         
16929         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16930         
16931         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16932         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16933         
16934         if(totalRows != 6){
16935             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16936             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16937         }
16938         
16939         this.fireEvent('monthchange', this, date);
16940         
16941         
16942         /*
16943         if(!this.internalRender){
16944             var main = this.el.dom.firstChild;
16945             var w = main.offsetWidth;
16946             this.el.setWidth(w + this.el.getBorderWidth("lr"));
16947             Roo.fly(main).setWidth(w);
16948             this.internalRender = true;
16949             // opera does not respect the auto grow header center column
16950             // then, after it gets a width opera refuses to recalculate
16951             // without a second pass
16952             if(Roo.isOpera && !this.secondPass){
16953                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16954                 this.secondPass = true;
16955                 this.update.defer(10, this, [date]);
16956             }
16957         }
16958         */
16959         
16960     },
16961     
16962     findCell : function(dt) {
16963         dt = dt.clearTime().getTime();
16964         var ret = false;
16965         this.cells.each(function(c){
16966             //Roo.log("check " +c.dateValue + '?=' + dt);
16967             if(c.dateValue == dt){
16968                 ret = c;
16969                 return false;
16970             }
16971             return true;
16972         });
16973         
16974         return ret;
16975     },
16976     
16977     findCells : function(ev) {
16978         var s = ev.start.clone().clearTime().getTime();
16979        // Roo.log(s);
16980         var e= ev.end.clone().clearTime().getTime();
16981        // Roo.log(e);
16982         var ret = [];
16983         this.cells.each(function(c){
16984              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16985             
16986             if(c.dateValue > e){
16987                 return ;
16988             }
16989             if(c.dateValue < s){
16990                 return ;
16991             }
16992             ret.push(c);
16993         });
16994         
16995         return ret;    
16996     },
16997     
16998 //    findBestRow: function(cells)
16999 //    {
17000 //        var ret = 0;
17001 //        
17002 //        for (var i =0 ; i < cells.length;i++) {
17003 //            ret  = Math.max(cells[i].rows || 0,ret);
17004 //        }
17005 //        return ret;
17006 //        
17007 //    },
17008     
17009     
17010     addItem : function(ev)
17011     {
17012         // look for vertical location slot in
17013         var cells = this.findCells(ev);
17014         
17015 //        ev.row = this.findBestRow(cells);
17016         
17017         // work out the location.
17018         
17019         var crow = false;
17020         var rows = [];
17021         for(var i =0; i < cells.length; i++) {
17022             
17023             cells[i].row = cells[0].row;
17024             
17025             if(i == 0){
17026                 cells[i].row = cells[i].row + 1;
17027             }
17028             
17029             if (!crow) {
17030                 crow = {
17031                     start : cells[i],
17032                     end :  cells[i]
17033                 };
17034                 continue;
17035             }
17036             if (crow.start.getY() == cells[i].getY()) {
17037                 // on same row.
17038                 crow.end = cells[i];
17039                 continue;
17040             }
17041             // different row.
17042             rows.push(crow);
17043             crow = {
17044                 start: cells[i],
17045                 end : cells[i]
17046             };
17047             
17048         }
17049         
17050         rows.push(crow);
17051         ev.els = [];
17052         ev.rows = rows;
17053         ev.cells = cells;
17054         
17055         cells[0].events.push(ev);
17056         
17057         this.calevents.push(ev);
17058     },
17059     
17060     clearEvents: function() {
17061         
17062         if(!this.calevents){
17063             return;
17064         }
17065         
17066         Roo.each(this.cells.elements, function(c){
17067             c.row = 0;
17068             c.events = [];
17069             c.more = [];
17070         });
17071         
17072         Roo.each(this.calevents, function(e) {
17073             Roo.each(e.els, function(el) {
17074                 el.un('mouseenter' ,this.onEventEnter, this);
17075                 el.un('mouseleave' ,this.onEventLeave, this);
17076                 el.remove();
17077             },this);
17078         },this);
17079         
17080         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17081             e.remove();
17082         });
17083         
17084     },
17085     
17086     renderEvents: function()
17087     {   
17088         var _this = this;
17089         
17090         this.cells.each(function(c) {
17091             
17092             if(c.row < 5){
17093                 return;
17094             }
17095             
17096             var ev = c.events;
17097             
17098             var r = 4;
17099             if(c.row != c.events.length){
17100                 r = 4 - (4 - (c.row - c.events.length));
17101             }
17102             
17103             c.events = ev.slice(0, r);
17104             c.more = ev.slice(r);
17105             
17106             if(c.more.length && c.more.length == 1){
17107                 c.events.push(c.more.pop());
17108             }
17109             
17110             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17111             
17112         });
17113             
17114         this.cells.each(function(c) {
17115             
17116             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17117             
17118             
17119             for (var e = 0; e < c.events.length; e++){
17120                 var ev = c.events[e];
17121                 var rows = ev.rows;
17122                 
17123                 for(var i = 0; i < rows.length; i++) {
17124                 
17125                     // how many rows should it span..
17126
17127                     var  cfg = {
17128                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17129                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17130
17131                         unselectable : "on",
17132                         cn : [
17133                             {
17134                                 cls: 'fc-event-inner',
17135                                 cn : [
17136     //                                {
17137     //                                  tag:'span',
17138     //                                  cls: 'fc-event-time',
17139     //                                  html : cells.length > 1 ? '' : ev.time
17140     //                                },
17141                                     {
17142                                       tag:'span',
17143                                       cls: 'fc-event-title',
17144                                       html : String.format('{0}', ev.title)
17145                                     }
17146
17147
17148                                 ]
17149                             },
17150                             {
17151                                 cls: 'ui-resizable-handle ui-resizable-e',
17152                                 html : '&nbsp;&nbsp;&nbsp'
17153                             }
17154
17155                         ]
17156                     };
17157
17158                     if (i == 0) {
17159                         cfg.cls += ' fc-event-start';
17160                     }
17161                     if ((i+1) == rows.length) {
17162                         cfg.cls += ' fc-event-end';
17163                     }
17164
17165                     var ctr = _this.el.select('.fc-event-container',true).first();
17166                     var cg = ctr.createChild(cfg);
17167
17168                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17169                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17170
17171                     var r = (c.more.length) ? 1 : 0;
17172                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
17173                     cg.setWidth(ebox.right - sbox.x -2);
17174
17175                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17176                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17177                     cg.on('click', _this.onEventClick, _this, ev);
17178
17179                     ev.els.push(cg);
17180                     
17181                 }
17182                 
17183             }
17184             
17185             
17186             if(c.more.length){
17187                 var  cfg = {
17188                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17189                     style : 'position: absolute',
17190                     unselectable : "on",
17191                     cn : [
17192                         {
17193                             cls: 'fc-event-inner',
17194                             cn : [
17195                                 {
17196                                   tag:'span',
17197                                   cls: 'fc-event-title',
17198                                   html : 'More'
17199                                 }
17200
17201
17202                             ]
17203                         },
17204                         {
17205                             cls: 'ui-resizable-handle ui-resizable-e',
17206                             html : '&nbsp;&nbsp;&nbsp'
17207                         }
17208
17209                     ]
17210                 };
17211
17212                 var ctr = _this.el.select('.fc-event-container',true).first();
17213                 var cg = ctr.createChild(cfg);
17214
17215                 var sbox = c.select('.fc-day-content',true).first().getBox();
17216                 var ebox = c.select('.fc-day-content',true).first().getBox();
17217                 //Roo.log(cg);
17218                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
17219                 cg.setWidth(ebox.right - sbox.x -2);
17220
17221                 cg.on('click', _this.onMoreEventClick, _this, c.more);
17222                 
17223             }
17224             
17225         });
17226         
17227         
17228         
17229     },
17230     
17231     onEventEnter: function (e, el,event,d) {
17232         this.fireEvent('evententer', this, el, event);
17233     },
17234     
17235     onEventLeave: function (e, el,event,d) {
17236         this.fireEvent('eventleave', this, el, event);
17237     },
17238     
17239     onEventClick: function (e, el,event,d) {
17240         this.fireEvent('eventclick', this, el, event);
17241     },
17242     
17243     onMonthChange: function () {
17244         this.store.load();
17245     },
17246     
17247     onMoreEventClick: function(e, el, more)
17248     {
17249         var _this = this;
17250         
17251         this.calpopover.placement = 'right';
17252         this.calpopover.setTitle('More');
17253         
17254         this.calpopover.setContent('');
17255         
17256         var ctr = this.calpopover.el.select('.popover-content', true).first();
17257         
17258         Roo.each(more, function(m){
17259             var cfg = {
17260                 cls : 'fc-event-hori fc-event-draggable',
17261                 html : m.title
17262             };
17263             var cg = ctr.createChild(cfg);
17264             
17265             cg.on('click', _this.onEventClick, _this, m);
17266         });
17267         
17268         this.calpopover.show(el);
17269         
17270         
17271     },
17272     
17273     onLoad: function () 
17274     {   
17275         this.calevents = [];
17276         var cal = this;
17277         
17278         if(this.store.getCount() > 0){
17279             this.store.data.each(function(d){
17280                cal.addItem({
17281                     id : d.data.id,
17282                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17283                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17284                     time : d.data.start_time,
17285                     title : d.data.title,
17286                     description : d.data.description,
17287                     venue : d.data.venue
17288                 });
17289             });
17290         }
17291         
17292         this.renderEvents();
17293         
17294         if(this.calevents.length && this.loadMask){
17295             this.maskEl.hide();
17296         }
17297     },
17298     
17299     onBeforeLoad: function()
17300     {
17301         this.clearEvents();
17302         if(this.loadMask){
17303             this.maskEl.show();
17304         }
17305     }
17306 });
17307
17308  
17309  /*
17310  * - LGPL
17311  *
17312  * element
17313  * 
17314  */
17315
17316 /**
17317  * @class Roo.bootstrap.Popover
17318  * @extends Roo.bootstrap.Component
17319  * Bootstrap Popover class
17320  * @cfg {String} html contents of the popover   (or false to use children..)
17321  * @cfg {String} title of popover (or false to hide)
17322  * @cfg {String} placement how it is placed
17323  * @cfg {String} trigger click || hover (or false to trigger manually)
17324  * @cfg {String} over what (parent or false to trigger manually.)
17325  * @cfg {Number} delay - delay before showing
17326  
17327  * @constructor
17328  * Create a new Popover
17329  * @param {Object} config The config object
17330  */
17331
17332 Roo.bootstrap.Popover = function(config){
17333     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17334     
17335     this.addEvents({
17336         // raw events
17337          /**
17338          * @event show
17339          * After the popover show
17340          * 
17341          * @param {Roo.bootstrap.Popover} this
17342          */
17343         "show" : true,
17344         /**
17345          * @event hide
17346          * After the popover hide
17347          * 
17348          * @param {Roo.bootstrap.Popover} this
17349          */
17350         "hide" : true
17351     });
17352 };
17353
17354 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
17355     
17356     title: 'Fill in a title',
17357     html: false,
17358     
17359     placement : 'right',
17360     trigger : 'hover', // hover
17361     
17362     delay : 0,
17363     
17364     over: 'parent',
17365     
17366     can_build_overlaid : false,
17367     
17368     getChildContainer : function()
17369     {
17370         return this.el.select('.popover-content',true).first();
17371     },
17372     
17373     getAutoCreate : function(){
17374          
17375         var cfg = {
17376            cls : 'popover roo-dynamic',
17377            style: 'display:block',
17378            cn : [
17379                 {
17380                     cls : 'arrow'
17381                 },
17382                 {
17383                     cls : 'popover-inner',
17384                     cn : [
17385                         {
17386                             tag: 'h3',
17387                             cls: 'popover-title',
17388                             html : this.title
17389                         },
17390                         {
17391                             cls : 'popover-content',
17392                             html : this.html
17393                         }
17394                     ]
17395                     
17396                 }
17397            ]
17398         };
17399         
17400         return cfg;
17401     },
17402     setTitle: function(str)
17403     {
17404         this.title = str;
17405         this.el.select('.popover-title',true).first().dom.innerHTML = str;
17406     },
17407     setContent: function(str)
17408     {
17409         this.html = str;
17410         this.el.select('.popover-content',true).first().dom.innerHTML = str;
17411     },
17412     // as it get's added to the bottom of the page.
17413     onRender : function(ct, position)
17414     {
17415         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17416         if(!this.el){
17417             var cfg = Roo.apply({},  this.getAutoCreate());
17418             cfg.id = Roo.id();
17419             
17420             if (this.cls) {
17421                 cfg.cls += ' ' + this.cls;
17422             }
17423             if (this.style) {
17424                 cfg.style = this.style;
17425             }
17426             //Roo.log("adding to ");
17427             this.el = Roo.get(document.body).createChild(cfg, position);
17428 //            Roo.log(this.el);
17429         }
17430         this.initEvents();
17431     },
17432     
17433     initEvents : function()
17434     {
17435         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17436         this.el.enableDisplayMode('block');
17437         this.el.hide();
17438         if (this.over === false) {
17439             return; 
17440         }
17441         if (this.triggers === false) {
17442             return;
17443         }
17444         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17445         var triggers = this.trigger ? this.trigger.split(' ') : [];
17446         Roo.each(triggers, function(trigger) {
17447         
17448             if (trigger == 'click') {
17449                 on_el.on('click', this.toggle, this);
17450             } else if (trigger != 'manual') {
17451                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
17452                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17453       
17454                 on_el.on(eventIn  ,this.enter, this);
17455                 on_el.on(eventOut, this.leave, this);
17456             }
17457         }, this);
17458         
17459     },
17460     
17461     
17462     // private
17463     timeout : null,
17464     hoverState : null,
17465     
17466     toggle : function () {
17467         this.hoverState == 'in' ? this.leave() : this.enter();
17468     },
17469     
17470     enter : function () {
17471         
17472         clearTimeout(this.timeout);
17473     
17474         this.hoverState = 'in';
17475     
17476         if (!this.delay || !this.delay.show) {
17477             this.show();
17478             return;
17479         }
17480         var _t = this;
17481         this.timeout = setTimeout(function () {
17482             if (_t.hoverState == 'in') {
17483                 _t.show();
17484             }
17485         }, this.delay.show)
17486     },
17487     
17488     leave : function() {
17489         clearTimeout(this.timeout);
17490     
17491         this.hoverState = 'out';
17492     
17493         if (!this.delay || !this.delay.hide) {
17494             this.hide();
17495             return;
17496         }
17497         var _t = this;
17498         this.timeout = setTimeout(function () {
17499             if (_t.hoverState == 'out') {
17500                 _t.hide();
17501             }
17502         }, this.delay.hide)
17503     },
17504     
17505     show : function (on_el)
17506     {
17507         if (!on_el) {
17508             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17509         }
17510         
17511         // set content.
17512         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17513         if (this.html !== false) {
17514             this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17515         }
17516         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17517         if (!this.title.length) {
17518             this.el.select('.popover-title',true).hide();
17519         }
17520         
17521         var placement = typeof this.placement == 'function' ?
17522             this.placement.call(this, this.el, on_el) :
17523             this.placement;
17524             
17525         var autoToken = /\s?auto?\s?/i;
17526         var autoPlace = autoToken.test(placement);
17527         if (autoPlace) {
17528             placement = placement.replace(autoToken, '') || 'top';
17529         }
17530         
17531         //this.el.detach()
17532         //this.el.setXY([0,0]);
17533         this.el.show();
17534         this.el.dom.style.display='block';
17535         this.el.addClass(placement);
17536         
17537         //this.el.appendTo(on_el);
17538         
17539         var p = this.getPosition();
17540         var box = this.el.getBox();
17541         
17542         if (autoPlace) {
17543             // fixme..
17544         }
17545         var align = Roo.bootstrap.Popover.alignment[placement];
17546         
17547 //        Roo.log(align);
17548         this.el.alignTo(on_el, align[0],align[1]);
17549         //var arrow = this.el.select('.arrow',true).first();
17550         //arrow.set(align[2], 
17551         
17552         this.el.addClass('in');
17553         
17554         
17555         if (this.el.hasClass('fade')) {
17556             // fade it?
17557         }
17558         
17559         this.hoverState = 'in';
17560         
17561         this.fireEvent('show', this);
17562         
17563     },
17564     hide : function()
17565     {
17566         this.el.setXY([0,0]);
17567         this.el.removeClass('in');
17568         this.el.hide();
17569         this.hoverState = null;
17570         
17571         this.fireEvent('hide', this);
17572     }
17573     
17574 });
17575
17576 Roo.bootstrap.Popover.alignment = {
17577     'left' : ['r-l', [-10,0], 'right'],
17578     'right' : ['l-r', [10,0], 'left'],
17579     'bottom' : ['t-b', [0,10], 'top'],
17580     'top' : [ 'b-t', [0,-10], 'bottom']
17581 };
17582
17583  /*
17584  * - LGPL
17585  *
17586  * Progress
17587  * 
17588  */
17589
17590 /**
17591  * @class Roo.bootstrap.Progress
17592  * @extends Roo.bootstrap.Component
17593  * Bootstrap Progress class
17594  * @cfg {Boolean} striped striped of the progress bar
17595  * @cfg {Boolean} active animated of the progress bar
17596  * 
17597  * 
17598  * @constructor
17599  * Create a new Progress
17600  * @param {Object} config The config object
17601  */
17602
17603 Roo.bootstrap.Progress = function(config){
17604     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17605 };
17606
17607 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
17608     
17609     striped : false,
17610     active: false,
17611     
17612     getAutoCreate : function(){
17613         var cfg = {
17614             tag: 'div',
17615             cls: 'progress'
17616         };
17617         
17618         
17619         if(this.striped){
17620             cfg.cls += ' progress-striped';
17621         }
17622       
17623         if(this.active){
17624             cfg.cls += ' active';
17625         }
17626         
17627         
17628         return cfg;
17629     }
17630    
17631 });
17632
17633  
17634
17635  /*
17636  * - LGPL
17637  *
17638  * ProgressBar
17639  * 
17640  */
17641
17642 /**
17643  * @class Roo.bootstrap.ProgressBar
17644  * @extends Roo.bootstrap.Component
17645  * Bootstrap ProgressBar class
17646  * @cfg {Number} aria_valuenow aria-value now
17647  * @cfg {Number} aria_valuemin aria-value min
17648  * @cfg {Number} aria_valuemax aria-value max
17649  * @cfg {String} label label for the progress bar
17650  * @cfg {String} panel (success | info | warning | danger )
17651  * @cfg {String} role role of the progress bar
17652  * @cfg {String} sr_only text
17653  * 
17654  * 
17655  * @constructor
17656  * Create a new ProgressBar
17657  * @param {Object} config The config object
17658  */
17659
17660 Roo.bootstrap.ProgressBar = function(config){
17661     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17662 };
17663
17664 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
17665     
17666     aria_valuenow : 0,
17667     aria_valuemin : 0,
17668     aria_valuemax : 100,
17669     label : false,
17670     panel : false,
17671     role : false,
17672     sr_only: false,
17673     
17674     getAutoCreate : function()
17675     {
17676         
17677         var cfg = {
17678             tag: 'div',
17679             cls: 'progress-bar',
17680             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17681         };
17682         
17683         if(this.sr_only){
17684             cfg.cn = {
17685                 tag: 'span',
17686                 cls: 'sr-only',
17687                 html: this.sr_only
17688             }
17689         }
17690         
17691         if(this.role){
17692             cfg.role = this.role;
17693         }
17694         
17695         if(this.aria_valuenow){
17696             cfg['aria-valuenow'] = this.aria_valuenow;
17697         }
17698         
17699         if(this.aria_valuemin){
17700             cfg['aria-valuemin'] = this.aria_valuemin;
17701         }
17702         
17703         if(this.aria_valuemax){
17704             cfg['aria-valuemax'] = this.aria_valuemax;
17705         }
17706         
17707         if(this.label && !this.sr_only){
17708             cfg.html = this.label;
17709         }
17710         
17711         if(this.panel){
17712             cfg.cls += ' progress-bar-' + this.panel;
17713         }
17714         
17715         return cfg;
17716     },
17717     
17718     update : function(aria_valuenow)
17719     {
17720         this.aria_valuenow = aria_valuenow;
17721         
17722         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17723     }
17724    
17725 });
17726
17727  
17728
17729  /*
17730  * - LGPL
17731  *
17732  * column
17733  * 
17734  */
17735
17736 /**
17737  * @class Roo.bootstrap.TabGroup
17738  * @extends Roo.bootstrap.Column
17739  * Bootstrap Column class
17740  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17741  * @cfg {Boolean} carousel true to make the group behave like a carousel
17742  * @cfg {Boolean} bullets show bullets for the panels
17743  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17744  * @cfg {Number} timer auto slide timer .. default 0 millisecond
17745  * @cfg {Boolean} showarrow (true|false) show arrow default true
17746  * 
17747  * @constructor
17748  * Create a new TabGroup
17749  * @param {Object} config The config object
17750  */
17751
17752 Roo.bootstrap.TabGroup = function(config){
17753     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17754     if (!this.navId) {
17755         this.navId = Roo.id();
17756     }
17757     this.tabs = [];
17758     Roo.bootstrap.TabGroup.register(this);
17759     
17760 };
17761
17762 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
17763     
17764     carousel : false,
17765     transition : false,
17766     bullets : 0,
17767     timer : 0,
17768     autoslide : false,
17769     slideFn : false,
17770     slideOnTouch : false,
17771     showarrow : true,
17772     
17773     getAutoCreate : function()
17774     {
17775         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17776         
17777         cfg.cls += ' tab-content';
17778         
17779         if (this.carousel) {
17780             cfg.cls += ' carousel slide';
17781             
17782             cfg.cn = [{
17783                cls : 'carousel-inner',
17784                cn : []
17785             }];
17786         
17787             if(this.bullets  && !Roo.isTouch){
17788                 
17789                 var bullets = {
17790                     cls : 'carousel-bullets',
17791                     cn : []
17792                 };
17793                
17794                 if(this.bullets_cls){
17795                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17796                 }
17797                 
17798                 bullets.cn.push({
17799                     cls : 'clear'
17800                 });
17801                 
17802                 cfg.cn[0].cn.push(bullets);
17803             }
17804             
17805             if(this.showarrow){
17806                 cfg.cn[0].cn.push({
17807                     tag : 'div',
17808                     class : 'carousel-arrow',
17809                     cn : [
17810                         {
17811                             tag : 'div',
17812                             class : 'carousel-prev',
17813                             cn : [
17814                                 {
17815                                     tag : 'i',
17816                                     class : 'fa fa-chevron-left'
17817                                 }
17818                             ]
17819                         },
17820                         {
17821                             tag : 'div',
17822                             class : 'carousel-next',
17823                             cn : [
17824                                 {
17825                                     tag : 'i',
17826                                     class : 'fa fa-chevron-right'
17827                                 }
17828                             ]
17829                         }
17830                     ]
17831                 });
17832             }
17833             
17834         }
17835         
17836         return cfg;
17837     },
17838     
17839     initEvents:  function()
17840     {
17841 //        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17842 //            this.el.on("touchstart", this.onTouchStart, this);
17843 //        }
17844         
17845         if(this.autoslide){
17846             var _this = this;
17847             
17848             this.slideFn = window.setInterval(function() {
17849                 _this.showPanelNext();
17850             }, this.timer);
17851         }
17852         
17853         if(this.showarrow){
17854             this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17855             this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17856         }
17857         
17858         
17859     },
17860     
17861 //    onTouchStart : function(e, el, o)
17862 //    {
17863 //        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17864 //            return;
17865 //        }
17866 //        
17867 //        this.showPanelNext();
17868 //    },
17869     
17870     
17871     getChildContainer : function()
17872     {
17873         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17874     },
17875     
17876     /**
17877     * register a Navigation item
17878     * @param {Roo.bootstrap.NavItem} the navitem to add
17879     */
17880     register : function(item)
17881     {
17882         this.tabs.push( item);
17883         item.navId = this.navId; // not really needed..
17884         this.addBullet();
17885     
17886     },
17887     
17888     getActivePanel : function()
17889     {
17890         var r = false;
17891         Roo.each(this.tabs, function(t) {
17892             if (t.active) {
17893                 r = t;
17894                 return false;
17895             }
17896             return null;
17897         });
17898         return r;
17899         
17900     },
17901     getPanelByName : function(n)
17902     {
17903         var r = false;
17904         Roo.each(this.tabs, function(t) {
17905             if (t.tabId == n) {
17906                 r = t;
17907                 return false;
17908             }
17909             return null;
17910         });
17911         return r;
17912     },
17913     indexOfPanel : function(p)
17914     {
17915         var r = false;
17916         Roo.each(this.tabs, function(t,i) {
17917             if (t.tabId == p.tabId) {
17918                 r = i;
17919                 return false;
17920             }
17921             return null;
17922         });
17923         return r;
17924     },
17925     /**
17926      * show a specific panel
17927      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17928      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17929      */
17930     showPanel : function (pan)
17931     {
17932         if(this.transition || typeof(pan) == 'undefined'){
17933             Roo.log("waiting for the transitionend");
17934             return;
17935         }
17936         
17937         if (typeof(pan) == 'number') {
17938             pan = this.tabs[pan];
17939         }
17940         
17941         if (typeof(pan) == 'string') {
17942             pan = this.getPanelByName(pan);
17943         }
17944         
17945         var cur = this.getActivePanel();
17946         
17947         if(!pan || !cur){
17948             Roo.log('pan or acitve pan is undefined');
17949             return false;
17950         }
17951         
17952         if (pan.tabId == this.getActivePanel().tabId) {
17953             return true;
17954         }
17955         
17956         if (false === cur.fireEvent('beforedeactivate')) {
17957             return false;
17958         }
17959         
17960         if(this.bullets > 0 && !Roo.isTouch){
17961             this.setActiveBullet(this.indexOfPanel(pan));
17962         }
17963         
17964         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17965             
17966             this.transition = true;
17967             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
17968             var lr = dir == 'next' ? 'left' : 'right';
17969             pan.el.addClass(dir); // or prev
17970             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17971             cur.el.addClass(lr); // or right
17972             pan.el.addClass(lr);
17973             
17974             var _this = this;
17975             cur.el.on('transitionend', function() {
17976                 Roo.log("trans end?");
17977                 
17978                 pan.el.removeClass([lr,dir]);
17979                 pan.setActive(true);
17980                 
17981                 cur.el.removeClass([lr]);
17982                 cur.setActive(false);
17983                 
17984                 _this.transition = false;
17985                 
17986             }, this, { single:  true } );
17987             
17988             return true;
17989         }
17990         
17991         cur.setActive(false);
17992         pan.setActive(true);
17993         
17994         return true;
17995         
17996     },
17997     showPanelNext : function()
17998     {
17999         var i = this.indexOfPanel(this.getActivePanel());
18000         
18001         if (i >= this.tabs.length - 1 && !this.autoslide) {
18002             return;
18003         }
18004         
18005         if (i >= this.tabs.length - 1 && this.autoslide) {
18006             i = -1;
18007         }
18008         
18009         this.showPanel(this.tabs[i+1]);
18010     },
18011     
18012     showPanelPrev : function()
18013     {
18014         var i = this.indexOfPanel(this.getActivePanel());
18015         
18016         if (i  < 1 && !this.autoslide) {
18017             return;
18018         }
18019         
18020         if (i < 1 && this.autoslide) {
18021             i = this.tabs.length;
18022         }
18023         
18024         this.showPanel(this.tabs[i-1]);
18025     },
18026     
18027     
18028     addBullet: function()
18029     {
18030         if(!this.bullets || Roo.isTouch){
18031             return;
18032         }
18033         var ctr = this.el.select('.carousel-bullets',true).first();
18034         var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18035         var bullet = ctr.createChild({
18036             cls : 'bullet bullet-' + i
18037         },ctr.dom.lastChild);
18038         
18039         
18040         var _this = this;
18041         
18042         bullet.on('click', (function(e, el, o, ii, t){
18043
18044             e.preventDefault();
18045
18046             this.showPanel(ii);
18047
18048             if(this.autoslide && this.slideFn){
18049                 clearInterval(this.slideFn);
18050                 this.slideFn = window.setInterval(function() {
18051                     _this.showPanelNext();
18052                 }, this.timer);
18053             }
18054
18055         }).createDelegate(this, [i, bullet], true));
18056                 
18057         
18058     },
18059      
18060     setActiveBullet : function(i)
18061     {
18062         if(Roo.isTouch){
18063             return;
18064         }
18065         
18066         Roo.each(this.el.select('.bullet', true).elements, function(el){
18067             el.removeClass('selected');
18068         });
18069
18070         var bullet = this.el.select('.bullet-' + i, true).first();
18071         
18072         if(!bullet){
18073             return;
18074         }
18075         
18076         bullet.addClass('selected');
18077     }
18078     
18079     
18080   
18081 });
18082
18083  
18084
18085  
18086  
18087 Roo.apply(Roo.bootstrap.TabGroup, {
18088     
18089     groups: {},
18090      /**
18091     * register a Navigation Group
18092     * @param {Roo.bootstrap.NavGroup} the navgroup to add
18093     */
18094     register : function(navgrp)
18095     {
18096         this.groups[navgrp.navId] = navgrp;
18097         
18098     },
18099     /**
18100     * fetch a Navigation Group based on the navigation ID
18101     * if one does not exist , it will get created.
18102     * @param {string} the navgroup to add
18103     * @returns {Roo.bootstrap.NavGroup} the navgroup 
18104     */
18105     get: function(navId) {
18106         if (typeof(this.groups[navId]) == 'undefined') {
18107             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18108         }
18109         return this.groups[navId] ;
18110     }
18111     
18112     
18113     
18114 });
18115
18116  /*
18117  * - LGPL
18118  *
18119  * TabPanel
18120  * 
18121  */
18122
18123 /**
18124  * @class Roo.bootstrap.TabPanel
18125  * @extends Roo.bootstrap.Component
18126  * Bootstrap TabPanel class
18127  * @cfg {Boolean} active panel active
18128  * @cfg {String} html panel content
18129  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18130  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18131  * @cfg {String} href click to link..
18132  * 
18133  * 
18134  * @constructor
18135  * Create a new TabPanel
18136  * @param {Object} config The config object
18137  */
18138
18139 Roo.bootstrap.TabPanel = function(config){
18140     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18141     this.addEvents({
18142         /**
18143              * @event changed
18144              * Fires when the active status changes
18145              * @param {Roo.bootstrap.TabPanel} this
18146              * @param {Boolean} state the new state
18147             
18148          */
18149         'changed': true,
18150         /**
18151              * @event beforedeactivate
18152              * Fires before a tab is de-activated - can be used to do validation on a form.
18153              * @param {Roo.bootstrap.TabPanel} this
18154              * @return {Boolean} false if there is an error
18155             
18156          */
18157         'beforedeactivate': true
18158      });
18159     
18160     this.tabId = this.tabId || Roo.id();
18161   
18162 };
18163
18164 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
18165     
18166     active: false,
18167     html: false,
18168     tabId: false,
18169     navId : false,
18170     href : '',
18171     
18172     getAutoCreate : function(){
18173         var cfg = {
18174             tag: 'div',
18175             // item is needed for carousel - not sure if it has any effect otherwise
18176             cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18177             html: this.html || ''
18178         };
18179         
18180         if(this.active){
18181             cfg.cls += ' active';
18182         }
18183         
18184         if(this.tabId){
18185             cfg.tabId = this.tabId;
18186         }
18187         
18188         
18189         return cfg;
18190     },
18191     
18192     initEvents:  function()
18193     {
18194         var p = this.parent();
18195         
18196         this.navId = this.navId || p.navId;
18197         
18198         if (typeof(this.navId) != 'undefined') {
18199             // not really needed.. but just in case.. parent should be a NavGroup.
18200             var tg = Roo.bootstrap.TabGroup.get(this.navId);
18201             
18202             tg.register(this);
18203             
18204             var i = tg.tabs.length - 1;
18205             
18206             if(this.active && tg.bullets > 0 && i < tg.bullets){
18207                 tg.setActiveBullet(i);
18208             }
18209         }
18210         
18211         this.el.on('click', this.onClick, this);
18212         
18213         if(Roo.isTouch){
18214             this.el.on("touchstart", this.onTouchStart, this);
18215             this.el.on("touchmove", this.onTouchMove, this);
18216             this.el.on("touchend", this.onTouchEnd, this);
18217         }
18218         
18219     },
18220     
18221     onRender : function(ct, position)
18222     {
18223         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18224     },
18225     
18226     setActive : function(state)
18227     {
18228         Roo.log("panel - set active " + this.tabId + "=" + state);
18229         
18230         this.active = state;
18231         if (!state) {
18232             this.el.removeClass('active');
18233             
18234         } else  if (!this.el.hasClass('active')) {
18235             this.el.addClass('active');
18236         }
18237         
18238         this.fireEvent('changed', this, state);
18239     },
18240     
18241     onClick : function(e)
18242     {
18243         e.preventDefault();
18244         
18245         if(!this.href.length){
18246             return;
18247         }
18248         
18249         window.location.href = this.href;
18250     },
18251     
18252     startX : 0,
18253     startY : 0,
18254     endX : 0,
18255     endY : 0,
18256     swiping : false,
18257     
18258     onTouchStart : function(e)
18259     {
18260         this.swiping = false;
18261         
18262         this.startX = e.browserEvent.touches[0].clientX;
18263         this.startY = e.browserEvent.touches[0].clientY;
18264     },
18265     
18266     onTouchMove : function(e)
18267     {
18268         this.swiping = true;
18269         
18270         this.endX = e.browserEvent.touches[0].clientX;
18271         this.endY = e.browserEvent.touches[0].clientY;
18272     },
18273     
18274     onTouchEnd : function(e)
18275     {
18276         if(!this.swiping){
18277             this.onClick(e);
18278             return;
18279         }
18280         
18281         var tabGroup = this.parent();
18282         
18283         if(this.endX > this.startX){ // swiping right
18284             tabGroup.showPanelPrev();
18285             return;
18286         }
18287         
18288         if(this.startX > this.endX){ // swiping left
18289             tabGroup.showPanelNext();
18290             return;
18291         }
18292     }
18293     
18294     
18295 });
18296  
18297
18298  
18299
18300  /*
18301  * - LGPL
18302  *
18303  * DateField
18304  * 
18305  */
18306
18307 /**
18308  * @class Roo.bootstrap.DateField
18309  * @extends Roo.bootstrap.Input
18310  * Bootstrap DateField class
18311  * @cfg {Number} weekStart default 0
18312  * @cfg {String} viewMode default empty, (months|years)
18313  * @cfg {String} minViewMode default empty, (months|years)
18314  * @cfg {Number} startDate default -Infinity
18315  * @cfg {Number} endDate default Infinity
18316  * @cfg {Boolean} todayHighlight default false
18317  * @cfg {Boolean} todayBtn default false
18318  * @cfg {Boolean} calendarWeeks default false
18319  * @cfg {Object} daysOfWeekDisabled default empty
18320  * @cfg {Boolean} singleMode default false (true | false)
18321  * 
18322  * @cfg {Boolean} keyboardNavigation default true
18323  * @cfg {String} language default en
18324  * 
18325  * @constructor
18326  * Create a new DateField
18327  * @param {Object} config The config object
18328  */
18329
18330 Roo.bootstrap.DateField = function(config){
18331     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18332      this.addEvents({
18333             /**
18334              * @event show
18335              * Fires when this field show.
18336              * @param {Roo.bootstrap.DateField} this
18337              * @param {Mixed} date The date value
18338              */
18339             show : true,
18340             /**
18341              * @event show
18342              * Fires when this field hide.
18343              * @param {Roo.bootstrap.DateField} this
18344              * @param {Mixed} date The date value
18345              */
18346             hide : true,
18347             /**
18348              * @event select
18349              * Fires when select a date.
18350              * @param {Roo.bootstrap.DateField} this
18351              * @param {Mixed} date The date value
18352              */
18353             select : true,
18354             /**
18355              * @event beforeselect
18356              * Fires when before select a date.
18357              * @param {Roo.bootstrap.DateField} this
18358              * @param {Mixed} date The date value
18359              */
18360             beforeselect : true
18361         });
18362 };
18363
18364 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
18365     
18366     /**
18367      * @cfg {String} format
18368      * The default date format string which can be overriden for localization support.  The format must be
18369      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18370      */
18371     format : "m/d/y",
18372     /**
18373      * @cfg {String} altFormats
18374      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18375      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18376      */
18377     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18378     
18379     weekStart : 0,
18380     
18381     viewMode : '',
18382     
18383     minViewMode : '',
18384     
18385     todayHighlight : false,
18386     
18387     todayBtn: false,
18388     
18389     language: 'en',
18390     
18391     keyboardNavigation: true,
18392     
18393     calendarWeeks: false,
18394     
18395     startDate: -Infinity,
18396     
18397     endDate: Infinity,
18398     
18399     daysOfWeekDisabled: [],
18400     
18401     _events: [],
18402     
18403     singleMode : false,
18404     
18405     UTCDate: function()
18406     {
18407         return new Date(Date.UTC.apply(Date, arguments));
18408     },
18409     
18410     UTCToday: function()
18411     {
18412         var today = new Date();
18413         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18414     },
18415     
18416     getDate: function() {
18417             var d = this.getUTCDate();
18418             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18419     },
18420     
18421     getUTCDate: function() {
18422             return this.date;
18423     },
18424     
18425     setDate: function(d) {
18426             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18427     },
18428     
18429     setUTCDate: function(d) {
18430             this.date = d;
18431             this.setValue(this.formatDate(this.date));
18432     },
18433         
18434     onRender: function(ct, position)
18435     {
18436         
18437         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18438         
18439         this.language = this.language || 'en';
18440         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18441         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18442         
18443         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18444         this.format = this.format || 'm/d/y';
18445         this.isInline = false;
18446         this.isInput = true;
18447         this.component = this.el.select('.add-on', true).first() || false;
18448         this.component = (this.component && this.component.length === 0) ? false : this.component;
18449         this.hasInput = this.component && this.inputEl().length;
18450         
18451         if (typeof(this.minViewMode === 'string')) {
18452             switch (this.minViewMode) {
18453                 case 'months':
18454                     this.minViewMode = 1;
18455                     break;
18456                 case 'years':
18457                     this.minViewMode = 2;
18458                     break;
18459                 default:
18460                     this.minViewMode = 0;
18461                     break;
18462             }
18463         }
18464         
18465         if (typeof(this.viewMode === 'string')) {
18466             switch (this.viewMode) {
18467                 case 'months':
18468                     this.viewMode = 1;
18469                     break;
18470                 case 'years':
18471                     this.viewMode = 2;
18472                     break;
18473                 default:
18474                     this.viewMode = 0;
18475                     break;
18476             }
18477         }
18478                 
18479         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18480         
18481 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18482         
18483         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18484         
18485         this.picker().on('mousedown', this.onMousedown, this);
18486         this.picker().on('click', this.onClick, this);
18487         
18488         this.picker().addClass('datepicker-dropdown');
18489         
18490         this.startViewMode = this.viewMode;
18491         
18492         if(this.singleMode){
18493             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18494                 v.setVisibilityMode(Roo.Element.DISPLAY);
18495                 v.hide();
18496             });
18497             
18498             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18499                 v.setStyle('width', '189px');
18500             });
18501         }
18502         
18503         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18504             if(!this.calendarWeeks){
18505                 v.remove();
18506                 return;
18507             }
18508             
18509             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18510             v.attr('colspan', function(i, val){
18511                 return parseInt(val) + 1;
18512             });
18513         });
18514                         
18515         
18516         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18517         
18518         this.setStartDate(this.startDate);
18519         this.setEndDate(this.endDate);
18520         
18521         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18522         
18523         this.fillDow();
18524         this.fillMonths();
18525         this.update();
18526         this.showMode();
18527         
18528         if(this.isInline) {
18529             this.show();
18530         }
18531     },
18532     
18533     picker : function()
18534     {
18535         return this.pickerEl;
18536 //        return this.el.select('.datepicker', true).first();
18537     },
18538     
18539     fillDow: function()
18540     {
18541         var dowCnt = this.weekStart;
18542         
18543         var dow = {
18544             tag: 'tr',
18545             cn: [
18546                 
18547             ]
18548         };
18549         
18550         if(this.calendarWeeks){
18551             dow.cn.push({
18552                 tag: 'th',
18553                 cls: 'cw',
18554                 html: '&nbsp;'
18555             })
18556         }
18557         
18558         while (dowCnt < this.weekStart + 7) {
18559             dow.cn.push({
18560                 tag: 'th',
18561                 cls: 'dow',
18562                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18563             });
18564         }
18565         
18566         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18567     },
18568     
18569     fillMonths: function()
18570     {    
18571         var i = 0;
18572         var months = this.picker().select('>.datepicker-months td', true).first();
18573         
18574         months.dom.innerHTML = '';
18575         
18576         while (i < 12) {
18577             var month = {
18578                 tag: 'span',
18579                 cls: 'month',
18580                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18581             };
18582             
18583             months.createChild(month);
18584         }
18585         
18586     },
18587     
18588     update: function()
18589     {
18590         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;
18591         
18592         if (this.date < this.startDate) {
18593             this.viewDate = new Date(this.startDate);
18594         } else if (this.date > this.endDate) {
18595             this.viewDate = new Date(this.endDate);
18596         } else {
18597             this.viewDate = new Date(this.date);
18598         }
18599         
18600         this.fill();
18601     },
18602     
18603     fill: function() 
18604     {
18605         var d = new Date(this.viewDate),
18606                 year = d.getUTCFullYear(),
18607                 month = d.getUTCMonth(),
18608                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18609                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18610                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18611                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18612                 currentDate = this.date && this.date.valueOf(),
18613                 today = this.UTCToday();
18614         
18615         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18616         
18617 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18618         
18619 //        this.picker.select('>tfoot th.today').
18620 //                                              .text(dates[this.language].today)
18621 //                                              .toggle(this.todayBtn !== false);
18622     
18623         this.updateNavArrows();
18624         this.fillMonths();
18625                                                 
18626         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18627         
18628         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18629          
18630         prevMonth.setUTCDate(day);
18631         
18632         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18633         
18634         var nextMonth = new Date(prevMonth);
18635         
18636         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18637         
18638         nextMonth = nextMonth.valueOf();
18639         
18640         var fillMonths = false;
18641         
18642         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18643         
18644         while(prevMonth.valueOf() <= nextMonth) {
18645             var clsName = '';
18646             
18647             if (prevMonth.getUTCDay() === this.weekStart) {
18648                 if(fillMonths){
18649                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18650                 }
18651                     
18652                 fillMonths = {
18653                     tag: 'tr',
18654                     cn: []
18655                 };
18656                 
18657                 if(this.calendarWeeks){
18658                     // ISO 8601: First week contains first thursday.
18659                     // ISO also states week starts on Monday, but we can be more abstract here.
18660                     var
18661                     // Start of current week: based on weekstart/current date
18662                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18663                     // Thursday of this week
18664                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18665                     // First Thursday of year, year from thursday
18666                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18667                     // Calendar week: ms between thursdays, div ms per day, div 7 days
18668                     calWeek =  (th - yth) / 864e5 / 7 + 1;
18669                     
18670                     fillMonths.cn.push({
18671                         tag: 'td',
18672                         cls: 'cw',
18673                         html: calWeek
18674                     });
18675                 }
18676             }
18677             
18678             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18679                 clsName += ' old';
18680             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18681                 clsName += ' new';
18682             }
18683             if (this.todayHighlight &&
18684                 prevMonth.getUTCFullYear() == today.getFullYear() &&
18685                 prevMonth.getUTCMonth() == today.getMonth() &&
18686                 prevMonth.getUTCDate() == today.getDate()) {
18687                 clsName += ' today';
18688             }
18689             
18690             if (currentDate && prevMonth.valueOf() === currentDate) {
18691                 clsName += ' active';
18692             }
18693             
18694             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18695                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18696                     clsName += ' disabled';
18697             }
18698             
18699             fillMonths.cn.push({
18700                 tag: 'td',
18701                 cls: 'day ' + clsName,
18702                 html: prevMonth.getDate()
18703             });
18704             
18705             prevMonth.setDate(prevMonth.getDate()+1);
18706         }
18707           
18708         var currentYear = this.date && this.date.getUTCFullYear();
18709         var currentMonth = this.date && this.date.getUTCMonth();
18710         
18711         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18712         
18713         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18714             v.removeClass('active');
18715             
18716             if(currentYear === year && k === currentMonth){
18717                 v.addClass('active');
18718             }
18719             
18720             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18721                 v.addClass('disabled');
18722             }
18723             
18724         });
18725         
18726         
18727         year = parseInt(year/10, 10) * 10;
18728         
18729         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18730         
18731         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18732         
18733         year -= 1;
18734         for (var i = -1; i < 11; i++) {
18735             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18736                 tag: 'span',
18737                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18738                 html: year
18739             });
18740             
18741             year += 1;
18742         }
18743     },
18744     
18745     showMode: function(dir) 
18746     {
18747         if (dir) {
18748             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18749         }
18750         
18751         Roo.each(this.picker().select('>div',true).elements, function(v){
18752             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18753             v.hide();
18754         });
18755         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18756     },
18757     
18758     place: function()
18759     {
18760         if(this.isInline) {
18761             return;
18762         }
18763         
18764         this.picker().removeClass(['bottom', 'top']);
18765         
18766         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18767             /*
18768              * place to the top of element!
18769              *
18770              */
18771             
18772             this.picker().addClass('top');
18773             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18774             
18775             return;
18776         }
18777         
18778         this.picker().addClass('bottom');
18779         
18780         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18781     },
18782     
18783     parseDate : function(value)
18784     {
18785         if(!value || value instanceof Date){
18786             return value;
18787         }
18788         var v = Date.parseDate(value, this.format);
18789         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18790             v = Date.parseDate(value, 'Y-m-d');
18791         }
18792         if(!v && this.altFormats){
18793             if(!this.altFormatsArray){
18794                 this.altFormatsArray = this.altFormats.split("|");
18795             }
18796             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18797                 v = Date.parseDate(value, this.altFormatsArray[i]);
18798             }
18799         }
18800         return v;
18801     },
18802     
18803     formatDate : function(date, fmt)
18804     {   
18805         return (!date || !(date instanceof Date)) ?
18806         date : date.dateFormat(fmt || this.format);
18807     },
18808     
18809     onFocus : function()
18810     {
18811         Roo.bootstrap.DateField.superclass.onFocus.call(this);
18812         this.show();
18813     },
18814     
18815     onBlur : function()
18816     {
18817         Roo.bootstrap.DateField.superclass.onBlur.call(this);
18818         
18819         var d = this.inputEl().getValue();
18820         
18821         this.setValue(d);
18822                 
18823         this.hide();
18824     },
18825     
18826     show : function()
18827     {
18828         this.picker().show();
18829         this.update();
18830         this.place();
18831         
18832         this.fireEvent('show', this, this.date);
18833     },
18834     
18835     hide : function()
18836     {
18837         if(this.isInline) {
18838             return;
18839         }
18840         this.picker().hide();
18841         this.viewMode = this.startViewMode;
18842         this.showMode();
18843         
18844         this.fireEvent('hide', this, this.date);
18845         
18846     },
18847     
18848     onMousedown: function(e)
18849     {
18850         e.stopPropagation();
18851         e.preventDefault();
18852     },
18853     
18854     keyup: function(e)
18855     {
18856         Roo.bootstrap.DateField.superclass.keyup.call(this);
18857         this.update();
18858     },
18859
18860     setValue: function(v)
18861     {
18862         if(this.fireEvent('beforeselect', this, v) !== false){
18863             var d = new Date(this.parseDate(v) ).clearTime();
18864         
18865             if(isNaN(d.getTime())){
18866                 this.date = this.viewDate = '';
18867                 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18868                 return;
18869             }
18870
18871             v = this.formatDate(d);
18872
18873             Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18874
18875             this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18876
18877             this.update();
18878
18879             this.fireEvent('select', this, this.date);
18880         }
18881     },
18882     
18883     getValue: function()
18884     {
18885         return this.formatDate(this.date);
18886     },
18887     
18888     fireKey: function(e)
18889     {
18890         if (!this.picker().isVisible()){
18891             if (e.keyCode == 27) { // allow escape to hide and re-show picker
18892                 this.show();
18893             }
18894             return;
18895         }
18896         
18897         var dateChanged = false,
18898         dir, day, month,
18899         newDate, newViewDate;
18900         
18901         switch(e.keyCode){
18902             case 27: // escape
18903                 this.hide();
18904                 e.preventDefault();
18905                 break;
18906             case 37: // left
18907             case 39: // right
18908                 if (!this.keyboardNavigation) {
18909                     break;
18910                 }
18911                 dir = e.keyCode == 37 ? -1 : 1;
18912                 
18913                 if (e.ctrlKey){
18914                     newDate = this.moveYear(this.date, dir);
18915                     newViewDate = this.moveYear(this.viewDate, dir);
18916                 } else if (e.shiftKey){
18917                     newDate = this.moveMonth(this.date, dir);
18918                     newViewDate = this.moveMonth(this.viewDate, dir);
18919                 } else {
18920                     newDate = new Date(this.date);
18921                     newDate.setUTCDate(this.date.getUTCDate() + dir);
18922                     newViewDate = new Date(this.viewDate);
18923                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18924                 }
18925                 if (this.dateWithinRange(newDate)){
18926                     this.date = newDate;
18927                     this.viewDate = newViewDate;
18928                     this.setValue(this.formatDate(this.date));
18929 //                    this.update();
18930                     e.preventDefault();
18931                     dateChanged = true;
18932                 }
18933                 break;
18934             case 38: // up
18935             case 40: // down
18936                 if (!this.keyboardNavigation) {
18937                     break;
18938                 }
18939                 dir = e.keyCode == 38 ? -1 : 1;
18940                 if (e.ctrlKey){
18941                     newDate = this.moveYear(this.date, dir);
18942                     newViewDate = this.moveYear(this.viewDate, dir);
18943                 } else if (e.shiftKey){
18944                     newDate = this.moveMonth(this.date, dir);
18945                     newViewDate = this.moveMonth(this.viewDate, dir);
18946                 } else {
18947                     newDate = new Date(this.date);
18948                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18949                     newViewDate = new Date(this.viewDate);
18950                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18951                 }
18952                 if (this.dateWithinRange(newDate)){
18953                     this.date = newDate;
18954                     this.viewDate = newViewDate;
18955                     this.setValue(this.formatDate(this.date));
18956 //                    this.update();
18957                     e.preventDefault();
18958                     dateChanged = true;
18959                 }
18960                 break;
18961             case 13: // enter
18962                 this.setValue(this.formatDate(this.date));
18963                 this.hide();
18964                 e.preventDefault();
18965                 break;
18966             case 9: // tab
18967                 this.setValue(this.formatDate(this.date));
18968                 this.hide();
18969                 break;
18970             case 16: // shift
18971             case 17: // ctrl
18972             case 18: // alt
18973                 break;
18974             default :
18975                 this.hide();
18976                 
18977         }
18978     },
18979     
18980     
18981     onClick: function(e) 
18982     {
18983         e.stopPropagation();
18984         e.preventDefault();
18985         
18986         var target = e.getTarget();
18987         
18988         if(target.nodeName.toLowerCase() === 'i'){
18989             target = Roo.get(target).dom.parentNode;
18990         }
18991         
18992         var nodeName = target.nodeName;
18993         var className = target.className;
18994         var html = target.innerHTML;
18995         //Roo.log(nodeName);
18996         
18997         switch(nodeName.toLowerCase()) {
18998             case 'th':
18999                 switch(className) {
19000                     case 'switch':
19001                         this.showMode(1);
19002                         break;
19003                     case 'prev':
19004                     case 'next':
19005                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19006                         switch(this.viewMode){
19007                                 case 0:
19008                                         this.viewDate = this.moveMonth(this.viewDate, dir);
19009                                         break;
19010                                 case 1:
19011                                 case 2:
19012                                         this.viewDate = this.moveYear(this.viewDate, dir);
19013                                         break;
19014                         }
19015                         this.fill();
19016                         break;
19017                     case 'today':
19018                         var date = new Date();
19019                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19020 //                        this.fill()
19021                         this.setValue(this.formatDate(this.date));
19022                         
19023                         this.hide();
19024                         break;
19025                 }
19026                 break;
19027             case 'span':
19028                 if (className.indexOf('disabled') < 0) {
19029                     this.viewDate.setUTCDate(1);
19030                     if (className.indexOf('month') > -1) {
19031                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19032                     } else {
19033                         var year = parseInt(html, 10) || 0;
19034                         this.viewDate.setUTCFullYear(year);
19035                         
19036                     }
19037                     
19038                     if(this.singleMode){
19039                         this.setValue(this.formatDate(this.viewDate));
19040                         this.hide();
19041                         return;
19042                     }
19043                     
19044                     this.showMode(-1);
19045                     this.fill();
19046                 }
19047                 break;
19048                 
19049             case 'td':
19050                 //Roo.log(className);
19051                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19052                     var day = parseInt(html, 10) || 1;
19053                     var year = this.viewDate.getUTCFullYear(),
19054                         month = this.viewDate.getUTCMonth();
19055
19056                     if (className.indexOf('old') > -1) {
19057                         if(month === 0 ){
19058                             month = 11;
19059                             year -= 1;
19060                         }else{
19061                             month -= 1;
19062                         }
19063                     } else if (className.indexOf('new') > -1) {
19064                         if (month == 11) {
19065                             month = 0;
19066                             year += 1;
19067                         } else {
19068                             month += 1;
19069                         }
19070                     }
19071                     //Roo.log([year,month,day]);
19072                     this.date = this.UTCDate(year, month, day,0,0,0,0);
19073                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19074 //                    this.fill();
19075                     //Roo.log(this.formatDate(this.date));
19076                     this.setValue(this.formatDate(this.date));
19077                     this.hide();
19078                 }
19079                 break;
19080         }
19081     },
19082     
19083     setStartDate: function(startDate)
19084     {
19085         this.startDate = startDate || -Infinity;
19086         if (this.startDate !== -Infinity) {
19087             this.startDate = this.parseDate(this.startDate);
19088         }
19089         this.update();
19090         this.updateNavArrows();
19091     },
19092
19093     setEndDate: function(endDate)
19094     {
19095         this.endDate = endDate || Infinity;
19096         if (this.endDate !== Infinity) {
19097             this.endDate = this.parseDate(this.endDate);
19098         }
19099         this.update();
19100         this.updateNavArrows();
19101     },
19102     
19103     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19104     {
19105         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19106         if (typeof(this.daysOfWeekDisabled) !== 'object') {
19107             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19108         }
19109         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19110             return parseInt(d, 10);
19111         });
19112         this.update();
19113         this.updateNavArrows();
19114     },
19115     
19116     updateNavArrows: function() 
19117     {
19118         if(this.singleMode){
19119             return;
19120         }
19121         
19122         var d = new Date(this.viewDate),
19123         year = d.getUTCFullYear(),
19124         month = d.getUTCMonth();
19125         
19126         Roo.each(this.picker().select('.prev', true).elements, function(v){
19127             v.show();
19128             switch (this.viewMode) {
19129                 case 0:
19130
19131                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19132                         v.hide();
19133                     }
19134                     break;
19135                 case 1:
19136                 case 2:
19137                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19138                         v.hide();
19139                     }
19140                     break;
19141             }
19142         });
19143         
19144         Roo.each(this.picker().select('.next', true).elements, function(v){
19145             v.show();
19146             switch (this.viewMode) {
19147                 case 0:
19148
19149                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19150                         v.hide();
19151                     }
19152                     break;
19153                 case 1:
19154                 case 2:
19155                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19156                         v.hide();
19157                     }
19158                     break;
19159             }
19160         })
19161     },
19162     
19163     moveMonth: function(date, dir)
19164     {
19165         if (!dir) {
19166             return date;
19167         }
19168         var new_date = new Date(date.valueOf()),
19169         day = new_date.getUTCDate(),
19170         month = new_date.getUTCMonth(),
19171         mag = Math.abs(dir),
19172         new_month, test;
19173         dir = dir > 0 ? 1 : -1;
19174         if (mag == 1){
19175             test = dir == -1
19176             // If going back one month, make sure month is not current month
19177             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19178             ? function(){
19179                 return new_date.getUTCMonth() == month;
19180             }
19181             // If going forward one month, make sure month is as expected
19182             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19183             : function(){
19184                 return new_date.getUTCMonth() != new_month;
19185             };
19186             new_month = month + dir;
19187             new_date.setUTCMonth(new_month);
19188             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19189             if (new_month < 0 || new_month > 11) {
19190                 new_month = (new_month + 12) % 12;
19191             }
19192         } else {
19193             // For magnitudes >1, move one month at a time...
19194             for (var i=0; i<mag; i++) {
19195                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19196                 new_date = this.moveMonth(new_date, dir);
19197             }
19198             // ...then reset the day, keeping it in the new month
19199             new_month = new_date.getUTCMonth();
19200             new_date.setUTCDate(day);
19201             test = function(){
19202                 return new_month != new_date.getUTCMonth();
19203             };
19204         }
19205         // Common date-resetting loop -- if date is beyond end of month, make it
19206         // end of month
19207         while (test()){
19208             new_date.setUTCDate(--day);
19209             new_date.setUTCMonth(new_month);
19210         }
19211         return new_date;
19212     },
19213
19214     moveYear: function(date, dir)
19215     {
19216         return this.moveMonth(date, dir*12);
19217     },
19218
19219     dateWithinRange: function(date)
19220     {
19221         return date >= this.startDate && date <= this.endDate;
19222     },
19223
19224     
19225     remove: function() 
19226     {
19227         this.picker().remove();
19228     },
19229     
19230     validateValue : function(value)
19231     {
19232         if(this.getVisibilityEl().hasClass('hidden')){
19233             return true;
19234         }
19235         
19236         if(value.length < 1)  {
19237             if(this.allowBlank){
19238                 return true;
19239             }
19240             return false;
19241         }
19242         
19243         if(value.length < this.minLength){
19244             return false;
19245         }
19246         if(value.length > this.maxLength){
19247             return false;
19248         }
19249         if(this.vtype){
19250             var vt = Roo.form.VTypes;
19251             if(!vt[this.vtype](value, this)){
19252                 return false;
19253             }
19254         }
19255         if(typeof this.validator == "function"){
19256             var msg = this.validator(value);
19257             if(msg !== true){
19258                 return false;
19259             }
19260         }
19261         
19262         if(this.regex && !this.regex.test(value)){
19263             return false;
19264         }
19265         
19266         if(typeof(this.parseDate(value)) == 'undefined'){
19267             return false;
19268         }
19269         
19270         if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19271             return false;
19272         }      
19273         
19274         if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19275             return false;
19276         } 
19277         
19278         
19279         return true;
19280     },
19281     
19282     setVisible : function(visible)
19283     {
19284         if(!this.getEl()){
19285             return;
19286         }
19287         
19288         this.getEl().removeClass('hidden');
19289         
19290         if(visible){
19291             return;
19292         }
19293         
19294         this.getEl().addClass('hidden');
19295     }
19296    
19297 });
19298
19299 Roo.apply(Roo.bootstrap.DateField,  {
19300     
19301     head : {
19302         tag: 'thead',
19303         cn: [
19304         {
19305             tag: 'tr',
19306             cn: [
19307             {
19308                 tag: 'th',
19309                 cls: 'prev',
19310                 html: '<i class="fa fa-arrow-left"/>'
19311             },
19312             {
19313                 tag: 'th',
19314                 cls: 'switch',
19315                 colspan: '5'
19316             },
19317             {
19318                 tag: 'th',
19319                 cls: 'next',
19320                 html: '<i class="fa fa-arrow-right"/>'
19321             }
19322
19323             ]
19324         }
19325         ]
19326     },
19327     
19328     content : {
19329         tag: 'tbody',
19330         cn: [
19331         {
19332             tag: 'tr',
19333             cn: [
19334             {
19335                 tag: 'td',
19336                 colspan: '7'
19337             }
19338             ]
19339         }
19340         ]
19341     },
19342     
19343     footer : {
19344         tag: 'tfoot',
19345         cn: [
19346         {
19347             tag: 'tr',
19348             cn: [
19349             {
19350                 tag: 'th',
19351                 colspan: '7',
19352                 cls: 'today'
19353             }
19354                     
19355             ]
19356         }
19357         ]
19358     },
19359     
19360     dates:{
19361         en: {
19362             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19363             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19364             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19365             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19366             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19367             today: "Today"
19368         }
19369     },
19370     
19371     modes: [
19372     {
19373         clsName: 'days',
19374         navFnc: 'Month',
19375         navStep: 1
19376     },
19377     {
19378         clsName: 'months',
19379         navFnc: 'FullYear',
19380         navStep: 1
19381     },
19382     {
19383         clsName: 'years',
19384         navFnc: 'FullYear',
19385         navStep: 10
19386     }]
19387 });
19388
19389 Roo.apply(Roo.bootstrap.DateField,  {
19390   
19391     template : {
19392         tag: 'div',
19393         cls: 'datepicker dropdown-menu roo-dynamic',
19394         cn: [
19395         {
19396             tag: 'div',
19397             cls: 'datepicker-days',
19398             cn: [
19399             {
19400                 tag: 'table',
19401                 cls: 'table-condensed',
19402                 cn:[
19403                 Roo.bootstrap.DateField.head,
19404                 {
19405                     tag: 'tbody'
19406                 },
19407                 Roo.bootstrap.DateField.footer
19408                 ]
19409             }
19410             ]
19411         },
19412         {
19413             tag: 'div',
19414             cls: 'datepicker-months',
19415             cn: [
19416             {
19417                 tag: 'table',
19418                 cls: 'table-condensed',
19419                 cn:[
19420                 Roo.bootstrap.DateField.head,
19421                 Roo.bootstrap.DateField.content,
19422                 Roo.bootstrap.DateField.footer
19423                 ]
19424             }
19425             ]
19426         },
19427         {
19428             tag: 'div',
19429             cls: 'datepicker-years',
19430             cn: [
19431             {
19432                 tag: 'table',
19433                 cls: 'table-condensed',
19434                 cn:[
19435                 Roo.bootstrap.DateField.head,
19436                 Roo.bootstrap.DateField.content,
19437                 Roo.bootstrap.DateField.footer
19438                 ]
19439             }
19440             ]
19441         }
19442         ]
19443     }
19444 });
19445
19446  
19447
19448  /*
19449  * - LGPL
19450  *
19451  * TimeField
19452  * 
19453  */
19454
19455 /**
19456  * @class Roo.bootstrap.TimeField
19457  * @extends Roo.bootstrap.Input
19458  * Bootstrap DateField class
19459  * 
19460  * 
19461  * @constructor
19462  * Create a new TimeField
19463  * @param {Object} config The config object
19464  */
19465
19466 Roo.bootstrap.TimeField = function(config){
19467     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19468     this.addEvents({
19469             /**
19470              * @event show
19471              * Fires when this field show.
19472              * @param {Roo.bootstrap.DateField} thisthis
19473              * @param {Mixed} date The date value
19474              */
19475             show : true,
19476             /**
19477              * @event show
19478              * Fires when this field hide.
19479              * @param {Roo.bootstrap.DateField} this
19480              * @param {Mixed} date The date value
19481              */
19482             hide : true,
19483             /**
19484              * @event select
19485              * Fires when select a date.
19486              * @param {Roo.bootstrap.DateField} this
19487              * @param {Mixed} date The date value
19488              */
19489             select : true
19490         });
19491 };
19492
19493 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
19494     
19495     /**
19496      * @cfg {String} format
19497      * The default time format string which can be overriden for localization support.  The format must be
19498      * valid according to {@link Date#parseDate} (defaults to 'H:i').
19499      */
19500     format : "H:i",
19501        
19502     onRender: function(ct, position)
19503     {
19504         
19505         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19506                 
19507         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19508         
19509         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19510         
19511         this.pop = this.picker().select('>.datepicker-time',true).first();
19512         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19513         
19514         this.picker().on('mousedown', this.onMousedown, this);
19515         this.picker().on('click', this.onClick, this);
19516         
19517         this.picker().addClass('datepicker-dropdown');
19518     
19519         this.fillTime();
19520         this.update();
19521             
19522         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19523         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19524         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19525         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19526         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19527         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19528
19529     },
19530     
19531     fireKey: function(e){
19532         if (!this.picker().isVisible()){
19533             if (e.keyCode == 27) { // allow escape to hide and re-show picker
19534                 this.show();
19535             }
19536             return;
19537         }
19538
19539         e.preventDefault();
19540         
19541         switch(e.keyCode){
19542             case 27: // escape
19543                 this.hide();
19544                 break;
19545             case 37: // left
19546             case 39: // right
19547                 this.onTogglePeriod();
19548                 break;
19549             case 38: // up
19550                 this.onIncrementMinutes();
19551                 break;
19552             case 40: // down
19553                 this.onDecrementMinutes();
19554                 break;
19555             case 13: // enter
19556             case 9: // tab
19557                 this.setTime();
19558                 break;
19559         }
19560     },
19561     
19562     onClick: function(e) {
19563         e.stopPropagation();
19564         e.preventDefault();
19565     },
19566     
19567     picker : function()
19568     {
19569         return this.el.select('.datepicker', true).first();
19570     },
19571     
19572     fillTime: function()
19573     {    
19574         var time = this.pop.select('tbody', true).first();
19575         
19576         time.dom.innerHTML = '';
19577         
19578         time.createChild({
19579             tag: 'tr',
19580             cn: [
19581                 {
19582                     tag: 'td',
19583                     cn: [
19584                         {
19585                             tag: 'a',
19586                             href: '#',
19587                             cls: 'btn',
19588                             cn: [
19589                                 {
19590                                     tag: 'span',
19591                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
19592                                 }
19593                             ]
19594                         } 
19595                     ]
19596                 },
19597                 {
19598                     tag: 'td',
19599                     cls: 'separator'
19600                 },
19601                 {
19602                     tag: 'td',
19603                     cn: [
19604                         {
19605                             tag: 'a',
19606                             href: '#',
19607                             cls: 'btn',
19608                             cn: [
19609                                 {
19610                                     tag: 'span',
19611                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
19612                                 }
19613                             ]
19614                         }
19615                     ]
19616                 },
19617                 {
19618                     tag: 'td',
19619                     cls: 'separator'
19620                 }
19621             ]
19622         });
19623         
19624         time.createChild({
19625             tag: 'tr',
19626             cn: [
19627                 {
19628                     tag: 'td',
19629                     cn: [
19630                         {
19631                             tag: 'span',
19632                             cls: 'timepicker-hour',
19633                             html: '00'
19634                         }  
19635                     ]
19636                 },
19637                 {
19638                     tag: 'td',
19639                     cls: 'separator',
19640                     html: ':'
19641                 },
19642                 {
19643                     tag: 'td',
19644                     cn: [
19645                         {
19646                             tag: 'span',
19647                             cls: 'timepicker-minute',
19648                             html: '00'
19649                         }  
19650                     ]
19651                 },
19652                 {
19653                     tag: 'td',
19654                     cls: 'separator'
19655                 },
19656                 {
19657                     tag: 'td',
19658                     cn: [
19659                         {
19660                             tag: 'button',
19661                             type: 'button',
19662                             cls: 'btn btn-primary period',
19663                             html: 'AM'
19664                             
19665                         }
19666                     ]
19667                 }
19668             ]
19669         });
19670         
19671         time.createChild({
19672             tag: 'tr',
19673             cn: [
19674                 {
19675                     tag: 'td',
19676                     cn: [
19677                         {
19678                             tag: 'a',
19679                             href: '#',
19680                             cls: 'btn',
19681                             cn: [
19682                                 {
19683                                     tag: 'span',
19684                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
19685                                 }
19686                             ]
19687                         }
19688                     ]
19689                 },
19690                 {
19691                     tag: 'td',
19692                     cls: 'separator'
19693                 },
19694                 {
19695                     tag: 'td',
19696                     cn: [
19697                         {
19698                             tag: 'a',
19699                             href: '#',
19700                             cls: 'btn',
19701                             cn: [
19702                                 {
19703                                     tag: 'span',
19704                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
19705                                 }
19706                             ]
19707                         }
19708                     ]
19709                 },
19710                 {
19711                     tag: 'td',
19712                     cls: 'separator'
19713                 }
19714             ]
19715         });
19716         
19717     },
19718     
19719     update: function()
19720     {
19721         
19722         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19723         
19724         this.fill();
19725     },
19726     
19727     fill: function() 
19728     {
19729         var hours = this.time.getHours();
19730         var minutes = this.time.getMinutes();
19731         var period = 'AM';
19732         
19733         if(hours > 11){
19734             period = 'PM';
19735         }
19736         
19737         if(hours == 0){
19738             hours = 12;
19739         }
19740         
19741         
19742         if(hours > 12){
19743             hours = hours - 12;
19744         }
19745         
19746         if(hours < 10){
19747             hours = '0' + hours;
19748         }
19749         
19750         if(minutes < 10){
19751             minutes = '0' + minutes;
19752         }
19753         
19754         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19755         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19756         this.pop.select('button', true).first().dom.innerHTML = period;
19757         
19758     },
19759     
19760     place: function()
19761     {   
19762         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19763         
19764         var cls = ['bottom'];
19765         
19766         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19767             cls.pop();
19768             cls.push('top');
19769         }
19770         
19771         cls.push('right');
19772         
19773         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19774             cls.pop();
19775             cls.push('left');
19776         }
19777         
19778         this.picker().addClass(cls.join('-'));
19779         
19780         var _this = this;
19781         
19782         Roo.each(cls, function(c){
19783             if(c == 'bottom'){
19784                 _this.picker().setTop(_this.inputEl().getHeight());
19785                 return;
19786             }
19787             if(c == 'top'){
19788                 _this.picker().setTop(0 - _this.picker().getHeight());
19789                 return;
19790             }
19791             
19792             if(c == 'left'){
19793                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19794                 return;
19795             }
19796             if(c == 'right'){
19797                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19798                 return;
19799             }
19800         });
19801         
19802     },
19803   
19804     onFocus : function()
19805     {
19806         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19807         this.show();
19808     },
19809     
19810     onBlur : function()
19811     {
19812         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19813         this.hide();
19814     },
19815     
19816     show : function()
19817     {
19818         this.picker().show();
19819         this.pop.show();
19820         this.update();
19821         this.place();
19822         
19823         this.fireEvent('show', this, this.date);
19824     },
19825     
19826     hide : function()
19827     {
19828         this.picker().hide();
19829         this.pop.hide();
19830         
19831         this.fireEvent('hide', this, this.date);
19832     },
19833     
19834     setTime : function()
19835     {
19836         this.hide();
19837         this.setValue(this.time.format(this.format));
19838         
19839         this.fireEvent('select', this, this.date);
19840         
19841         
19842     },
19843     
19844     onMousedown: function(e){
19845         e.stopPropagation();
19846         e.preventDefault();
19847     },
19848     
19849     onIncrementHours: function()
19850     {
19851         Roo.log('onIncrementHours');
19852         this.time = this.time.add(Date.HOUR, 1);
19853         this.update();
19854         
19855     },
19856     
19857     onDecrementHours: function()
19858     {
19859         Roo.log('onDecrementHours');
19860         this.time = this.time.add(Date.HOUR, -1);
19861         this.update();
19862     },
19863     
19864     onIncrementMinutes: function()
19865     {
19866         Roo.log('onIncrementMinutes');
19867         this.time = this.time.add(Date.MINUTE, 1);
19868         this.update();
19869     },
19870     
19871     onDecrementMinutes: function()
19872     {
19873         Roo.log('onDecrementMinutes');
19874         this.time = this.time.add(Date.MINUTE, -1);
19875         this.update();
19876     },
19877     
19878     onTogglePeriod: function()
19879     {
19880         Roo.log('onTogglePeriod');
19881         this.time = this.time.add(Date.HOUR, 12);
19882         this.update();
19883     }
19884     
19885    
19886 });
19887
19888 Roo.apply(Roo.bootstrap.TimeField,  {
19889     
19890     content : {
19891         tag: 'tbody',
19892         cn: [
19893             {
19894                 tag: 'tr',
19895                 cn: [
19896                 {
19897                     tag: 'td',
19898                     colspan: '7'
19899                 }
19900                 ]
19901             }
19902         ]
19903     },
19904     
19905     footer : {
19906         tag: 'tfoot',
19907         cn: [
19908             {
19909                 tag: 'tr',
19910                 cn: [
19911                 {
19912                     tag: 'th',
19913                     colspan: '7',
19914                     cls: '',
19915                     cn: [
19916                         {
19917                             tag: 'button',
19918                             cls: 'btn btn-info ok',
19919                             html: 'OK'
19920                         }
19921                     ]
19922                 }
19923
19924                 ]
19925             }
19926         ]
19927     }
19928 });
19929
19930 Roo.apply(Roo.bootstrap.TimeField,  {
19931   
19932     template : {
19933         tag: 'div',
19934         cls: 'datepicker dropdown-menu',
19935         cn: [
19936             {
19937                 tag: 'div',
19938                 cls: 'datepicker-time',
19939                 cn: [
19940                 {
19941                     tag: 'table',
19942                     cls: 'table-condensed',
19943                     cn:[
19944                     Roo.bootstrap.TimeField.content,
19945                     Roo.bootstrap.TimeField.footer
19946                     ]
19947                 }
19948                 ]
19949             }
19950         ]
19951     }
19952 });
19953
19954  
19955
19956  /*
19957  * - LGPL
19958  *
19959  * MonthField
19960  * 
19961  */
19962
19963 /**
19964  * @class Roo.bootstrap.MonthField
19965  * @extends Roo.bootstrap.Input
19966  * Bootstrap MonthField class
19967  * 
19968  * @cfg {String} language default en
19969  * 
19970  * @constructor
19971  * Create a new MonthField
19972  * @param {Object} config The config object
19973  */
19974
19975 Roo.bootstrap.MonthField = function(config){
19976     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19977     
19978     this.addEvents({
19979         /**
19980          * @event show
19981          * Fires when this field show.
19982          * @param {Roo.bootstrap.MonthField} this
19983          * @param {Mixed} date The date value
19984          */
19985         show : true,
19986         /**
19987          * @event show
19988          * Fires when this field hide.
19989          * @param {Roo.bootstrap.MonthField} this
19990          * @param {Mixed} date The date value
19991          */
19992         hide : true,
19993         /**
19994          * @event select
19995          * Fires when select a date.
19996          * @param {Roo.bootstrap.MonthField} this
19997          * @param {String} oldvalue The old value
19998          * @param {String} newvalue The new value
19999          */
20000         select : true
20001     });
20002 };
20003
20004 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
20005     
20006     onRender: function(ct, position)
20007     {
20008         
20009         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20010         
20011         this.language = this.language || 'en';
20012         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20013         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20014         
20015         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20016         this.isInline = false;
20017         this.isInput = true;
20018         this.component = this.el.select('.add-on', true).first() || false;
20019         this.component = (this.component && this.component.length === 0) ? false : this.component;
20020         this.hasInput = this.component && this.inputEL().length;
20021         
20022         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20023         
20024         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20025         
20026         this.picker().on('mousedown', this.onMousedown, this);
20027         this.picker().on('click', this.onClick, this);
20028         
20029         this.picker().addClass('datepicker-dropdown');
20030         
20031         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20032             v.setStyle('width', '189px');
20033         });
20034         
20035         this.fillMonths();
20036         
20037         this.update();
20038         
20039         if(this.isInline) {
20040             this.show();
20041         }
20042         
20043     },
20044     
20045     setValue: function(v, suppressEvent)
20046     {   
20047         var o = this.getValue();
20048         
20049         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20050         
20051         this.update();
20052
20053         if(suppressEvent !== true){
20054             this.fireEvent('select', this, o, v);
20055         }
20056         
20057     },
20058     
20059     getValue: function()
20060     {
20061         return this.value;
20062     },
20063     
20064     onClick: function(e) 
20065     {
20066         e.stopPropagation();
20067         e.preventDefault();
20068         
20069         var target = e.getTarget();
20070         
20071         if(target.nodeName.toLowerCase() === 'i'){
20072             target = Roo.get(target).dom.parentNode;
20073         }
20074         
20075         var nodeName = target.nodeName;
20076         var className = target.className;
20077         var html = target.innerHTML;
20078         
20079         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20080             return;
20081         }
20082         
20083         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20084         
20085         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20086         
20087         this.hide();
20088                         
20089     },
20090     
20091     picker : function()
20092     {
20093         return this.pickerEl;
20094     },
20095     
20096     fillMonths: function()
20097     {    
20098         var i = 0;
20099         var months = this.picker().select('>.datepicker-months td', true).first();
20100         
20101         months.dom.innerHTML = '';
20102         
20103         while (i < 12) {
20104             var month = {
20105                 tag: 'span',
20106                 cls: 'month',
20107                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20108             };
20109             
20110             months.createChild(month);
20111         }
20112         
20113     },
20114     
20115     update: function()
20116     {
20117         var _this = this;
20118         
20119         if(typeof(this.vIndex) == 'undefined' && this.value.length){
20120             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20121         }
20122         
20123         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20124             e.removeClass('active');
20125             
20126             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20127                 e.addClass('active');
20128             }
20129         })
20130     },
20131     
20132     place: function()
20133     {
20134         if(this.isInline) {
20135             return;
20136         }
20137         
20138         this.picker().removeClass(['bottom', 'top']);
20139         
20140         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20141             /*
20142              * place to the top of element!
20143              *
20144              */
20145             
20146             this.picker().addClass('top');
20147             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20148             
20149             return;
20150         }
20151         
20152         this.picker().addClass('bottom');
20153         
20154         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20155     },
20156     
20157     onFocus : function()
20158     {
20159         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20160         this.show();
20161     },
20162     
20163     onBlur : function()
20164     {
20165         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20166         
20167         var d = this.inputEl().getValue();
20168         
20169         this.setValue(d);
20170                 
20171         this.hide();
20172     },
20173     
20174     show : function()
20175     {
20176         this.picker().show();
20177         this.picker().select('>.datepicker-months', true).first().show();
20178         this.update();
20179         this.place();
20180         
20181         this.fireEvent('show', this, this.date);
20182     },
20183     
20184     hide : function()
20185     {
20186         if(this.isInline) {
20187             return;
20188         }
20189         this.picker().hide();
20190         this.fireEvent('hide', this, this.date);
20191         
20192     },
20193     
20194     onMousedown: function(e)
20195     {
20196         e.stopPropagation();
20197         e.preventDefault();
20198     },
20199     
20200     keyup: function(e)
20201     {
20202         Roo.bootstrap.MonthField.superclass.keyup.call(this);
20203         this.update();
20204     },
20205
20206     fireKey: function(e)
20207     {
20208         if (!this.picker().isVisible()){
20209             if (e.keyCode == 27)   {// allow escape to hide and re-show picker
20210                 this.show();
20211             }
20212             return;
20213         }
20214         
20215         var dir;
20216         
20217         switch(e.keyCode){
20218             case 27: // escape
20219                 this.hide();
20220                 e.preventDefault();
20221                 break;
20222             case 37: // left
20223             case 39: // right
20224                 dir = e.keyCode == 37 ? -1 : 1;
20225                 
20226                 this.vIndex = this.vIndex + dir;
20227                 
20228                 if(this.vIndex < 0){
20229                     this.vIndex = 0;
20230                 }
20231                 
20232                 if(this.vIndex > 11){
20233                     this.vIndex = 11;
20234                 }
20235                 
20236                 if(isNaN(this.vIndex)){
20237                     this.vIndex = 0;
20238                 }
20239                 
20240                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20241                 
20242                 break;
20243             case 38: // up
20244             case 40: // down
20245                 
20246                 dir = e.keyCode == 38 ? -1 : 1;
20247                 
20248                 this.vIndex = this.vIndex + dir * 4;
20249                 
20250                 if(this.vIndex < 0){
20251                     this.vIndex = 0;
20252                 }
20253                 
20254                 if(this.vIndex > 11){
20255                     this.vIndex = 11;
20256                 }
20257                 
20258                 if(isNaN(this.vIndex)){
20259                     this.vIndex = 0;
20260                 }
20261                 
20262                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20263                 break;
20264                 
20265             case 13: // enter
20266                 
20267                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20268                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20269                 }
20270                 
20271                 this.hide();
20272                 e.preventDefault();
20273                 break;
20274             case 9: // tab
20275                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20276                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20277                 }
20278                 this.hide();
20279                 break;
20280             case 16: // shift
20281             case 17: // ctrl
20282             case 18: // alt
20283                 break;
20284             default :
20285                 this.hide();
20286                 
20287         }
20288     },
20289     
20290     remove: function() 
20291     {
20292         this.picker().remove();
20293     }
20294    
20295 });
20296
20297 Roo.apply(Roo.bootstrap.MonthField,  {
20298     
20299     content : {
20300         tag: 'tbody',
20301         cn: [
20302         {
20303             tag: 'tr',
20304             cn: [
20305             {
20306                 tag: 'td',
20307                 colspan: '7'
20308             }
20309             ]
20310         }
20311         ]
20312     },
20313     
20314     dates:{
20315         en: {
20316             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20317             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20318         }
20319     }
20320 });
20321
20322 Roo.apply(Roo.bootstrap.MonthField,  {
20323   
20324     template : {
20325         tag: 'div',
20326         cls: 'datepicker dropdown-menu roo-dynamic',
20327         cn: [
20328             {
20329                 tag: 'div',
20330                 cls: 'datepicker-months',
20331                 cn: [
20332                 {
20333                     tag: 'table',
20334                     cls: 'table-condensed',
20335                     cn:[
20336                         Roo.bootstrap.DateField.content
20337                     ]
20338                 }
20339                 ]
20340             }
20341         ]
20342     }
20343 });
20344
20345  
20346
20347  
20348  /*
20349  * - LGPL
20350  *
20351  * CheckBox
20352  * 
20353  */
20354
20355 /**
20356  * @class Roo.bootstrap.CheckBox
20357  * @extends Roo.bootstrap.Input
20358  * Bootstrap CheckBox class
20359  * 
20360  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20361  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20362  * @cfg {String} boxLabel The text that appears beside the checkbox
20363  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20364  * @cfg {Boolean} checked initnal the element
20365  * @cfg {Boolean} inline inline the element (default false)
20366  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20367  * @cfg {String} tooltip label tooltip
20368  * 
20369  * @constructor
20370  * Create a new CheckBox
20371  * @param {Object} config The config object
20372  */
20373
20374 Roo.bootstrap.CheckBox = function(config){
20375     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20376    
20377     this.addEvents({
20378         /**
20379         * @event check
20380         * Fires when the element is checked or unchecked.
20381         * @param {Roo.bootstrap.CheckBox} this This input
20382         * @param {Boolean} checked The new checked value
20383         */
20384        check : true,
20385        /**
20386         * @event click
20387         * Fires when the element is click.
20388         * @param {Roo.bootstrap.CheckBox} this This input
20389         */
20390        click : true
20391     });
20392     
20393 };
20394
20395 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
20396   
20397     inputType: 'checkbox',
20398     inputValue: 1,
20399     valueOff: 0,
20400     boxLabel: false,
20401     checked: false,
20402     weight : false,
20403     inline: false,
20404     tooltip : '',
20405     
20406     getAutoCreate : function()
20407     {
20408         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20409         
20410         var id = Roo.id();
20411         
20412         var cfg = {};
20413         
20414         cfg.cls = 'form-group ' + this.inputType; //input-group
20415         
20416         if(this.inline){
20417             cfg.cls += ' ' + this.inputType + '-inline';
20418         }
20419         
20420         var input =  {
20421             tag: 'input',
20422             id : id,
20423             type : this.inputType,
20424             value : this.inputValue,
20425             cls : 'roo-' + this.inputType, //'form-box',
20426             placeholder : this.placeholder || ''
20427             
20428         };
20429         
20430         if(this.inputType != 'radio'){
20431             var hidden =  {
20432                 tag: 'input',
20433                 type : 'hidden',
20434                 cls : 'roo-hidden-value',
20435                 value : this.checked ? this.inputValue : this.valueOff
20436             };
20437         }
20438         
20439             
20440         if (this.weight) { // Validity check?
20441             cfg.cls += " " + this.inputType + "-" + this.weight;
20442         }
20443         
20444         if (this.disabled) {
20445             input.disabled=true;
20446         }
20447         
20448         if(this.checked){
20449             input.checked = this.checked;
20450         }
20451         
20452         if (this.name) {
20453             
20454             input.name = this.name;
20455             
20456             if(this.inputType != 'radio'){
20457                 hidden.name = this.name;
20458                 input.name = '_hidden_' + this.name;
20459             }
20460         }
20461         
20462         if (this.size) {
20463             input.cls += ' input-' + this.size;
20464         }
20465         
20466         var settings=this;
20467         
20468         ['xs','sm','md','lg'].map(function(size){
20469             if (settings[size]) {
20470                 cfg.cls += ' col-' + size + '-' + settings[size];
20471             }
20472         });
20473         
20474         var inputblock = input;
20475          
20476         if (this.before || this.after) {
20477             
20478             inputblock = {
20479                 cls : 'input-group',
20480                 cn :  [] 
20481             };
20482             
20483             if (this.before) {
20484                 inputblock.cn.push({
20485                     tag :'span',
20486                     cls : 'input-group-addon',
20487                     html : this.before
20488                 });
20489             }
20490             
20491             inputblock.cn.push(input);
20492             
20493             if(this.inputType != 'radio'){
20494                 inputblock.cn.push(hidden);
20495             }
20496             
20497             if (this.after) {
20498                 inputblock.cn.push({
20499                     tag :'span',
20500                     cls : 'input-group-addon',
20501                     html : this.after
20502                 });
20503             }
20504             
20505         }
20506         
20507         if (align ==='left' && this.fieldLabel.length) {
20508 //                Roo.log("left and has label");
20509             cfg.cn = [
20510                 {
20511                     tag: 'label',
20512                     'for' :  id,
20513                     cls : 'control-label',
20514                     html : this.fieldLabel
20515                 },
20516                 {
20517                     cls : "", 
20518                     cn: [
20519                         inputblock
20520                     ]
20521                 }
20522             ];
20523             
20524             if(this.labelWidth > 12){
20525                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20526             }
20527             
20528             if(this.labelWidth < 13 && this.labelmd == 0){
20529                 this.labelmd = this.labelWidth;
20530             }
20531             
20532             if(this.labellg > 0){
20533                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20534                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20535             }
20536             
20537             if(this.labelmd > 0){
20538                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20539                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20540             }
20541             
20542             if(this.labelsm > 0){
20543                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20544                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20545             }
20546             
20547             if(this.labelxs > 0){
20548                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20549                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20550             }
20551             
20552         } else if ( this.fieldLabel.length) {
20553 //                Roo.log(" label");
20554                 cfg.cn = [
20555                    
20556                     {
20557                         tag: this.boxLabel ? 'span' : 'label',
20558                         'for': id,
20559                         cls: 'control-label box-input-label',
20560                         //cls : 'input-group-addon',
20561                         html : this.fieldLabel
20562                     },
20563                     
20564                     inputblock
20565                     
20566                 ];
20567
20568         } else {
20569             
20570 //                Roo.log(" no label && no align");
20571                 cfg.cn = [  inputblock ] ;
20572                 
20573                 
20574         }
20575         
20576         if(this.boxLabel){
20577              var boxLabelCfg = {
20578                 tag: 'label',
20579                 //'for': id, // box label is handled by onclick - so no for...
20580                 cls: 'box-label',
20581                 html: this.boxLabel
20582             };
20583             
20584             if(this.tooltip){
20585                 boxLabelCfg.tooltip = this.tooltip;
20586             }
20587              
20588             cfg.cn.push(boxLabelCfg);
20589         }
20590         
20591         if(this.inputType != 'radio'){
20592             cfg.cn.push(hidden);
20593         }
20594         
20595         return cfg;
20596         
20597     },
20598     
20599     /**
20600      * return the real input element.
20601      */
20602     inputEl: function ()
20603     {
20604         return this.el.select('input.roo-' + this.inputType,true).first();
20605     },
20606     hiddenEl: function ()
20607     {
20608         return this.el.select('input.roo-hidden-value',true).first();
20609     },
20610     
20611     labelEl: function()
20612     {
20613         return this.el.select('label.control-label',true).first();
20614     },
20615     /* depricated... */
20616     
20617     label: function()
20618     {
20619         return this.labelEl();
20620     },
20621     
20622     boxLabelEl: function()
20623     {
20624         return this.el.select('label.box-label',true).first();
20625     },
20626     
20627     initEvents : function()
20628     {
20629 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20630         
20631         this.inputEl().on('click', this.onClick,  this);
20632         
20633         if (this.boxLabel) { 
20634             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
20635         }
20636         
20637         this.startValue = this.getValue();
20638         
20639         if(this.groupId){
20640             Roo.bootstrap.CheckBox.register(this);
20641         }
20642     },
20643     
20644     onClick : function(e)
20645     {   
20646         if(this.fireEvent('click', this, e) !== false){
20647             this.setChecked(!this.checked);
20648         }
20649         
20650     },
20651     
20652     setChecked : function(state,suppressEvent)
20653     {
20654         this.startValue = this.getValue();
20655
20656         if(this.inputType == 'radio'){
20657             
20658             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20659                 e.dom.checked = false;
20660             });
20661             
20662             this.inputEl().dom.checked = true;
20663             
20664             this.inputEl().dom.value = this.inputValue;
20665             
20666             if(suppressEvent !== true){
20667                 this.fireEvent('check', this, true);
20668             }
20669             
20670             this.validate();
20671             
20672             return;
20673         }
20674         
20675         this.checked = state;
20676         
20677         this.inputEl().dom.checked = state;
20678         
20679         
20680         this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20681         
20682         if(suppressEvent !== true){
20683             this.fireEvent('check', this, state);
20684         }
20685         
20686         this.validate();
20687     },
20688     
20689     getValue : function()
20690     {
20691         if(this.inputType == 'radio'){
20692             return this.getGroupValue();
20693         }
20694         
20695         return this.hiddenEl().dom.value;
20696         
20697     },
20698     
20699     getGroupValue : function()
20700     {
20701         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20702             return '';
20703         }
20704         
20705         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20706     },
20707     
20708     setValue : function(v,suppressEvent)
20709     {
20710         if(this.inputType == 'radio'){
20711             this.setGroupValue(v, suppressEvent);
20712             return;
20713         }
20714         
20715         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20716         
20717         this.validate();
20718     },
20719     
20720     setGroupValue : function(v, suppressEvent)
20721     {
20722         this.startValue = this.getValue();
20723         
20724         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20725             e.dom.checked = false;
20726             
20727             if(e.dom.value == v){
20728                 e.dom.checked = true;
20729             }
20730         });
20731         
20732         if(suppressEvent !== true){
20733             this.fireEvent('check', this, true);
20734         }
20735
20736         this.validate();
20737         
20738         return;
20739     },
20740     
20741     validate : function()
20742     {
20743         if(this.getVisibilityEl().hasClass('hidden')){
20744             return true;
20745         }
20746         
20747         if(
20748                 this.disabled || 
20749                 (this.inputType == 'radio' && this.validateRadio()) ||
20750                 (this.inputType == 'checkbox' && this.validateCheckbox())
20751         ){
20752             this.markValid();
20753             return true;
20754         }
20755         
20756         this.markInvalid();
20757         return false;
20758     },
20759     
20760     validateRadio : function()
20761     {
20762         if(this.getVisibilityEl().hasClass('hidden')){
20763             return true;
20764         }
20765         
20766         if(this.allowBlank){
20767             return true;
20768         }
20769         
20770         var valid = false;
20771         
20772         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20773             if(!e.dom.checked){
20774                 return;
20775             }
20776             
20777             valid = true;
20778             
20779             return false;
20780         });
20781         
20782         return valid;
20783     },
20784     
20785     validateCheckbox : function()
20786     {
20787         if(!this.groupId){
20788             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20789             //return (this.getValue() == this.inputValue) ? true : false;
20790         }
20791         
20792         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20793         
20794         if(!group){
20795             return false;
20796         }
20797         
20798         var r = false;
20799         
20800         for(var i in group){
20801             if(group[i].el.isVisible(true)){
20802                 r = false;
20803                 break;
20804             }
20805             
20806             r = true;
20807         }
20808         
20809         for(var i in group){
20810             if(r){
20811                 break;
20812             }
20813             
20814             r = (group[i].getValue() == group[i].inputValue) ? true : false;
20815         }
20816         
20817         return r;
20818     },
20819     
20820     /**
20821      * Mark this field as valid
20822      */
20823     markValid : function()
20824     {
20825         var _this = this;
20826         
20827         this.fireEvent('valid', this);
20828         
20829         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20830         
20831         if(this.groupId){
20832             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20833         }
20834         
20835         if(label){
20836             label.markValid();
20837         }
20838
20839         if(this.inputType == 'radio'){
20840             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20841                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20842                 e.findParent('.form-group', false, true).addClass(_this.validClass);
20843             });
20844             
20845             return;
20846         }
20847
20848         if(!this.groupId){
20849             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20850             this.el.findParent('.form-group', false, true).addClass(this.validClass);
20851             return;
20852         }
20853         
20854         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20855         
20856         if(!group){
20857             return;
20858         }
20859         
20860         for(var i in group){
20861             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20862             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20863         }
20864     },
20865     
20866      /**
20867      * Mark this field as invalid
20868      * @param {String} msg The validation message
20869      */
20870     markInvalid : function(msg)
20871     {
20872         if(this.allowBlank){
20873             return;
20874         }
20875         
20876         var _this = this;
20877         
20878         this.fireEvent('invalid', this, msg);
20879         
20880         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20881         
20882         if(this.groupId){
20883             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20884         }
20885         
20886         if(label){
20887             label.markInvalid();
20888         }
20889             
20890         if(this.inputType == 'radio'){
20891             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20892                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20893                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20894             });
20895             
20896             return;
20897         }
20898         
20899         if(!this.groupId){
20900             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20901             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20902             return;
20903         }
20904         
20905         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20906         
20907         if(!group){
20908             return;
20909         }
20910         
20911         for(var i in group){
20912             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20913             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20914         }
20915         
20916     },
20917     
20918     clearInvalid : function()
20919     {
20920         Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20921         
20922         // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20923         
20924         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20925         
20926         if (label && label.iconEl) {
20927             label.iconEl.removeClass(label.validClass);
20928             label.iconEl.removeClass(label.invalidClass);
20929         }
20930     },
20931     
20932     disable : function()
20933     {
20934         if(this.inputType != 'radio'){
20935             Roo.bootstrap.CheckBox.superclass.disable.call(this);
20936             return;
20937         }
20938         
20939         var _this = this;
20940         
20941         if(this.rendered){
20942             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20943                 _this.getActionEl().addClass(this.disabledClass);
20944                 e.dom.disabled = true;
20945             });
20946         }
20947         
20948         this.disabled = true;
20949         this.fireEvent("disable", this);
20950         return this;
20951     },
20952
20953     enable : function()
20954     {
20955         if(this.inputType != 'radio'){
20956             Roo.bootstrap.CheckBox.superclass.enable.call(this);
20957             return;
20958         }
20959         
20960         var _this = this;
20961         
20962         if(this.rendered){
20963             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20964                 _this.getActionEl().removeClass(this.disabledClass);
20965                 e.dom.disabled = false;
20966             });
20967         }
20968         
20969         this.disabled = false;
20970         this.fireEvent("enable", this);
20971         return this;
20972     },
20973     
20974     setBoxLabel : function(v)
20975     {
20976         this.boxLabel = v;
20977         
20978         if(this.rendered){
20979             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20980         }
20981     }
20982
20983 });
20984
20985 Roo.apply(Roo.bootstrap.CheckBox, {
20986     
20987     groups: {},
20988     
20989      /**
20990     * register a CheckBox Group
20991     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20992     */
20993     register : function(checkbox)
20994     {
20995         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20996             this.groups[checkbox.groupId] = {};
20997         }
20998         
20999         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21000             return;
21001         }
21002         
21003         this.groups[checkbox.groupId][checkbox.name] = checkbox;
21004         
21005     },
21006     /**
21007     * fetch a CheckBox Group based on the group ID
21008     * @param {string} the group ID
21009     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21010     */
21011     get: function(groupId) {
21012         if (typeof(this.groups[groupId]) == 'undefined') {
21013             return false;
21014         }
21015         
21016         return this.groups[groupId] ;
21017     }
21018     
21019     
21020 });
21021 /*
21022  * - LGPL
21023  *
21024  * RadioItem
21025  * 
21026  */
21027
21028 /**
21029  * @class Roo.bootstrap.Radio
21030  * @extends Roo.bootstrap.Component
21031  * Bootstrap Radio class
21032  * @cfg {String} boxLabel - the label associated
21033  * @cfg {String} value - the value of radio
21034  * 
21035  * @constructor
21036  * Create a new Radio
21037  * @param {Object} config The config object
21038  */
21039 Roo.bootstrap.Radio = function(config){
21040     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21041     
21042 };
21043
21044 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21045     
21046     boxLabel : '',
21047     
21048     value : '',
21049     
21050     getAutoCreate : function()
21051     {
21052         var cfg = {
21053             tag : 'div',
21054             cls : 'form-group radio',
21055             cn : [
21056                 {
21057                     tag : 'label',
21058                     cls : 'box-label',
21059                     html : this.boxLabel
21060                 }
21061             ]
21062         };
21063         
21064         return cfg;
21065     },
21066     
21067     initEvents : function() 
21068     {
21069         this.parent().register(this);
21070         
21071         this.el.on('click', this.onClick, this);
21072         
21073     },
21074     
21075     onClick : function(e)
21076     {
21077         if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21078             this.setChecked(true);
21079         }
21080     },
21081     
21082     setChecked : function(state, suppressEvent)
21083     {
21084         this.parent().setValue(this.value, suppressEvent);
21085         
21086     },
21087     
21088     setBoxLabel : function(v)
21089     {
21090         this.boxLabel = v;
21091         
21092         if(this.rendered){
21093             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21094         }
21095     }
21096     
21097 });
21098  
21099
21100  /*
21101  * - LGPL
21102  *
21103  * Input
21104  * 
21105  */
21106
21107 /**
21108  * @class Roo.bootstrap.SecurePass
21109  * @extends Roo.bootstrap.Input
21110  * Bootstrap SecurePass class
21111  *
21112  * 
21113  * @constructor
21114  * Create a new SecurePass
21115  * @param {Object} config The config object
21116  */
21117  
21118 Roo.bootstrap.SecurePass = function (config) {
21119     // these go here, so the translation tool can replace them..
21120     this.errors = {
21121         PwdEmpty: "Please type a password, and then retype it to confirm.",
21122         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21123         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21124         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21125         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21126         FNInPwd: "Your password can't contain your first name. Please type a different password.",
21127         LNInPwd: "Your password can't contain your last name. Please type a different password.",
21128         TooWeak: "Your password is Too Weak."
21129     },
21130     this.meterLabel = "Password strength:";
21131     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21132     this.meterClass = [
21133         "roo-password-meter-tooweak", 
21134         "roo-password-meter-weak", 
21135         "roo-password-meter-medium", 
21136         "roo-password-meter-strong", 
21137         "roo-password-meter-grey"
21138     ];
21139     
21140     this.errors = {};
21141     
21142     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21143 }
21144
21145 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21146     /**
21147      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21148      * {
21149      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
21150      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21151      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21152      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21153      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21154      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
21155      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
21156      * })
21157      */
21158     // private
21159     
21160     meterWidth: 300,
21161     errorMsg :'',    
21162     errors: false,
21163     imageRoot: '/',
21164     /**
21165      * @cfg {String/Object} Label for the strength meter (defaults to
21166      * 'Password strength:')
21167      */
21168     // private
21169     meterLabel: '',
21170     /**
21171      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21172      * ['Weak', 'Medium', 'Strong'])
21173      */
21174     // private    
21175     pwdStrengths: false,    
21176     // private
21177     strength: 0,
21178     // private
21179     _lastPwd: null,
21180     // private
21181     kCapitalLetter: 0,
21182     kSmallLetter: 1,
21183     kDigit: 2,
21184     kPunctuation: 3,
21185     
21186     insecure: false,
21187     // private
21188     initEvents: function ()
21189     {
21190         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21191
21192         if (this.el.is('input[type=password]') && Roo.isSafari) {
21193             this.el.on('keydown', this.SafariOnKeyDown, this);
21194         }
21195
21196         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21197     },
21198     // private
21199     onRender: function (ct, position)
21200     {
21201         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21202         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21203         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21204
21205         this.trigger.createChild({
21206                    cn: [
21207                     {
21208                     //id: 'PwdMeter',
21209                     tag: 'div',
21210                     cls: 'roo-password-meter-grey col-xs-12',
21211                     style: {
21212                         //width: 0,
21213                         //width: this.meterWidth + 'px'                                                
21214                         }
21215                     },
21216                     {                            
21217                          cls: 'roo-password-meter-text'                          
21218                     }
21219                 ]            
21220         });
21221
21222          
21223         if (this.hideTrigger) {
21224             this.trigger.setDisplayed(false);
21225         }
21226         this.setSize(this.width || '', this.height || '');
21227     },
21228     // private
21229     onDestroy: function ()
21230     {
21231         if (this.trigger) {
21232             this.trigger.removeAllListeners();
21233             this.trigger.remove();
21234         }
21235         if (this.wrap) {
21236             this.wrap.remove();
21237         }
21238         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21239     },
21240     // private
21241     checkStrength: function ()
21242     {
21243         var pwd = this.inputEl().getValue();
21244         if (pwd == this._lastPwd) {
21245             return;
21246         }
21247
21248         var strength;
21249         if (this.ClientSideStrongPassword(pwd)) {
21250             strength = 3;
21251         } else if (this.ClientSideMediumPassword(pwd)) {
21252             strength = 2;
21253         } else if (this.ClientSideWeakPassword(pwd)) {
21254             strength = 1;
21255         } else {
21256             strength = 0;
21257         }
21258         
21259         Roo.log('strength1: ' + strength);
21260         
21261         //var pm = this.trigger.child('div/div/div').dom;
21262         var pm = this.trigger.child('div/div');
21263         pm.removeClass(this.meterClass);
21264         pm.addClass(this.meterClass[strength]);
21265                 
21266         
21267         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21268                 
21269         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21270         
21271         this._lastPwd = pwd;
21272     },
21273     reset: function ()
21274     {
21275         Roo.bootstrap.SecurePass.superclass.reset.call(this);
21276         
21277         this._lastPwd = '';
21278         
21279         var pm = this.trigger.child('div/div');
21280         pm.removeClass(this.meterClass);
21281         pm.addClass('roo-password-meter-grey');        
21282         
21283         
21284         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21285         
21286         pt.innerHTML = '';
21287         this.inputEl().dom.type='password';
21288     },
21289     // private
21290     validateValue: function (value)
21291     {
21292         
21293         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21294             return false;
21295         }
21296         if (value.length == 0) {
21297             if (this.allowBlank) {
21298                 this.clearInvalid();
21299                 return true;
21300             }
21301
21302             this.markInvalid(this.errors.PwdEmpty);
21303             this.errorMsg = this.errors.PwdEmpty;
21304             return false;
21305         }
21306         
21307         if(this.insecure){
21308             return true;
21309         }
21310         
21311         if ('[\x21-\x7e]*'.match(value)) {
21312             this.markInvalid(this.errors.PwdBadChar);
21313             this.errorMsg = this.errors.PwdBadChar;
21314             return false;
21315         }
21316         if (value.length < 6) {
21317             this.markInvalid(this.errors.PwdShort);
21318             this.errorMsg = this.errors.PwdShort;
21319             return false;
21320         }
21321         if (value.length > 16) {
21322             this.markInvalid(this.errors.PwdLong);
21323             this.errorMsg = this.errors.PwdLong;
21324             return false;
21325         }
21326         var strength;
21327         if (this.ClientSideStrongPassword(value)) {
21328             strength = 3;
21329         } else if (this.ClientSideMediumPassword(value)) {
21330             strength = 2;
21331         } else if (this.ClientSideWeakPassword(value)) {
21332             strength = 1;
21333         } else {
21334             strength = 0;
21335         }
21336
21337         
21338         if (strength < 2) {
21339             //this.markInvalid(this.errors.TooWeak);
21340             this.errorMsg = this.errors.TooWeak;
21341             //return false;
21342         }
21343         
21344         
21345         console.log('strength2: ' + strength);
21346         
21347         //var pm = this.trigger.child('div/div/div').dom;
21348         
21349         var pm = this.trigger.child('div/div');
21350         pm.removeClass(this.meterClass);
21351         pm.addClass(this.meterClass[strength]);
21352                 
21353         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21354                 
21355         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21356         
21357         this.errorMsg = ''; 
21358         return true;
21359     },
21360     // private
21361     CharacterSetChecks: function (type)
21362     {
21363         this.type = type;
21364         this.fResult = false;
21365     },
21366     // private
21367     isctype: function (character, type)
21368     {
21369         switch (type) {  
21370             case this.kCapitalLetter:
21371                 if (character >= 'A' && character <= 'Z') {
21372                     return true;
21373                 }
21374                 break;
21375             
21376             case this.kSmallLetter:
21377                 if (character >= 'a' && character <= 'z') {
21378                     return true;
21379                 }
21380                 break;
21381             
21382             case this.kDigit:
21383                 if (character >= '0' && character <= '9') {
21384                     return true;
21385                 }
21386                 break;
21387             
21388             case this.kPunctuation:
21389                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21390                     return true;
21391                 }
21392                 break;
21393             
21394             default:
21395                 return false;
21396         }
21397
21398     },
21399     // private
21400     IsLongEnough: function (pwd, size)
21401     {
21402         return !(pwd == null || isNaN(size) || pwd.length < size);
21403     },
21404     // private
21405     SpansEnoughCharacterSets: function (word, nb)
21406     {
21407         if (!this.IsLongEnough(word, nb))
21408         {
21409             return false;
21410         }
21411
21412         var characterSetChecks = new Array(
21413             new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21414             new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21415         );
21416         
21417         for (var index = 0; index < word.length; ++index) {
21418             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21419                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21420                     characterSetChecks[nCharSet].fResult = true;
21421                     break;
21422                 }
21423             }
21424         }
21425
21426         var nCharSets = 0;
21427         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21428             if (characterSetChecks[nCharSet].fResult) {
21429                 ++nCharSets;
21430             }
21431         }
21432
21433         if (nCharSets < nb) {
21434             return false;
21435         }
21436         return true;
21437     },
21438     // private
21439     ClientSideStrongPassword: function (pwd)
21440     {
21441         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21442     },
21443     // private
21444     ClientSideMediumPassword: function (pwd)
21445     {
21446         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21447     },
21448     // private
21449     ClientSideWeakPassword: function (pwd)
21450     {
21451         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21452     }
21453           
21454 })//<script type="text/javascript">
21455
21456 /*
21457  * Based  Ext JS Library 1.1.1
21458  * Copyright(c) 2006-2007, Ext JS, LLC.
21459  * LGPL
21460  *
21461  */
21462  
21463 /**
21464  * @class Roo.HtmlEditorCore
21465  * @extends Roo.Component
21466  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21467  *
21468  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21469  */
21470
21471 Roo.HtmlEditorCore = function(config){
21472     
21473     
21474     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21475     
21476     
21477     this.addEvents({
21478         /**
21479          * @event initialize
21480          * Fires when the editor is fully initialized (including the iframe)
21481          * @param {Roo.HtmlEditorCore} this
21482          */
21483         initialize: true,
21484         /**
21485          * @event activate
21486          * Fires when the editor is first receives the focus. Any insertion must wait
21487          * until after this event.
21488          * @param {Roo.HtmlEditorCore} this
21489          */
21490         activate: true,
21491          /**
21492          * @event beforesync
21493          * Fires before the textarea is updated with content from the editor iframe. Return false
21494          * to cancel the sync.
21495          * @param {Roo.HtmlEditorCore} this
21496          * @param {String} html
21497          */
21498         beforesync: true,
21499          /**
21500          * @event beforepush
21501          * Fires before the iframe editor is updated with content from the textarea. Return false
21502          * to cancel the push.
21503          * @param {Roo.HtmlEditorCore} this
21504          * @param {String} html
21505          */
21506         beforepush: true,
21507          /**
21508          * @event sync
21509          * Fires when the textarea is updated with content from the editor iframe.
21510          * @param {Roo.HtmlEditorCore} this
21511          * @param {String} html
21512          */
21513         sync: true,
21514          /**
21515          * @event push
21516          * Fires when the iframe editor is updated with content from the textarea.
21517          * @param {Roo.HtmlEditorCore} this
21518          * @param {String} html
21519          */
21520         push: true,
21521         
21522         /**
21523          * @event editorevent
21524          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21525          * @param {Roo.HtmlEditorCore} this
21526          */
21527         editorevent: true
21528         
21529     });
21530     
21531     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21532     
21533     // defaults : white / black...
21534     this.applyBlacklists();
21535     
21536     
21537     
21538 };
21539
21540
21541 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
21542
21543
21544      /**
21545      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
21546      */
21547     
21548     owner : false,
21549     
21550      /**
21551      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
21552      *                        Roo.resizable.
21553      */
21554     resizable : false,
21555      /**
21556      * @cfg {Number} height (in pixels)
21557      */   
21558     height: 300,
21559    /**
21560      * @cfg {Number} width (in pixels)
21561      */   
21562     width: 500,
21563     
21564     /**
21565      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21566      * 
21567      */
21568     stylesheets: false,
21569     
21570     // id of frame..
21571     frameId: false,
21572     
21573     // private properties
21574     validationEvent : false,
21575     deferHeight: true,
21576     initialized : false,
21577     activated : false,
21578     sourceEditMode : false,
21579     onFocus : Roo.emptyFn,
21580     iframePad:3,
21581     hideMode:'offsets',
21582     
21583     clearUp: true,
21584     
21585     // blacklist + whitelisted elements..
21586     black: false,
21587     white: false,
21588      
21589     bodyCls : '',
21590
21591     /**
21592      * Protected method that will not generally be called directly. It
21593      * is called when the editor initializes the iframe with HTML contents. Override this method if you
21594      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21595      */
21596     getDocMarkup : function(){
21597         // body styles..
21598         var st = '';
21599         
21600         // inherit styels from page...?? 
21601         if (this.stylesheets === false) {
21602             
21603             Roo.get(document.head).select('style').each(function(node) {
21604                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21605             });
21606             
21607             Roo.get(document.head).select('link').each(function(node) { 
21608                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21609             });
21610             
21611         } else if (!this.stylesheets.length) {
21612                 // simple..
21613                 st = '<style type="text/css">' +
21614                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21615                    '</style>';
21616         } else { 
21617             st = '<style type="text/css">' +
21618                     this.stylesheets +
21619                 '</style>';
21620         }
21621         
21622         st +=  '<style type="text/css">' +
21623             'IMG { cursor: pointer } ' +
21624         '</style>';
21625
21626         var cls = 'roo-htmleditor-body';
21627         
21628         if(this.bodyCls.length){
21629             cls += ' ' + this.bodyCls;
21630         }
21631         
21632         return '<html><head>' + st  +
21633             //<style type="text/css">' +
21634             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21635             //'</style>' +
21636             ' </head><body class="' +  cls + '"></body></html>';
21637     },
21638
21639     // private
21640     onRender : function(ct, position)
21641     {
21642         var _t = this;
21643         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21644         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21645         
21646         
21647         this.el.dom.style.border = '0 none';
21648         this.el.dom.setAttribute('tabIndex', -1);
21649         this.el.addClass('x-hidden hide');
21650         
21651         
21652         
21653         if(Roo.isIE){ // fix IE 1px bogus margin
21654             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21655         }
21656        
21657         
21658         this.frameId = Roo.id();
21659         
21660          
21661         
21662         var iframe = this.owner.wrap.createChild({
21663             tag: 'iframe',
21664             cls: 'form-control', // bootstrap..
21665             id: this.frameId,
21666             name: this.frameId,
21667             frameBorder : 'no',
21668             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
21669         }, this.el
21670         );
21671         
21672         
21673         this.iframe = iframe.dom;
21674
21675          this.assignDocWin();
21676         
21677         this.doc.designMode = 'on';
21678        
21679         this.doc.open();
21680         this.doc.write(this.getDocMarkup());
21681         this.doc.close();
21682
21683         
21684         var task = { // must defer to wait for browser to be ready
21685             run : function(){
21686                 //console.log("run task?" + this.doc.readyState);
21687                 this.assignDocWin();
21688                 if(this.doc.body || this.doc.readyState == 'complete'){
21689                     try {
21690                         this.doc.designMode="on";
21691                     } catch (e) {
21692                         return;
21693                     }
21694                     Roo.TaskMgr.stop(task);
21695                     this.initEditor.defer(10, this);
21696                 }
21697             },
21698             interval : 10,
21699             duration: 10000,
21700             scope: this
21701         };
21702         Roo.TaskMgr.start(task);
21703
21704     },
21705
21706     // private
21707     onResize : function(w, h)
21708     {
21709          Roo.log('resize: ' +w + ',' + h );
21710         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21711         if(!this.iframe){
21712             return;
21713         }
21714         if(typeof w == 'number'){
21715             
21716             this.iframe.style.width = w + 'px';
21717         }
21718         if(typeof h == 'number'){
21719             
21720             this.iframe.style.height = h + 'px';
21721             if(this.doc){
21722                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21723             }
21724         }
21725         
21726     },
21727
21728     /**
21729      * Toggles the editor between standard and source edit mode.
21730      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21731      */
21732     toggleSourceEdit : function(sourceEditMode){
21733         
21734         this.sourceEditMode = sourceEditMode === true;
21735         
21736         if(this.sourceEditMode){
21737  
21738             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
21739             
21740         }else{
21741             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21742             //this.iframe.className = '';
21743             this.deferFocus();
21744         }
21745         //this.setSize(this.owner.wrap.getSize());
21746         //this.fireEvent('editmodechange', this, this.sourceEditMode);
21747     },
21748
21749     
21750   
21751
21752     /**
21753      * Protected method that will not generally be called directly. If you need/want
21754      * custom HTML cleanup, this is the method you should override.
21755      * @param {String} html The HTML to be cleaned
21756      * return {String} The cleaned HTML
21757      */
21758     cleanHtml : function(html){
21759         html = String(html);
21760         if(html.length > 5){
21761             if(Roo.isSafari){ // strip safari nonsense
21762                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21763             }
21764         }
21765         if(html == '&nbsp;'){
21766             html = '';
21767         }
21768         return html;
21769     },
21770
21771     /**
21772      * HTML Editor -> Textarea
21773      * Protected method that will not generally be called directly. Syncs the contents
21774      * of the editor iframe with the textarea.
21775      */
21776     syncValue : function(){
21777         if(this.initialized){
21778             var bd = (this.doc.body || this.doc.documentElement);
21779             //this.cleanUpPaste(); -- this is done else where and causes havoc..
21780             var html = bd.innerHTML;
21781             if(Roo.isSafari){
21782                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21783                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21784                 if(m && m[1]){
21785                     html = '<div style="'+m[0]+'">' + html + '</div>';
21786                 }
21787             }
21788             html = this.cleanHtml(html);
21789             // fix up the special chars.. normaly like back quotes in word...
21790             // however we do not want to do this with chinese..
21791             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21792                 var cc = b.charCodeAt();
21793                 if (
21794                     (cc >= 0x4E00 && cc < 0xA000 ) ||
21795                     (cc >= 0x3400 && cc < 0x4E00 ) ||
21796                     (cc >= 0xf900 && cc < 0xfb00 )
21797                 ) {
21798                         return b;
21799                 }
21800                 return "&#"+cc+";" 
21801             });
21802             if(this.owner.fireEvent('beforesync', this, html) !== false){
21803                 this.el.dom.value = html;
21804                 this.owner.fireEvent('sync', this, html);
21805             }
21806         }
21807     },
21808
21809     /**
21810      * Protected method that will not generally be called directly. Pushes the value of the textarea
21811      * into the iframe editor.
21812      */
21813     pushValue : function(){
21814         if(this.initialized){
21815             var v = this.el.dom.value.trim();
21816             
21817 //            if(v.length < 1){
21818 //                v = '&#160;';
21819 //            }
21820             
21821             if(this.owner.fireEvent('beforepush', this, v) !== false){
21822                 var d = (this.doc.body || this.doc.documentElement);
21823                 d.innerHTML = v;
21824                 this.cleanUpPaste();
21825                 this.el.dom.value = d.innerHTML;
21826                 this.owner.fireEvent('push', this, v);
21827             }
21828         }
21829     },
21830
21831     // private
21832     deferFocus : function(){
21833         this.focus.defer(10, this);
21834     },
21835
21836     // doc'ed in Field
21837     focus : function(){
21838         if(this.win && !this.sourceEditMode){
21839             this.win.focus();
21840         }else{
21841             this.el.focus();
21842         }
21843     },
21844     
21845     assignDocWin: function()
21846     {
21847         var iframe = this.iframe;
21848         
21849          if(Roo.isIE){
21850             this.doc = iframe.contentWindow.document;
21851             this.win = iframe.contentWindow;
21852         } else {
21853 //            if (!Roo.get(this.frameId)) {
21854 //                return;
21855 //            }
21856 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21857 //            this.win = Roo.get(this.frameId).dom.contentWindow;
21858             
21859             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21860                 return;
21861             }
21862             
21863             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21864             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21865         }
21866     },
21867     
21868     // private
21869     initEditor : function(){
21870         //console.log("INIT EDITOR");
21871         this.assignDocWin();
21872         
21873         
21874         
21875         this.doc.designMode="on";
21876         this.doc.open();
21877         this.doc.write(this.getDocMarkup());
21878         this.doc.close();
21879         
21880         var dbody = (this.doc.body || this.doc.documentElement);
21881         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21882         // this copies styles from the containing element into thsi one..
21883         // not sure why we need all of this..
21884         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21885         
21886         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21887         //ss['background-attachment'] = 'fixed'; // w3c
21888         dbody.bgProperties = 'fixed'; // ie
21889         //Roo.DomHelper.applyStyles(dbody, ss);
21890         Roo.EventManager.on(this.doc, {
21891             //'mousedown': this.onEditorEvent,
21892             'mouseup': this.onEditorEvent,
21893             'dblclick': this.onEditorEvent,
21894             'click': this.onEditorEvent,
21895             'keyup': this.onEditorEvent,
21896             buffer:100,
21897             scope: this
21898         });
21899         if(Roo.isGecko){
21900             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21901         }
21902         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21903             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21904         }
21905         this.initialized = true;
21906
21907         this.owner.fireEvent('initialize', this);
21908         this.pushValue();
21909     },
21910
21911     // private
21912     onDestroy : function(){
21913         
21914         
21915         
21916         if(this.rendered){
21917             
21918             //for (var i =0; i < this.toolbars.length;i++) {
21919             //    // fixme - ask toolbars for heights?
21920             //    this.toolbars[i].onDestroy();
21921            // }
21922             
21923             //this.wrap.dom.innerHTML = '';
21924             //this.wrap.remove();
21925         }
21926     },
21927
21928     // private
21929     onFirstFocus : function(){
21930         
21931         this.assignDocWin();
21932         
21933         
21934         this.activated = true;
21935          
21936     
21937         if(Roo.isGecko){ // prevent silly gecko errors
21938             this.win.focus();
21939             var s = this.win.getSelection();
21940             if(!s.focusNode || s.focusNode.nodeType != 3){
21941                 var r = s.getRangeAt(0);
21942                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21943                 r.collapse(true);
21944                 this.deferFocus();
21945             }
21946             try{
21947                 this.execCmd('useCSS', true);
21948                 this.execCmd('styleWithCSS', false);
21949             }catch(e){}
21950         }
21951         this.owner.fireEvent('activate', this);
21952     },
21953
21954     // private
21955     adjustFont: function(btn){
21956         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21957         //if(Roo.isSafari){ // safari
21958         //    adjust *= 2;
21959        // }
21960         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21961         if(Roo.isSafari){ // safari
21962             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21963             v =  (v < 10) ? 10 : v;
21964             v =  (v > 48) ? 48 : v;
21965             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21966             
21967         }
21968         
21969         
21970         v = Math.max(1, v+adjust);
21971         
21972         this.execCmd('FontSize', v  );
21973     },
21974
21975     onEditorEvent : function(e)
21976     {
21977         this.owner.fireEvent('editorevent', this, e);
21978       //  this.updateToolbar();
21979         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21980     },
21981
21982     insertTag : function(tg)
21983     {
21984         // could be a bit smarter... -> wrap the current selected tRoo..
21985         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21986             
21987             range = this.createRange(this.getSelection());
21988             var wrappingNode = this.doc.createElement(tg.toLowerCase());
21989             wrappingNode.appendChild(range.extractContents());
21990             range.insertNode(wrappingNode);
21991
21992             return;
21993             
21994             
21995             
21996         }
21997         this.execCmd("formatblock",   tg);
21998         
21999     },
22000     
22001     insertText : function(txt)
22002     {
22003         
22004         
22005         var range = this.createRange();
22006         range.deleteContents();
22007                //alert(Sender.getAttribute('label'));
22008                
22009         range.insertNode(this.doc.createTextNode(txt));
22010     } ,
22011     
22012      
22013
22014     /**
22015      * Executes a Midas editor command on the editor document and performs necessary focus and
22016      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22017      * @param {String} cmd The Midas command
22018      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22019      */
22020     relayCmd : function(cmd, value){
22021         this.win.focus();
22022         this.execCmd(cmd, value);
22023         this.owner.fireEvent('editorevent', this);
22024         //this.updateToolbar();
22025         this.owner.deferFocus();
22026     },
22027
22028     /**
22029      * Executes a Midas editor command directly on the editor document.
22030      * For visual commands, you should use {@link #relayCmd} instead.
22031      * <b>This should only be called after the editor is initialized.</b>
22032      * @param {String} cmd The Midas command
22033      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22034      */
22035     execCmd : function(cmd, value){
22036         this.doc.execCommand(cmd, false, value === undefined ? null : value);
22037         this.syncValue();
22038     },
22039  
22040  
22041    
22042     /**
22043      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22044      * to insert tRoo.
22045      * @param {String} text | dom node.. 
22046      */
22047     insertAtCursor : function(text)
22048     {
22049         
22050         if(!this.activated){
22051             return;
22052         }
22053         /*
22054         if(Roo.isIE){
22055             this.win.focus();
22056             var r = this.doc.selection.createRange();
22057             if(r){
22058                 r.collapse(true);
22059                 r.pasteHTML(text);
22060                 this.syncValue();
22061                 this.deferFocus();
22062             
22063             }
22064             return;
22065         }
22066         */
22067         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22068             this.win.focus();
22069             
22070             
22071             // from jquery ui (MIT licenced)
22072             var range, node;
22073             var win = this.win;
22074             
22075             if (win.getSelection && win.getSelection().getRangeAt) {
22076                 range = win.getSelection().getRangeAt(0);
22077                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22078                 range.insertNode(node);
22079             } else if (win.document.selection && win.document.selection.createRange) {
22080                 // no firefox support
22081                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22082                 win.document.selection.createRange().pasteHTML(txt);
22083             } else {
22084                 // no firefox support
22085                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22086                 this.execCmd('InsertHTML', txt);
22087             } 
22088             
22089             this.syncValue();
22090             
22091             this.deferFocus();
22092         }
22093     },
22094  // private
22095     mozKeyPress : function(e){
22096         if(e.ctrlKey){
22097             var c = e.getCharCode(), cmd;
22098           
22099             if(c > 0){
22100                 c = String.fromCharCode(c).toLowerCase();
22101                 switch(c){
22102                     case 'b':
22103                         cmd = 'bold';
22104                         break;
22105                     case 'i':
22106                         cmd = 'italic';
22107                         break;
22108                     
22109                     case 'u':
22110                         cmd = 'underline';
22111                         break;
22112                     
22113                     case 'v':
22114                         this.cleanUpPaste.defer(100, this);
22115                         return;
22116                         
22117                 }
22118                 if(cmd){
22119                     this.win.focus();
22120                     this.execCmd(cmd);
22121                     this.deferFocus();
22122                     e.preventDefault();
22123                 }
22124                 
22125             }
22126         }
22127     },
22128
22129     // private
22130     fixKeys : function(){ // load time branching for fastest keydown performance
22131         if(Roo.isIE){
22132             return function(e){
22133                 var k = e.getKey(), r;
22134                 if(k == e.TAB){
22135                     e.stopEvent();
22136                     r = this.doc.selection.createRange();
22137                     if(r){
22138                         r.collapse(true);
22139                         r.pasteHTML('&#160;&#160;&#160;&#160;');
22140                         this.deferFocus();
22141                     }
22142                     return;
22143                 }
22144                 
22145                 if(k == e.ENTER){
22146                     r = this.doc.selection.createRange();
22147                     if(r){
22148                         var target = r.parentElement();
22149                         if(!target || target.tagName.toLowerCase() != 'li'){
22150                             e.stopEvent();
22151                             r.pasteHTML('<br />');
22152                             r.collapse(false);
22153                             r.select();
22154                         }
22155                     }
22156                 }
22157                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22158                     this.cleanUpPaste.defer(100, this);
22159                     return;
22160                 }
22161                 
22162                 
22163             };
22164         }else if(Roo.isOpera){
22165             return function(e){
22166                 var k = e.getKey();
22167                 if(k == e.TAB){
22168                     e.stopEvent();
22169                     this.win.focus();
22170                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
22171                     this.deferFocus();
22172                 }
22173                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22174                     this.cleanUpPaste.defer(100, this);
22175                     return;
22176                 }
22177                 
22178             };
22179         }else if(Roo.isSafari){
22180             return function(e){
22181                 var k = e.getKey();
22182                 
22183                 if(k == e.TAB){
22184                     e.stopEvent();
22185                     this.execCmd('InsertText','\t');
22186                     this.deferFocus();
22187                     return;
22188                 }
22189                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22190                     this.cleanUpPaste.defer(100, this);
22191                     return;
22192                 }
22193                 
22194              };
22195         }
22196     }(),
22197     
22198     getAllAncestors: function()
22199     {
22200         var p = this.getSelectedNode();
22201         var a = [];
22202         if (!p) {
22203             a.push(p); // push blank onto stack..
22204             p = this.getParentElement();
22205         }
22206         
22207         
22208         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22209             a.push(p);
22210             p = p.parentNode;
22211         }
22212         a.push(this.doc.body);
22213         return a;
22214     },
22215     lastSel : false,
22216     lastSelNode : false,
22217     
22218     
22219     getSelection : function() 
22220     {
22221         this.assignDocWin();
22222         return Roo.isIE ? this.doc.selection : this.win.getSelection();
22223     },
22224     
22225     getSelectedNode: function() 
22226     {
22227         // this may only work on Gecko!!!
22228         
22229         // should we cache this!!!!
22230         
22231         
22232         
22233          
22234         var range = this.createRange(this.getSelection()).cloneRange();
22235         
22236         if (Roo.isIE) {
22237             var parent = range.parentElement();
22238             while (true) {
22239                 var testRange = range.duplicate();
22240                 testRange.moveToElementText(parent);
22241                 if (testRange.inRange(range)) {
22242                     break;
22243                 }
22244                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22245                     break;
22246                 }
22247                 parent = parent.parentElement;
22248             }
22249             return parent;
22250         }
22251         
22252         // is ancestor a text element.
22253         var ac =  range.commonAncestorContainer;
22254         if (ac.nodeType == 3) {
22255             ac = ac.parentNode;
22256         }
22257         
22258         var ar = ac.childNodes;
22259          
22260         var nodes = [];
22261         var other_nodes = [];
22262         var has_other_nodes = false;
22263         for (var i=0;i<ar.length;i++) {
22264             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
22265                 continue;
22266             }
22267             // fullly contained node.
22268             
22269             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22270                 nodes.push(ar[i]);
22271                 continue;
22272             }
22273             
22274             // probably selected..
22275             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22276                 other_nodes.push(ar[i]);
22277                 continue;
22278             }
22279             // outer..
22280             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
22281                 continue;
22282             }
22283             
22284             
22285             has_other_nodes = true;
22286         }
22287         if (!nodes.length && other_nodes.length) {
22288             nodes= other_nodes;
22289         }
22290         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22291             return false;
22292         }
22293         
22294         return nodes[0];
22295     },
22296     createRange: function(sel)
22297     {
22298         // this has strange effects when using with 
22299         // top toolbar - not sure if it's a great idea.
22300         //this.editor.contentWindow.focus();
22301         if (typeof sel != "undefined") {
22302             try {
22303                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22304             } catch(e) {
22305                 return this.doc.createRange();
22306             }
22307         } else {
22308             return this.doc.createRange();
22309         }
22310     },
22311     getParentElement: function()
22312     {
22313         
22314         this.assignDocWin();
22315         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22316         
22317         var range = this.createRange(sel);
22318          
22319         try {
22320             var p = range.commonAncestorContainer;
22321             while (p.nodeType == 3) { // text node
22322                 p = p.parentNode;
22323             }
22324             return p;
22325         } catch (e) {
22326             return null;
22327         }
22328     
22329     },
22330     /***
22331      *
22332      * Range intersection.. the hard stuff...
22333      *  '-1' = before
22334      *  '0' = hits..
22335      *  '1' = after.
22336      *         [ -- selected range --- ]
22337      *   [fail]                        [fail]
22338      *
22339      *    basically..
22340      *      if end is before start or  hits it. fail.
22341      *      if start is after end or hits it fail.
22342      *
22343      *   if either hits (but other is outside. - then it's not 
22344      *   
22345      *    
22346      **/
22347     
22348     
22349     // @see http://www.thismuchiknow.co.uk/?p=64.
22350     rangeIntersectsNode : function(range, node)
22351     {
22352         var nodeRange = node.ownerDocument.createRange();
22353         try {
22354             nodeRange.selectNode(node);
22355         } catch (e) {
22356             nodeRange.selectNodeContents(node);
22357         }
22358     
22359         var rangeStartRange = range.cloneRange();
22360         rangeStartRange.collapse(true);
22361     
22362         var rangeEndRange = range.cloneRange();
22363         rangeEndRange.collapse(false);
22364     
22365         var nodeStartRange = nodeRange.cloneRange();
22366         nodeStartRange.collapse(true);
22367     
22368         var nodeEndRange = nodeRange.cloneRange();
22369         nodeEndRange.collapse(false);
22370     
22371         return rangeStartRange.compareBoundaryPoints(
22372                  Range.START_TO_START, nodeEndRange) == -1 &&
22373                rangeEndRange.compareBoundaryPoints(
22374                  Range.START_TO_START, nodeStartRange) == 1;
22375         
22376          
22377     },
22378     rangeCompareNode : function(range, node)
22379     {
22380         var nodeRange = node.ownerDocument.createRange();
22381         try {
22382             nodeRange.selectNode(node);
22383         } catch (e) {
22384             nodeRange.selectNodeContents(node);
22385         }
22386         
22387         
22388         range.collapse(true);
22389     
22390         nodeRange.collapse(true);
22391      
22392         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22393         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
22394          
22395         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22396         
22397         var nodeIsBefore   =  ss == 1;
22398         var nodeIsAfter    = ee == -1;
22399         
22400         if (nodeIsBefore && nodeIsAfter) {
22401             return 0; // outer
22402         }
22403         if (!nodeIsBefore && nodeIsAfter) {
22404             return 1; //right trailed.
22405         }
22406         
22407         if (nodeIsBefore && !nodeIsAfter) {
22408             return 2;  // left trailed.
22409         }
22410         // fully contined.
22411         return 3;
22412     },
22413
22414     // private? - in a new class?
22415     cleanUpPaste :  function()
22416     {
22417         // cleans up the whole document..
22418         Roo.log('cleanuppaste');
22419         
22420         this.cleanUpChildren(this.doc.body);
22421         var clean = this.cleanWordChars(this.doc.body.innerHTML);
22422         if (clean != this.doc.body.innerHTML) {
22423             this.doc.body.innerHTML = clean;
22424         }
22425         
22426     },
22427     
22428     cleanWordChars : function(input) {// change the chars to hex code
22429         var he = Roo.HtmlEditorCore;
22430         
22431         var output = input;
22432         Roo.each(he.swapCodes, function(sw) { 
22433             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22434             
22435             output = output.replace(swapper, sw[1]);
22436         });
22437         
22438         return output;
22439     },
22440     
22441     
22442     cleanUpChildren : function (n)
22443     {
22444         if (!n.childNodes.length) {
22445             return;
22446         }
22447         for (var i = n.childNodes.length-1; i > -1 ; i--) {
22448            this.cleanUpChild(n.childNodes[i]);
22449         }
22450     },
22451     
22452     
22453         
22454     
22455     cleanUpChild : function (node)
22456     {
22457         var ed = this;
22458         //console.log(node);
22459         if (node.nodeName == "#text") {
22460             // clean up silly Windows -- stuff?
22461             return; 
22462         }
22463         if (node.nodeName == "#comment") {
22464             node.parentNode.removeChild(node);
22465             // clean up silly Windows -- stuff?
22466             return; 
22467         }
22468         var lcname = node.tagName.toLowerCase();
22469         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22470         // whitelist of tags..
22471         
22472         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22473             // remove node.
22474             node.parentNode.removeChild(node);
22475             return;
22476             
22477         }
22478         
22479         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22480         
22481         // remove <a name=....> as rendering on yahoo mailer is borked with this.
22482         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22483         
22484         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22485         //    remove_keep_children = true;
22486         //}
22487         
22488         if (remove_keep_children) {
22489             this.cleanUpChildren(node);
22490             // inserts everything just before this node...
22491             while (node.childNodes.length) {
22492                 var cn = node.childNodes[0];
22493                 node.removeChild(cn);
22494                 node.parentNode.insertBefore(cn, node);
22495             }
22496             node.parentNode.removeChild(node);
22497             return;
22498         }
22499         
22500         if (!node.attributes || !node.attributes.length) {
22501             this.cleanUpChildren(node);
22502             return;
22503         }
22504         
22505         function cleanAttr(n,v)
22506         {
22507             
22508             if (v.match(/^\./) || v.match(/^\//)) {
22509                 return;
22510             }
22511             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22512                 return;
22513             }
22514             if (v.match(/^#/)) {
22515                 return;
22516             }
22517 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22518             node.removeAttribute(n);
22519             
22520         }
22521         
22522         var cwhite = this.cwhite;
22523         var cblack = this.cblack;
22524             
22525         function cleanStyle(n,v)
22526         {
22527             if (v.match(/expression/)) { //XSS?? should we even bother..
22528                 node.removeAttribute(n);
22529                 return;
22530             }
22531             
22532             var parts = v.split(/;/);
22533             var clean = [];
22534             
22535             Roo.each(parts, function(p) {
22536                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22537                 if (!p.length) {
22538                     return true;
22539                 }
22540                 var l = p.split(':').shift().replace(/\s+/g,'');
22541                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22542                 
22543                 if ( cwhite.length && cblack.indexOf(l) > -1) {
22544 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22545                     //node.removeAttribute(n);
22546                     return true;
22547                 }
22548                 //Roo.log()
22549                 // only allow 'c whitelisted system attributes'
22550                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
22551 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22552                     //node.removeAttribute(n);
22553                     return true;
22554                 }
22555                 
22556                 
22557                  
22558                 
22559                 clean.push(p);
22560                 return true;
22561             });
22562             if (clean.length) { 
22563                 node.setAttribute(n, clean.join(';'));
22564             } else {
22565                 node.removeAttribute(n);
22566             }
22567             
22568         }
22569         
22570         
22571         for (var i = node.attributes.length-1; i > -1 ; i--) {
22572             var a = node.attributes[i];
22573             //console.log(a);
22574             
22575             if (a.name.toLowerCase().substr(0,2)=='on')  {
22576                 node.removeAttribute(a.name);
22577                 continue;
22578             }
22579             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22580                 node.removeAttribute(a.name);
22581                 continue;
22582             }
22583             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22584                 cleanAttr(a.name,a.value); // fixme..
22585                 continue;
22586             }
22587             if (a.name == 'style') {
22588                 cleanStyle(a.name,a.value);
22589                 continue;
22590             }
22591             /// clean up MS crap..
22592             // tecnically this should be a list of valid class'es..
22593             
22594             
22595             if (a.name == 'class') {
22596                 if (a.value.match(/^Mso/)) {
22597                     node.className = '';
22598                 }
22599                 
22600                 if (a.value.match(/^body$/)) {
22601                     node.className = '';
22602                 }
22603                 continue;
22604             }
22605             
22606             // style cleanup!?
22607             // class cleanup?
22608             
22609         }
22610         
22611         
22612         this.cleanUpChildren(node);
22613         
22614         
22615     },
22616     
22617     /**
22618      * Clean up MS wordisms...
22619      */
22620     cleanWord : function(node)
22621     {
22622         
22623         
22624         if (!node) {
22625             this.cleanWord(this.doc.body);
22626             return;
22627         }
22628         if (node.nodeName == "#text") {
22629             // clean up silly Windows -- stuff?
22630             return; 
22631         }
22632         if (node.nodeName == "#comment") {
22633             node.parentNode.removeChild(node);
22634             // clean up silly Windows -- stuff?
22635             return; 
22636         }
22637         
22638         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22639             node.parentNode.removeChild(node);
22640             return;
22641         }
22642         
22643         // remove - but keep children..
22644         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22645             while (node.childNodes.length) {
22646                 var cn = node.childNodes[0];
22647                 node.removeChild(cn);
22648                 node.parentNode.insertBefore(cn, node);
22649             }
22650             node.parentNode.removeChild(node);
22651             this.iterateChildren(node, this.cleanWord);
22652             return;
22653         }
22654         // clean styles
22655         if (node.className.length) {
22656             
22657             var cn = node.className.split(/\W+/);
22658             var cna = [];
22659             Roo.each(cn, function(cls) {
22660                 if (cls.match(/Mso[a-zA-Z]+/)) {
22661                     return;
22662                 }
22663                 cna.push(cls);
22664             });
22665             node.className = cna.length ? cna.join(' ') : '';
22666             if (!cna.length) {
22667                 node.removeAttribute("class");
22668             }
22669         }
22670         
22671         if (node.hasAttribute("lang")) {
22672             node.removeAttribute("lang");
22673         }
22674         
22675         if (node.hasAttribute("style")) {
22676             
22677             var styles = node.getAttribute("style").split(";");
22678             var nstyle = [];
22679             Roo.each(styles, function(s) {
22680                 if (!s.match(/:/)) {
22681                     return;
22682                 }
22683                 var kv = s.split(":");
22684                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22685                     return;
22686                 }
22687                 // what ever is left... we allow.
22688                 nstyle.push(s);
22689             });
22690             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22691             if (!nstyle.length) {
22692                 node.removeAttribute('style');
22693             }
22694         }
22695         this.iterateChildren(node, this.cleanWord);
22696         
22697         
22698         
22699     },
22700     /**
22701      * iterateChildren of a Node, calling fn each time, using this as the scole..
22702      * @param {DomNode} node node to iterate children of.
22703      * @param {Function} fn method of this class to call on each item.
22704      */
22705     iterateChildren : function(node, fn)
22706     {
22707         if (!node.childNodes.length) {
22708                 return;
22709         }
22710         for (var i = node.childNodes.length-1; i > -1 ; i--) {
22711            fn.call(this, node.childNodes[i])
22712         }
22713     },
22714     
22715     
22716     /**
22717      * cleanTableWidths.
22718      *
22719      * Quite often pasting from word etc.. results in tables with column and widths.
22720      * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22721      *
22722      */
22723     cleanTableWidths : function(node)
22724     {
22725          
22726          
22727         if (!node) {
22728             this.cleanTableWidths(this.doc.body);
22729             return;
22730         }
22731         
22732         // ignore list...
22733         if (node.nodeName == "#text" || node.nodeName == "#comment") {
22734             return; 
22735         }
22736         Roo.log(node.tagName);
22737         if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22738             this.iterateChildren(node, this.cleanTableWidths);
22739             return;
22740         }
22741         if (node.hasAttribute('width')) {
22742             node.removeAttribute('width');
22743         }
22744         
22745          
22746         if (node.hasAttribute("style")) {
22747             // pretty basic...
22748             
22749             var styles = node.getAttribute("style").split(";");
22750             var nstyle = [];
22751             Roo.each(styles, function(s) {
22752                 if (!s.match(/:/)) {
22753                     return;
22754                 }
22755                 var kv = s.split(":");
22756                 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22757                     return;
22758                 }
22759                 // what ever is left... we allow.
22760                 nstyle.push(s);
22761             });
22762             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22763             if (!nstyle.length) {
22764                 node.removeAttribute('style');
22765             }
22766         }
22767         
22768         this.iterateChildren(node, this.cleanTableWidths);
22769         
22770         
22771     },
22772     
22773     
22774     
22775     
22776     domToHTML : function(currentElement, depth, nopadtext) {
22777         
22778         depth = depth || 0;
22779         nopadtext = nopadtext || false;
22780     
22781         if (!currentElement) {
22782             return this.domToHTML(this.doc.body);
22783         }
22784         
22785         //Roo.log(currentElement);
22786         var j;
22787         var allText = false;
22788         var nodeName = currentElement.nodeName;
22789         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22790         
22791         if  (nodeName == '#text') {
22792             
22793             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22794         }
22795         
22796         
22797         var ret = '';
22798         if (nodeName != 'BODY') {
22799              
22800             var i = 0;
22801             // Prints the node tagName, such as <A>, <IMG>, etc
22802             if (tagName) {
22803                 var attr = [];
22804                 for(i = 0; i < currentElement.attributes.length;i++) {
22805                     // quoting?
22806                     var aname = currentElement.attributes.item(i).name;
22807                     if (!currentElement.attributes.item(i).value.length) {
22808                         continue;
22809                     }
22810                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22811                 }
22812                 
22813                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22814             } 
22815             else {
22816                 
22817                 // eack
22818             }
22819         } else {
22820             tagName = false;
22821         }
22822         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22823             return ret;
22824         }
22825         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22826             nopadtext = true;
22827         }
22828         
22829         
22830         // Traverse the tree
22831         i = 0;
22832         var currentElementChild = currentElement.childNodes.item(i);
22833         var allText = true;
22834         var innerHTML  = '';
22835         lastnode = '';
22836         while (currentElementChild) {
22837             // Formatting code (indent the tree so it looks nice on the screen)
22838             var nopad = nopadtext;
22839             if (lastnode == 'SPAN') {
22840                 nopad  = true;
22841             }
22842             // text
22843             if  (currentElementChild.nodeName == '#text') {
22844                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22845                 toadd = nopadtext ? toadd : toadd.trim();
22846                 if (!nopad && toadd.length > 80) {
22847                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
22848                 }
22849                 innerHTML  += toadd;
22850                 
22851                 i++;
22852                 currentElementChild = currentElement.childNodes.item(i);
22853                 lastNode = '';
22854                 continue;
22855             }
22856             allText = false;
22857             
22858             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
22859                 
22860             // Recursively traverse the tree structure of the child node
22861             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
22862             lastnode = currentElementChild.nodeName;
22863             i++;
22864             currentElementChild=currentElement.childNodes.item(i);
22865         }
22866         
22867         ret += innerHTML;
22868         
22869         if (!allText) {
22870                 // The remaining code is mostly for formatting the tree
22871             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
22872         }
22873         
22874         
22875         if (tagName) {
22876             ret+= "</"+tagName+">";
22877         }
22878         return ret;
22879         
22880     },
22881         
22882     applyBlacklists : function()
22883     {
22884         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
22885         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
22886         
22887         this.white = [];
22888         this.black = [];
22889         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22890             if (b.indexOf(tag) > -1) {
22891                 return;
22892             }
22893             this.white.push(tag);
22894             
22895         }, this);
22896         
22897         Roo.each(w, function(tag) {
22898             if (b.indexOf(tag) > -1) {
22899                 return;
22900             }
22901             if (this.white.indexOf(tag) > -1) {
22902                 return;
22903             }
22904             this.white.push(tag);
22905             
22906         }, this);
22907         
22908         
22909         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22910             if (w.indexOf(tag) > -1) {
22911                 return;
22912             }
22913             this.black.push(tag);
22914             
22915         }, this);
22916         
22917         Roo.each(b, function(tag) {
22918             if (w.indexOf(tag) > -1) {
22919                 return;
22920             }
22921             if (this.black.indexOf(tag) > -1) {
22922                 return;
22923             }
22924             this.black.push(tag);
22925             
22926         }, this);
22927         
22928         
22929         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
22930         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
22931         
22932         this.cwhite = [];
22933         this.cblack = [];
22934         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22935             if (b.indexOf(tag) > -1) {
22936                 return;
22937             }
22938             this.cwhite.push(tag);
22939             
22940         }, this);
22941         
22942         Roo.each(w, function(tag) {
22943             if (b.indexOf(tag) > -1) {
22944                 return;
22945             }
22946             if (this.cwhite.indexOf(tag) > -1) {
22947                 return;
22948             }
22949             this.cwhite.push(tag);
22950             
22951         }, this);
22952         
22953         
22954         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22955             if (w.indexOf(tag) > -1) {
22956                 return;
22957             }
22958             this.cblack.push(tag);
22959             
22960         }, this);
22961         
22962         Roo.each(b, function(tag) {
22963             if (w.indexOf(tag) > -1) {
22964                 return;
22965             }
22966             if (this.cblack.indexOf(tag) > -1) {
22967                 return;
22968             }
22969             this.cblack.push(tag);
22970             
22971         }, this);
22972     },
22973     
22974     setStylesheets : function(stylesheets)
22975     {
22976         if(typeof(stylesheets) == 'string'){
22977             Roo.get(this.iframe.contentDocument.head).createChild({
22978                 tag : 'link',
22979                 rel : 'stylesheet',
22980                 type : 'text/css',
22981                 href : stylesheets
22982             });
22983             
22984             return;
22985         }
22986         var _this = this;
22987      
22988         Roo.each(stylesheets, function(s) {
22989             if(!s.length){
22990                 return;
22991             }
22992             
22993             Roo.get(_this.iframe.contentDocument.head).createChild({
22994                 tag : 'link',
22995                 rel : 'stylesheet',
22996                 type : 'text/css',
22997                 href : s
22998             });
22999         });
23000
23001         
23002     },
23003     
23004     removeStylesheets : function()
23005     {
23006         var _this = this;
23007         
23008         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23009             s.remove();
23010         });
23011     },
23012     
23013     setStyle : function(style)
23014     {
23015         Roo.get(this.iframe.contentDocument.head).createChild({
23016             tag : 'style',
23017             type : 'text/css',
23018             html : style
23019         });
23020
23021         return;
23022     }
23023     
23024     // hide stuff that is not compatible
23025     /**
23026      * @event blur
23027      * @hide
23028      */
23029     /**
23030      * @event change
23031      * @hide
23032      */
23033     /**
23034      * @event focus
23035      * @hide
23036      */
23037     /**
23038      * @event specialkey
23039      * @hide
23040      */
23041     /**
23042      * @cfg {String} fieldClass @hide
23043      */
23044     /**
23045      * @cfg {String} focusClass @hide
23046      */
23047     /**
23048      * @cfg {String} autoCreate @hide
23049      */
23050     /**
23051      * @cfg {String} inputType @hide
23052      */
23053     /**
23054      * @cfg {String} invalidClass @hide
23055      */
23056     /**
23057      * @cfg {String} invalidText @hide
23058      */
23059     /**
23060      * @cfg {String} msgFx @hide
23061      */
23062     /**
23063      * @cfg {String} validateOnBlur @hide
23064      */
23065 });
23066
23067 Roo.HtmlEditorCore.white = [
23068         'area', 'br', 'img', 'input', 'hr', 'wbr',
23069         
23070        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
23071        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
23072        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
23073        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
23074        'table',   'ul',         'xmp', 
23075        
23076        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
23077       'thead',   'tr', 
23078      
23079       'dir', 'menu', 'ol', 'ul', 'dl',
23080        
23081       'embed',  'object'
23082 ];
23083
23084
23085 Roo.HtmlEditorCore.black = [
23086     //    'embed',  'object', // enable - backend responsiblity to clean thiese
23087         'applet', // 
23088         'base',   'basefont', 'bgsound', 'blink',  'body', 
23089         'frame',  'frameset', 'head',    'html',   'ilayer', 
23090         'iframe', 'layer',  'link',     'meta',    'object',   
23091         'script', 'style' ,'title',  'xml' // clean later..
23092 ];
23093 Roo.HtmlEditorCore.clean = [
23094     'script', 'style', 'title', 'xml'
23095 ];
23096 Roo.HtmlEditorCore.remove = [
23097     'font'
23098 ];
23099 // attributes..
23100
23101 Roo.HtmlEditorCore.ablack = [
23102     'on'
23103 ];
23104     
23105 Roo.HtmlEditorCore.aclean = [ 
23106     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
23107 ];
23108
23109 // protocols..
23110 Roo.HtmlEditorCore.pwhite= [
23111         'http',  'https',  'mailto'
23112 ];
23113
23114 // white listed style attributes.
23115 Roo.HtmlEditorCore.cwhite= [
23116       //  'text-align', /// default is to allow most things..
23117       
23118          
23119 //        'font-size'//??
23120 ];
23121
23122 // black listed style attributes.
23123 Roo.HtmlEditorCore.cblack= [
23124       //  'font-size' -- this can be set by the project 
23125 ];
23126
23127
23128 Roo.HtmlEditorCore.swapCodes   =[ 
23129     [    8211, "--" ], 
23130     [    8212, "--" ], 
23131     [    8216,  "'" ],  
23132     [    8217, "'" ],  
23133     [    8220, '"' ],  
23134     [    8221, '"' ],  
23135     [    8226, "*" ],  
23136     [    8230, "..." ]
23137 ]; 
23138
23139     /*
23140  * - LGPL
23141  *
23142  * HtmlEditor
23143  * 
23144  */
23145
23146 /**
23147  * @class Roo.bootstrap.HtmlEditor
23148  * @extends Roo.bootstrap.TextArea
23149  * Bootstrap HtmlEditor class
23150
23151  * @constructor
23152  * Create a new HtmlEditor
23153  * @param {Object} config The config object
23154  */
23155
23156 Roo.bootstrap.HtmlEditor = function(config){
23157     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23158     if (!this.toolbars) {
23159         this.toolbars = [];
23160     }
23161     
23162     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23163     this.addEvents({
23164             /**
23165              * @event initialize
23166              * Fires when the editor is fully initialized (including the iframe)
23167              * @param {HtmlEditor} this
23168              */
23169             initialize: true,
23170             /**
23171              * @event activate
23172              * Fires when the editor is first receives the focus. Any insertion must wait
23173              * until after this event.
23174              * @param {HtmlEditor} this
23175              */
23176             activate: true,
23177              /**
23178              * @event beforesync
23179              * Fires before the textarea is updated with content from the editor iframe. Return false
23180              * to cancel the sync.
23181              * @param {HtmlEditor} this
23182              * @param {String} html
23183              */
23184             beforesync: true,
23185              /**
23186              * @event beforepush
23187              * Fires before the iframe editor is updated with content from the textarea. Return false
23188              * to cancel the push.
23189              * @param {HtmlEditor} this
23190              * @param {String} html
23191              */
23192             beforepush: true,
23193              /**
23194              * @event sync
23195              * Fires when the textarea is updated with content from the editor iframe.
23196              * @param {HtmlEditor} this
23197              * @param {String} html
23198              */
23199             sync: true,
23200              /**
23201              * @event push
23202              * Fires when the iframe editor is updated with content from the textarea.
23203              * @param {HtmlEditor} this
23204              * @param {String} html
23205              */
23206             push: true,
23207              /**
23208              * @event editmodechange
23209              * Fires when the editor switches edit modes
23210              * @param {HtmlEditor} this
23211              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23212              */
23213             editmodechange: true,
23214             /**
23215              * @event editorevent
23216              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23217              * @param {HtmlEditor} this
23218              */
23219             editorevent: true,
23220             /**
23221              * @event firstfocus
23222              * Fires when on first focus - needed by toolbars..
23223              * @param {HtmlEditor} this
23224              */
23225             firstfocus: true,
23226             /**
23227              * @event autosave
23228              * Auto save the htmlEditor value as a file into Events
23229              * @param {HtmlEditor} this
23230              */
23231             autosave: true,
23232             /**
23233              * @event savedpreview
23234              * preview the saved version of htmlEditor
23235              * @param {HtmlEditor} this
23236              */
23237             savedpreview: true
23238         });
23239 };
23240
23241
23242 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
23243     
23244     
23245       /**
23246      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23247      */
23248     toolbars : false,
23249     
23250      /**
23251     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23252     */
23253     btns : [],
23254    
23255      /**
23256      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
23257      *                        Roo.resizable.
23258      */
23259     resizable : false,
23260      /**
23261      * @cfg {Number} height (in pixels)
23262      */   
23263     height: 300,
23264    /**
23265      * @cfg {Number} width (in pixels)
23266      */   
23267     width: false,
23268     
23269     /**
23270      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23271      * 
23272      */
23273     stylesheets: false,
23274     
23275     // id of frame..
23276     frameId: false,
23277     
23278     // private properties
23279     validationEvent : false,
23280     deferHeight: true,
23281     initialized : false,
23282     activated : false,
23283     
23284     onFocus : Roo.emptyFn,
23285     iframePad:3,
23286     hideMode:'offsets',
23287     
23288     tbContainer : false,
23289     
23290     bodyCls : '',
23291     
23292     toolbarContainer :function() {
23293         return this.wrap.select('.x-html-editor-tb',true).first();
23294     },
23295
23296     /**
23297      * Protected method that will not generally be called directly. It
23298      * is called when the editor creates its toolbar. Override this method if you need to
23299      * add custom toolbar buttons.
23300      * @param {HtmlEditor} editor
23301      */
23302     createToolbar : function(){
23303         Roo.log('renewing');
23304         Roo.log("create toolbars");
23305         
23306         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23307         this.toolbars[0].render(this.toolbarContainer());
23308         
23309         return;
23310         
23311 //        if (!editor.toolbars || !editor.toolbars.length) {
23312 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23313 //        }
23314 //        
23315 //        for (var i =0 ; i < editor.toolbars.length;i++) {
23316 //            editor.toolbars[i] = Roo.factory(
23317 //                    typeof(editor.toolbars[i]) == 'string' ?
23318 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
23319 //                Roo.bootstrap.HtmlEditor);
23320 //            editor.toolbars[i].init(editor);
23321 //        }
23322     },
23323
23324      
23325     // private
23326     onRender : function(ct, position)
23327     {
23328        // Roo.log("Call onRender: " + this.xtype);
23329         var _t = this;
23330         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23331       
23332         this.wrap = this.inputEl().wrap({
23333             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23334         });
23335         
23336         this.editorcore.onRender(ct, position);
23337          
23338         if (this.resizable) {
23339             this.resizeEl = new Roo.Resizable(this.wrap, {
23340                 pinned : true,
23341                 wrap: true,
23342                 dynamic : true,
23343                 minHeight : this.height,
23344                 height: this.height,
23345                 handles : this.resizable,
23346                 width: this.width,
23347                 listeners : {
23348                     resize : function(r, w, h) {
23349                         _t.onResize(w,h); // -something
23350                     }
23351                 }
23352             });
23353             
23354         }
23355         this.createToolbar(this);
23356        
23357         
23358         if(!this.width && this.resizable){
23359             this.setSize(this.wrap.getSize());
23360         }
23361         if (this.resizeEl) {
23362             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23363             // should trigger onReize..
23364         }
23365         
23366     },
23367
23368     // private
23369     onResize : function(w, h)
23370     {
23371         Roo.log('resize: ' +w + ',' + h );
23372         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23373         var ew = false;
23374         var eh = false;
23375         
23376         if(this.inputEl() ){
23377             if(typeof w == 'number'){
23378                 var aw = w - this.wrap.getFrameWidth('lr');
23379                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23380                 ew = aw;
23381             }
23382             if(typeof h == 'number'){
23383                  var tbh = -11;  // fixme it needs to tool bar size!
23384                 for (var i =0; i < this.toolbars.length;i++) {
23385                     // fixme - ask toolbars for heights?
23386                     tbh += this.toolbars[i].el.getHeight();
23387                     //if (this.toolbars[i].footer) {
23388                     //    tbh += this.toolbars[i].footer.el.getHeight();
23389                     //}
23390                 }
23391               
23392                 
23393                 
23394                 
23395                 
23396                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23397                 ah -= 5; // knock a few pixes off for look..
23398                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23399                 var eh = ah;
23400             }
23401         }
23402         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23403         this.editorcore.onResize(ew,eh);
23404         
23405     },
23406
23407     /**
23408      * Toggles the editor between standard and source edit mode.
23409      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23410      */
23411     toggleSourceEdit : function(sourceEditMode)
23412     {
23413         this.editorcore.toggleSourceEdit(sourceEditMode);
23414         
23415         if(this.editorcore.sourceEditMode){
23416             Roo.log('editor - showing textarea');
23417             
23418 //            Roo.log('in');
23419 //            Roo.log(this.syncValue());
23420             this.syncValue();
23421             this.inputEl().removeClass(['hide', 'x-hidden']);
23422             this.inputEl().dom.removeAttribute('tabIndex');
23423             this.inputEl().focus();
23424         }else{
23425             Roo.log('editor - hiding textarea');
23426 //            Roo.log('out')
23427 //            Roo.log(this.pushValue()); 
23428             this.pushValue();
23429             
23430             this.inputEl().addClass(['hide', 'x-hidden']);
23431             this.inputEl().dom.setAttribute('tabIndex', -1);
23432             //this.deferFocus();
23433         }
23434          
23435         if(this.resizable){
23436             this.setSize(this.wrap.getSize());
23437         }
23438         
23439         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23440     },
23441  
23442     // private (for BoxComponent)
23443     adjustSize : Roo.BoxComponent.prototype.adjustSize,
23444
23445     // private (for BoxComponent)
23446     getResizeEl : function(){
23447         return this.wrap;
23448     },
23449
23450     // private (for BoxComponent)
23451     getPositionEl : function(){
23452         return this.wrap;
23453     },
23454
23455     // private
23456     initEvents : function(){
23457         this.originalValue = this.getValue();
23458     },
23459
23460 //    /**
23461 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23462 //     * @method
23463 //     */
23464 //    markInvalid : Roo.emptyFn,
23465 //    /**
23466 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23467 //     * @method
23468 //     */
23469 //    clearInvalid : Roo.emptyFn,
23470
23471     setValue : function(v){
23472         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23473         this.editorcore.pushValue();
23474     },
23475
23476      
23477     // private
23478     deferFocus : function(){
23479         this.focus.defer(10, this);
23480     },
23481
23482     // doc'ed in Field
23483     focus : function(){
23484         this.editorcore.focus();
23485         
23486     },
23487       
23488
23489     // private
23490     onDestroy : function(){
23491         
23492         
23493         
23494         if(this.rendered){
23495             
23496             for (var i =0; i < this.toolbars.length;i++) {
23497                 // fixme - ask toolbars for heights?
23498                 this.toolbars[i].onDestroy();
23499             }
23500             
23501             this.wrap.dom.innerHTML = '';
23502             this.wrap.remove();
23503         }
23504     },
23505
23506     // private
23507     onFirstFocus : function(){
23508         //Roo.log("onFirstFocus");
23509         this.editorcore.onFirstFocus();
23510          for (var i =0; i < this.toolbars.length;i++) {
23511             this.toolbars[i].onFirstFocus();
23512         }
23513         
23514     },
23515     
23516     // private
23517     syncValue : function()
23518     {   
23519         this.editorcore.syncValue();
23520     },
23521     
23522     pushValue : function()
23523     {   
23524         this.editorcore.pushValue();
23525     }
23526      
23527     
23528     // hide stuff that is not compatible
23529     /**
23530      * @event blur
23531      * @hide
23532      */
23533     /**
23534      * @event change
23535      * @hide
23536      */
23537     /**
23538      * @event focus
23539      * @hide
23540      */
23541     /**
23542      * @event specialkey
23543      * @hide
23544      */
23545     /**
23546      * @cfg {String} fieldClass @hide
23547      */
23548     /**
23549      * @cfg {String} focusClass @hide
23550      */
23551     /**
23552      * @cfg {String} autoCreate @hide
23553      */
23554     /**
23555      * @cfg {String} inputType @hide
23556      */
23557     /**
23558      * @cfg {String} invalidClass @hide
23559      */
23560     /**
23561      * @cfg {String} invalidText @hide
23562      */
23563     /**
23564      * @cfg {String} msgFx @hide
23565      */
23566     /**
23567      * @cfg {String} validateOnBlur @hide
23568      */
23569 });
23570  
23571     
23572    
23573    
23574    
23575       
23576 Roo.namespace('Roo.bootstrap.htmleditor');
23577 /**
23578  * @class Roo.bootstrap.HtmlEditorToolbar1
23579  * Basic Toolbar
23580  * 
23581  * Usage:
23582  *
23583  new Roo.bootstrap.HtmlEditor({
23584     ....
23585     toolbars : [
23586         new Roo.bootstrap.HtmlEditorToolbar1({
23587             disable : { fonts: 1 , format: 1, ..., ... , ...],
23588             btns : [ .... ]
23589         })
23590     }
23591      
23592  * 
23593  * @cfg {Object} disable List of elements to disable..
23594  * @cfg {Array} btns List of additional buttons.
23595  * 
23596  * 
23597  * NEEDS Extra CSS? 
23598  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23599  */
23600  
23601 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23602 {
23603     
23604     Roo.apply(this, config);
23605     
23606     // default disabled, based on 'good practice'..
23607     this.disable = this.disable || {};
23608     Roo.applyIf(this.disable, {
23609         fontSize : true,
23610         colors : true,
23611         specialElements : true
23612     });
23613     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23614     
23615     this.editor = config.editor;
23616     this.editorcore = config.editor.editorcore;
23617     
23618     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23619     
23620     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23621     // dont call parent... till later.
23622 }
23623 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
23624      
23625     bar : true,
23626     
23627     editor : false,
23628     editorcore : false,
23629     
23630     
23631     formats : [
23632         "p" ,  
23633         "h1","h2","h3","h4","h5","h6", 
23634         "pre", "code", 
23635         "abbr", "acronym", "address", "cite", "samp", "var",
23636         'div','span'
23637     ],
23638     
23639     onRender : function(ct, position)
23640     {
23641        // Roo.log("Call onRender: " + this.xtype);
23642         
23643        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23644        Roo.log(this.el);
23645        this.el.dom.style.marginBottom = '0';
23646        var _this = this;
23647        var editorcore = this.editorcore;
23648        var editor= this.editor;
23649        
23650        var children = [];
23651        var btn = function(id,cmd , toggle, handler, html){
23652        
23653             var  event = toggle ? 'toggle' : 'click';
23654        
23655             var a = {
23656                 size : 'sm',
23657                 xtype: 'Button',
23658                 xns: Roo.bootstrap,
23659                 glyphicon : id,
23660                 cmd : id || cmd,
23661                 enableToggle:toggle !== false,
23662                 html : html || '',
23663                 pressed : toggle ? false : null,
23664                 listeners : {}
23665             };
23666             a.listeners[toggle ? 'toggle' : 'click'] = function() {
23667                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
23668             };
23669             children.push(a);
23670             return a;
23671        }
23672        
23673     //    var cb_box = function...
23674         
23675         var style = {
23676                 xtype: 'Button',
23677                 size : 'sm',
23678                 xns: Roo.bootstrap,
23679                 glyphicon : 'font',
23680                 //html : 'submit'
23681                 menu : {
23682                     xtype: 'Menu',
23683                     xns: Roo.bootstrap,
23684                     items:  []
23685                 }
23686         };
23687         Roo.each(this.formats, function(f) {
23688             style.menu.items.push({
23689                 xtype :'MenuItem',
23690                 xns: Roo.bootstrap,
23691                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23692                 tagname : f,
23693                 listeners : {
23694                     click : function()
23695                     {
23696                         editorcore.insertTag(this.tagname);
23697                         editor.focus();
23698                     }
23699                 }
23700                 
23701             });
23702         });
23703         children.push(style);   
23704         
23705         btn('bold',false,true);
23706         btn('italic',false,true);
23707         btn('align-left', 'justifyleft',true);
23708         btn('align-center', 'justifycenter',true);
23709         btn('align-right' , 'justifyright',true);
23710         btn('link', false, false, function(btn) {
23711             //Roo.log("create link?");
23712             var url = prompt(this.createLinkText, this.defaultLinkValue);
23713             if(url && url != 'http:/'+'/'){
23714                 this.editorcore.relayCmd('createlink', url);
23715             }
23716         }),
23717         btn('list','insertunorderedlist',true);
23718         btn('pencil', false,true, function(btn){
23719                 Roo.log(this);
23720                 this.toggleSourceEdit(btn.pressed);
23721         });
23722         
23723         if (this.editor.btns.length > 0) {
23724             for (var i = 0; i<this.editor.btns.length; i++) {
23725                 children.push(this.editor.btns[i]);
23726             }
23727         }
23728         
23729         /*
23730         var cog = {
23731                 xtype: 'Button',
23732                 size : 'sm',
23733                 xns: Roo.bootstrap,
23734                 glyphicon : 'cog',
23735                 //html : 'submit'
23736                 menu : {
23737                     xtype: 'Menu',
23738                     xns: Roo.bootstrap,
23739                     items:  []
23740                 }
23741         };
23742         
23743         cog.menu.items.push({
23744             xtype :'MenuItem',
23745             xns: Roo.bootstrap,
23746             html : Clean styles,
23747             tagname : f,
23748             listeners : {
23749                 click : function()
23750                 {
23751                     editorcore.insertTag(this.tagname);
23752                     editor.focus();
23753                 }
23754             }
23755             
23756         });
23757        */
23758         
23759          
23760        this.xtype = 'NavSimplebar';
23761         
23762         for(var i=0;i< children.length;i++) {
23763             
23764             this.buttons.add(this.addxtypeChild(children[i]));
23765             
23766         }
23767         
23768         editor.on('editorevent', this.updateToolbar, this);
23769     },
23770     onBtnClick : function(id)
23771     {
23772        this.editorcore.relayCmd(id);
23773        this.editorcore.focus();
23774     },
23775     
23776     /**
23777      * Protected method that will not generally be called directly. It triggers
23778      * a toolbar update by reading the markup state of the current selection in the editor.
23779      */
23780     updateToolbar: function(){
23781
23782         if(!this.editorcore.activated){
23783             this.editor.onFirstFocus(); // is this neeed?
23784             return;
23785         }
23786
23787         var btns = this.buttons; 
23788         var doc = this.editorcore.doc;
23789         btns.get('bold').setActive(doc.queryCommandState('bold'));
23790         btns.get('italic').setActive(doc.queryCommandState('italic'));
23791         //btns.get('underline').setActive(doc.queryCommandState('underline'));
23792         
23793         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23794         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23795         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23796         
23797         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23798         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23799          /*
23800         
23801         var ans = this.editorcore.getAllAncestors();
23802         if (this.formatCombo) {
23803             
23804             
23805             var store = this.formatCombo.store;
23806             this.formatCombo.setValue("");
23807             for (var i =0; i < ans.length;i++) {
23808                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23809                     // select it..
23810                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23811                     break;
23812                 }
23813             }
23814         }
23815         
23816         
23817         
23818         // hides menus... - so this cant be on a menu...
23819         Roo.bootstrap.MenuMgr.hideAll();
23820         */
23821         Roo.bootstrap.MenuMgr.hideAll();
23822         //this.editorsyncValue();
23823     },
23824     onFirstFocus: function() {
23825         this.buttons.each(function(item){
23826            item.enable();
23827         });
23828     },
23829     toggleSourceEdit : function(sourceEditMode){
23830         
23831           
23832         if(sourceEditMode){
23833             Roo.log("disabling buttons");
23834            this.buttons.each( function(item){
23835                 if(item.cmd != 'pencil'){
23836                     item.disable();
23837                 }
23838             });
23839           
23840         }else{
23841             Roo.log("enabling buttons");
23842             if(this.editorcore.initialized){
23843                 this.buttons.each( function(item){
23844                     item.enable();
23845                 });
23846             }
23847             
23848         }
23849         Roo.log("calling toggole on editor");
23850         // tell the editor that it's been pressed..
23851         this.editor.toggleSourceEdit(sourceEditMode);
23852        
23853     }
23854 });
23855
23856
23857
23858
23859
23860 /**
23861  * @class Roo.bootstrap.Table.AbstractSelectionModel
23862  * @extends Roo.util.Observable
23863  * Abstract base class for grid SelectionModels.  It provides the interface that should be
23864  * implemented by descendant classes.  This class should not be directly instantiated.
23865  * @constructor
23866  */
23867 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23868     this.locked = false;
23869     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23870 };
23871
23872
23873 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
23874     /** @ignore Called by the grid automatically. Do not call directly. */
23875     init : function(grid){
23876         this.grid = grid;
23877         this.initEvents();
23878     },
23879
23880     /**
23881      * Locks the selections.
23882      */
23883     lock : function(){
23884         this.locked = true;
23885     },
23886
23887     /**
23888      * Unlocks the selections.
23889      */
23890     unlock : function(){
23891         this.locked = false;
23892     },
23893
23894     /**
23895      * Returns true if the selections are locked.
23896      * @return {Boolean}
23897      */
23898     isLocked : function(){
23899         return this.locked;
23900     }
23901 });
23902 /**
23903  * @extends Roo.bootstrap.Table.AbstractSelectionModel
23904  * @class Roo.bootstrap.Table.RowSelectionModel
23905  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23906  * It supports multiple selections and keyboard selection/navigation. 
23907  * @constructor
23908  * @param {Object} config
23909  */
23910
23911 Roo.bootstrap.Table.RowSelectionModel = function(config){
23912     Roo.apply(this, config);
23913     this.selections = new Roo.util.MixedCollection(false, function(o){
23914         return o.id;
23915     });
23916
23917     this.last = false;
23918     this.lastActive = false;
23919
23920     this.addEvents({
23921         /**
23922              * @event selectionchange
23923              * Fires when the selection changes
23924              * @param {SelectionModel} this
23925              */
23926             "selectionchange" : true,
23927         /**
23928              * @event afterselectionchange
23929              * Fires after the selection changes (eg. by key press or clicking)
23930              * @param {SelectionModel} this
23931              */
23932             "afterselectionchange" : true,
23933         /**
23934              * @event beforerowselect
23935              * Fires when a row is selected being selected, return false to cancel.
23936              * @param {SelectionModel} this
23937              * @param {Number} rowIndex The selected index
23938              * @param {Boolean} keepExisting False if other selections will be cleared
23939              */
23940             "beforerowselect" : true,
23941         /**
23942              * @event rowselect
23943              * Fires when a row is selected.
23944              * @param {SelectionModel} this
23945              * @param {Number} rowIndex The selected index
23946              * @param {Roo.data.Record} r The record
23947              */
23948             "rowselect" : true,
23949         /**
23950              * @event rowdeselect
23951              * Fires when a row is deselected.
23952              * @param {SelectionModel} this
23953              * @param {Number} rowIndex The selected index
23954              */
23955         "rowdeselect" : true
23956     });
23957     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23958     this.locked = false;
23959  };
23960
23961 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
23962     /**
23963      * @cfg {Boolean} singleSelect
23964      * True to allow selection of only one row at a time (defaults to false)
23965      */
23966     singleSelect : false,
23967
23968     // private
23969     initEvents : function()
23970     {
23971
23972         //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23973         //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
23974         //}else{ // allow click to work like normal
23975          //   this.grid.on("rowclick", this.handleDragableRowClick, this);
23976         //}
23977         //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23978         this.grid.on("rowclick", this.handleMouseDown, this);
23979         
23980         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23981             "up" : function(e){
23982                 if(!e.shiftKey){
23983                     this.selectPrevious(e.shiftKey);
23984                 }else if(this.last !== false && this.lastActive !== false){
23985                     var last = this.last;
23986                     this.selectRange(this.last,  this.lastActive-1);
23987                     this.grid.getView().focusRow(this.lastActive);
23988                     if(last !== false){
23989                         this.last = last;
23990                     }
23991                 }else{
23992                     this.selectFirstRow();
23993                 }
23994                 this.fireEvent("afterselectionchange", this);
23995             },
23996             "down" : function(e){
23997                 if(!e.shiftKey){
23998                     this.selectNext(e.shiftKey);
23999                 }else if(this.last !== false && this.lastActive !== false){
24000                     var last = this.last;
24001                     this.selectRange(this.last,  this.lastActive+1);
24002                     this.grid.getView().focusRow(this.lastActive);
24003                     if(last !== false){
24004                         this.last = last;
24005                     }
24006                 }else{
24007                     this.selectFirstRow();
24008                 }
24009                 this.fireEvent("afterselectionchange", this);
24010             },
24011             scope: this
24012         });
24013         this.grid.store.on('load', function(){
24014             this.selections.clear();
24015         },this);
24016         /*
24017         var view = this.grid.view;
24018         view.on("refresh", this.onRefresh, this);
24019         view.on("rowupdated", this.onRowUpdated, this);
24020         view.on("rowremoved", this.onRemove, this);
24021         */
24022     },
24023
24024     // private
24025     onRefresh : function()
24026     {
24027         var ds = this.grid.store, i, v = this.grid.view;
24028         var s = this.selections;
24029         s.each(function(r){
24030             if((i = ds.indexOfId(r.id)) != -1){
24031                 v.onRowSelect(i);
24032             }else{
24033                 s.remove(r);
24034             }
24035         });
24036     },
24037
24038     // private
24039     onRemove : function(v, index, r){
24040         this.selections.remove(r);
24041     },
24042
24043     // private
24044     onRowUpdated : function(v, index, r){
24045         if(this.isSelected(r)){
24046             v.onRowSelect(index);
24047         }
24048     },
24049
24050     /**
24051      * Select records.
24052      * @param {Array} records The records to select
24053      * @param {Boolean} keepExisting (optional) True to keep existing selections
24054      */
24055     selectRecords : function(records, keepExisting)
24056     {
24057         if(!keepExisting){
24058             this.clearSelections();
24059         }
24060             var ds = this.grid.store;
24061         for(var i = 0, len = records.length; i < len; i++){
24062             this.selectRow(ds.indexOf(records[i]), true);
24063         }
24064     },
24065
24066     /**
24067      * Gets the number of selected rows.
24068      * @return {Number}
24069      */
24070     getCount : function(){
24071         return this.selections.length;
24072     },
24073
24074     /**
24075      * Selects the first row in the grid.
24076      */
24077     selectFirstRow : function(){
24078         this.selectRow(0);
24079     },
24080
24081     /**
24082      * Select the last row.
24083      * @param {Boolean} keepExisting (optional) True to keep existing selections
24084      */
24085     selectLastRow : function(keepExisting){
24086         //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24087         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24088     },
24089
24090     /**
24091      * Selects the row immediately following the last selected row.
24092      * @param {Boolean} keepExisting (optional) True to keep existing selections
24093      */
24094     selectNext : function(keepExisting)
24095     {
24096             if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24097             this.selectRow(this.last+1, keepExisting);
24098             this.grid.getView().focusRow(this.last);
24099         }
24100     },
24101
24102     /**
24103      * Selects the row that precedes the last selected row.
24104      * @param {Boolean} keepExisting (optional) True to keep existing selections
24105      */
24106     selectPrevious : function(keepExisting){
24107         if(this.last){
24108             this.selectRow(this.last-1, keepExisting);
24109             this.grid.getView().focusRow(this.last);
24110         }
24111     },
24112
24113     /**
24114      * Returns the selected records
24115      * @return {Array} Array of selected records
24116      */
24117     getSelections : function(){
24118         return [].concat(this.selections.items);
24119     },
24120
24121     /**
24122      * Returns the first selected record.
24123      * @return {Record}
24124      */
24125     getSelected : function(){
24126         return this.selections.itemAt(0);
24127     },
24128
24129
24130     /**
24131      * Clears all selections.
24132      */
24133     clearSelections : function(fast)
24134     {
24135         if(this.locked) {
24136             return;
24137         }
24138         if(fast !== true){
24139                 var ds = this.grid.store;
24140             var s = this.selections;
24141             s.each(function(r){
24142                 this.deselectRow(ds.indexOfId(r.id));
24143             }, this);
24144             s.clear();
24145         }else{
24146             this.selections.clear();
24147         }
24148         this.last = false;
24149     },
24150
24151
24152     /**
24153      * Selects all rows.
24154      */
24155     selectAll : function(){
24156         if(this.locked) {
24157             return;
24158         }
24159         this.selections.clear();
24160         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24161             this.selectRow(i, true);
24162         }
24163     },
24164
24165     /**
24166      * Returns True if there is a selection.
24167      * @return {Boolean}
24168      */
24169     hasSelection : function(){
24170         return this.selections.length > 0;
24171     },
24172
24173     /**
24174      * Returns True if the specified row is selected.
24175      * @param {Number/Record} record The record or index of the record to check
24176      * @return {Boolean}
24177      */
24178     isSelected : function(index){
24179             var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24180         return (r && this.selections.key(r.id) ? true : false);
24181     },
24182
24183     /**
24184      * Returns True if the specified record id is selected.
24185      * @param {String} id The id of record to check
24186      * @return {Boolean}
24187      */
24188     isIdSelected : function(id){
24189         return (this.selections.key(id) ? true : false);
24190     },
24191
24192
24193     // private
24194     handleMouseDBClick : function(e, t){
24195         
24196     },
24197     // private
24198     handleMouseDown : function(e, t)
24199     {
24200             var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24201         if(this.isLocked() || rowIndex < 0 ){
24202             return;
24203         };
24204         if(e.shiftKey && this.last !== false){
24205             var last = this.last;
24206             this.selectRange(last, rowIndex, e.ctrlKey);
24207             this.last = last; // reset the last
24208             t.focus();
24209     
24210         }else{
24211             var isSelected = this.isSelected(rowIndex);
24212             //Roo.log("select row:" + rowIndex);
24213             if(isSelected){
24214                 this.deselectRow(rowIndex);
24215             } else {
24216                         this.selectRow(rowIndex, true);
24217             }
24218     
24219             /*
24220                 if(e.button !== 0 && isSelected){
24221                 alert('rowIndex 2: ' + rowIndex);
24222                     view.focusRow(rowIndex);
24223                 }else if(e.ctrlKey && isSelected){
24224                     this.deselectRow(rowIndex);
24225                 }else if(!isSelected){
24226                     this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24227                     view.focusRow(rowIndex);
24228                 }
24229             */
24230         }
24231         this.fireEvent("afterselectionchange", this);
24232     },
24233     // private
24234     handleDragableRowClick :  function(grid, rowIndex, e) 
24235     {
24236         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24237             this.selectRow(rowIndex, false);
24238             grid.view.focusRow(rowIndex);
24239              this.fireEvent("afterselectionchange", this);
24240         }
24241     },
24242     
24243     /**
24244      * Selects multiple rows.
24245      * @param {Array} rows Array of the indexes of the row to select
24246      * @param {Boolean} keepExisting (optional) True to keep existing selections
24247      */
24248     selectRows : function(rows, keepExisting){
24249         if(!keepExisting){
24250             this.clearSelections();
24251         }
24252         for(var i = 0, len = rows.length; i < len; i++){
24253             this.selectRow(rows[i], true);
24254         }
24255     },
24256
24257     /**
24258      * Selects a range of rows. All rows in between startRow and endRow are also selected.
24259      * @param {Number} startRow The index of the first row in the range
24260      * @param {Number} endRow The index of the last row in the range
24261      * @param {Boolean} keepExisting (optional) True to retain existing selections
24262      */
24263     selectRange : function(startRow, endRow, keepExisting){
24264         if(this.locked) {
24265             return;
24266         }
24267         if(!keepExisting){
24268             this.clearSelections();
24269         }
24270         if(startRow <= endRow){
24271             for(var i = startRow; i <= endRow; i++){
24272                 this.selectRow(i, true);
24273             }
24274         }else{
24275             for(var i = startRow; i >= endRow; i--){
24276                 this.selectRow(i, true);
24277             }
24278         }
24279     },
24280
24281     /**
24282      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24283      * @param {Number} startRow The index of the first row in the range
24284      * @param {Number} endRow The index of the last row in the range
24285      */
24286     deselectRange : function(startRow, endRow, preventViewNotify){
24287         if(this.locked) {
24288             return;
24289         }
24290         for(var i = startRow; i <= endRow; i++){
24291             this.deselectRow(i, preventViewNotify);
24292         }
24293     },
24294
24295     /**
24296      * Selects a row.
24297      * @param {Number} row The index of the row to select
24298      * @param {Boolean} keepExisting (optional) True to keep existing selections
24299      */
24300     selectRow : function(index, keepExisting, preventViewNotify)
24301     {
24302             if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24303             return;
24304         }
24305         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24306             if(!keepExisting || this.singleSelect){
24307                 this.clearSelections();
24308             }
24309             
24310             var r = this.grid.store.getAt(index);
24311             //console.log('selectRow - record id :' + r.id);
24312             
24313             this.selections.add(r);
24314             this.last = this.lastActive = index;
24315             if(!preventViewNotify){
24316                 var proxy = new Roo.Element(
24317                                 this.grid.getRowDom(index)
24318                 );
24319                 proxy.addClass('bg-info info');
24320             }
24321             this.fireEvent("rowselect", this, index, r);
24322             this.fireEvent("selectionchange", this);
24323         }
24324     },
24325
24326     /**
24327      * Deselects a row.
24328      * @param {Number} row The index of the row to deselect
24329      */
24330     deselectRow : function(index, preventViewNotify)
24331     {
24332         if(this.locked) {
24333             return;
24334         }
24335         if(this.last == index){
24336             this.last = false;
24337         }
24338         if(this.lastActive == index){
24339             this.lastActive = false;
24340         }
24341         
24342         var r = this.grid.store.getAt(index);
24343         if (!r) {
24344             return;
24345         }
24346         
24347         this.selections.remove(r);
24348         //.console.log('deselectRow - record id :' + r.id);
24349         if(!preventViewNotify){
24350         
24351             var proxy = new Roo.Element(
24352                 this.grid.getRowDom(index)
24353             );
24354             proxy.removeClass('bg-info info');
24355         }
24356         this.fireEvent("rowdeselect", this, index);
24357         this.fireEvent("selectionchange", this);
24358     },
24359
24360     // private
24361     restoreLast : function(){
24362         if(this._last){
24363             this.last = this._last;
24364         }
24365     },
24366
24367     // private
24368     acceptsNav : function(row, col, cm){
24369         return !cm.isHidden(col) && cm.isCellEditable(col, row);
24370     },
24371
24372     // private
24373     onEditorKey : function(field, e){
24374         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24375         if(k == e.TAB){
24376             e.stopEvent();
24377             ed.completeEdit();
24378             if(e.shiftKey){
24379                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24380             }else{
24381                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24382             }
24383         }else if(k == e.ENTER && !e.ctrlKey){
24384             e.stopEvent();
24385             ed.completeEdit();
24386             if(e.shiftKey){
24387                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24388             }else{
24389                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24390             }
24391         }else if(k == e.ESC){
24392             ed.cancelEdit();
24393         }
24394         if(newCell){
24395             g.startEditing(newCell[0], newCell[1]);
24396         }
24397     }
24398 });
24399 /*
24400  * Based on:
24401  * Ext JS Library 1.1.1
24402  * Copyright(c) 2006-2007, Ext JS, LLC.
24403  *
24404  * Originally Released Under LGPL - original licence link has changed is not relivant.
24405  *
24406  * Fork - LGPL
24407  * <script type="text/javascript">
24408  */
24409  
24410 /**
24411  * @class Roo.bootstrap.PagingToolbar
24412  * @extends Roo.bootstrap.NavSimplebar
24413  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24414  * @constructor
24415  * Create a new PagingToolbar
24416  * @param {Object} config The config object
24417  * @param {Roo.data.Store} store
24418  */
24419 Roo.bootstrap.PagingToolbar = function(config)
24420 {
24421     // old args format still supported... - xtype is prefered..
24422         // created from xtype...
24423     
24424     this.ds = config.dataSource;
24425     
24426     if (config.store && !this.ds) {
24427         this.store= Roo.factory(config.store, Roo.data);
24428         this.ds = this.store;
24429         this.ds.xmodule = this.xmodule || false;
24430     }
24431     
24432     this.toolbarItems = [];
24433     if (config.items) {
24434         this.toolbarItems = config.items;
24435     }
24436     
24437     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24438     
24439     this.cursor = 0;
24440     
24441     if (this.ds) { 
24442         this.bind(this.ds);
24443     }
24444     
24445     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24446     
24447 };
24448
24449 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24450     /**
24451      * @cfg {Roo.data.Store} dataSource
24452      * The underlying data store providing the paged data
24453      */
24454     /**
24455      * @cfg {String/HTMLElement/Element} container
24456      * container The id or element that will contain the toolbar
24457      */
24458     /**
24459      * @cfg {Boolean} displayInfo
24460      * True to display the displayMsg (defaults to false)
24461      */
24462     /**
24463      * @cfg {Number} pageSize
24464      * The number of records to display per page (defaults to 20)
24465      */
24466     pageSize: 20,
24467     /**
24468      * @cfg {String} displayMsg
24469      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24470      */
24471     displayMsg : 'Displaying {0} - {1} of {2}',
24472     /**
24473      * @cfg {String} emptyMsg
24474      * The message to display when no records are found (defaults to "No data to display")
24475      */
24476     emptyMsg : 'No data to display',
24477     /**
24478      * Customizable piece of the default paging text (defaults to "Page")
24479      * @type String
24480      */
24481     beforePageText : "Page",
24482     /**
24483      * Customizable piece of the default paging text (defaults to "of %0")
24484      * @type String
24485      */
24486     afterPageText : "of {0}",
24487     /**
24488      * Customizable piece of the default paging text (defaults to "First Page")
24489      * @type String
24490      */
24491     firstText : "First Page",
24492     /**
24493      * Customizable piece of the default paging text (defaults to "Previous Page")
24494      * @type String
24495      */
24496     prevText : "Previous Page",
24497     /**
24498      * Customizable piece of the default paging text (defaults to "Next Page")
24499      * @type String
24500      */
24501     nextText : "Next Page",
24502     /**
24503      * Customizable piece of the default paging text (defaults to "Last Page")
24504      * @type String
24505      */
24506     lastText : "Last Page",
24507     /**
24508      * Customizable piece of the default paging text (defaults to "Refresh")
24509      * @type String
24510      */
24511     refreshText : "Refresh",
24512
24513     buttons : false,
24514     // private
24515     onRender : function(ct, position) 
24516     {
24517         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24518         this.navgroup.parentId = this.id;
24519         this.navgroup.onRender(this.el, null);
24520         // add the buttons to the navgroup
24521         
24522         if(this.displayInfo){
24523             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24524             this.displayEl = this.el.select('.x-paging-info', true).first();
24525 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24526 //            this.displayEl = navel.el.select('span',true).first();
24527         }
24528         
24529         var _this = this;
24530         
24531         if(this.buttons){
24532             Roo.each(_this.buttons, function(e){ // this might need to use render????
24533                Roo.factory(e).render(_this.el);
24534             });
24535         }
24536             
24537         Roo.each(_this.toolbarItems, function(e) {
24538             _this.navgroup.addItem(e);
24539         });
24540         
24541         
24542         this.first = this.navgroup.addItem({
24543             tooltip: this.firstText,
24544             cls: "prev",
24545             icon : 'fa fa-backward',
24546             disabled: true,
24547             preventDefault: true,
24548             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24549         });
24550         
24551         this.prev =  this.navgroup.addItem({
24552             tooltip: this.prevText,
24553             cls: "prev",
24554             icon : 'fa fa-step-backward',
24555             disabled: true,
24556             preventDefault: true,
24557             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
24558         });
24559     //this.addSeparator();
24560         
24561         
24562         var field = this.navgroup.addItem( {
24563             tagtype : 'span',
24564             cls : 'x-paging-position',
24565             
24566             html : this.beforePageText  +
24567                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24568                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
24569          } ); //?? escaped?
24570         
24571         this.field = field.el.select('input', true).first();
24572         this.field.on("keydown", this.onPagingKeydown, this);
24573         this.field.on("focus", function(){this.dom.select();});
24574     
24575     
24576         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
24577         //this.field.setHeight(18);
24578         //this.addSeparator();
24579         this.next = this.navgroup.addItem({
24580             tooltip: this.nextText,
24581             cls: "next",
24582             html : ' <i class="fa fa-step-forward">',
24583             disabled: true,
24584             preventDefault: true,
24585             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
24586         });
24587         this.last = this.navgroup.addItem({
24588             tooltip: this.lastText,
24589             icon : 'fa fa-forward',
24590             cls: "next",
24591             disabled: true,
24592             preventDefault: true,
24593             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
24594         });
24595     //this.addSeparator();
24596         this.loading = this.navgroup.addItem({
24597             tooltip: this.refreshText,
24598             icon: 'fa fa-refresh',
24599             preventDefault: true,
24600             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24601         });
24602         
24603     },
24604
24605     // private
24606     updateInfo : function(){
24607         if(this.displayEl){
24608             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24609             var msg = count == 0 ?
24610                 this.emptyMsg :
24611                 String.format(
24612                     this.displayMsg,
24613                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
24614                 );
24615             this.displayEl.update(msg);
24616         }
24617     },
24618
24619     // private
24620     onLoad : function(ds, r, o)
24621     {
24622         this.cursor = o.params.start ? o.params.start : 0;
24623         
24624         var d = this.getPageData(),
24625             ap = d.activePage,
24626             ps = d.pages;
24627         
24628         
24629         this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24630         this.field.dom.value = ap;
24631         this.first.setDisabled(ap == 1);
24632         this.prev.setDisabled(ap == 1);
24633         this.next.setDisabled(ap == ps);
24634         this.last.setDisabled(ap == ps);
24635         this.loading.enable();
24636         this.updateInfo();
24637     },
24638
24639     // private
24640     getPageData : function(){
24641         var total = this.ds.getTotalCount();
24642         return {
24643             total : total,
24644             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24645             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24646         };
24647     },
24648
24649     // private
24650     onLoadError : function(){
24651         this.loading.enable();
24652     },
24653
24654     // private
24655     onPagingKeydown : function(e){
24656         var k = e.getKey();
24657         var d = this.getPageData();
24658         if(k == e.RETURN){
24659             var v = this.field.dom.value, pageNum;
24660             if(!v || isNaN(pageNum = parseInt(v, 10))){
24661                 this.field.dom.value = d.activePage;
24662                 return;
24663             }
24664             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24665             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24666             e.stopEvent();
24667         }
24668         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))
24669         {
24670           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24671           this.field.dom.value = pageNum;
24672           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24673           e.stopEvent();
24674         }
24675         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24676         {
24677           var v = this.field.dom.value, pageNum; 
24678           var increment = (e.shiftKey) ? 10 : 1;
24679           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24680                 increment *= -1;
24681           }
24682           if(!v || isNaN(pageNum = parseInt(v, 10))) {
24683             this.field.dom.value = d.activePage;
24684             return;
24685           }
24686           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24687           {
24688             this.field.dom.value = parseInt(v, 10) + increment;
24689             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24690             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24691           }
24692           e.stopEvent();
24693         }
24694     },
24695
24696     // private
24697     beforeLoad : function(){
24698         if(this.loading){
24699             this.loading.disable();
24700         }
24701     },
24702
24703     // private
24704     onClick : function(which){
24705         
24706         var ds = this.ds;
24707         if (!ds) {
24708             return;
24709         }
24710         
24711         switch(which){
24712             case "first":
24713                 ds.load({params:{start: 0, limit: this.pageSize}});
24714             break;
24715             case "prev":
24716                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24717             break;
24718             case "next":
24719                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24720             break;
24721             case "last":
24722                 var total = ds.getTotalCount();
24723                 var extra = total % this.pageSize;
24724                 var lastStart = extra ? (total - extra) : total-this.pageSize;
24725                 ds.load({params:{start: lastStart, limit: this.pageSize}});
24726             break;
24727             case "refresh":
24728                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24729             break;
24730         }
24731     },
24732
24733     /**
24734      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24735      * @param {Roo.data.Store} store The data store to unbind
24736      */
24737     unbind : function(ds){
24738         ds.un("beforeload", this.beforeLoad, this);
24739         ds.un("load", this.onLoad, this);
24740         ds.un("loadexception", this.onLoadError, this);
24741         ds.un("remove", this.updateInfo, this);
24742         ds.un("add", this.updateInfo, this);
24743         this.ds = undefined;
24744     },
24745
24746     /**
24747      * Binds the paging toolbar to the specified {@link Roo.data.Store}
24748      * @param {Roo.data.Store} store The data store to bind
24749      */
24750     bind : function(ds){
24751         ds.on("beforeload", this.beforeLoad, this);
24752         ds.on("load", this.onLoad, this);
24753         ds.on("loadexception", this.onLoadError, this);
24754         ds.on("remove", this.updateInfo, this);
24755         ds.on("add", this.updateInfo, this);
24756         this.ds = ds;
24757     }
24758 });/*
24759  * - LGPL
24760  *
24761  * element
24762  * 
24763  */
24764
24765 /**
24766  * @class Roo.bootstrap.MessageBar
24767  * @extends Roo.bootstrap.Component
24768  * Bootstrap MessageBar class
24769  * @cfg {String} html contents of the MessageBar
24770  * @cfg {String} weight (info | success | warning | danger) default info
24771  * @cfg {String} beforeClass insert the bar before the given class
24772  * @cfg {Boolean} closable (true | false) default false
24773  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24774  * 
24775  * @constructor
24776  * Create a new Element
24777  * @param {Object} config The config object
24778  */
24779
24780 Roo.bootstrap.MessageBar = function(config){
24781     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24782 };
24783
24784 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
24785     
24786     html: '',
24787     weight: 'info',
24788     closable: false,
24789     fixed: false,
24790     beforeClass: 'bootstrap-sticky-wrap',
24791     
24792     getAutoCreate : function(){
24793         
24794         var cfg = {
24795             tag: 'div',
24796             cls: 'alert alert-dismissable alert-' + this.weight,
24797             cn: [
24798                 {
24799                     tag: 'span',
24800                     cls: 'message',
24801                     html: this.html || ''
24802                 }
24803             ]
24804         };
24805         
24806         if(this.fixed){
24807             cfg.cls += ' alert-messages-fixed';
24808         }
24809         
24810         if(this.closable){
24811             cfg.cn.push({
24812                 tag: 'button',
24813                 cls: 'close',
24814                 html: 'x'
24815             });
24816         }
24817         
24818         return cfg;
24819     },
24820     
24821     onRender : function(ct, position)
24822     {
24823         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24824         
24825         if(!this.el){
24826             var cfg = Roo.apply({},  this.getAutoCreate());
24827             cfg.id = Roo.id();
24828             
24829             if (this.cls) {
24830                 cfg.cls += ' ' + this.cls;
24831             }
24832             if (this.style) {
24833                 cfg.style = this.style;
24834             }
24835             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24836             
24837             this.el.setVisibilityMode(Roo.Element.DISPLAY);
24838         }
24839         
24840         this.el.select('>button.close').on('click', this.hide, this);
24841         
24842     },
24843     
24844     show : function()
24845     {
24846         if (!this.rendered) {
24847             this.render();
24848         }
24849         
24850         this.el.show();
24851         
24852         this.fireEvent('show', this);
24853         
24854     },
24855     
24856     hide : function()
24857     {
24858         if (!this.rendered) {
24859             this.render();
24860         }
24861         
24862         this.el.hide();
24863         
24864         this.fireEvent('hide', this);
24865     },
24866     
24867     update : function()
24868     {
24869 //        var e = this.el.dom.firstChild;
24870 //        
24871 //        if(this.closable){
24872 //            e = e.nextSibling;
24873 //        }
24874 //        
24875 //        e.data = this.html || '';
24876
24877         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24878     }
24879    
24880 });
24881
24882  
24883
24884      /*
24885  * - LGPL
24886  *
24887  * Graph
24888  * 
24889  */
24890
24891
24892 /**
24893  * @class Roo.bootstrap.Graph
24894  * @extends Roo.bootstrap.Component
24895  * Bootstrap Graph class
24896 > Prameters
24897  -sm {number} sm 4
24898  -md {number} md 5
24899  @cfg {String} graphtype  bar | vbar | pie
24900  @cfg {number} g_x coodinator | centre x (pie)
24901  @cfg {number} g_y coodinator | centre y (pie)
24902  @cfg {number} g_r radius (pie)
24903  @cfg {number} g_height height of the chart (respected by all elements in the set)
24904  @cfg {number} g_width width of the chart (respected by all elements in the set)
24905  @cfg {Object} title The title of the chart
24906     
24907  -{Array}  values
24908  -opts (object) options for the chart 
24909      o {
24910      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24911      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24912      o vgutter (number)
24913      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.
24914      o stacked (boolean) whether or not to tread values as in a stacked bar chart
24915      o to
24916      o stretch (boolean)
24917      o }
24918  -opts (object) options for the pie
24919      o{
24920      o cut
24921      o startAngle (number)
24922      o endAngle (number)
24923      } 
24924  *
24925  * @constructor
24926  * Create a new Input
24927  * @param {Object} config The config object
24928  */
24929
24930 Roo.bootstrap.Graph = function(config){
24931     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24932     
24933     this.addEvents({
24934         // img events
24935         /**
24936          * @event click
24937          * The img click event for the img.
24938          * @param {Roo.EventObject} e
24939          */
24940         "click" : true
24941     });
24942 };
24943
24944 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
24945     
24946     sm: 4,
24947     md: 5,
24948     graphtype: 'bar',
24949     g_height: 250,
24950     g_width: 400,
24951     g_x: 50,
24952     g_y: 50,
24953     g_r: 30,
24954     opts:{
24955         //g_colors: this.colors,
24956         g_type: 'soft',
24957         g_gutter: '20%'
24958
24959     },
24960     title : false,
24961
24962     getAutoCreate : function(){
24963         
24964         var cfg = {
24965             tag: 'div',
24966             html : null
24967         };
24968         
24969         
24970         return  cfg;
24971     },
24972
24973     onRender : function(ct,position){
24974         
24975         
24976         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24977         
24978         if (typeof(Raphael) == 'undefined') {
24979             Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24980             return;
24981         }
24982         
24983         this.raphael = Raphael(this.el.dom);
24984         
24985                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24986                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24987                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24988                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24989                 /*
24990                 r.text(160, 10, "Single Series Chart").attr(txtattr);
24991                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24992                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24993                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24994                 
24995                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24996                 r.barchart(330, 10, 300, 220, data1);
24997                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24998                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24999                 */
25000                 
25001                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25002                 // r.barchart(30, 30, 560, 250,  xdata, {
25003                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25004                 //     axis : "0 0 1 1",
25005                 //     axisxlabels :  xdata
25006                 //     //yvalues : cols,
25007                    
25008                 // });
25009 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25010 //        
25011 //        this.load(null,xdata,{
25012 //                axis : "0 0 1 1",
25013 //                axisxlabels :  xdata
25014 //                });
25015
25016     },
25017
25018     load : function(graphtype,xdata,opts)
25019     {
25020         this.raphael.clear();
25021         if(!graphtype) {
25022             graphtype = this.graphtype;
25023         }
25024         if(!opts){
25025             opts = this.opts;
25026         }
25027         var r = this.raphael,
25028             fin = function () {
25029                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25030             },
25031             fout = function () {
25032                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25033             },
25034             pfin = function() {
25035                 this.sector.stop();
25036                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25037
25038                 if (this.label) {
25039                     this.label[0].stop();
25040                     this.label[0].attr({ r: 7.5 });
25041                     this.label[1].attr({ "font-weight": 800 });
25042                 }
25043             },
25044             pfout = function() {
25045                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25046
25047                 if (this.label) {
25048                     this.label[0].animate({ r: 5 }, 500, "bounce");
25049                     this.label[1].attr({ "font-weight": 400 });
25050                 }
25051             };
25052
25053         switch(graphtype){
25054             case 'bar':
25055                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25056                 break;
25057             case 'hbar':
25058                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25059                 break;
25060             case 'pie':
25061 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
25062 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25063 //            
25064                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25065                 
25066                 break;
25067
25068         }
25069         
25070         if(this.title){
25071             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25072         }
25073         
25074     },
25075     
25076     setTitle: function(o)
25077     {
25078         this.title = o;
25079     },
25080     
25081     initEvents: function() {
25082         
25083         if(!this.href){
25084             this.el.on('click', this.onClick, this);
25085         }
25086     },
25087     
25088     onClick : function(e)
25089     {
25090         Roo.log('img onclick');
25091         this.fireEvent('click', this, e);
25092     }
25093    
25094 });
25095
25096  
25097 /*
25098  * - LGPL
25099  *
25100  * numberBox
25101  * 
25102  */
25103 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25104
25105 /**
25106  * @class Roo.bootstrap.dash.NumberBox
25107  * @extends Roo.bootstrap.Component
25108  * Bootstrap NumberBox class
25109  * @cfg {String} headline Box headline
25110  * @cfg {String} content Box content
25111  * @cfg {String} icon Box icon
25112  * @cfg {String} footer Footer text
25113  * @cfg {String} fhref Footer href
25114  * 
25115  * @constructor
25116  * Create a new NumberBox
25117  * @param {Object} config The config object
25118  */
25119
25120
25121 Roo.bootstrap.dash.NumberBox = function(config){
25122     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25123     
25124 };
25125
25126 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
25127     
25128     headline : '',
25129     content : '',
25130     icon : '',
25131     footer : '',
25132     fhref : '',
25133     ficon : '',
25134     
25135     getAutoCreate : function(){
25136         
25137         var cfg = {
25138             tag : 'div',
25139             cls : 'small-box ',
25140             cn : [
25141                 {
25142                     tag : 'div',
25143                     cls : 'inner',
25144                     cn :[
25145                         {
25146                             tag : 'h3',
25147                             cls : 'roo-headline',
25148                             html : this.headline
25149                         },
25150                         {
25151                             tag : 'p',
25152                             cls : 'roo-content',
25153                             html : this.content
25154                         }
25155                     ]
25156                 }
25157             ]
25158         };
25159         
25160         if(this.icon){
25161             cfg.cn.push({
25162                 tag : 'div',
25163                 cls : 'icon',
25164                 cn :[
25165                     {
25166                         tag : 'i',
25167                         cls : 'ion ' + this.icon
25168                     }
25169                 ]
25170             });
25171         }
25172         
25173         if(this.footer){
25174             var footer = {
25175                 tag : 'a',
25176                 cls : 'small-box-footer',
25177                 href : this.fhref || '#',
25178                 html : this.footer
25179             };
25180             
25181             cfg.cn.push(footer);
25182             
25183         }
25184         
25185         return  cfg;
25186     },
25187
25188     onRender : function(ct,position){
25189         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25190
25191
25192        
25193                 
25194     },
25195
25196     setHeadline: function (value)
25197     {
25198         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25199     },
25200     
25201     setFooter: function (value, href)
25202     {
25203         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25204         
25205         if(href){
25206             this.el.select('a.small-box-footer',true).first().attr('href', href);
25207         }
25208         
25209     },
25210
25211     setContent: function (value)
25212     {
25213         this.el.select('.roo-content',true).first().dom.innerHTML = value;
25214     },
25215
25216     initEvents: function() 
25217     {   
25218         
25219     }
25220     
25221 });
25222
25223  
25224 /*
25225  * - LGPL
25226  *
25227  * TabBox
25228  * 
25229  */
25230 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25231
25232 /**
25233  * @class Roo.bootstrap.dash.TabBox
25234  * @extends Roo.bootstrap.Component
25235  * Bootstrap TabBox class
25236  * @cfg {String} title Title of the TabBox
25237  * @cfg {String} icon Icon of the TabBox
25238  * @cfg {Boolean} showtabs (true|false) show the tabs default true
25239  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25240  * 
25241  * @constructor
25242  * Create a new TabBox
25243  * @param {Object} config The config object
25244  */
25245
25246
25247 Roo.bootstrap.dash.TabBox = function(config){
25248     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25249     this.addEvents({
25250         // raw events
25251         /**
25252          * @event addpane
25253          * When a pane is added
25254          * @param {Roo.bootstrap.dash.TabPane} pane
25255          */
25256         "addpane" : true,
25257         /**
25258          * @event activatepane
25259          * When a pane is activated
25260          * @param {Roo.bootstrap.dash.TabPane} pane
25261          */
25262         "activatepane" : true
25263         
25264          
25265     });
25266     
25267     this.panes = [];
25268 };
25269
25270 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
25271
25272     title : '',
25273     icon : false,
25274     showtabs : true,
25275     tabScrollable : false,
25276     
25277     getChildContainer : function()
25278     {
25279         return this.el.select('.tab-content', true).first();
25280     },
25281     
25282     getAutoCreate : function(){
25283         
25284         var header = {
25285             tag: 'li',
25286             cls: 'pull-left header',
25287             html: this.title,
25288             cn : []
25289         };
25290         
25291         if(this.icon){
25292             header.cn.push({
25293                 tag: 'i',
25294                 cls: 'fa ' + this.icon
25295             });
25296         }
25297         
25298         var h = {
25299             tag: 'ul',
25300             cls: 'nav nav-tabs pull-right',
25301             cn: [
25302                 header
25303             ]
25304         };
25305         
25306         if(this.tabScrollable){
25307             h = {
25308                 tag: 'div',
25309                 cls: 'tab-header',
25310                 cn: [
25311                     {
25312                         tag: 'ul',
25313                         cls: 'nav nav-tabs pull-right',
25314                         cn: [
25315                             header
25316                         ]
25317                     }
25318                 ]
25319             };
25320         }
25321         
25322         var cfg = {
25323             tag: 'div',
25324             cls: 'nav-tabs-custom',
25325             cn: [
25326                 h,
25327                 {
25328                     tag: 'div',
25329                     cls: 'tab-content no-padding',
25330                     cn: []
25331                 }
25332             ]
25333         };
25334
25335         return  cfg;
25336     },
25337     initEvents : function()
25338     {
25339         //Roo.log('add add pane handler');
25340         this.on('addpane', this.onAddPane, this);
25341     },
25342      /**
25343      * Updates the box title
25344      * @param {String} html to set the title to.
25345      */
25346     setTitle : function(value)
25347     {
25348         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25349     },
25350     onAddPane : function(pane)
25351     {
25352         this.panes.push(pane);
25353         //Roo.log('addpane');
25354         //Roo.log(pane);
25355         // tabs are rendere left to right..
25356         if(!this.showtabs){
25357             return;
25358         }
25359         
25360         var ctr = this.el.select('.nav-tabs', true).first();
25361          
25362          
25363         var existing = ctr.select('.nav-tab',true);
25364         var qty = existing.getCount();;
25365         
25366         
25367         var tab = ctr.createChild({
25368             tag : 'li',
25369             cls : 'nav-tab' + (qty ? '' : ' active'),
25370             cn : [
25371                 {
25372                     tag : 'a',
25373                     href:'#',
25374                     html : pane.title
25375                 }
25376             ]
25377         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25378         pane.tab = tab;
25379         
25380         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25381         if (!qty) {
25382             pane.el.addClass('active');
25383         }
25384         
25385                 
25386     },
25387     onTabClick : function(ev,un,ob,pane)
25388     {
25389         //Roo.log('tab - prev default');
25390         ev.preventDefault();
25391         
25392         
25393         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25394         pane.tab.addClass('active');
25395         //Roo.log(pane.title);
25396         this.getChildContainer().select('.tab-pane',true).removeClass('active');
25397         // technically we should have a deactivate event.. but maybe add later.
25398         // and it should not de-activate the selected tab...
25399         this.fireEvent('activatepane', pane);
25400         pane.el.addClass('active');
25401         pane.fireEvent('activate');
25402         
25403         
25404     },
25405     
25406     getActivePane : function()
25407     {
25408         var r = false;
25409         Roo.each(this.panes, function(p) {
25410             if(p.el.hasClass('active')){
25411                 r = p;
25412                 return false;
25413             }
25414             
25415             return;
25416         });
25417         
25418         return r;
25419     }
25420     
25421     
25422 });
25423
25424  
25425 /*
25426  * - LGPL
25427  *
25428  * Tab pane
25429  * 
25430  */
25431 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25432 /**
25433  * @class Roo.bootstrap.TabPane
25434  * @extends Roo.bootstrap.Component
25435  * Bootstrap TabPane class
25436  * @cfg {Boolean} active (false | true) Default false
25437  * @cfg {String} title title of panel
25438
25439  * 
25440  * @constructor
25441  * Create a new TabPane
25442  * @param {Object} config The config object
25443  */
25444
25445 Roo.bootstrap.dash.TabPane = function(config){
25446     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25447     
25448     this.addEvents({
25449         // raw events
25450         /**
25451          * @event activate
25452          * When a pane is activated
25453          * @param {Roo.bootstrap.dash.TabPane} pane
25454          */
25455         "activate" : true
25456          
25457     });
25458 };
25459
25460 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
25461     
25462     active : false,
25463     title : '',
25464     
25465     // the tabBox that this is attached to.
25466     tab : false,
25467      
25468     getAutoCreate : function() 
25469     {
25470         var cfg = {
25471             tag: 'div',
25472             cls: 'tab-pane'
25473         };
25474         
25475         if(this.active){
25476             cfg.cls += ' active';
25477         }
25478         
25479         return cfg;
25480     },
25481     initEvents  : function()
25482     {
25483         //Roo.log('trigger add pane handler');
25484         this.parent().fireEvent('addpane', this)
25485     },
25486     
25487      /**
25488      * Updates the tab title 
25489      * @param {String} html to set the title to.
25490      */
25491     setTitle: function(str)
25492     {
25493         if (!this.tab) {
25494             return;
25495         }
25496         this.title = str;
25497         this.tab.select('a', true).first().dom.innerHTML = str;
25498         
25499     }
25500     
25501     
25502     
25503 });
25504
25505  
25506
25507
25508  /*
25509  * - LGPL
25510  *
25511  * menu
25512  * 
25513  */
25514 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25515
25516 /**
25517  * @class Roo.bootstrap.menu.Menu
25518  * @extends Roo.bootstrap.Component
25519  * Bootstrap Menu class - container for Menu
25520  * @cfg {String} html Text of the menu
25521  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25522  * @cfg {String} icon Font awesome icon
25523  * @cfg {String} pos Menu align to (top | bottom) default bottom
25524  * 
25525  * 
25526  * @constructor
25527  * Create a new Menu
25528  * @param {Object} config The config object
25529  */
25530
25531
25532 Roo.bootstrap.menu.Menu = function(config){
25533     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25534     
25535     this.addEvents({
25536         /**
25537          * @event beforeshow
25538          * Fires before this menu is displayed
25539          * @param {Roo.bootstrap.menu.Menu} this
25540          */
25541         beforeshow : true,
25542         /**
25543          * @event beforehide
25544          * Fires before this menu is hidden
25545          * @param {Roo.bootstrap.menu.Menu} this
25546          */
25547         beforehide : true,
25548         /**
25549          * @event show
25550          * Fires after this menu is displayed
25551          * @param {Roo.bootstrap.menu.Menu} this
25552          */
25553         show : true,
25554         /**
25555          * @event hide
25556          * Fires after this menu is hidden
25557          * @param {Roo.bootstrap.menu.Menu} this
25558          */
25559         hide : true,
25560         /**
25561          * @event click
25562          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25563          * @param {Roo.bootstrap.menu.Menu} this
25564          * @param {Roo.EventObject} e
25565          */
25566         click : true
25567     });
25568     
25569 };
25570
25571 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
25572     
25573     submenu : false,
25574     html : '',
25575     weight : 'default',
25576     icon : false,
25577     pos : 'bottom',
25578     
25579     
25580     getChildContainer : function() {
25581         if(this.isSubMenu){
25582             return this.el;
25583         }
25584         
25585         return this.el.select('ul.dropdown-menu', true).first();  
25586     },
25587     
25588     getAutoCreate : function()
25589     {
25590         var text = [
25591             {
25592                 tag : 'span',
25593                 cls : 'roo-menu-text',
25594                 html : this.html
25595             }
25596         ];
25597         
25598         if(this.icon){
25599             text.unshift({
25600                 tag : 'i',
25601                 cls : 'fa ' + this.icon
25602             })
25603         }
25604         
25605         
25606         var cfg = {
25607             tag : 'div',
25608             cls : 'btn-group',
25609             cn : [
25610                 {
25611                     tag : 'button',
25612                     cls : 'dropdown-button btn btn-' + this.weight,
25613                     cn : text
25614                 },
25615                 {
25616                     tag : 'button',
25617                     cls : 'dropdown-toggle btn btn-' + this.weight,
25618                     cn : [
25619                         {
25620                             tag : 'span',
25621                             cls : 'caret'
25622                         }
25623                     ]
25624                 },
25625                 {
25626                     tag : 'ul',
25627                     cls : 'dropdown-menu'
25628                 }
25629             ]
25630             
25631         };
25632         
25633         if(this.pos == 'top'){
25634             cfg.cls += ' dropup';
25635         }
25636         
25637         if(this.isSubMenu){
25638             cfg = {
25639                 tag : 'ul',
25640                 cls : 'dropdown-menu'
25641             }
25642         }
25643         
25644         return cfg;
25645     },
25646     
25647     onRender : function(ct, position)
25648     {
25649         this.isSubMenu = ct.hasClass('dropdown-submenu');
25650         
25651         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25652     },
25653     
25654     initEvents : function() 
25655     {
25656         if(this.isSubMenu){
25657             return;
25658         }
25659         
25660         this.hidden = true;
25661         
25662         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25663         this.triggerEl.on('click', this.onTriggerPress, this);
25664         
25665         this.buttonEl = this.el.select('button.dropdown-button', true).first();
25666         this.buttonEl.on('click', this.onClick, this);
25667         
25668     },
25669     
25670     list : function()
25671     {
25672         if(this.isSubMenu){
25673             return this.el;
25674         }
25675         
25676         return this.el.select('ul.dropdown-menu', true).first();
25677     },
25678     
25679     onClick : function(e)
25680     {
25681         this.fireEvent("click", this, e);
25682     },
25683     
25684     onTriggerPress  : function(e)
25685     {   
25686         if (this.isVisible()) {
25687             this.hide();
25688         } else {
25689             this.show();
25690         }
25691     },
25692     
25693     isVisible : function(){
25694         return !this.hidden;
25695     },
25696     
25697     show : function()
25698     {
25699         this.fireEvent("beforeshow", this);
25700         
25701         this.hidden = false;
25702         this.el.addClass('open');
25703         
25704         Roo.get(document).on("mouseup", this.onMouseUp, this);
25705         
25706         this.fireEvent("show", this);
25707         
25708         
25709     },
25710     
25711     hide : function()
25712     {
25713         this.fireEvent("beforehide", this);
25714         
25715         this.hidden = true;
25716         this.el.removeClass('open');
25717         
25718         Roo.get(document).un("mouseup", this.onMouseUp);
25719         
25720         this.fireEvent("hide", this);
25721     },
25722     
25723     onMouseUp : function()
25724     {
25725         this.hide();
25726     }
25727     
25728 });
25729
25730  
25731  /*
25732  * - LGPL
25733  *
25734  * menu item
25735  * 
25736  */
25737 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25738
25739 /**
25740  * @class Roo.bootstrap.menu.Item
25741  * @extends Roo.bootstrap.Component
25742  * Bootstrap MenuItem class
25743  * @cfg {Boolean} submenu (true | false) default false
25744  * @cfg {String} html text of the item
25745  * @cfg {String} href the link
25746  * @cfg {Boolean} disable (true | false) default false
25747  * @cfg {Boolean} preventDefault (true | false) default true
25748  * @cfg {String} icon Font awesome icon
25749  * @cfg {String} pos Submenu align to (left | right) default right 
25750  * 
25751  * 
25752  * @constructor
25753  * Create a new Item
25754  * @param {Object} config The config object
25755  */
25756
25757
25758 Roo.bootstrap.menu.Item = function(config){
25759     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25760     this.addEvents({
25761         /**
25762          * @event mouseover
25763          * Fires when the mouse is hovering over this menu
25764          * @param {Roo.bootstrap.menu.Item} this
25765          * @param {Roo.EventObject} e
25766          */
25767         mouseover : true,
25768         /**
25769          * @event mouseout
25770          * Fires when the mouse exits this menu
25771          * @param {Roo.bootstrap.menu.Item} this
25772          * @param {Roo.EventObject} e
25773          */
25774         mouseout : true,
25775         // raw events
25776         /**
25777          * @event click
25778          * The raw click event for the entire grid.
25779          * @param {Roo.EventObject} e
25780          */
25781         click : true
25782     });
25783 };
25784
25785 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
25786     
25787     submenu : false,
25788     href : '',
25789     html : '',
25790     preventDefault: true,
25791     disable : false,
25792     icon : false,
25793     pos : 'right',
25794     
25795     getAutoCreate : function()
25796     {
25797         var text = [
25798             {
25799                 tag : 'span',
25800                 cls : 'roo-menu-item-text',
25801                 html : this.html
25802             }
25803         ];
25804         
25805         if(this.icon){
25806             text.unshift({
25807                 tag : 'i',
25808                 cls : 'fa ' + this.icon
25809             })
25810         }
25811         
25812         var cfg = {
25813             tag : 'li',
25814             cn : [
25815                 {
25816                     tag : 'a',
25817                     href : this.href || '#',
25818                     cn : text
25819                 }
25820             ]
25821         };
25822         
25823         if(this.disable){
25824             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25825         }
25826         
25827         if(this.submenu){
25828             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25829             
25830             if(this.pos == 'left'){
25831                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25832             }
25833         }
25834         
25835         return cfg;
25836     },
25837     
25838     initEvents : function() 
25839     {
25840         this.el.on('mouseover', this.onMouseOver, this);
25841         this.el.on('mouseout', this.onMouseOut, this);
25842         
25843         this.el.select('a', true).first().on('click', this.onClick, this);
25844         
25845     },
25846     
25847     onClick : function(e)
25848     {
25849         if(this.preventDefault){
25850             e.preventDefault();
25851         }
25852         
25853         this.fireEvent("click", this, e);
25854     },
25855     
25856     onMouseOver : function(e)
25857     {
25858         if(this.submenu && this.pos == 'left'){
25859             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25860         }
25861         
25862         this.fireEvent("mouseover", this, e);
25863     },
25864     
25865     onMouseOut : function(e)
25866     {
25867         this.fireEvent("mouseout", this, e);
25868     }
25869 });
25870
25871  
25872
25873  /*
25874  * - LGPL
25875  *
25876  * menu separator
25877  * 
25878  */
25879 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25880
25881 /**
25882  * @class Roo.bootstrap.menu.Separator
25883  * @extends Roo.bootstrap.Component
25884  * Bootstrap Separator class
25885  * 
25886  * @constructor
25887  * Create a new Separator
25888  * @param {Object} config The config object
25889  */
25890
25891
25892 Roo.bootstrap.menu.Separator = function(config){
25893     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25894 };
25895
25896 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
25897     
25898     getAutoCreate : function(){
25899         var cfg = {
25900             tag : 'li',
25901             cls: 'divider'
25902         };
25903         
25904         return cfg;
25905     }
25906    
25907 });
25908
25909  
25910
25911  /*
25912  * - LGPL
25913  *
25914  * Tooltip
25915  * 
25916  */
25917
25918 /**
25919  * @class Roo.bootstrap.Tooltip
25920  * Bootstrap Tooltip class
25921  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25922  * to determine which dom element triggers the tooltip.
25923  * 
25924  * It needs to add support for additional attributes like tooltip-position
25925  * 
25926  * @constructor
25927  * Create a new Toolti
25928  * @param {Object} config The config object
25929  */
25930
25931 Roo.bootstrap.Tooltip = function(config){
25932     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25933     
25934     this.alignment = Roo.bootstrap.Tooltip.alignment;
25935     
25936     if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25937         this.alignment = config.alignment;
25938     }
25939     
25940 };
25941
25942 Roo.apply(Roo.bootstrap.Tooltip, {
25943     /**
25944      * @function init initialize tooltip monitoring.
25945      * @static
25946      */
25947     currentEl : false,
25948     currentTip : false,
25949     currentRegion : false,
25950     
25951     //  init : delay?
25952     
25953     init : function()
25954     {
25955         Roo.get(document).on('mouseover', this.enter ,this);
25956         Roo.get(document).on('mouseout', this.leave, this);
25957          
25958         
25959         this.currentTip = new Roo.bootstrap.Tooltip();
25960     },
25961     
25962     enter : function(ev)
25963     {
25964         var dom = ev.getTarget();
25965         
25966         //Roo.log(['enter',dom]);
25967         var el = Roo.fly(dom);
25968         if (this.currentEl) {
25969             //Roo.log(dom);
25970             //Roo.log(this.currentEl);
25971             //Roo.log(this.currentEl.contains(dom));
25972             if (this.currentEl == el) {
25973                 return;
25974             }
25975             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25976                 return;
25977             }
25978
25979         }
25980         
25981         if (this.currentTip.el) {
25982             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25983         }    
25984         //Roo.log(ev);
25985         
25986         if(!el || el.dom == document){
25987             return;
25988         }
25989         
25990         var bindEl = el;
25991         
25992         // you can not look for children, as if el is the body.. then everythign is the child..
25993         if (!el.attr('tooltip')) { //
25994             if (!el.select("[tooltip]").elements.length) {
25995                 return;
25996             }
25997             // is the mouse over this child...?
25998             bindEl = el.select("[tooltip]").first();
25999             var xy = ev.getXY();
26000             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26001                 //Roo.log("not in region.");
26002                 return;
26003             }
26004             //Roo.log("child element over..");
26005             
26006         }
26007         this.currentEl = bindEl;
26008         this.currentTip.bind(bindEl);
26009         this.currentRegion = Roo.lib.Region.getRegion(dom);
26010         this.currentTip.enter();
26011         
26012     },
26013     leave : function(ev)
26014     {
26015         var dom = ev.getTarget();
26016         //Roo.log(['leave',dom]);
26017         if (!this.currentEl) {
26018             return;
26019         }
26020         
26021         
26022         if (dom != this.currentEl.dom) {
26023             return;
26024         }
26025         var xy = ev.getXY();
26026         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
26027             return;
26028         }
26029         // only activate leave if mouse cursor is outside... bounding box..
26030         
26031         
26032         
26033         
26034         if (this.currentTip) {
26035             this.currentTip.leave();
26036         }
26037         //Roo.log('clear currentEl');
26038         this.currentEl = false;
26039         
26040         
26041     },
26042     alignment : {
26043         'left' : ['r-l', [-2,0], 'right'],
26044         'right' : ['l-r', [2,0], 'left'],
26045         'bottom' : ['t-b', [0,2], 'top'],
26046         'top' : [ 'b-t', [0,-2], 'bottom']
26047     }
26048     
26049 });
26050
26051
26052 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
26053     
26054     
26055     bindEl : false,
26056     
26057     delay : null, // can be { show : 300 , hide: 500}
26058     
26059     timeout : null,
26060     
26061     hoverState : null, //???
26062     
26063     placement : 'bottom', 
26064     
26065     alignment : false,
26066     
26067     getAutoCreate : function(){
26068     
26069         var cfg = {
26070            cls : 'tooltip',
26071            role : 'tooltip',
26072            cn : [
26073                 {
26074                     cls : 'tooltip-arrow'
26075                 },
26076                 {
26077                     cls : 'tooltip-inner'
26078                 }
26079            ]
26080         };
26081         
26082         return cfg;
26083     },
26084     bind : function(el)
26085     {
26086         this.bindEl = el;
26087     },
26088       
26089     
26090     enter : function () {
26091        
26092         if (this.timeout != null) {
26093             clearTimeout(this.timeout);
26094         }
26095         
26096         this.hoverState = 'in';
26097          //Roo.log("enter - show");
26098         if (!this.delay || !this.delay.show) {
26099             this.show();
26100             return;
26101         }
26102         var _t = this;
26103         this.timeout = setTimeout(function () {
26104             if (_t.hoverState == 'in') {
26105                 _t.show();
26106             }
26107         }, this.delay.show);
26108     },
26109     leave : function()
26110     {
26111         clearTimeout(this.timeout);
26112     
26113         this.hoverState = 'out';
26114          if (!this.delay || !this.delay.hide) {
26115             this.hide();
26116             return;
26117         }
26118        
26119         var _t = this;
26120         this.timeout = setTimeout(function () {
26121             //Roo.log("leave - timeout");
26122             
26123             if (_t.hoverState == 'out') {
26124                 _t.hide();
26125                 Roo.bootstrap.Tooltip.currentEl = false;
26126             }
26127         }, delay);
26128     },
26129     
26130     show : function (msg)
26131     {
26132         if (!this.el) {
26133             this.render(document.body);
26134         }
26135         // set content.
26136         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26137         
26138         var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26139         
26140         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26141         
26142         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26143         
26144         var placement = typeof this.placement == 'function' ?
26145             this.placement.call(this, this.el, on_el) :
26146             this.placement;
26147             
26148         var autoToken = /\s?auto?\s?/i;
26149         var autoPlace = autoToken.test(placement);
26150         if (autoPlace) {
26151             placement = placement.replace(autoToken, '') || 'top';
26152         }
26153         
26154         //this.el.detach()
26155         //this.el.setXY([0,0]);
26156         this.el.show();
26157         //this.el.dom.style.display='block';
26158         
26159         //this.el.appendTo(on_el);
26160         
26161         var p = this.getPosition();
26162         var box = this.el.getBox();
26163         
26164         if (autoPlace) {
26165             // fixme..
26166         }
26167         
26168         var align = this.alignment[placement];
26169         
26170         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26171         
26172         if(placement == 'top' || placement == 'bottom'){
26173             if(xy[0] < 0){
26174                 placement = 'right';
26175             }
26176             
26177             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26178                 placement = 'left';
26179             }
26180             
26181             var scroll = Roo.select('body', true).first().getScroll();
26182             
26183             if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26184                 placement = 'top';
26185             }
26186             
26187         }
26188         
26189         this.el.alignTo(this.bindEl, align[0],align[1]);
26190         //var arrow = this.el.select('.arrow',true).first();
26191         //arrow.set(align[2], 
26192         
26193         this.el.addClass(placement);
26194         
26195         this.el.addClass('in fade');
26196         
26197         this.hoverState = null;
26198         
26199         if (this.el.hasClass('fade')) {
26200             // fade it?
26201         }
26202         
26203     },
26204     hide : function()
26205     {
26206          
26207         if (!this.el) {
26208             return;
26209         }
26210         //this.el.setXY([0,0]);
26211         this.el.removeClass('in');
26212         //this.el.hide();
26213         
26214     }
26215     
26216 });
26217  
26218
26219  /*
26220  * - LGPL
26221  *
26222  * Location Picker
26223  * 
26224  */
26225
26226 /**
26227  * @class Roo.bootstrap.LocationPicker
26228  * @extends Roo.bootstrap.Component
26229  * Bootstrap LocationPicker class
26230  * @cfg {Number} latitude Position when init default 0
26231  * @cfg {Number} longitude Position when init default 0
26232  * @cfg {Number} zoom default 15
26233  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26234  * @cfg {Boolean} mapTypeControl default false
26235  * @cfg {Boolean} disableDoubleClickZoom default false
26236  * @cfg {Boolean} scrollwheel default true
26237  * @cfg {Boolean} streetViewControl default false
26238  * @cfg {Number} radius default 0
26239  * @cfg {String} locationName
26240  * @cfg {Boolean} draggable default true
26241  * @cfg {Boolean} enableAutocomplete default false
26242  * @cfg {Boolean} enableReverseGeocode default true
26243  * @cfg {String} markerTitle
26244  * 
26245  * @constructor
26246  * Create a new LocationPicker
26247  * @param {Object} config The config object
26248  */
26249
26250
26251 Roo.bootstrap.LocationPicker = function(config){
26252     
26253     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26254     
26255     this.addEvents({
26256         /**
26257          * @event initial
26258          * Fires when the picker initialized.
26259          * @param {Roo.bootstrap.LocationPicker} this
26260          * @param {Google Location} location
26261          */
26262         initial : true,
26263         /**
26264          * @event positionchanged
26265          * Fires when the picker position changed.
26266          * @param {Roo.bootstrap.LocationPicker} this
26267          * @param {Google Location} location
26268          */
26269         positionchanged : true,
26270         /**
26271          * @event resize
26272          * Fires when the map resize.
26273          * @param {Roo.bootstrap.LocationPicker} this
26274          */
26275         resize : true,
26276         /**
26277          * @event show
26278          * Fires when the map show.
26279          * @param {Roo.bootstrap.LocationPicker} this
26280          */
26281         show : true,
26282         /**
26283          * @event hide
26284          * Fires when the map hide.
26285          * @param {Roo.bootstrap.LocationPicker} this
26286          */
26287         hide : true,
26288         /**
26289          * @event mapClick
26290          * Fires when click the map.
26291          * @param {Roo.bootstrap.LocationPicker} this
26292          * @param {Map event} e
26293          */
26294         mapClick : true,
26295         /**
26296          * @event mapRightClick
26297          * Fires when right click the map.
26298          * @param {Roo.bootstrap.LocationPicker} this
26299          * @param {Map event} e
26300          */
26301         mapRightClick : true,
26302         /**
26303          * @event markerClick
26304          * Fires when click the marker.
26305          * @param {Roo.bootstrap.LocationPicker} this
26306          * @param {Map event} e
26307          */
26308         markerClick : true,
26309         /**
26310          * @event markerRightClick
26311          * Fires when right click the marker.
26312          * @param {Roo.bootstrap.LocationPicker} this
26313          * @param {Map event} e
26314          */
26315         markerRightClick : true,
26316         /**
26317          * @event OverlayViewDraw
26318          * Fires when OverlayView Draw
26319          * @param {Roo.bootstrap.LocationPicker} this
26320          */
26321         OverlayViewDraw : true,
26322         /**
26323          * @event OverlayViewOnAdd
26324          * Fires when OverlayView Draw
26325          * @param {Roo.bootstrap.LocationPicker} this
26326          */
26327         OverlayViewOnAdd : true,
26328         /**
26329          * @event OverlayViewOnRemove
26330          * Fires when OverlayView Draw
26331          * @param {Roo.bootstrap.LocationPicker} this
26332          */
26333         OverlayViewOnRemove : true,
26334         /**
26335          * @event OverlayViewShow
26336          * Fires when OverlayView Draw
26337          * @param {Roo.bootstrap.LocationPicker} this
26338          * @param {Pixel} cpx
26339          */
26340         OverlayViewShow : true,
26341         /**
26342          * @event OverlayViewHide
26343          * Fires when OverlayView Draw
26344          * @param {Roo.bootstrap.LocationPicker} this
26345          */
26346         OverlayViewHide : true,
26347         /**
26348          * @event loadexception
26349          * Fires when load google lib failed.
26350          * @param {Roo.bootstrap.LocationPicker} this
26351          */
26352         loadexception : true
26353     });
26354         
26355 };
26356
26357 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
26358     
26359     gMapContext: false,
26360     
26361     latitude: 0,
26362     longitude: 0,
26363     zoom: 15,
26364     mapTypeId: false,
26365     mapTypeControl: false,
26366     disableDoubleClickZoom: false,
26367     scrollwheel: true,
26368     streetViewControl: false,
26369     radius: 0,
26370     locationName: '',
26371     draggable: true,
26372     enableAutocomplete: false,
26373     enableReverseGeocode: true,
26374     markerTitle: '',
26375     
26376     getAutoCreate: function()
26377     {
26378
26379         var cfg = {
26380             tag: 'div',
26381             cls: 'roo-location-picker'
26382         };
26383         
26384         return cfg
26385     },
26386     
26387     initEvents: function(ct, position)
26388     {       
26389         if(!this.el.getWidth() || this.isApplied()){
26390             return;
26391         }
26392         
26393         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26394         
26395         this.initial();
26396     },
26397     
26398     initial: function()
26399     {
26400         if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26401             this.fireEvent('loadexception', this);
26402             return;
26403         }
26404         
26405         if(!this.mapTypeId){
26406             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26407         }
26408         
26409         this.gMapContext = this.GMapContext();
26410         
26411         this.initOverlayView();
26412         
26413         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26414         
26415         var _this = this;
26416                 
26417         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26418             _this.setPosition(_this.gMapContext.marker.position);
26419         });
26420         
26421         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26422             _this.fireEvent('mapClick', this, event);
26423             
26424         });
26425
26426         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26427             _this.fireEvent('mapRightClick', this, event);
26428             
26429         });
26430         
26431         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26432             _this.fireEvent('markerClick', this, event);
26433             
26434         });
26435
26436         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26437             _this.fireEvent('markerRightClick', this, event);
26438             
26439         });
26440         
26441         this.setPosition(this.gMapContext.location);
26442         
26443         this.fireEvent('initial', this, this.gMapContext.location);
26444     },
26445     
26446     initOverlayView: function()
26447     {
26448         var _this = this;
26449         
26450         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26451             
26452             draw: function()
26453             {
26454                 _this.fireEvent('OverlayViewDraw', _this);
26455             },
26456             
26457             onAdd: function()
26458             {
26459                 _this.fireEvent('OverlayViewOnAdd', _this);
26460             },
26461             
26462             onRemove: function()
26463             {
26464                 _this.fireEvent('OverlayViewOnRemove', _this);
26465             },
26466             
26467             show: function(cpx)
26468             {
26469                 _this.fireEvent('OverlayViewShow', _this, cpx);
26470             },
26471             
26472             hide: function()
26473             {
26474                 _this.fireEvent('OverlayViewHide', _this);
26475             }
26476             
26477         });
26478     },
26479     
26480     fromLatLngToContainerPixel: function(event)
26481     {
26482         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26483     },
26484     
26485     isApplied: function() 
26486     {
26487         return this.getGmapContext() == false ? false : true;
26488     },
26489     
26490     getGmapContext: function() 
26491     {
26492         return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26493     },
26494     
26495     GMapContext: function() 
26496     {
26497         var position = new google.maps.LatLng(this.latitude, this.longitude);
26498         
26499         var _map = new google.maps.Map(this.el.dom, {
26500             center: position,
26501             zoom: this.zoom,
26502             mapTypeId: this.mapTypeId,
26503             mapTypeControl: this.mapTypeControl,
26504             disableDoubleClickZoom: this.disableDoubleClickZoom,
26505             scrollwheel: this.scrollwheel,
26506             streetViewControl: this.streetViewControl,
26507             locationName: this.locationName,
26508             draggable: this.draggable,
26509             enableAutocomplete: this.enableAutocomplete,
26510             enableReverseGeocode: this.enableReverseGeocode
26511         });
26512         
26513         var _marker = new google.maps.Marker({
26514             position: position,
26515             map: _map,
26516             title: this.markerTitle,
26517             draggable: this.draggable
26518         });
26519         
26520         return {
26521             map: _map,
26522             marker: _marker,
26523             circle: null,
26524             location: position,
26525             radius: this.radius,
26526             locationName: this.locationName,
26527             addressComponents: {
26528                 formatted_address: null,
26529                 addressLine1: null,
26530                 addressLine2: null,
26531                 streetName: null,
26532                 streetNumber: null,
26533                 city: null,
26534                 district: null,
26535                 state: null,
26536                 stateOrProvince: null
26537             },
26538             settings: this,
26539             domContainer: this.el.dom,
26540             geodecoder: new google.maps.Geocoder()
26541         };
26542     },
26543     
26544     drawCircle: function(center, radius, options) 
26545     {
26546         if (this.gMapContext.circle != null) {
26547             this.gMapContext.circle.setMap(null);
26548         }
26549         if (radius > 0) {
26550             radius *= 1;
26551             options = Roo.apply({}, options, {
26552                 strokeColor: "#0000FF",
26553                 strokeOpacity: .35,
26554                 strokeWeight: 2,
26555                 fillColor: "#0000FF",
26556                 fillOpacity: .2
26557             });
26558             
26559             options.map = this.gMapContext.map;
26560             options.radius = radius;
26561             options.center = center;
26562             this.gMapContext.circle = new google.maps.Circle(options);
26563             return this.gMapContext.circle;
26564         }
26565         
26566         return null;
26567     },
26568     
26569     setPosition: function(location) 
26570     {
26571         this.gMapContext.location = location;
26572         this.gMapContext.marker.setPosition(location);
26573         this.gMapContext.map.panTo(location);
26574         this.drawCircle(location, this.gMapContext.radius, {});
26575         
26576         var _this = this;
26577         
26578         if (this.gMapContext.settings.enableReverseGeocode) {
26579             this.gMapContext.geodecoder.geocode({
26580                 latLng: this.gMapContext.location
26581             }, function(results, status) {
26582                 
26583                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26584                     _this.gMapContext.locationName = results[0].formatted_address;
26585                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26586                     
26587                     _this.fireEvent('positionchanged', this, location);
26588                 }
26589             });
26590             
26591             return;
26592         }
26593         
26594         this.fireEvent('positionchanged', this, location);
26595     },
26596     
26597     resize: function()
26598     {
26599         google.maps.event.trigger(this.gMapContext.map, "resize");
26600         
26601         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26602         
26603         this.fireEvent('resize', this);
26604     },
26605     
26606     setPositionByLatLng: function(latitude, longitude)
26607     {
26608         this.setPosition(new google.maps.LatLng(latitude, longitude));
26609     },
26610     
26611     getCurrentPosition: function() 
26612     {
26613         return {
26614             latitude: this.gMapContext.location.lat(),
26615             longitude: this.gMapContext.location.lng()
26616         };
26617     },
26618     
26619     getAddressName: function() 
26620     {
26621         return this.gMapContext.locationName;
26622     },
26623     
26624     getAddressComponents: function() 
26625     {
26626         return this.gMapContext.addressComponents;
26627     },
26628     
26629     address_component_from_google_geocode: function(address_components) 
26630     {
26631         var result = {};
26632         
26633         for (var i = 0; i < address_components.length; i++) {
26634             var component = address_components[i];
26635             if (component.types.indexOf("postal_code") >= 0) {
26636                 result.postalCode = component.short_name;
26637             } else if (component.types.indexOf("street_number") >= 0) {
26638                 result.streetNumber = component.short_name;
26639             } else if (component.types.indexOf("route") >= 0) {
26640                 result.streetName = component.short_name;
26641             } else if (component.types.indexOf("neighborhood") >= 0) {
26642                 result.city = component.short_name;
26643             } else if (component.types.indexOf("locality") >= 0) {
26644                 result.city = component.short_name;
26645             } else if (component.types.indexOf("sublocality") >= 0) {
26646                 result.district = component.short_name;
26647             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26648                 result.stateOrProvince = component.short_name;
26649             } else if (component.types.indexOf("country") >= 0) {
26650                 result.country = component.short_name;
26651             }
26652         }
26653         
26654         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26655         result.addressLine2 = "";
26656         return result;
26657     },
26658     
26659     setZoomLevel: function(zoom)
26660     {
26661         this.gMapContext.map.setZoom(zoom);
26662     },
26663     
26664     show: function()
26665     {
26666         if(!this.el){
26667             return;
26668         }
26669         
26670         this.el.show();
26671         
26672         this.resize();
26673         
26674         this.fireEvent('show', this);
26675     },
26676     
26677     hide: function()
26678     {
26679         if(!this.el){
26680             return;
26681         }
26682         
26683         this.el.hide();
26684         
26685         this.fireEvent('hide', this);
26686     }
26687     
26688 });
26689
26690 Roo.apply(Roo.bootstrap.LocationPicker, {
26691     
26692     OverlayView : function(map, options)
26693     {
26694         options = options || {};
26695         
26696         this.setMap(map);
26697     }
26698     
26699     
26700 });/*
26701  * - LGPL
26702  *
26703  * Alert
26704  * 
26705  */
26706
26707 /**
26708  * @class Roo.bootstrap.Alert
26709  * @extends Roo.bootstrap.Component
26710  * Bootstrap Alert class
26711  * @cfg {String} title The title of alert
26712  * @cfg {String} html The content of alert
26713  * @cfg {String} weight (  success | info | warning | danger )
26714  * @cfg {String} faicon font-awesomeicon
26715  * 
26716  * @constructor
26717  * Create a new alert
26718  * @param {Object} config The config object
26719  */
26720
26721
26722 Roo.bootstrap.Alert = function(config){
26723     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26724     
26725 };
26726
26727 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
26728     
26729     title: '',
26730     html: '',
26731     weight: false,
26732     faicon: false,
26733     
26734     getAutoCreate : function()
26735     {
26736         
26737         var cfg = {
26738             tag : 'div',
26739             cls : 'alert',
26740             cn : [
26741                 {
26742                     tag : 'i',
26743                     cls : 'roo-alert-icon'
26744                     
26745                 },
26746                 {
26747                     tag : 'b',
26748                     cls : 'roo-alert-title',
26749                     html : this.title
26750                 },
26751                 {
26752                     tag : 'span',
26753                     cls : 'roo-alert-text',
26754                     html : this.html
26755                 }
26756             ]
26757         };
26758         
26759         if(this.faicon){
26760             cfg.cn[0].cls += ' fa ' + this.faicon;
26761         }
26762         
26763         if(this.weight){
26764             cfg.cls += ' alert-' + this.weight;
26765         }
26766         
26767         return cfg;
26768     },
26769     
26770     initEvents: function() 
26771     {
26772         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26773     },
26774     
26775     setTitle : function(str)
26776     {
26777         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26778     },
26779     
26780     setText : function(str)
26781     {
26782         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26783     },
26784     
26785     setWeight : function(weight)
26786     {
26787         if(this.weight){
26788             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26789         }
26790         
26791         this.weight = weight;
26792         
26793         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26794     },
26795     
26796     setIcon : function(icon)
26797     {
26798         if(this.faicon){
26799             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26800         }
26801         
26802         this.faicon = icon;
26803         
26804         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26805     },
26806     
26807     hide: function() 
26808     {
26809         this.el.hide();   
26810     },
26811     
26812     show: function() 
26813     {  
26814         this.el.show();   
26815     }
26816     
26817 });
26818
26819  
26820 /*
26821 * Licence: LGPL
26822 */
26823
26824 /**
26825  * @class Roo.bootstrap.UploadCropbox
26826  * @extends Roo.bootstrap.Component
26827  * Bootstrap UploadCropbox class
26828  * @cfg {String} emptyText show when image has been loaded
26829  * @cfg {String} rotateNotify show when image too small to rotate
26830  * @cfg {Number} errorTimeout default 3000
26831  * @cfg {Number} minWidth default 300
26832  * @cfg {Number} minHeight default 300
26833  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26834  * @cfg {Boolean} isDocument (true|false) default false
26835  * @cfg {String} url action url
26836  * @cfg {String} paramName default 'imageUpload'
26837  * @cfg {String} method default POST
26838  * @cfg {Boolean} loadMask (true|false) default true
26839  * @cfg {Boolean} loadingText default 'Loading...'
26840  * 
26841  * @constructor
26842  * Create a new UploadCropbox
26843  * @param {Object} config The config object
26844  */
26845
26846 Roo.bootstrap.UploadCropbox = function(config){
26847     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26848     
26849     this.addEvents({
26850         /**
26851          * @event beforeselectfile
26852          * Fire before select file
26853          * @param {Roo.bootstrap.UploadCropbox} this
26854          */
26855         "beforeselectfile" : true,
26856         /**
26857          * @event initial
26858          * Fire after initEvent
26859          * @param {Roo.bootstrap.UploadCropbox} this
26860          */
26861         "initial" : true,
26862         /**
26863          * @event crop
26864          * Fire after initEvent
26865          * @param {Roo.bootstrap.UploadCropbox} this
26866          * @param {String} data
26867          */
26868         "crop" : true,
26869         /**
26870          * @event prepare
26871          * Fire when preparing the file data
26872          * @param {Roo.bootstrap.UploadCropbox} this
26873          * @param {Object} file
26874          */
26875         "prepare" : true,
26876         /**
26877          * @event exception
26878          * Fire when get exception
26879          * @param {Roo.bootstrap.UploadCropbox} this
26880          * @param {XMLHttpRequest} xhr
26881          */
26882         "exception" : true,
26883         /**
26884          * @event beforeloadcanvas
26885          * Fire before load the canvas
26886          * @param {Roo.bootstrap.UploadCropbox} this
26887          * @param {String} src
26888          */
26889         "beforeloadcanvas" : true,
26890         /**
26891          * @event trash
26892          * Fire when trash image
26893          * @param {Roo.bootstrap.UploadCropbox} this
26894          */
26895         "trash" : true,
26896         /**
26897          * @event download
26898          * Fire when download the image
26899          * @param {Roo.bootstrap.UploadCropbox} this
26900          */
26901         "download" : true,
26902         /**
26903          * @event footerbuttonclick
26904          * Fire when footerbuttonclick
26905          * @param {Roo.bootstrap.UploadCropbox} this
26906          * @param {String} type
26907          */
26908         "footerbuttonclick" : true,
26909         /**
26910          * @event resize
26911          * Fire when resize
26912          * @param {Roo.bootstrap.UploadCropbox} this
26913          */
26914         "resize" : true,
26915         /**
26916          * @event rotate
26917          * Fire when rotate the image
26918          * @param {Roo.bootstrap.UploadCropbox} this
26919          * @param {String} pos
26920          */
26921         "rotate" : true,
26922         /**
26923          * @event inspect
26924          * Fire when inspect the file
26925          * @param {Roo.bootstrap.UploadCropbox} this
26926          * @param {Object} file
26927          */
26928         "inspect" : true,
26929         /**
26930          * @event upload
26931          * Fire when xhr upload the file
26932          * @param {Roo.bootstrap.UploadCropbox} this
26933          * @param {Object} data
26934          */
26935         "upload" : true,
26936         /**
26937          * @event arrange
26938          * Fire when arrange the file data
26939          * @param {Roo.bootstrap.UploadCropbox} this
26940          * @param {Object} formData
26941          */
26942         "arrange" : true
26943     });
26944     
26945     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26946 };
26947
26948 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
26949     
26950     emptyText : 'Click to upload image',
26951     rotateNotify : 'Image is too small to rotate',
26952     errorTimeout : 3000,
26953     scale : 0,
26954     baseScale : 1,
26955     rotate : 0,
26956     dragable : false,
26957     pinching : false,
26958     mouseX : 0,
26959     mouseY : 0,
26960     cropData : false,
26961     minWidth : 300,
26962     minHeight : 300,
26963     file : false,
26964     exif : {},
26965     baseRotate : 1,
26966     cropType : 'image/jpeg',
26967     buttons : false,
26968     canvasLoaded : false,
26969     isDocument : false,
26970     method : 'POST',
26971     paramName : 'imageUpload',
26972     loadMask : true,
26973     loadingText : 'Loading...',
26974     maskEl : false,
26975     
26976     getAutoCreate : function()
26977     {
26978         var cfg = {
26979             tag : 'div',
26980             cls : 'roo-upload-cropbox',
26981             cn : [
26982                 {
26983                     tag : 'input',
26984                     cls : 'roo-upload-cropbox-selector',
26985                     type : 'file'
26986                 },
26987                 {
26988                     tag : 'div',
26989                     cls : 'roo-upload-cropbox-body',
26990                     style : 'cursor:pointer',
26991                     cn : [
26992                         {
26993                             tag : 'div',
26994                             cls : 'roo-upload-cropbox-preview'
26995                         },
26996                         {
26997                             tag : 'div',
26998                             cls : 'roo-upload-cropbox-thumb'
26999                         },
27000                         {
27001                             tag : 'div',
27002                             cls : 'roo-upload-cropbox-empty-notify',
27003                             html : this.emptyText
27004                         },
27005                         {
27006                             tag : 'div',
27007                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27008                             html : this.rotateNotify
27009                         }
27010                     ]
27011                 },
27012                 {
27013                     tag : 'div',
27014                     cls : 'roo-upload-cropbox-footer',
27015                     cn : {
27016                         tag : 'div',
27017                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27018                         cn : []
27019                     }
27020                 }
27021             ]
27022         };
27023         
27024         return cfg;
27025     },
27026     
27027     onRender : function(ct, position)
27028     {
27029         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27030         
27031         if (this.buttons.length) {
27032             
27033             Roo.each(this.buttons, function(bb) {
27034                 
27035                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27036                 
27037                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27038                 
27039             }, this);
27040         }
27041         
27042         if(this.loadMask){
27043             this.maskEl = this.el;
27044         }
27045     },
27046     
27047     initEvents : function()
27048     {
27049         this.urlAPI = (window.createObjectURL && window) || 
27050                                 (window.URL && URL.revokeObjectURL && URL) || 
27051                                 (window.webkitURL && webkitURL);
27052                         
27053         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27054         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27055         
27056         this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27057         this.selectorEl.hide();
27058         
27059         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27060         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27061         
27062         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27063         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27064         this.thumbEl.hide();
27065         
27066         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27067         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27068         
27069         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27070         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27071         this.errorEl.hide();
27072         
27073         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27074         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27075         this.footerEl.hide();
27076         
27077         this.setThumbBoxSize();
27078         
27079         this.bind();
27080         
27081         this.resize();
27082         
27083         this.fireEvent('initial', this);
27084     },
27085
27086     bind : function()
27087     {
27088         var _this = this;
27089         
27090         window.addEventListener("resize", function() { _this.resize(); } );
27091         
27092         this.bodyEl.on('click', this.beforeSelectFile, this);
27093         
27094         if(Roo.isTouch){
27095             this.bodyEl.on('touchstart', this.onTouchStart, this);
27096             this.bodyEl.on('touchmove', this.onTouchMove, this);
27097             this.bodyEl.on('touchend', this.onTouchEnd, this);
27098         }
27099         
27100         if(!Roo.isTouch){
27101             this.bodyEl.on('mousedown', this.onMouseDown, this);
27102             this.bodyEl.on('mousemove', this.onMouseMove, this);
27103             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27104             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27105             Roo.get(document).on('mouseup', this.onMouseUp, this);
27106         }
27107         
27108         this.selectorEl.on('change', this.onFileSelected, this);
27109     },
27110     
27111     reset : function()
27112     {    
27113         this.scale = 0;
27114         this.baseScale = 1;
27115         this.rotate = 0;
27116         this.baseRotate = 1;
27117         this.dragable = false;
27118         this.pinching = false;
27119         this.mouseX = 0;
27120         this.mouseY = 0;
27121         this.cropData = false;
27122         this.notifyEl.dom.innerHTML = this.emptyText;
27123         
27124         this.selectorEl.dom.value = '';
27125         
27126     },
27127     
27128     resize : function()
27129     {
27130         if(this.fireEvent('resize', this) != false){
27131             this.setThumbBoxPosition();
27132             this.setCanvasPosition();
27133         }
27134     },
27135     
27136     onFooterButtonClick : function(e, el, o, type)
27137     {
27138         switch (type) {
27139             case 'rotate-left' :
27140                 this.onRotateLeft(e);
27141                 break;
27142             case 'rotate-right' :
27143                 this.onRotateRight(e);
27144                 break;
27145             case 'picture' :
27146                 this.beforeSelectFile(e);
27147                 break;
27148             case 'trash' :
27149                 this.trash(e);
27150                 break;
27151             case 'crop' :
27152                 this.crop(e);
27153                 break;
27154             case 'download' :
27155                 this.download(e);
27156                 break;
27157             default :
27158                 break;
27159         }
27160         
27161         this.fireEvent('footerbuttonclick', this, type);
27162     },
27163     
27164     beforeSelectFile : function(e)
27165     {
27166         e.preventDefault();
27167         
27168         if(this.fireEvent('beforeselectfile', this) != false){
27169             this.selectorEl.dom.click();
27170         }
27171     },
27172     
27173     onFileSelected : function(e)
27174     {
27175         e.preventDefault();
27176         
27177         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27178             return;
27179         }
27180         
27181         var file = this.selectorEl.dom.files[0];
27182         
27183         if(this.fireEvent('inspect', this, file) != false){
27184             this.prepare(file);
27185         }
27186         
27187     },
27188     
27189     trash : function(e)
27190     {
27191         this.fireEvent('trash', this);
27192     },
27193     
27194     download : function(e)
27195     {
27196         this.fireEvent('download', this);
27197     },
27198     
27199     loadCanvas : function(src)
27200     {   
27201         if(this.fireEvent('beforeloadcanvas', this, src) != false){
27202             
27203             this.reset();
27204             
27205             this.imageEl = document.createElement('img');
27206             
27207             var _this = this;
27208             
27209             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27210             
27211             this.imageEl.src = src;
27212         }
27213     },
27214     
27215     onLoadCanvas : function()
27216     {   
27217         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27218         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27219         
27220         this.bodyEl.un('click', this.beforeSelectFile, this);
27221         
27222         this.notifyEl.hide();
27223         this.thumbEl.show();
27224         this.footerEl.show();
27225         
27226         this.baseRotateLevel();
27227         
27228         if(this.isDocument){
27229             this.setThumbBoxSize();
27230         }
27231         
27232         this.setThumbBoxPosition();
27233         
27234         this.baseScaleLevel();
27235         
27236         this.draw();
27237         
27238         this.resize();
27239         
27240         this.canvasLoaded = true;
27241         
27242         if(this.loadMask){
27243             this.maskEl.unmask();
27244         }
27245         
27246     },
27247     
27248     setCanvasPosition : function()
27249     {   
27250         if(!this.canvasEl){
27251             return;
27252         }
27253         
27254         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27255         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27256         
27257         this.previewEl.setLeft(pw);
27258         this.previewEl.setTop(ph);
27259         
27260     },
27261     
27262     onMouseDown : function(e)
27263     {   
27264         e.stopEvent();
27265         
27266         this.dragable = true;
27267         this.pinching = false;
27268         
27269         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27270             this.dragable = false;
27271             return;
27272         }
27273         
27274         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27275         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27276         
27277     },
27278     
27279     onMouseMove : function(e)
27280     {   
27281         e.stopEvent();
27282         
27283         if(!this.canvasLoaded){
27284             return;
27285         }
27286         
27287         if (!this.dragable){
27288             return;
27289         }
27290         
27291         var minX = Math.ceil(this.thumbEl.getLeft(true));
27292         var minY = Math.ceil(this.thumbEl.getTop(true));
27293         
27294         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27295         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27296         
27297         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27298         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27299         
27300         x = x - this.mouseX;
27301         y = y - this.mouseY;
27302         
27303         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27304         var bgY = Math.ceil(y + this.previewEl.getTop(true));
27305         
27306         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27307         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27308         
27309         this.previewEl.setLeft(bgX);
27310         this.previewEl.setTop(bgY);
27311         
27312         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27313         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27314     },
27315     
27316     onMouseUp : function(e)
27317     {   
27318         e.stopEvent();
27319         
27320         this.dragable = false;
27321     },
27322     
27323     onMouseWheel : function(e)
27324     {   
27325         e.stopEvent();
27326         
27327         this.startScale = this.scale;
27328         
27329         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27330         
27331         if(!this.zoomable()){
27332             this.scale = this.startScale;
27333             return;
27334         }
27335         
27336         this.draw();
27337         
27338         return;
27339     },
27340     
27341     zoomable : function()
27342     {
27343         var minScale = this.thumbEl.getWidth() / this.minWidth;
27344         
27345         if(this.minWidth < this.minHeight){
27346             minScale = this.thumbEl.getHeight() / this.minHeight;
27347         }
27348         
27349         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27350         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27351         
27352         if(
27353                 this.isDocument &&
27354                 (this.rotate == 0 || this.rotate == 180) && 
27355                 (
27356                     width > this.imageEl.OriginWidth || 
27357                     height > this.imageEl.OriginHeight ||
27358                     (width < this.minWidth && height < this.minHeight)
27359                 )
27360         ){
27361             return false;
27362         }
27363         
27364         if(
27365                 this.isDocument &&
27366                 (this.rotate == 90 || this.rotate == 270) && 
27367                 (
27368                     width > this.imageEl.OriginWidth || 
27369                     height > this.imageEl.OriginHeight ||
27370                     (width < this.minHeight && height < this.minWidth)
27371                 )
27372         ){
27373             return false;
27374         }
27375         
27376         if(
27377                 !this.isDocument &&
27378                 (this.rotate == 0 || this.rotate == 180) && 
27379                 (
27380                     width < this.minWidth || 
27381                     width > this.imageEl.OriginWidth || 
27382                     height < this.minHeight || 
27383                     height > this.imageEl.OriginHeight
27384                 )
27385         ){
27386             return false;
27387         }
27388         
27389         if(
27390                 !this.isDocument &&
27391                 (this.rotate == 90 || this.rotate == 270) && 
27392                 (
27393                     width < this.minHeight || 
27394                     width > this.imageEl.OriginWidth || 
27395                     height < this.minWidth || 
27396                     height > this.imageEl.OriginHeight
27397                 )
27398         ){
27399             return false;
27400         }
27401         
27402         return true;
27403         
27404     },
27405     
27406     onRotateLeft : function(e)
27407     {   
27408         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27409             
27410             var minScale = this.thumbEl.getWidth() / this.minWidth;
27411             
27412             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27413             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27414             
27415             this.startScale = this.scale;
27416             
27417             while (this.getScaleLevel() < minScale){
27418             
27419                 this.scale = this.scale + 1;
27420                 
27421                 if(!this.zoomable()){
27422                     break;
27423                 }
27424                 
27425                 if(
27426                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27427                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27428                 ){
27429                     continue;
27430                 }
27431                 
27432                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27433
27434                 this.draw();
27435                 
27436                 return;
27437             }
27438             
27439             this.scale = this.startScale;
27440             
27441             this.onRotateFail();
27442             
27443             return false;
27444         }
27445         
27446         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27447
27448         if(this.isDocument){
27449             this.setThumbBoxSize();
27450             this.setThumbBoxPosition();
27451             this.setCanvasPosition();
27452         }
27453         
27454         this.draw();
27455         
27456         this.fireEvent('rotate', this, 'left');
27457         
27458     },
27459     
27460     onRotateRight : function(e)
27461     {
27462         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27463             
27464             var minScale = this.thumbEl.getWidth() / this.minWidth;
27465         
27466             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27467             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27468             
27469             this.startScale = this.scale;
27470             
27471             while (this.getScaleLevel() < minScale){
27472             
27473                 this.scale = this.scale + 1;
27474                 
27475                 if(!this.zoomable()){
27476                     break;
27477                 }
27478                 
27479                 if(
27480                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27481                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27482                 ){
27483                     continue;
27484                 }
27485                 
27486                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27487
27488                 this.draw();
27489                 
27490                 return;
27491             }
27492             
27493             this.scale = this.startScale;
27494             
27495             this.onRotateFail();
27496             
27497             return false;
27498         }
27499         
27500         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27501
27502         if(this.isDocument){
27503             this.setThumbBoxSize();
27504             this.setThumbBoxPosition();
27505             this.setCanvasPosition();
27506         }
27507         
27508         this.draw();
27509         
27510         this.fireEvent('rotate', this, 'right');
27511     },
27512     
27513     onRotateFail : function()
27514     {
27515         this.errorEl.show(true);
27516         
27517         var _this = this;
27518         
27519         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27520     },
27521     
27522     draw : function()
27523     {
27524         this.previewEl.dom.innerHTML = '';
27525         
27526         var canvasEl = document.createElement("canvas");
27527         
27528         var contextEl = canvasEl.getContext("2d");
27529         
27530         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27531         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27532         var center = this.imageEl.OriginWidth / 2;
27533         
27534         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27535             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27536             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27537             center = this.imageEl.OriginHeight / 2;
27538         }
27539         
27540         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27541         
27542         contextEl.translate(center, center);
27543         contextEl.rotate(this.rotate * Math.PI / 180);
27544
27545         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27546         
27547         this.canvasEl = document.createElement("canvas");
27548         
27549         this.contextEl = this.canvasEl.getContext("2d");
27550         
27551         switch (this.rotate) {
27552             case 0 :
27553                 
27554                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27555                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27556                 
27557                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27558                 
27559                 break;
27560             case 90 : 
27561                 
27562                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27563                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27564                 
27565                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27566                     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);
27567                     break;
27568                 }
27569                 
27570                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27571                 
27572                 break;
27573             case 180 :
27574                 
27575                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27576                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27577                 
27578                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27579                     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);
27580                     break;
27581                 }
27582                 
27583                 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);
27584                 
27585                 break;
27586             case 270 :
27587                 
27588                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27589                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27590         
27591                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27592                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27593                     break;
27594                 }
27595                 
27596                 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);
27597                 
27598                 break;
27599             default : 
27600                 break;
27601         }
27602         
27603         this.previewEl.appendChild(this.canvasEl);
27604         
27605         this.setCanvasPosition();
27606     },
27607     
27608     crop : function()
27609     {
27610         if(!this.canvasLoaded){
27611             return;
27612         }
27613         
27614         var imageCanvas = document.createElement("canvas");
27615         
27616         var imageContext = imageCanvas.getContext("2d");
27617         
27618         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27619         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27620         
27621         var center = imageCanvas.width / 2;
27622         
27623         imageContext.translate(center, center);
27624         
27625         imageContext.rotate(this.rotate * Math.PI / 180);
27626         
27627         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27628         
27629         var canvas = document.createElement("canvas");
27630         
27631         var context = canvas.getContext("2d");
27632                 
27633         canvas.width = this.minWidth;
27634         canvas.height = this.minHeight;
27635
27636         switch (this.rotate) {
27637             case 0 :
27638                 
27639                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27640                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27641                 
27642                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27643                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27644                 
27645                 var targetWidth = this.minWidth - 2 * x;
27646                 var targetHeight = this.minHeight - 2 * y;
27647                 
27648                 var scale = 1;
27649                 
27650                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27651                     scale = targetWidth / width;
27652                 }
27653                 
27654                 if(x > 0 && y == 0){
27655                     scale = targetHeight / height;
27656                 }
27657                 
27658                 if(x > 0 && y > 0){
27659                     scale = targetWidth / width;
27660                     
27661                     if(width < height){
27662                         scale = targetHeight / height;
27663                     }
27664                 }
27665                 
27666                 context.scale(scale, scale);
27667                 
27668                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27669                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27670
27671                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27672                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27673
27674                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27675                 
27676                 break;
27677             case 90 : 
27678                 
27679                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27680                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27681                 
27682                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27683                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27684                 
27685                 var targetWidth = this.minWidth - 2 * x;
27686                 var targetHeight = this.minHeight - 2 * y;
27687                 
27688                 var scale = 1;
27689                 
27690                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27691                     scale = targetWidth / width;
27692                 }
27693                 
27694                 if(x > 0 && y == 0){
27695                     scale = targetHeight / height;
27696                 }
27697                 
27698                 if(x > 0 && y > 0){
27699                     scale = targetWidth / width;
27700                     
27701                     if(width < height){
27702                         scale = targetHeight / height;
27703                     }
27704                 }
27705                 
27706                 context.scale(scale, scale);
27707                 
27708                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27709                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27710
27711                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27712                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27713                 
27714                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27715                 
27716                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27717                 
27718                 break;
27719             case 180 :
27720                 
27721                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27722                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27723                 
27724                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27725                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27726                 
27727                 var targetWidth = this.minWidth - 2 * x;
27728                 var targetHeight = this.minHeight - 2 * y;
27729                 
27730                 var scale = 1;
27731                 
27732                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27733                     scale = targetWidth / width;
27734                 }
27735                 
27736                 if(x > 0 && y == 0){
27737                     scale = targetHeight / height;
27738                 }
27739                 
27740                 if(x > 0 && y > 0){
27741                     scale = targetWidth / width;
27742                     
27743                     if(width < height){
27744                         scale = targetHeight / height;
27745                     }
27746                 }
27747                 
27748                 context.scale(scale, scale);
27749                 
27750                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27751                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27752
27753                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27754                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27755
27756                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27757                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27758                 
27759                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27760                 
27761                 break;
27762             case 270 :
27763                 
27764                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27765                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27766                 
27767                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27768                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27769                 
27770                 var targetWidth = this.minWidth - 2 * x;
27771                 var targetHeight = this.minHeight - 2 * y;
27772                 
27773                 var scale = 1;
27774                 
27775                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27776                     scale = targetWidth / width;
27777                 }
27778                 
27779                 if(x > 0 && y == 0){
27780                     scale = targetHeight / height;
27781                 }
27782                 
27783                 if(x > 0 && y > 0){
27784                     scale = targetWidth / width;
27785                     
27786                     if(width < height){
27787                         scale = targetHeight / height;
27788                     }
27789                 }
27790                 
27791                 context.scale(scale, scale);
27792                 
27793                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27794                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27795
27796                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27797                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27798                 
27799                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27800                 
27801                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27802                 
27803                 break;
27804             default : 
27805                 break;
27806         }
27807         
27808         this.cropData = canvas.toDataURL(this.cropType);
27809         
27810         if(this.fireEvent('crop', this, this.cropData) !== false){
27811             this.process(this.file, this.cropData);
27812         }
27813         
27814         return;
27815         
27816     },
27817     
27818     setThumbBoxSize : function()
27819     {
27820         var width, height;
27821         
27822         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27823             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27824             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27825             
27826             this.minWidth = width;
27827             this.minHeight = height;
27828             
27829             if(this.rotate == 90 || this.rotate == 270){
27830                 this.minWidth = height;
27831                 this.minHeight = width;
27832             }
27833         }
27834         
27835         height = 300;
27836         width = Math.ceil(this.minWidth * height / this.minHeight);
27837         
27838         if(this.minWidth > this.minHeight){
27839             width = 300;
27840             height = Math.ceil(this.minHeight * width / this.minWidth);
27841         }
27842         
27843         this.thumbEl.setStyle({
27844             width : width + 'px',
27845             height : height + 'px'
27846         });
27847
27848         return;
27849             
27850     },
27851     
27852     setThumbBoxPosition : function()
27853     {
27854         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27855         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27856         
27857         this.thumbEl.setLeft(x);
27858         this.thumbEl.setTop(y);
27859         
27860     },
27861     
27862     baseRotateLevel : function()
27863     {
27864         this.baseRotate = 1;
27865         
27866         if(
27867                 typeof(this.exif) != 'undefined' &&
27868                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27869                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27870         ){
27871             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27872         }
27873         
27874         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27875         
27876     },
27877     
27878     baseScaleLevel : function()
27879     {
27880         var width, height;
27881         
27882         if(this.isDocument){
27883             
27884             if(this.baseRotate == 6 || this.baseRotate == 8){
27885             
27886                 height = this.thumbEl.getHeight();
27887                 this.baseScale = height / this.imageEl.OriginWidth;
27888
27889                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27890                     width = this.thumbEl.getWidth();
27891                     this.baseScale = width / this.imageEl.OriginHeight;
27892                 }
27893
27894                 return;
27895             }
27896
27897             height = this.thumbEl.getHeight();
27898             this.baseScale = height / this.imageEl.OriginHeight;
27899
27900             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27901                 width = this.thumbEl.getWidth();
27902                 this.baseScale = width / this.imageEl.OriginWidth;
27903             }
27904
27905             return;
27906         }
27907         
27908         if(this.baseRotate == 6 || this.baseRotate == 8){
27909             
27910             width = this.thumbEl.getHeight();
27911             this.baseScale = width / this.imageEl.OriginHeight;
27912             
27913             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27914                 height = this.thumbEl.getWidth();
27915                 this.baseScale = height / this.imageEl.OriginHeight;
27916             }
27917             
27918             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27919                 height = this.thumbEl.getWidth();
27920                 this.baseScale = height / this.imageEl.OriginHeight;
27921                 
27922                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27923                     width = this.thumbEl.getHeight();
27924                     this.baseScale = width / this.imageEl.OriginWidth;
27925                 }
27926             }
27927             
27928             return;
27929         }
27930         
27931         width = this.thumbEl.getWidth();
27932         this.baseScale = width / this.imageEl.OriginWidth;
27933         
27934         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27935             height = this.thumbEl.getHeight();
27936             this.baseScale = height / this.imageEl.OriginHeight;
27937         }
27938         
27939         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27940             
27941             height = this.thumbEl.getHeight();
27942             this.baseScale = height / this.imageEl.OriginHeight;
27943             
27944             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27945                 width = this.thumbEl.getWidth();
27946                 this.baseScale = width / this.imageEl.OriginWidth;
27947             }
27948             
27949         }
27950         
27951         return;
27952     },
27953     
27954     getScaleLevel : function()
27955     {
27956         return this.baseScale * Math.pow(1.1, this.scale);
27957     },
27958     
27959     onTouchStart : function(e)
27960     {
27961         if(!this.canvasLoaded){
27962             this.beforeSelectFile(e);
27963             return;
27964         }
27965         
27966         var touches = e.browserEvent.touches;
27967         
27968         if(!touches){
27969             return;
27970         }
27971         
27972         if(touches.length == 1){
27973             this.onMouseDown(e);
27974             return;
27975         }
27976         
27977         if(touches.length != 2){
27978             return;
27979         }
27980         
27981         var coords = [];
27982         
27983         for(var i = 0, finger; finger = touches[i]; i++){
27984             coords.push(finger.pageX, finger.pageY);
27985         }
27986         
27987         var x = Math.pow(coords[0] - coords[2], 2);
27988         var y = Math.pow(coords[1] - coords[3], 2);
27989         
27990         this.startDistance = Math.sqrt(x + y);
27991         
27992         this.startScale = this.scale;
27993         
27994         this.pinching = true;
27995         this.dragable = false;
27996         
27997     },
27998     
27999     onTouchMove : function(e)
28000     {
28001         if(!this.pinching && !this.dragable){
28002             return;
28003         }
28004         
28005         var touches = e.browserEvent.touches;
28006         
28007         if(!touches){
28008             return;
28009         }
28010         
28011         if(this.dragable){
28012             this.onMouseMove(e);
28013             return;
28014         }
28015         
28016         var coords = [];
28017         
28018         for(var i = 0, finger; finger = touches[i]; i++){
28019             coords.push(finger.pageX, finger.pageY);
28020         }
28021         
28022         var x = Math.pow(coords[0] - coords[2], 2);
28023         var y = Math.pow(coords[1] - coords[3], 2);
28024         
28025         this.endDistance = Math.sqrt(x + y);
28026         
28027         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28028         
28029         if(!this.zoomable()){
28030             this.scale = this.startScale;
28031             return;
28032         }
28033         
28034         this.draw();
28035         
28036     },
28037     
28038     onTouchEnd : function(e)
28039     {
28040         this.pinching = false;
28041         this.dragable = false;
28042         
28043     },
28044     
28045     process : function(file, crop)
28046     {
28047         if(this.loadMask){
28048             this.maskEl.mask(this.loadingText);
28049         }
28050         
28051         this.xhr = new XMLHttpRequest();
28052         
28053         file.xhr = this.xhr;
28054
28055         this.xhr.open(this.method, this.url, true);
28056         
28057         var headers = {
28058             "Accept": "application/json",
28059             "Cache-Control": "no-cache",
28060             "X-Requested-With": "XMLHttpRequest"
28061         };
28062         
28063         for (var headerName in headers) {
28064             var headerValue = headers[headerName];
28065             if (headerValue) {
28066                 this.xhr.setRequestHeader(headerName, headerValue);
28067             }
28068         }
28069         
28070         var _this = this;
28071         
28072         this.xhr.onload = function()
28073         {
28074             _this.xhrOnLoad(_this.xhr);
28075         }
28076         
28077         this.xhr.onerror = function()
28078         {
28079             _this.xhrOnError(_this.xhr);
28080         }
28081         
28082         var formData = new FormData();
28083
28084         formData.append('returnHTML', 'NO');
28085         
28086         if(crop){
28087             formData.append('crop', crop);
28088         }
28089         
28090         if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28091             formData.append(this.paramName, file, file.name);
28092         }
28093         
28094         if(typeof(file.filename) != 'undefined'){
28095             formData.append('filename', file.filename);
28096         }
28097         
28098         if(typeof(file.mimetype) != 'undefined'){
28099             formData.append('mimetype', file.mimetype);
28100         }
28101         
28102         if(this.fireEvent('arrange', this, formData) != false){
28103             this.xhr.send(formData);
28104         };
28105     },
28106     
28107     xhrOnLoad : function(xhr)
28108     {
28109         if(this.loadMask){
28110             this.maskEl.unmask();
28111         }
28112         
28113         if (xhr.readyState !== 4) {
28114             this.fireEvent('exception', this, xhr);
28115             return;
28116         }
28117
28118         var response = Roo.decode(xhr.responseText);
28119         
28120         if(!response.success){
28121             this.fireEvent('exception', this, xhr);
28122             return;
28123         }
28124         
28125         var response = Roo.decode(xhr.responseText);
28126         
28127         this.fireEvent('upload', this, response);
28128         
28129     },
28130     
28131     xhrOnError : function()
28132     {
28133         if(this.loadMask){
28134             this.maskEl.unmask();
28135         }
28136         
28137         Roo.log('xhr on error');
28138         
28139         var response = Roo.decode(xhr.responseText);
28140           
28141         Roo.log(response);
28142         
28143     },
28144     
28145     prepare : function(file)
28146     {   
28147         if(this.loadMask){
28148             this.maskEl.mask(this.loadingText);
28149         }
28150         
28151         this.file = false;
28152         this.exif = {};
28153         
28154         if(typeof(file) === 'string'){
28155             this.loadCanvas(file);
28156             return;
28157         }
28158         
28159         if(!file || !this.urlAPI){
28160             return;
28161         }
28162         
28163         this.file = file;
28164         this.cropType = file.type;
28165         
28166         var _this = this;
28167         
28168         if(this.fireEvent('prepare', this, this.file) != false){
28169             
28170             var reader = new FileReader();
28171             
28172             reader.onload = function (e) {
28173                 if (e.target.error) {
28174                     Roo.log(e.target.error);
28175                     return;
28176                 }
28177                 
28178                 var buffer = e.target.result,
28179                     dataView = new DataView(buffer),
28180                     offset = 2,
28181                     maxOffset = dataView.byteLength - 4,
28182                     markerBytes,
28183                     markerLength;
28184                 
28185                 if (dataView.getUint16(0) === 0xffd8) {
28186                     while (offset < maxOffset) {
28187                         markerBytes = dataView.getUint16(offset);
28188                         
28189                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28190                             markerLength = dataView.getUint16(offset + 2) + 2;
28191                             if (offset + markerLength > dataView.byteLength) {
28192                                 Roo.log('Invalid meta data: Invalid segment size.');
28193                                 break;
28194                             }
28195                             
28196                             if(markerBytes == 0xffe1){
28197                                 _this.parseExifData(
28198                                     dataView,
28199                                     offset,
28200                                     markerLength
28201                                 );
28202                             }
28203                             
28204                             offset += markerLength;
28205                             
28206                             continue;
28207                         }
28208                         
28209                         break;
28210                     }
28211                     
28212                 }
28213                 
28214                 var url = _this.urlAPI.createObjectURL(_this.file);
28215                 
28216                 _this.loadCanvas(url);
28217                 
28218                 return;
28219             }
28220             
28221             reader.readAsArrayBuffer(this.file);
28222             
28223         }
28224         
28225     },
28226     
28227     parseExifData : function(dataView, offset, length)
28228     {
28229         var tiffOffset = offset + 10,
28230             littleEndian,
28231             dirOffset;
28232     
28233         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28234             // No Exif data, might be XMP data instead
28235             return;
28236         }
28237         
28238         // Check for the ASCII code for "Exif" (0x45786966):
28239         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28240             // No Exif data, might be XMP data instead
28241             return;
28242         }
28243         if (tiffOffset + 8 > dataView.byteLength) {
28244             Roo.log('Invalid Exif data: Invalid segment size.');
28245             return;
28246         }
28247         // Check for the two null bytes:
28248         if (dataView.getUint16(offset + 8) !== 0x0000) {
28249             Roo.log('Invalid Exif data: Missing byte alignment offset.');
28250             return;
28251         }
28252         // Check the byte alignment:
28253         switch (dataView.getUint16(tiffOffset)) {
28254         case 0x4949:
28255             littleEndian = true;
28256             break;
28257         case 0x4D4D:
28258             littleEndian = false;
28259             break;
28260         default:
28261             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28262             return;
28263         }
28264         // Check for the TIFF tag marker (0x002A):
28265         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28266             Roo.log('Invalid Exif data: Missing TIFF marker.');
28267             return;
28268         }
28269         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28270         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28271         
28272         this.parseExifTags(
28273             dataView,
28274             tiffOffset,
28275             tiffOffset + dirOffset,
28276             littleEndian
28277         );
28278     },
28279     
28280     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28281     {
28282         var tagsNumber,
28283             dirEndOffset,
28284             i;
28285         if (dirOffset + 6 > dataView.byteLength) {
28286             Roo.log('Invalid Exif data: Invalid directory offset.');
28287             return;
28288         }
28289         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28290         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28291         if (dirEndOffset + 4 > dataView.byteLength) {
28292             Roo.log('Invalid Exif data: Invalid directory size.');
28293             return;
28294         }
28295         for (i = 0; i < tagsNumber; i += 1) {
28296             this.parseExifTag(
28297                 dataView,
28298                 tiffOffset,
28299                 dirOffset + 2 + 12 * i, // tag offset
28300                 littleEndian
28301             );
28302         }
28303         // Return the offset to the next directory:
28304         return dataView.getUint32(dirEndOffset, littleEndian);
28305     },
28306     
28307     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
28308     {
28309         var tag = dataView.getUint16(offset, littleEndian);
28310         
28311         this.exif[tag] = this.getExifValue(
28312             dataView,
28313             tiffOffset,
28314             offset,
28315             dataView.getUint16(offset + 2, littleEndian), // tag type
28316             dataView.getUint32(offset + 4, littleEndian), // tag length
28317             littleEndian
28318         );
28319     },
28320     
28321     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28322     {
28323         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28324             tagSize,
28325             dataOffset,
28326             values,
28327             i,
28328             str,
28329             c;
28330     
28331         if (!tagType) {
28332             Roo.log('Invalid Exif data: Invalid tag type.');
28333             return;
28334         }
28335         
28336         tagSize = tagType.size * length;
28337         // Determine if the value is contained in the dataOffset bytes,
28338         // or if the value at the dataOffset is a pointer to the actual data:
28339         dataOffset = tagSize > 4 ?
28340                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28341         if (dataOffset + tagSize > dataView.byteLength) {
28342             Roo.log('Invalid Exif data: Invalid data offset.');
28343             return;
28344         }
28345         if (length === 1) {
28346             return tagType.getValue(dataView, dataOffset, littleEndian);
28347         }
28348         values = [];
28349         for (i = 0; i < length; i += 1) {
28350             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28351         }
28352         
28353         if (tagType.ascii) {
28354             str = '';
28355             // Concatenate the chars:
28356             for (i = 0; i < values.length; i += 1) {
28357                 c = values[i];
28358                 // Ignore the terminating NULL byte(s):
28359                 if (c === '\u0000') {
28360                     break;
28361                 }
28362                 str += c;
28363             }
28364             return str;
28365         }
28366         return values;
28367     }
28368     
28369 });
28370
28371 Roo.apply(Roo.bootstrap.UploadCropbox, {
28372     tags : {
28373         'Orientation': 0x0112
28374     },
28375     
28376     Orientation: {
28377             1: 0, //'top-left',
28378 //            2: 'top-right',
28379             3: 180, //'bottom-right',
28380 //            4: 'bottom-left',
28381 //            5: 'left-top',
28382             6: 90, //'right-top',
28383 //            7: 'right-bottom',
28384             8: 270 //'left-bottom'
28385     },
28386     
28387     exifTagTypes : {
28388         // byte, 8-bit unsigned int:
28389         1: {
28390             getValue: function (dataView, dataOffset) {
28391                 return dataView.getUint8(dataOffset);
28392             },
28393             size: 1
28394         },
28395         // ascii, 8-bit byte:
28396         2: {
28397             getValue: function (dataView, dataOffset) {
28398                 return String.fromCharCode(dataView.getUint8(dataOffset));
28399             },
28400             size: 1,
28401             ascii: true
28402         },
28403         // short, 16 bit int:
28404         3: {
28405             getValue: function (dataView, dataOffset, littleEndian) {
28406                 return dataView.getUint16(dataOffset, littleEndian);
28407             },
28408             size: 2
28409         },
28410         // long, 32 bit int:
28411         4: {
28412             getValue: function (dataView, dataOffset, littleEndian) {
28413                 return dataView.getUint32(dataOffset, littleEndian);
28414             },
28415             size: 4
28416         },
28417         // rational = two long values, first is numerator, second is denominator:
28418         5: {
28419             getValue: function (dataView, dataOffset, littleEndian) {
28420                 return dataView.getUint32(dataOffset, littleEndian) /
28421                     dataView.getUint32(dataOffset + 4, littleEndian);
28422             },
28423             size: 8
28424         },
28425         // slong, 32 bit signed int:
28426         9: {
28427             getValue: function (dataView, dataOffset, littleEndian) {
28428                 return dataView.getInt32(dataOffset, littleEndian);
28429             },
28430             size: 4
28431         },
28432         // srational, two slongs, first is numerator, second is denominator:
28433         10: {
28434             getValue: function (dataView, dataOffset, littleEndian) {
28435                 return dataView.getInt32(dataOffset, littleEndian) /
28436                     dataView.getInt32(dataOffset + 4, littleEndian);
28437             },
28438             size: 8
28439         }
28440     },
28441     
28442     footer : {
28443         STANDARD : [
28444             {
28445                 tag : 'div',
28446                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28447                 action : 'rotate-left',
28448                 cn : [
28449                     {
28450                         tag : 'button',
28451                         cls : 'btn btn-default',
28452                         html : '<i class="fa fa-undo"></i>'
28453                     }
28454                 ]
28455             },
28456             {
28457                 tag : 'div',
28458                 cls : 'btn-group roo-upload-cropbox-picture',
28459                 action : 'picture',
28460                 cn : [
28461                     {
28462                         tag : 'button',
28463                         cls : 'btn btn-default',
28464                         html : '<i class="fa fa-picture-o"></i>'
28465                     }
28466                 ]
28467             },
28468             {
28469                 tag : 'div',
28470                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28471                 action : 'rotate-right',
28472                 cn : [
28473                     {
28474                         tag : 'button',
28475                         cls : 'btn btn-default',
28476                         html : '<i class="fa fa-repeat"></i>'
28477                     }
28478                 ]
28479             }
28480         ],
28481         DOCUMENT : [
28482             {
28483                 tag : 'div',
28484                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28485                 action : 'rotate-left',
28486                 cn : [
28487                     {
28488                         tag : 'button',
28489                         cls : 'btn btn-default',
28490                         html : '<i class="fa fa-undo"></i>'
28491                     }
28492                 ]
28493             },
28494             {
28495                 tag : 'div',
28496                 cls : 'btn-group roo-upload-cropbox-download',
28497                 action : 'download',
28498                 cn : [
28499                     {
28500                         tag : 'button',
28501                         cls : 'btn btn-default',
28502                         html : '<i class="fa fa-download"></i>'
28503                     }
28504                 ]
28505             },
28506             {
28507                 tag : 'div',
28508                 cls : 'btn-group roo-upload-cropbox-crop',
28509                 action : 'crop',
28510                 cn : [
28511                     {
28512                         tag : 'button',
28513                         cls : 'btn btn-default',
28514                         html : '<i class="fa fa-crop"></i>'
28515                     }
28516                 ]
28517             },
28518             {
28519                 tag : 'div',
28520                 cls : 'btn-group roo-upload-cropbox-trash',
28521                 action : 'trash',
28522                 cn : [
28523                     {
28524                         tag : 'button',
28525                         cls : 'btn btn-default',
28526                         html : '<i class="fa fa-trash"></i>'
28527                     }
28528                 ]
28529             },
28530             {
28531                 tag : 'div',
28532                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28533                 action : 'rotate-right',
28534                 cn : [
28535                     {
28536                         tag : 'button',
28537                         cls : 'btn btn-default',
28538                         html : '<i class="fa fa-repeat"></i>'
28539                     }
28540                 ]
28541             }
28542         ],
28543         ROTATOR : [
28544             {
28545                 tag : 'div',
28546                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28547                 action : 'rotate-left',
28548                 cn : [
28549                     {
28550                         tag : 'button',
28551                         cls : 'btn btn-default',
28552                         html : '<i class="fa fa-undo"></i>'
28553                     }
28554                 ]
28555             },
28556             {
28557                 tag : 'div',
28558                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28559                 action : 'rotate-right',
28560                 cn : [
28561                     {
28562                         tag : 'button',
28563                         cls : 'btn btn-default',
28564                         html : '<i class="fa fa-repeat"></i>'
28565                     }
28566                 ]
28567             }
28568         ]
28569     }
28570 });
28571
28572 /*
28573 * Licence: LGPL
28574 */
28575
28576 /**
28577  * @class Roo.bootstrap.DocumentManager
28578  * @extends Roo.bootstrap.Component
28579  * Bootstrap DocumentManager class
28580  * @cfg {String} paramName default 'imageUpload'
28581  * @cfg {String} toolTipName default 'filename'
28582  * @cfg {String} method default POST
28583  * @cfg {String} url action url
28584  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28585  * @cfg {Boolean} multiple multiple upload default true
28586  * @cfg {Number} thumbSize default 300
28587  * @cfg {String} fieldLabel
28588  * @cfg {Number} labelWidth default 4
28589  * @cfg {String} labelAlign (left|top) default left
28590  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28591 * @cfg {Number} labellg set the width of label (1-12)
28592  * @cfg {Number} labelmd set the width of label (1-12)
28593  * @cfg {Number} labelsm set the width of label (1-12)
28594  * @cfg {Number} labelxs set the width of label (1-12)
28595  * 
28596  * @constructor
28597  * Create a new DocumentManager
28598  * @param {Object} config The config object
28599  */
28600
28601 Roo.bootstrap.DocumentManager = function(config){
28602     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28603     
28604     this.files = [];
28605     this.delegates = [];
28606     
28607     this.addEvents({
28608         /**
28609          * @event initial
28610          * Fire when initial the DocumentManager
28611          * @param {Roo.bootstrap.DocumentManager} this
28612          */
28613         "initial" : true,
28614         /**
28615          * @event inspect
28616          * inspect selected file
28617          * @param {Roo.bootstrap.DocumentManager} this
28618          * @param {File} file
28619          */
28620         "inspect" : true,
28621         /**
28622          * @event exception
28623          * Fire when xhr load exception
28624          * @param {Roo.bootstrap.DocumentManager} this
28625          * @param {XMLHttpRequest} xhr
28626          */
28627         "exception" : true,
28628         /**
28629          * @event afterupload
28630          * Fire when xhr load exception
28631          * @param {Roo.bootstrap.DocumentManager} this
28632          * @param {XMLHttpRequest} xhr
28633          */
28634         "afterupload" : true,
28635         /**
28636          * @event prepare
28637          * prepare the form data
28638          * @param {Roo.bootstrap.DocumentManager} this
28639          * @param {Object} formData
28640          */
28641         "prepare" : true,
28642         /**
28643          * @event remove
28644          * Fire when remove the file
28645          * @param {Roo.bootstrap.DocumentManager} this
28646          * @param {Object} file
28647          */
28648         "remove" : true,
28649         /**
28650          * @event refresh
28651          * Fire after refresh the file
28652          * @param {Roo.bootstrap.DocumentManager} this
28653          */
28654         "refresh" : true,
28655         /**
28656          * @event click
28657          * Fire after click the image
28658          * @param {Roo.bootstrap.DocumentManager} this
28659          * @param {Object} file
28660          */
28661         "click" : true,
28662         /**
28663          * @event edit
28664          * Fire when upload a image and editable set to true
28665          * @param {Roo.bootstrap.DocumentManager} this
28666          * @param {Object} file
28667          */
28668         "edit" : true,
28669         /**
28670          * @event beforeselectfile
28671          * Fire before select file
28672          * @param {Roo.bootstrap.DocumentManager} this
28673          */
28674         "beforeselectfile" : true,
28675         /**
28676          * @event process
28677          * Fire before process file
28678          * @param {Roo.bootstrap.DocumentManager} this
28679          * @param {Object} file
28680          */
28681         "process" : true,
28682         /**
28683          * @event previewrendered
28684          * Fire when preview rendered
28685          * @param {Roo.bootstrap.DocumentManager} this
28686          * @param {Object} file
28687          */
28688         "previewrendered" : true
28689         
28690     });
28691 };
28692
28693 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
28694     
28695     boxes : 0,
28696     inputName : '',
28697     thumbSize : 300,
28698     multiple : true,
28699     files : false,
28700     method : 'POST',
28701     url : '',
28702     paramName : 'imageUpload',
28703     toolTipName : 'filename',
28704     fieldLabel : '',
28705     labelWidth : 4,
28706     labelAlign : 'left',
28707     editable : true,
28708     delegates : false,
28709     xhr : false, 
28710     
28711     labellg : 0,
28712     labelmd : 0,
28713     labelsm : 0,
28714     labelxs : 0,
28715     
28716     getAutoCreate : function()
28717     {   
28718         var managerWidget = {
28719             tag : 'div',
28720             cls : 'roo-document-manager',
28721             cn : [
28722                 {
28723                     tag : 'input',
28724                     cls : 'roo-document-manager-selector',
28725                     type : 'file'
28726                 },
28727                 {
28728                     tag : 'div',
28729                     cls : 'roo-document-manager-uploader',
28730                     cn : [
28731                         {
28732                             tag : 'div',
28733                             cls : 'roo-document-manager-upload-btn',
28734                             html : '<i class="fa fa-plus"></i>'
28735                         }
28736                     ]
28737                     
28738                 }
28739             ]
28740         };
28741         
28742         var content = [
28743             {
28744                 tag : 'div',
28745                 cls : 'column col-md-12',
28746                 cn : managerWidget
28747             }
28748         ];
28749         
28750         if(this.fieldLabel.length){
28751             
28752             content = [
28753                 {
28754                     tag : 'div',
28755                     cls : 'column col-md-12',
28756                     html : this.fieldLabel
28757                 },
28758                 {
28759                     tag : 'div',
28760                     cls : 'column col-md-12',
28761                     cn : managerWidget
28762                 }
28763             ];
28764
28765             if(this.labelAlign == 'left'){
28766                 content = [
28767                     {
28768                         tag : 'div',
28769                         cls : 'column',
28770                         html : this.fieldLabel
28771                     },
28772                     {
28773                         tag : 'div',
28774                         cls : 'column',
28775                         cn : managerWidget
28776                     }
28777                 ];
28778                 
28779                 if(this.labelWidth > 12){
28780                     content[0].style = "width: " + this.labelWidth + 'px';
28781                 }
28782
28783                 if(this.labelWidth < 13 && this.labelmd == 0){
28784                     this.labelmd = this.labelWidth;
28785                 }
28786
28787                 if(this.labellg > 0){
28788                     content[0].cls += ' col-lg-' + this.labellg;
28789                     content[1].cls += ' col-lg-' + (12 - this.labellg);
28790                 }
28791
28792                 if(this.labelmd > 0){
28793                     content[0].cls += ' col-md-' + this.labelmd;
28794                     content[1].cls += ' col-md-' + (12 - this.labelmd);
28795                 }
28796
28797                 if(this.labelsm > 0){
28798                     content[0].cls += ' col-sm-' + this.labelsm;
28799                     content[1].cls += ' col-sm-' + (12 - this.labelsm);
28800                 }
28801
28802                 if(this.labelxs > 0){
28803                     content[0].cls += ' col-xs-' + this.labelxs;
28804                     content[1].cls += ' col-xs-' + (12 - this.labelxs);
28805                 }
28806                 
28807             }
28808         }
28809         
28810         var cfg = {
28811             tag : 'div',
28812             cls : 'row clearfix',
28813             cn : content
28814         };
28815         
28816         return cfg;
28817         
28818     },
28819     
28820     initEvents : function()
28821     {
28822         this.managerEl = this.el.select('.roo-document-manager', true).first();
28823         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28824         
28825         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28826         this.selectorEl.hide();
28827         
28828         if(this.multiple){
28829             this.selectorEl.attr('multiple', 'multiple');
28830         }
28831         
28832         this.selectorEl.on('change', this.onFileSelected, this);
28833         
28834         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28835         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28836         
28837         this.uploader.on('click', this.onUploaderClick, this);
28838         
28839         this.renderProgressDialog();
28840         
28841         var _this = this;
28842         
28843         window.addEventListener("resize", function() { _this.refresh(); } );
28844         
28845         this.fireEvent('initial', this);
28846     },
28847     
28848     renderProgressDialog : function()
28849     {
28850         var _this = this;
28851         
28852         this.progressDialog = new Roo.bootstrap.Modal({
28853             cls : 'roo-document-manager-progress-dialog',
28854             allow_close : false,
28855             title : '',
28856             buttons : [
28857                 {
28858                     name  :'cancel',
28859                     weight : 'danger',
28860                     html : 'Cancel'
28861                 }
28862             ], 
28863             listeners : { 
28864                 btnclick : function() {
28865                     _this.uploadCancel();
28866                     this.hide();
28867                 }
28868             }
28869         });
28870          
28871         this.progressDialog.render(Roo.get(document.body));
28872          
28873         this.progress = new Roo.bootstrap.Progress({
28874             cls : 'roo-document-manager-progress',
28875             active : true,
28876             striped : true
28877         });
28878         
28879         this.progress.render(this.progressDialog.getChildContainer());
28880         
28881         this.progressBar = new Roo.bootstrap.ProgressBar({
28882             cls : 'roo-document-manager-progress-bar',
28883             aria_valuenow : 0,
28884             aria_valuemin : 0,
28885             aria_valuemax : 12,
28886             panel : 'success'
28887         });
28888         
28889         this.progressBar.render(this.progress.getChildContainer());
28890     },
28891     
28892     onUploaderClick : function(e)
28893     {
28894         e.preventDefault();
28895      
28896         if(this.fireEvent('beforeselectfile', this) != false){
28897             this.selectorEl.dom.click();
28898         }
28899         
28900     },
28901     
28902     onFileSelected : function(e)
28903     {
28904         e.preventDefault();
28905         
28906         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28907             return;
28908         }
28909         
28910         Roo.each(this.selectorEl.dom.files, function(file){
28911             if(this.fireEvent('inspect', this, file) != false){
28912                 this.files.push(file);
28913             }
28914         }, this);
28915         
28916         this.queue();
28917         
28918     },
28919     
28920     queue : function()
28921     {
28922         this.selectorEl.dom.value = '';
28923         
28924         if(!this.files || !this.files.length){
28925             return;
28926         }
28927         
28928         if(this.boxes > 0 && this.files.length > this.boxes){
28929             this.files = this.files.slice(0, this.boxes);
28930         }
28931         
28932         this.uploader.show();
28933         
28934         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28935             this.uploader.hide();
28936         }
28937         
28938         var _this = this;
28939         
28940         var files = [];
28941         
28942         var docs = [];
28943         
28944         Roo.each(this.files, function(file){
28945             
28946             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28947                 var f = this.renderPreview(file);
28948                 files.push(f);
28949                 return;
28950             }
28951             
28952             if(file.type.indexOf('image') != -1){
28953                 this.delegates.push(
28954                     (function(){
28955                         _this.process(file);
28956                     }).createDelegate(this)
28957                 );
28958         
28959                 return;
28960             }
28961             
28962             docs.push(
28963                 (function(){
28964                     _this.process(file);
28965                 }).createDelegate(this)
28966             );
28967             
28968         }, this);
28969         
28970         this.files = files;
28971         
28972         this.delegates = this.delegates.concat(docs);
28973         
28974         if(!this.delegates.length){
28975             this.refresh();
28976             return;
28977         }
28978         
28979         this.progressBar.aria_valuemax = this.delegates.length;
28980         
28981         this.arrange();
28982         
28983         return;
28984     },
28985     
28986     arrange : function()
28987     {
28988         if(!this.delegates.length){
28989             this.progressDialog.hide();
28990             this.refresh();
28991             return;
28992         }
28993         
28994         var delegate = this.delegates.shift();
28995         
28996         this.progressDialog.show();
28997         
28998         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28999         
29000         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29001         
29002         delegate();
29003     },
29004     
29005     refresh : function()
29006     {
29007         this.uploader.show();
29008         
29009         if(this.boxes > 0 && this.files.length > this.boxes - 1){
29010             this.uploader.hide();
29011         }
29012         
29013         Roo.isTouch ? this.closable(false) : this.closable(true);
29014         
29015         this.fireEvent('refresh', this);
29016     },
29017     
29018     onRemove : function(e, el, o)
29019     {
29020         e.preventDefault();
29021         
29022         this.fireEvent('remove', this, o);
29023         
29024     },
29025     
29026     remove : function(o)
29027     {
29028         var files = [];
29029         
29030         Roo.each(this.files, function(file){
29031             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29032                 files.push(file);
29033                 return;
29034             }
29035
29036             o.target.remove();
29037
29038         }, this);
29039         
29040         this.files = files;
29041         
29042         this.refresh();
29043     },
29044     
29045     clear : function()
29046     {
29047         Roo.each(this.files, function(file){
29048             if(!file.target){
29049                 return;
29050             }
29051             
29052             file.target.remove();
29053
29054         }, this);
29055         
29056         this.files = [];
29057         
29058         this.refresh();
29059     },
29060     
29061     onClick : function(e, el, o)
29062     {
29063         e.preventDefault();
29064         
29065         this.fireEvent('click', this, o);
29066         
29067     },
29068     
29069     closable : function(closable)
29070     {
29071         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29072             
29073             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29074             
29075             if(closable){
29076                 el.show();
29077                 return;
29078             }
29079             
29080             el.hide();
29081             
29082         }, this);
29083     },
29084     
29085     xhrOnLoad : function(xhr)
29086     {
29087         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29088             el.remove();
29089         }, this);
29090         
29091         if (xhr.readyState !== 4) {
29092             this.arrange();
29093             this.fireEvent('exception', this, xhr);
29094             return;
29095         }
29096
29097         var response = Roo.decode(xhr.responseText);
29098         
29099         if(!response.success){
29100             this.arrange();
29101             this.fireEvent('exception', this, xhr);
29102             return;
29103         }
29104         
29105         var file = this.renderPreview(response.data);
29106         
29107         this.files.push(file);
29108         
29109         this.arrange();
29110         
29111         this.fireEvent('afterupload', this, xhr);
29112         
29113     },
29114     
29115     xhrOnError : function(xhr)
29116     {
29117         Roo.log('xhr on error');
29118         
29119         var response = Roo.decode(xhr.responseText);
29120           
29121         Roo.log(response);
29122         
29123         this.arrange();
29124     },
29125     
29126     process : function(file)
29127     {
29128         if(this.fireEvent('process', this, file) !== false){
29129             if(this.editable && file.type.indexOf('image') != -1){
29130                 this.fireEvent('edit', this, file);
29131                 return;
29132             }
29133
29134             this.uploadStart(file, false);
29135
29136             return;
29137         }
29138         
29139     },
29140     
29141     uploadStart : function(file, crop)
29142     {
29143         this.xhr = new XMLHttpRequest();
29144         
29145         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29146             this.arrange();
29147             return;
29148         }
29149         
29150         file.xhr = this.xhr;
29151             
29152         this.managerEl.createChild({
29153             tag : 'div',
29154             cls : 'roo-document-manager-loading',
29155             cn : [
29156                 {
29157                     tag : 'div',
29158                     tooltip : file.name,
29159                     cls : 'roo-document-manager-thumb',
29160                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29161                 }
29162             ]
29163
29164         });
29165
29166         this.xhr.open(this.method, this.url, true);
29167         
29168         var headers = {
29169             "Accept": "application/json",
29170             "Cache-Control": "no-cache",
29171             "X-Requested-With": "XMLHttpRequest"
29172         };
29173         
29174         for (var headerName in headers) {
29175             var headerValue = headers[headerName];
29176             if (headerValue) {
29177                 this.xhr.setRequestHeader(headerName, headerValue);
29178             }
29179         }
29180         
29181         var _this = this;
29182         
29183         this.xhr.onload = function()
29184         {
29185             _this.xhrOnLoad(_this.xhr);
29186         }
29187         
29188         this.xhr.onerror = function()
29189         {
29190             _this.xhrOnError(_this.xhr);
29191         }
29192         
29193         var formData = new FormData();
29194
29195         formData.append('returnHTML', 'NO');
29196         
29197         if(crop){
29198             formData.append('crop', crop);
29199         }
29200         
29201         formData.append(this.paramName, file, file.name);
29202         
29203         var options = {
29204             file : file, 
29205             manually : false
29206         };
29207         
29208         if(this.fireEvent('prepare', this, formData, options) != false){
29209             
29210             if(options.manually){
29211                 return;
29212             }
29213             
29214             this.xhr.send(formData);
29215             return;
29216         };
29217         
29218         this.uploadCancel();
29219     },
29220     
29221     uploadCancel : function()
29222     {
29223         if (this.xhr) {
29224             this.xhr.abort();
29225         }
29226         
29227         this.delegates = [];
29228         
29229         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29230             el.remove();
29231         }, this);
29232         
29233         this.arrange();
29234     },
29235     
29236     renderPreview : function(file)
29237     {
29238         if(typeof(file.target) != 'undefined' && file.target){
29239             return file;
29240         }
29241         
29242         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29243         
29244         var previewEl = this.managerEl.createChild({
29245             tag : 'div',
29246             cls : 'roo-document-manager-preview',
29247             cn : [
29248                 {
29249                     tag : 'div',
29250                     tooltip : file[this.toolTipName],
29251                     cls : 'roo-document-manager-thumb',
29252                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29253                 },
29254                 {
29255                     tag : 'button',
29256                     cls : 'close',
29257                     html : '<i class="fa fa-times-circle"></i>'
29258                 }
29259             ]
29260         });
29261
29262         var close = previewEl.select('button.close', true).first();
29263
29264         close.on('click', this.onRemove, this, file);
29265
29266         file.target = previewEl;
29267
29268         var image = previewEl.select('img', true).first();
29269         
29270         var _this = this;
29271         
29272         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29273         
29274         image.on('click', this.onClick, this, file);
29275         
29276         this.fireEvent('previewrendered', this, file);
29277         
29278         return file;
29279         
29280     },
29281     
29282     onPreviewLoad : function(file, image)
29283     {
29284         if(typeof(file.target) == 'undefined' || !file.target){
29285             return;
29286         }
29287         
29288         var width = image.dom.naturalWidth || image.dom.width;
29289         var height = image.dom.naturalHeight || image.dom.height;
29290         
29291         if(width > height){
29292             file.target.addClass('wide');
29293             return;
29294         }
29295         
29296         file.target.addClass('tall');
29297         return;
29298         
29299     },
29300     
29301     uploadFromSource : function(file, crop)
29302     {
29303         this.xhr = new XMLHttpRequest();
29304         
29305         this.managerEl.createChild({
29306             tag : 'div',
29307             cls : 'roo-document-manager-loading',
29308             cn : [
29309                 {
29310                     tag : 'div',
29311                     tooltip : file.name,
29312                     cls : 'roo-document-manager-thumb',
29313                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29314                 }
29315             ]
29316
29317         });
29318
29319         this.xhr.open(this.method, this.url, true);
29320         
29321         var headers = {
29322             "Accept": "application/json",
29323             "Cache-Control": "no-cache",
29324             "X-Requested-With": "XMLHttpRequest"
29325         };
29326         
29327         for (var headerName in headers) {
29328             var headerValue = headers[headerName];
29329             if (headerValue) {
29330                 this.xhr.setRequestHeader(headerName, headerValue);
29331             }
29332         }
29333         
29334         var _this = this;
29335         
29336         this.xhr.onload = function()
29337         {
29338             _this.xhrOnLoad(_this.xhr);
29339         }
29340         
29341         this.xhr.onerror = function()
29342         {
29343             _this.xhrOnError(_this.xhr);
29344         }
29345         
29346         var formData = new FormData();
29347
29348         formData.append('returnHTML', 'NO');
29349         
29350         formData.append('crop', crop);
29351         
29352         if(typeof(file.filename) != 'undefined'){
29353             formData.append('filename', file.filename);
29354         }
29355         
29356         if(typeof(file.mimetype) != 'undefined'){
29357             formData.append('mimetype', file.mimetype);
29358         }
29359         
29360         Roo.log(formData);
29361         
29362         if(this.fireEvent('prepare', this, formData) != false){
29363             this.xhr.send(formData);
29364         };
29365     }
29366 });
29367
29368 /*
29369 * Licence: LGPL
29370 */
29371
29372 /**
29373  * @class Roo.bootstrap.DocumentViewer
29374  * @extends Roo.bootstrap.Component
29375  * Bootstrap DocumentViewer class
29376  * @cfg {Boolean} showDownload (true|false) show download button (default true)
29377  * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29378  * 
29379  * @constructor
29380  * Create a new DocumentViewer
29381  * @param {Object} config The config object
29382  */
29383
29384 Roo.bootstrap.DocumentViewer = function(config){
29385     Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29386     
29387     this.addEvents({
29388         /**
29389          * @event initial
29390          * Fire after initEvent
29391          * @param {Roo.bootstrap.DocumentViewer} this
29392          */
29393         "initial" : true,
29394         /**
29395          * @event click
29396          * Fire after click
29397          * @param {Roo.bootstrap.DocumentViewer} this
29398          */
29399         "click" : true,
29400         /**
29401          * @event download
29402          * Fire after download button
29403          * @param {Roo.bootstrap.DocumentViewer} this
29404          */
29405         "download" : true,
29406         /**
29407          * @event trash
29408          * Fire after trash button
29409          * @param {Roo.bootstrap.DocumentViewer} this
29410          */
29411         "trash" : true
29412         
29413     });
29414 };
29415
29416 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
29417     
29418     showDownload : true,
29419     
29420     showTrash : true,
29421     
29422     getAutoCreate : function()
29423     {
29424         var cfg = {
29425             tag : 'div',
29426             cls : 'roo-document-viewer',
29427             cn : [
29428                 {
29429                     tag : 'div',
29430                     cls : 'roo-document-viewer-body',
29431                     cn : [
29432                         {
29433                             tag : 'div',
29434                             cls : 'roo-document-viewer-thumb',
29435                             cn : [
29436                                 {
29437                                     tag : 'img',
29438                                     cls : 'roo-document-viewer-image'
29439                                 }
29440                             ]
29441                         }
29442                     ]
29443                 },
29444                 {
29445                     tag : 'div',
29446                     cls : 'roo-document-viewer-footer',
29447                     cn : {
29448                         tag : 'div',
29449                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29450                         cn : [
29451                             {
29452                                 tag : 'div',
29453                                 cls : 'btn-group roo-document-viewer-download',
29454                                 cn : [
29455                                     {
29456                                         tag : 'button',
29457                                         cls : 'btn btn-default',
29458                                         html : '<i class="fa fa-download"></i>'
29459                                     }
29460                                 ]
29461                             },
29462                             {
29463                                 tag : 'div',
29464                                 cls : 'btn-group roo-document-viewer-trash',
29465                                 cn : [
29466                                     {
29467                                         tag : 'button',
29468                                         cls : 'btn btn-default',
29469                                         html : '<i class="fa fa-trash"></i>'
29470                                     }
29471                                 ]
29472                             }
29473                         ]
29474                     }
29475                 }
29476             ]
29477         };
29478         
29479         return cfg;
29480     },
29481     
29482     initEvents : function()
29483     {
29484         this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29485         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29486         
29487         this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29488         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29489         
29490         this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29491         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29492         
29493         this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29494         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29495         
29496         this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29497         this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29498         
29499         this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29500         this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29501         
29502         this.bodyEl.on('click', this.onClick, this);
29503         this.downloadBtn.on('click', this.onDownload, this);
29504         this.trashBtn.on('click', this.onTrash, this);
29505         
29506         this.downloadBtn.hide();
29507         this.trashBtn.hide();
29508         
29509         if(this.showDownload){
29510             this.downloadBtn.show();
29511         }
29512         
29513         if(this.showTrash){
29514             this.trashBtn.show();
29515         }
29516         
29517         if(!this.showDownload && !this.showTrash) {
29518             this.footerEl.hide();
29519         }
29520         
29521     },
29522     
29523     initial : function()
29524     {
29525         this.fireEvent('initial', this);
29526         
29527     },
29528     
29529     onClick : function(e)
29530     {
29531         e.preventDefault();
29532         
29533         this.fireEvent('click', this);
29534     },
29535     
29536     onDownload : function(e)
29537     {
29538         e.preventDefault();
29539         
29540         this.fireEvent('download', this);
29541     },
29542     
29543     onTrash : function(e)
29544     {
29545         e.preventDefault();
29546         
29547         this.fireEvent('trash', this);
29548     }
29549     
29550 });
29551 /*
29552  * - LGPL
29553  *
29554  * nav progress bar
29555  * 
29556  */
29557
29558 /**
29559  * @class Roo.bootstrap.NavProgressBar
29560  * @extends Roo.bootstrap.Component
29561  * Bootstrap NavProgressBar class
29562  * 
29563  * @constructor
29564  * Create a new nav progress bar
29565  * @param {Object} config The config object
29566  */
29567
29568 Roo.bootstrap.NavProgressBar = function(config){
29569     Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29570
29571     this.bullets = this.bullets || [];
29572    
29573 //    Roo.bootstrap.NavProgressBar.register(this);
29574      this.addEvents({
29575         /**
29576              * @event changed
29577              * Fires when the active item changes
29578              * @param {Roo.bootstrap.NavProgressBar} this
29579              * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29580              * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
29581          */
29582         'changed': true
29583      });
29584     
29585 };
29586
29587 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
29588     
29589     bullets : [],
29590     barItems : [],
29591     
29592     getAutoCreate : function()
29593     {
29594         var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29595         
29596         cfg = {
29597             tag : 'div',
29598             cls : 'roo-navigation-bar-group',
29599             cn : [
29600                 {
29601                     tag : 'div',
29602                     cls : 'roo-navigation-top-bar'
29603                 },
29604                 {
29605                     tag : 'div',
29606                     cls : 'roo-navigation-bullets-bar',
29607                     cn : [
29608                         {
29609                             tag : 'ul',
29610                             cls : 'roo-navigation-bar'
29611                         }
29612                     ]
29613                 },
29614                 
29615                 {
29616                     tag : 'div',
29617                     cls : 'roo-navigation-bottom-bar'
29618                 }
29619             ]
29620             
29621         };
29622         
29623         return cfg;
29624         
29625     },
29626     
29627     initEvents: function() 
29628     {
29629         
29630     },
29631     
29632     onRender : function(ct, position) 
29633     {
29634         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29635         
29636         if(this.bullets.length){
29637             Roo.each(this.bullets, function(b){
29638                this.addItem(b);
29639             }, this);
29640         }
29641         
29642         this.format();
29643         
29644     },
29645     
29646     addItem : function(cfg)
29647     {
29648         var item = new Roo.bootstrap.NavProgressItem(cfg);
29649         
29650         item.parentId = this.id;
29651         item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29652         
29653         if(cfg.html){
29654             var top = new Roo.bootstrap.Element({
29655                 tag : 'div',
29656                 cls : 'roo-navigation-bar-text'
29657             });
29658             
29659             var bottom = new Roo.bootstrap.Element({
29660                 tag : 'div',
29661                 cls : 'roo-navigation-bar-text'
29662             });
29663             
29664             top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29665             bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29666             
29667             var topText = new Roo.bootstrap.Element({
29668                 tag : 'span',
29669                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29670             });
29671             
29672             var bottomText = new Roo.bootstrap.Element({
29673                 tag : 'span',
29674                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29675             });
29676             
29677             topText.onRender(top.el, null);
29678             bottomText.onRender(bottom.el, null);
29679             
29680             item.topEl = top;
29681             item.bottomEl = bottom;
29682         }
29683         
29684         this.barItems.push(item);
29685         
29686         return item;
29687     },
29688     
29689     getActive : function()
29690     {
29691         var active = false;
29692         
29693         Roo.each(this.barItems, function(v){
29694             
29695             if (!v.isActive()) {
29696                 return;
29697             }
29698             
29699             active = v;
29700             return false;
29701             
29702         });
29703         
29704         return active;
29705     },
29706     
29707     setActiveItem : function(item)
29708     {
29709         var prev = false;
29710         
29711         Roo.each(this.barItems, function(v){
29712             if (v.rid == item.rid) {
29713                 return ;
29714             }
29715             
29716             if (v.isActive()) {
29717                 v.setActive(false);
29718                 prev = v;
29719             }
29720         });
29721
29722         item.setActive(true);
29723         
29724         this.fireEvent('changed', this, item, prev);
29725     },
29726     
29727     getBarItem: function(rid)
29728     {
29729         var ret = false;
29730         
29731         Roo.each(this.barItems, function(e) {
29732             if (e.rid != rid) {
29733                 return;
29734             }
29735             
29736             ret =  e;
29737             return false;
29738         });
29739         
29740         return ret;
29741     },
29742     
29743     indexOfItem : function(item)
29744     {
29745         var index = false;
29746         
29747         Roo.each(this.barItems, function(v, i){
29748             
29749             if (v.rid != item.rid) {
29750                 return;
29751             }
29752             
29753             index = i;
29754             return false
29755         });
29756         
29757         return index;
29758     },
29759     
29760     setActiveNext : function()
29761     {
29762         var i = this.indexOfItem(this.getActive());
29763         
29764         if (i > this.barItems.length) {
29765             return;
29766         }
29767         
29768         this.setActiveItem(this.barItems[i+1]);
29769     },
29770     
29771     setActivePrev : function()
29772     {
29773         var i = this.indexOfItem(this.getActive());
29774         
29775         if (i  < 1) {
29776             return;
29777         }
29778         
29779         this.setActiveItem(this.barItems[i-1]);
29780     },
29781     
29782     format : function()
29783     {
29784         if(!this.barItems.length){
29785             return;
29786         }
29787      
29788         var width = 100 / this.barItems.length;
29789         
29790         Roo.each(this.barItems, function(i){
29791             i.el.setStyle('width', width + '%');
29792             i.topEl.el.setStyle('width', width + '%');
29793             i.bottomEl.el.setStyle('width', width + '%');
29794         }, this);
29795         
29796     }
29797     
29798 });
29799 /*
29800  * - LGPL
29801  *
29802  * Nav Progress Item
29803  * 
29804  */
29805
29806 /**
29807  * @class Roo.bootstrap.NavProgressItem
29808  * @extends Roo.bootstrap.Component
29809  * Bootstrap NavProgressItem class
29810  * @cfg {String} rid the reference id
29811  * @cfg {Boolean} active (true|false) Is item active default false
29812  * @cfg {Boolean} disabled (true|false) Is item active default false
29813  * @cfg {String} html
29814  * @cfg {String} position (top|bottom) text position default bottom
29815  * @cfg {String} icon show icon instead of number
29816  * 
29817  * @constructor
29818  * Create a new NavProgressItem
29819  * @param {Object} config The config object
29820  */
29821 Roo.bootstrap.NavProgressItem = function(config){
29822     Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29823     this.addEvents({
29824         // raw events
29825         /**
29826          * @event click
29827          * The raw click event for the entire grid.
29828          * @param {Roo.bootstrap.NavProgressItem} this
29829          * @param {Roo.EventObject} e
29830          */
29831         "click" : true
29832     });
29833    
29834 };
29835
29836 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
29837     
29838     rid : '',
29839     active : false,
29840     disabled : false,
29841     html : '',
29842     position : 'bottom',
29843     icon : false,
29844     
29845     getAutoCreate : function()
29846     {
29847         var iconCls = 'roo-navigation-bar-item-icon';
29848         
29849         iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29850         
29851         var cfg = {
29852             tag: 'li',
29853             cls: 'roo-navigation-bar-item',
29854             cn : [
29855                 {
29856                     tag : 'i',
29857                     cls : iconCls
29858                 }
29859             ]
29860         };
29861         
29862         if(this.active){
29863             cfg.cls += ' active';
29864         }
29865         if(this.disabled){
29866             cfg.cls += ' disabled';
29867         }
29868         
29869         return cfg;
29870     },
29871     
29872     disable : function()
29873     {
29874         this.setDisabled(true);
29875     },
29876     
29877     enable : function()
29878     {
29879         this.setDisabled(false);
29880     },
29881     
29882     initEvents: function() 
29883     {
29884         this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29885         
29886         this.iconEl.on('click', this.onClick, this);
29887     },
29888     
29889     onClick : function(e)
29890     {
29891         e.preventDefault();
29892         
29893         if(this.disabled){
29894             return;
29895         }
29896         
29897         if(this.fireEvent('click', this, e) === false){
29898             return;
29899         };
29900         
29901         this.parent().setActiveItem(this);
29902     },
29903     
29904     isActive: function () 
29905     {
29906         return this.active;
29907     },
29908     
29909     setActive : function(state)
29910     {
29911         if(this.active == state){
29912             return;
29913         }
29914         
29915         this.active = state;
29916         
29917         if (state) {
29918             this.el.addClass('active');
29919             return;
29920         }
29921         
29922         this.el.removeClass('active');
29923         
29924         return;
29925     },
29926     
29927     setDisabled : function(state)
29928     {
29929         if(this.disabled == state){
29930             return;
29931         }
29932         
29933         this.disabled = state;
29934         
29935         if (state) {
29936             this.el.addClass('disabled');
29937             return;
29938         }
29939         
29940         this.el.removeClass('disabled');
29941     },
29942     
29943     tooltipEl : function()
29944     {
29945         return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29946     }
29947 });
29948  
29949
29950  /*
29951  * - LGPL
29952  *
29953  * FieldLabel
29954  * 
29955  */
29956
29957 /**
29958  * @class Roo.bootstrap.FieldLabel
29959  * @extends Roo.bootstrap.Component
29960  * Bootstrap FieldLabel class
29961  * @cfg {String} html contents of the element
29962  * @cfg {String} tag tag of the element default label
29963  * @cfg {String} cls class of the element
29964  * @cfg {String} target label target 
29965  * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29966  * @cfg {String} invalidClass default "text-warning"
29967  * @cfg {String} validClass default "text-success"
29968  * @cfg {String} iconTooltip default "This field is required"
29969  * @cfg {String} indicatorpos (left|right) default left
29970  * 
29971  * @constructor
29972  * Create a new FieldLabel
29973  * @param {Object} config The config object
29974  */
29975
29976 Roo.bootstrap.FieldLabel = function(config){
29977     Roo.bootstrap.Element.superclass.constructor.call(this, config);
29978     
29979     this.addEvents({
29980             /**
29981              * @event invalid
29982              * Fires after the field has been marked as invalid.
29983              * @param {Roo.form.FieldLabel} this
29984              * @param {String} msg The validation message
29985              */
29986             invalid : true,
29987             /**
29988              * @event valid
29989              * Fires after the field has been validated with no errors.
29990              * @param {Roo.form.FieldLabel} this
29991              */
29992             valid : true
29993         });
29994 };
29995
29996 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
29997     
29998     tag: 'label',
29999     cls: '',
30000     html: '',
30001     target: '',
30002     allowBlank : true,
30003     invalidClass : 'has-warning',
30004     validClass : 'has-success',
30005     iconTooltip : 'This field is required',
30006     indicatorpos : 'left',
30007     
30008     getAutoCreate : function(){
30009         
30010         var cls = "";
30011         if (!this.allowBlank) {
30012             cls  = "visible";
30013         }
30014         
30015         var cfg = {
30016             tag : this.tag,
30017             cls : 'roo-bootstrap-field-label ' + this.cls,
30018             for : this.target,
30019             cn : [
30020                 {
30021                     tag : 'i',
30022                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30023                     tooltip : this.iconTooltip
30024                 },
30025                 {
30026                     tag : 'span',
30027                     html : this.html
30028                 }
30029             ] 
30030         };
30031         
30032         if(this.indicatorpos == 'right'){
30033             var cfg = {
30034                 tag : this.tag,
30035                 cls : 'roo-bootstrap-field-label ' + this.cls,
30036                 for : this.target,
30037                 cn : [
30038                     {
30039                         tag : 'span',
30040                         html : this.html
30041                     },
30042                     {
30043                         tag : 'i',
30044                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30045                         tooltip : this.iconTooltip
30046                     }
30047                 ] 
30048             };
30049         }
30050         
30051         return cfg;
30052     },
30053     
30054     initEvents: function() 
30055     {
30056         Roo.bootstrap.Element.superclass.initEvents.call(this);
30057         
30058         this.indicator = this.indicatorEl();
30059         
30060         if(this.indicator){
30061             this.indicator.removeClass('visible');
30062             this.indicator.addClass('invisible');
30063         }
30064         
30065         Roo.bootstrap.FieldLabel.register(this);
30066     },
30067     
30068     indicatorEl : function()
30069     {
30070         var indicator = this.el.select('i.roo-required-indicator',true).first();
30071         
30072         if(!indicator){
30073             return false;
30074         }
30075         
30076         return indicator;
30077         
30078     },
30079     
30080     /**
30081      * Mark this field as valid
30082      */
30083     markValid : function()
30084     {
30085         if(this.indicator){
30086             this.indicator.removeClass('visible');
30087             this.indicator.addClass('invisible');
30088         }
30089         
30090         this.el.removeClass(this.invalidClass);
30091         
30092         this.el.addClass(this.validClass);
30093         
30094         this.fireEvent('valid', this);
30095     },
30096     
30097     /**
30098      * Mark this field as invalid
30099      * @param {String} msg The validation message
30100      */
30101     markInvalid : function(msg)
30102     {
30103         if(this.indicator){
30104             this.indicator.removeClass('invisible');
30105             this.indicator.addClass('visible');
30106         }
30107         
30108         this.el.removeClass(this.validClass);
30109         
30110         this.el.addClass(this.invalidClass);
30111         
30112         this.fireEvent('invalid', this, msg);
30113     }
30114     
30115    
30116 });
30117
30118 Roo.apply(Roo.bootstrap.FieldLabel, {
30119     
30120     groups: {},
30121     
30122      /**
30123     * register a FieldLabel Group
30124     * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30125     */
30126     register : function(label)
30127     {
30128         if(this.groups.hasOwnProperty(label.target)){
30129             return;
30130         }
30131      
30132         this.groups[label.target] = label;
30133         
30134     },
30135     /**
30136     * fetch a FieldLabel Group based on the target
30137     * @param {string} target
30138     * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30139     */
30140     get: function(target) {
30141         if (typeof(this.groups[target]) == 'undefined') {
30142             return false;
30143         }
30144         
30145         return this.groups[target] ;
30146     }
30147 });
30148
30149  
30150
30151  /*
30152  * - LGPL
30153  *
30154  * page DateSplitField.
30155  * 
30156  */
30157
30158
30159 /**
30160  * @class Roo.bootstrap.DateSplitField
30161  * @extends Roo.bootstrap.Component
30162  * Bootstrap DateSplitField class
30163  * @cfg {string} fieldLabel - the label associated
30164  * @cfg {Number} labelWidth set the width of label (0-12)
30165  * @cfg {String} labelAlign (top|left)
30166  * @cfg {Boolean} dayAllowBlank (true|false) default false
30167  * @cfg {Boolean} monthAllowBlank (true|false) default false
30168  * @cfg {Boolean} yearAllowBlank (true|false) default false
30169  * @cfg {string} dayPlaceholder 
30170  * @cfg {string} monthPlaceholder
30171  * @cfg {string} yearPlaceholder
30172  * @cfg {string} dayFormat default 'd'
30173  * @cfg {string} monthFormat default 'm'
30174  * @cfg {string} yearFormat default 'Y'
30175  * @cfg {Number} labellg set the width of label (1-12)
30176  * @cfg {Number} labelmd set the width of label (1-12)
30177  * @cfg {Number} labelsm set the width of label (1-12)
30178  * @cfg {Number} labelxs set the width of label (1-12)
30179
30180  *     
30181  * @constructor
30182  * Create a new DateSplitField
30183  * @param {Object} config The config object
30184  */
30185
30186 Roo.bootstrap.DateSplitField = function(config){
30187     Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30188     
30189     this.addEvents({
30190         // raw events
30191          /**
30192          * @event years
30193          * getting the data of years
30194          * @param {Roo.bootstrap.DateSplitField} this
30195          * @param {Object} years
30196          */
30197         "years" : true,
30198         /**
30199          * @event days
30200          * getting the data of days
30201          * @param {Roo.bootstrap.DateSplitField} this
30202          * @param {Object} days
30203          */
30204         "days" : true,
30205         /**
30206          * @event invalid
30207          * Fires after the field has been marked as invalid.
30208          * @param {Roo.form.Field} this
30209          * @param {String} msg The validation message
30210          */
30211         invalid : true,
30212        /**
30213          * @event valid
30214          * Fires after the field has been validated with no errors.
30215          * @param {Roo.form.Field} this
30216          */
30217         valid : true
30218     });
30219 };
30220
30221 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
30222     
30223     fieldLabel : '',
30224     labelAlign : 'top',
30225     labelWidth : 3,
30226     dayAllowBlank : false,
30227     monthAllowBlank : false,
30228     yearAllowBlank : false,
30229     dayPlaceholder : '',
30230     monthPlaceholder : '',
30231     yearPlaceholder : '',
30232     dayFormat : 'd',
30233     monthFormat : 'm',
30234     yearFormat : 'Y',
30235     isFormField : true,
30236     labellg : 0,
30237     labelmd : 0,
30238     labelsm : 0,
30239     labelxs : 0,
30240     
30241     getAutoCreate : function()
30242     {
30243         var cfg = {
30244             tag : 'div',
30245             cls : 'row roo-date-split-field-group',
30246             cn : [
30247                 {
30248                     tag : 'input',
30249                     type : 'hidden',
30250                     cls : 'form-hidden-field roo-date-split-field-group-value',
30251                     name : this.name
30252                 }
30253             ]
30254         };
30255         
30256         var labelCls = 'col-md-12';
30257         var contentCls = 'col-md-4';
30258         
30259         if(this.fieldLabel){
30260             
30261             var label = {
30262                 tag : 'div',
30263                 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30264                 cn : [
30265                     {
30266                         tag : 'label',
30267                         html : this.fieldLabel
30268                     }
30269                 ]
30270             };
30271             
30272             if(this.labelAlign == 'left'){
30273             
30274                 if(this.labelWidth > 12){
30275                     label.style = "width: " + this.labelWidth + 'px';
30276                 }
30277
30278                 if(this.labelWidth < 13 && this.labelmd == 0){
30279                     this.labelmd = this.labelWidth;
30280                 }
30281
30282                 if(this.labellg > 0){
30283                     labelCls = ' col-lg-' + this.labellg;
30284                     contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30285                 }
30286
30287                 if(this.labelmd > 0){
30288                     labelCls = ' col-md-' + this.labelmd;
30289                     contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30290                 }
30291
30292                 if(this.labelsm > 0){
30293                     labelCls = ' col-sm-' + this.labelsm;
30294                     contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30295                 }
30296
30297                 if(this.labelxs > 0){
30298                     labelCls = ' col-xs-' + this.labelxs;
30299                     contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30300                 }
30301             }
30302             
30303             label.cls += ' ' + labelCls;
30304             
30305             cfg.cn.push(label);
30306         }
30307         
30308         Roo.each(['day', 'month', 'year'], function(t){
30309             cfg.cn.push({
30310                 tag : 'div',
30311                 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30312             });
30313         }, this);
30314         
30315         return cfg;
30316     },
30317     
30318     inputEl: function ()
30319     {
30320         return this.el.select('.roo-date-split-field-group-value', true).first();
30321     },
30322     
30323     onRender : function(ct, position) 
30324     {
30325         var _this = this;
30326         
30327         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30328         
30329         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30330         
30331         this.dayField = new Roo.bootstrap.ComboBox({
30332             allowBlank : this.dayAllowBlank,
30333             alwaysQuery : true,
30334             displayField : 'value',
30335             editable : false,
30336             fieldLabel : '',
30337             forceSelection : true,
30338             mode : 'local',
30339             placeholder : this.dayPlaceholder,
30340             selectOnFocus : true,
30341             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30342             triggerAction : 'all',
30343             typeAhead : true,
30344             valueField : 'value',
30345             store : new Roo.data.SimpleStore({
30346                 data : (function() {    
30347                     var days = [];
30348                     _this.fireEvent('days', _this, days);
30349                     return days;
30350                 })(),
30351                 fields : [ 'value' ]
30352             }),
30353             listeners : {
30354                 select : function (_self, record, index)
30355                 {
30356                     _this.setValue(_this.getValue());
30357                 }
30358             }
30359         });
30360
30361         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30362         
30363         this.monthField = new Roo.bootstrap.MonthField({
30364             after : '<i class=\"fa fa-calendar\"></i>',
30365             allowBlank : this.monthAllowBlank,
30366             placeholder : this.monthPlaceholder,
30367             readOnly : true,
30368             listeners : {
30369                 render : function (_self)
30370                 {
30371                     this.el.select('span.input-group-addon', true).first().on('click', function(e){
30372                         e.preventDefault();
30373                         _self.focus();
30374                     });
30375                 },
30376                 select : function (_self, oldvalue, newvalue)
30377                 {
30378                     _this.setValue(_this.getValue());
30379                 }
30380             }
30381         });
30382         
30383         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30384         
30385         this.yearField = new Roo.bootstrap.ComboBox({
30386             allowBlank : this.yearAllowBlank,
30387             alwaysQuery : true,
30388             displayField : 'value',
30389             editable : false,
30390             fieldLabel : '',
30391             forceSelection : true,
30392             mode : 'local',
30393             placeholder : this.yearPlaceholder,
30394             selectOnFocus : true,
30395             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30396             triggerAction : 'all',
30397             typeAhead : true,
30398             valueField : 'value',
30399             store : new Roo.data.SimpleStore({
30400                 data : (function() {
30401                     var years = [];
30402                     _this.fireEvent('years', _this, years);
30403                     return years;
30404                 })(),
30405                 fields : [ 'value' ]
30406             }),
30407             listeners : {
30408                 select : function (_self, record, index)
30409                 {
30410                     _this.setValue(_this.getValue());
30411                 }
30412             }
30413         });
30414
30415         this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30416     },
30417     
30418     setValue : function(v, format)
30419     {
30420         this.inputEl.dom.value = v;
30421         
30422         var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30423         
30424         var d = Date.parseDate(v, f);
30425         
30426         if(!d){
30427             this.validate();
30428             return;
30429         }
30430         
30431         this.setDay(d.format(this.dayFormat));
30432         this.setMonth(d.format(this.monthFormat));
30433         this.setYear(d.format(this.yearFormat));
30434         
30435         this.validate();
30436         
30437         return;
30438     },
30439     
30440     setDay : function(v)
30441     {
30442         this.dayField.setValue(v);
30443         this.inputEl.dom.value = this.getValue();
30444         this.validate();
30445         return;
30446     },
30447     
30448     setMonth : function(v)
30449     {
30450         this.monthField.setValue(v, true);
30451         this.inputEl.dom.value = this.getValue();
30452         this.validate();
30453         return;
30454     },
30455     
30456     setYear : function(v)
30457     {
30458         this.yearField.setValue(v);
30459         this.inputEl.dom.value = this.getValue();
30460         this.validate();
30461         return;
30462     },
30463     
30464     getDay : function()
30465     {
30466         return this.dayField.getValue();
30467     },
30468     
30469     getMonth : function()
30470     {
30471         return this.monthField.getValue();
30472     },
30473     
30474     getYear : function()
30475     {
30476         return this.yearField.getValue();
30477     },
30478     
30479     getValue : function()
30480     {
30481         var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30482         
30483         var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30484         
30485         return date;
30486     },
30487     
30488     reset : function()
30489     {
30490         this.setDay('');
30491         this.setMonth('');
30492         this.setYear('');
30493         this.inputEl.dom.value = '';
30494         this.validate();
30495         return;
30496     },
30497     
30498     validate : function()
30499     {
30500         var d = this.dayField.validate();
30501         var m = this.monthField.validate();
30502         var y = this.yearField.validate();
30503         
30504         var valid = true;
30505         
30506         if(
30507                 (!this.dayAllowBlank && !d) ||
30508                 (!this.monthAllowBlank && !m) ||
30509                 (!this.yearAllowBlank && !y)
30510         ){
30511             valid = false;
30512         }
30513         
30514         if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30515             return valid;
30516         }
30517         
30518         if(valid){
30519             this.markValid();
30520             return valid;
30521         }
30522         
30523         this.markInvalid();
30524         
30525         return valid;
30526     },
30527     
30528     markValid : function()
30529     {
30530         
30531         var label = this.el.select('label', true).first();
30532         var icon = this.el.select('i.fa-star', true).first();
30533
30534         if(label && icon){
30535             icon.remove();
30536         }
30537         
30538         this.fireEvent('valid', this);
30539     },
30540     
30541      /**
30542      * Mark this field as invalid
30543      * @param {String} msg The validation message
30544      */
30545     markInvalid : function(msg)
30546     {
30547         
30548         var label = this.el.select('label', true).first();
30549         var icon = this.el.select('i.fa-star', true).first();
30550
30551         if(label && !icon){
30552             this.el.select('.roo-date-split-field-label', true).createChild({
30553                 tag : 'i',
30554                 cls : 'text-danger fa fa-lg fa-star',
30555                 tooltip : 'This field is required',
30556                 style : 'margin-right:5px;'
30557             }, label, true);
30558         }
30559         
30560         this.fireEvent('invalid', this, msg);
30561     },
30562     
30563     clearInvalid : function()
30564     {
30565         var label = this.el.select('label', true).first();
30566         var icon = this.el.select('i.fa-star', true).first();
30567
30568         if(label && icon){
30569             icon.remove();
30570         }
30571         
30572         this.fireEvent('valid', this);
30573     },
30574     
30575     getName: function()
30576     {
30577         return this.name;
30578     }
30579     
30580 });
30581
30582  /**
30583  *
30584  * This is based on 
30585  * http://masonry.desandro.com
30586  *
30587  * The idea is to render all the bricks based on vertical width...
30588  *
30589  * The original code extends 'outlayer' - we might need to use that....
30590  * 
30591  */
30592
30593
30594 /**
30595  * @class Roo.bootstrap.LayoutMasonry
30596  * @extends Roo.bootstrap.Component
30597  * Bootstrap Layout Masonry class
30598  * 
30599  * @constructor
30600  * Create a new Element
30601  * @param {Object} config The config object
30602  */
30603
30604 Roo.bootstrap.LayoutMasonry = function(config){
30605     
30606     Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30607     
30608     this.bricks = [];
30609     
30610     Roo.bootstrap.LayoutMasonry.register(this);
30611     
30612     this.addEvents({
30613         // raw events
30614         /**
30615          * @event layout
30616          * Fire after layout the items
30617          * @param {Roo.bootstrap.LayoutMasonry} this
30618          * @param {Roo.EventObject} e
30619          */
30620         "layout" : true
30621     });
30622     
30623 };
30624
30625 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component,  {
30626     
30627     /**
30628      * @cfg {Boolean} isLayoutInstant = no animation?
30629      */   
30630     isLayoutInstant : false, // needed?
30631    
30632     /**
30633      * @cfg {Number} boxWidth  width of the columns
30634      */   
30635     boxWidth : 450,
30636     
30637       /**
30638      * @cfg {Number} boxHeight  - 0 for square, or fix it at a certian height
30639      */   
30640     boxHeight : 0,
30641     
30642     /**
30643      * @cfg {Number} padWidth padding below box..
30644      */   
30645     padWidth : 10, 
30646     
30647     /**
30648      * @cfg {Number} gutter gutter width..
30649      */   
30650     gutter : 10,
30651     
30652      /**
30653      * @cfg {Number} maxCols maximum number of columns
30654      */   
30655     
30656     maxCols: 0,
30657     
30658     /**
30659      * @cfg {Boolean} isAutoInitial defalut true
30660      */   
30661     isAutoInitial : true, 
30662     
30663     containerWidth: 0,
30664     
30665     /**
30666      * @cfg {Boolean} isHorizontal defalut false
30667      */   
30668     isHorizontal : false, 
30669
30670     currentSize : null,
30671     
30672     tag: 'div',
30673     
30674     cls: '',
30675     
30676     bricks: null, //CompositeElement
30677     
30678     cols : 1,
30679     
30680     _isLayoutInited : false,
30681     
30682 //    isAlternative : false, // only use for vertical layout...
30683     
30684     /**
30685      * @cfg {Number} alternativePadWidth padding below box..
30686      */   
30687     alternativePadWidth : 50,
30688     
30689     selectedBrick : [],
30690     
30691     getAutoCreate : function(){
30692         
30693         var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30694         
30695         var cfg = {
30696             tag: this.tag,
30697             cls: 'blog-masonary-wrapper ' + this.cls,
30698             cn : {
30699                 cls : 'mas-boxes masonary'
30700             }
30701         };
30702         
30703         return cfg;
30704     },
30705     
30706     getChildContainer: function( )
30707     {
30708         if (this.boxesEl) {
30709             return this.boxesEl;
30710         }
30711         
30712         this.boxesEl = this.el.select('.mas-boxes').first();
30713         
30714         return this.boxesEl;
30715     },
30716     
30717     
30718     initEvents : function()
30719     {
30720         var _this = this;
30721         
30722         if(this.isAutoInitial){
30723             Roo.log('hook children rendered');
30724             this.on('childrenrendered', function() {
30725                 Roo.log('children rendered');
30726                 _this.initial();
30727             } ,this);
30728         }
30729     },
30730     
30731     initial : function()
30732     {
30733         this.selectedBrick = [];
30734         
30735         this.currentSize = this.el.getBox(true);
30736         
30737         Roo.EventManager.onWindowResize(this.resize, this); 
30738
30739         if(!this.isAutoInitial){
30740             this.layout();
30741             return;
30742         }
30743         
30744         this.layout();
30745         
30746         return;
30747         //this.layout.defer(500,this);
30748         
30749     },
30750     
30751     resize : function()
30752     {
30753         var cs = this.el.getBox(true);
30754         
30755         if (
30756                 this.currentSize.width == cs.width && 
30757                 this.currentSize.x == cs.x && 
30758                 this.currentSize.height == cs.height && 
30759                 this.currentSize.y == cs.y 
30760         ) {
30761             Roo.log("no change in with or X or Y");
30762             return;
30763         }
30764         
30765         this.currentSize = cs;
30766         
30767         this.layout();
30768         
30769     },
30770     
30771     layout : function()
30772     {   
30773         this._resetLayout();
30774         
30775         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30776         
30777         this.layoutItems( isInstant );
30778       
30779         this._isLayoutInited = true;
30780         
30781         this.fireEvent('layout', this);
30782         
30783     },
30784     
30785     _resetLayout : function()
30786     {
30787         if(this.isHorizontal){
30788             this.horizontalMeasureColumns();
30789             return;
30790         }
30791         
30792         this.verticalMeasureColumns();
30793         
30794     },
30795     
30796     verticalMeasureColumns : function()
30797     {
30798         this.getContainerWidth();
30799         
30800 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30801 //            this.colWidth = Math.floor(this.containerWidth * 0.8);
30802 //            return;
30803 //        }
30804         
30805         var boxWidth = this.boxWidth + this.padWidth;
30806         
30807         if(this.containerWidth < this.boxWidth){
30808             boxWidth = this.containerWidth
30809         }
30810         
30811         var containerWidth = this.containerWidth;
30812         
30813         var cols = Math.floor(containerWidth / boxWidth);
30814         
30815         this.cols = Math.max( cols, 1 );
30816         
30817         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30818         
30819         var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30820         
30821         var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30822         
30823         this.colWidth = boxWidth + avail - this.padWidth;
30824         
30825         this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30826         this.unitHeight = this.boxHeight > 0 ? this.boxHeight  : this.unitWidth;
30827     },
30828     
30829     horizontalMeasureColumns : function()
30830     {
30831         this.getContainerWidth();
30832         
30833         var boxWidth = this.boxWidth;
30834         
30835         if(this.containerWidth < boxWidth){
30836             boxWidth = this.containerWidth;
30837         }
30838         
30839         this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30840         
30841         this.el.setHeight(boxWidth);
30842         
30843     },
30844     
30845     getContainerWidth : function()
30846     {
30847         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
30848     },
30849     
30850     layoutItems : function( isInstant )
30851     {
30852         Roo.log(this.bricks);
30853         
30854         var items = Roo.apply([], this.bricks);
30855         
30856         if(this.isHorizontal){
30857             this._horizontalLayoutItems( items , isInstant );
30858             return;
30859         }
30860         
30861 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30862 //            this._verticalAlternativeLayoutItems( items , isInstant );
30863 //            return;
30864 //        }
30865         
30866         this._verticalLayoutItems( items , isInstant );
30867         
30868     },
30869     
30870     _verticalLayoutItems : function ( items , isInstant)
30871     {
30872         if ( !items || !items.length ) {
30873             return;
30874         }
30875         
30876         var standard = [
30877             ['xs', 'xs', 'xs', 'tall'],
30878             ['xs', 'xs', 'tall'],
30879             ['xs', 'xs', 'sm'],
30880             ['xs', 'xs', 'xs'],
30881             ['xs', 'tall'],
30882             ['xs', 'sm'],
30883             ['xs', 'xs'],
30884             ['xs'],
30885             
30886             ['sm', 'xs', 'xs'],
30887             ['sm', 'xs'],
30888             ['sm'],
30889             
30890             ['tall', 'xs', 'xs', 'xs'],
30891             ['tall', 'xs', 'xs'],
30892             ['tall', 'xs'],
30893             ['tall']
30894             
30895         ];
30896         
30897         var queue = [];
30898         
30899         var boxes = [];
30900         
30901         var box = [];
30902         
30903         Roo.each(items, function(item, k){
30904             
30905             switch (item.size) {
30906                 // these layouts take up a full box,
30907                 case 'md' :
30908                 case 'md-left' :
30909                 case 'md-right' :
30910                 case 'wide' :
30911                     
30912                     if(box.length){
30913                         boxes.push(box);
30914                         box = [];
30915                     }
30916                     
30917                     boxes.push([item]);
30918                     
30919                     break;
30920                     
30921                 case 'xs' :
30922                 case 'sm' :
30923                 case 'tall' :
30924                     
30925                     box.push(item);
30926                     
30927                     break;
30928                 default :
30929                     break;
30930                     
30931             }
30932             
30933         }, this);
30934         
30935         if(box.length){
30936             boxes.push(box);
30937             box = [];
30938         }
30939         
30940         var filterPattern = function(box, length)
30941         {
30942             if(!box.length){
30943                 return;
30944             }
30945             
30946             var match = false;
30947             
30948             var pattern = box.slice(0, length);
30949             
30950             var format = [];
30951             
30952             Roo.each(pattern, function(i){
30953                 format.push(i.size);
30954             }, this);
30955             
30956             Roo.each(standard, function(s){
30957                 
30958                 if(String(s) != String(format)){
30959                     return;
30960                 }
30961                 
30962                 match = true;
30963                 return false;
30964                 
30965             }, this);
30966             
30967             if(!match && length == 1){
30968                 return;
30969             }
30970             
30971             if(!match){
30972                 filterPattern(box, length - 1);
30973                 return;
30974             }
30975                 
30976             queue.push(pattern);
30977
30978             box = box.slice(length, box.length);
30979
30980             filterPattern(box, 4);
30981
30982             return;
30983             
30984         }
30985         
30986         Roo.each(boxes, function(box, k){
30987             
30988             if(!box.length){
30989                 return;
30990             }
30991             
30992             if(box.length == 1){
30993                 queue.push(box);
30994                 return;
30995             }
30996             
30997             filterPattern(box, 4);
30998             
30999         }, this);
31000         
31001         this._processVerticalLayoutQueue( queue, isInstant );
31002         
31003     },
31004     
31005 //    _verticalAlternativeLayoutItems : function( items , isInstant )
31006 //    {
31007 //        if ( !items || !items.length ) {
31008 //            return;
31009 //        }
31010 //
31011 //        this._processVerticalAlternativeLayoutQueue( items, isInstant );
31012 //        
31013 //    },
31014     
31015     _horizontalLayoutItems : function ( items , isInstant)
31016     {
31017         if ( !items || !items.length || items.length < 3) {
31018             return;
31019         }
31020         
31021         items.reverse();
31022         
31023         var eItems = items.slice(0, 3);
31024         
31025         items = items.slice(3, items.length);
31026         
31027         var standard = [
31028             ['xs', 'xs', 'xs', 'wide'],
31029             ['xs', 'xs', 'wide'],
31030             ['xs', 'xs', 'sm'],
31031             ['xs', 'xs', 'xs'],
31032             ['xs', 'wide'],
31033             ['xs', 'sm'],
31034             ['xs', 'xs'],
31035             ['xs'],
31036             
31037             ['sm', 'xs', 'xs'],
31038             ['sm', 'xs'],
31039             ['sm'],
31040             
31041             ['wide', 'xs', 'xs', 'xs'],
31042             ['wide', 'xs', 'xs'],
31043             ['wide', 'xs'],
31044             ['wide'],
31045             
31046             ['wide-thin']
31047         ];
31048         
31049         var queue = [];
31050         
31051         var boxes = [];
31052         
31053         var box = [];
31054         
31055         Roo.each(items, function(item, k){
31056             
31057             switch (item.size) {
31058                 case 'md' :
31059                 case 'md-left' :
31060                 case 'md-right' :
31061                 case 'tall' :
31062                     
31063                     if(box.length){
31064                         boxes.push(box);
31065                         box = [];
31066                     }
31067                     
31068                     boxes.push([item]);
31069                     
31070                     break;
31071                     
31072                 case 'xs' :
31073                 case 'sm' :
31074                 case 'wide' :
31075                 case 'wide-thin' :
31076                     
31077                     box.push(item);
31078                     
31079                     break;
31080                 default :
31081                     break;
31082                     
31083             }
31084             
31085         }, this);
31086         
31087         if(box.length){
31088             boxes.push(box);
31089             box = [];
31090         }
31091         
31092         var filterPattern = function(box, length)
31093         {
31094             if(!box.length){
31095                 return;
31096             }
31097             
31098             var match = false;
31099             
31100             var pattern = box.slice(0, length);
31101             
31102             var format = [];
31103             
31104             Roo.each(pattern, function(i){
31105                 format.push(i.size);
31106             }, this);
31107             
31108             Roo.each(standard, function(s){
31109                 
31110                 if(String(s) != String(format)){
31111                     return;
31112                 }
31113                 
31114                 match = true;
31115                 return false;
31116                 
31117             }, this);
31118             
31119             if(!match && length == 1){
31120                 return;
31121             }
31122             
31123             if(!match){
31124                 filterPattern(box, length - 1);
31125                 return;
31126             }
31127                 
31128             queue.push(pattern);
31129
31130             box = box.slice(length, box.length);
31131
31132             filterPattern(box, 4);
31133
31134             return;
31135             
31136         }
31137         
31138         Roo.each(boxes, function(box, k){
31139             
31140             if(!box.length){
31141                 return;
31142             }
31143             
31144             if(box.length == 1){
31145                 queue.push(box);
31146                 return;
31147             }
31148             
31149             filterPattern(box, 4);
31150             
31151         }, this);
31152         
31153         
31154         var prune = [];
31155         
31156         var pos = this.el.getBox(true);
31157         
31158         var minX = pos.x;
31159         
31160         var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31161         
31162         var hit_end = false;
31163         
31164         Roo.each(queue, function(box){
31165             
31166             if(hit_end){
31167                 
31168                 Roo.each(box, function(b){
31169                 
31170                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31171                     b.el.hide();
31172
31173                 }, this);
31174
31175                 return;
31176             }
31177             
31178             var mx = 0;
31179             
31180             Roo.each(box, function(b){
31181                 
31182                 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31183                 b.el.show();
31184
31185                 mx = Math.max(mx, b.x);
31186                 
31187             }, this);
31188             
31189             maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31190             
31191             if(maxX < minX){
31192                 
31193                 Roo.each(box, function(b){
31194                 
31195                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31196                     b.el.hide();
31197                     
31198                 }, this);
31199                 
31200                 hit_end = true;
31201                 
31202                 return;
31203             }
31204             
31205             prune.push(box);
31206             
31207         }, this);
31208         
31209         this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31210     },
31211     
31212     /** Sets position of item in DOM
31213     * @param {Element} item
31214     * @param {Number} x - horizontal position
31215     * @param {Number} y - vertical position
31216     * @param {Boolean} isInstant - disables transitions
31217     */
31218     _processVerticalLayoutQueue : function( queue, isInstant )
31219     {
31220         var pos = this.el.getBox(true);
31221         var x = pos.x;
31222         var y = pos.y;
31223         var maxY = [];
31224         
31225         for (var i = 0; i < this.cols; i++){
31226             maxY[i] = pos.y;
31227         }
31228         
31229         Roo.each(queue, function(box, k){
31230             
31231             var col = k % this.cols;
31232             
31233             Roo.each(box, function(b,kk){
31234                 
31235                 b.el.position('absolute');
31236                 
31237                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31238                 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31239                 
31240                 if(b.size == 'md-left' || b.size == 'md-right'){
31241                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31242                     height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31243                 }
31244                 
31245                 b.el.setWidth(width);
31246                 b.el.setHeight(height);
31247                 // iframe?
31248                 b.el.select('iframe',true).setSize(width,height);
31249                 
31250             }, this);
31251             
31252             for (var i = 0; i < this.cols; i++){
31253                 
31254                 if(maxY[i] < maxY[col]){
31255                     col = i;
31256                     continue;
31257                 }
31258                 
31259                 col = Math.min(col, i);
31260                 
31261             }
31262             
31263             x = pos.x + col * (this.colWidth + this.padWidth);
31264             
31265             y = maxY[col];
31266             
31267             var positions = [];
31268             
31269             switch (box.length){
31270                 case 1 :
31271                     positions = this.getVerticalOneBoxColPositions(x, y, box);
31272                     break;
31273                 case 2 :
31274                     positions = this.getVerticalTwoBoxColPositions(x, y, box);
31275                     break;
31276                 case 3 :
31277                     positions = this.getVerticalThreeBoxColPositions(x, y, box);
31278                     break;
31279                 case 4 :
31280                     positions = this.getVerticalFourBoxColPositions(x, y, box);
31281                     break;
31282                 default :
31283                     break;
31284             }
31285             
31286             Roo.each(box, function(b,kk){
31287                 
31288                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31289                 
31290                 var sz = b.el.getSize();
31291                 
31292                 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31293                 
31294             }, this);
31295             
31296         }, this);
31297         
31298         var mY = 0;
31299         
31300         for (var i = 0; i < this.cols; i++){
31301             mY = Math.max(mY, maxY[i]);
31302         }
31303         
31304         this.el.setHeight(mY - pos.y);
31305         
31306     },
31307     
31308 //    _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31309 //    {
31310 //        var pos = this.el.getBox(true);
31311 //        var x = pos.x;
31312 //        var y = pos.y;
31313 //        var maxX = pos.right;
31314 //        
31315 //        var maxHeight = 0;
31316 //        
31317 //        Roo.each(items, function(item, k){
31318 //            
31319 //            var c = k % 2;
31320 //            
31321 //            item.el.position('absolute');
31322 //                
31323 //            var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31324 //
31325 //            item.el.setWidth(width);
31326 //
31327 //            var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31328 //
31329 //            item.el.setHeight(height);
31330 //            
31331 //            if(c == 0){
31332 //                item.el.setXY([x, y], isInstant ? false : true);
31333 //            } else {
31334 //                item.el.setXY([maxX - width, y], isInstant ? false : true);
31335 //            }
31336 //            
31337 //            y = y + height + this.alternativePadWidth;
31338 //            
31339 //            maxHeight = maxHeight + height + this.alternativePadWidth;
31340 //            
31341 //        }, this);
31342 //        
31343 //        this.el.setHeight(maxHeight);
31344 //        
31345 //    },
31346     
31347     _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31348     {
31349         var pos = this.el.getBox(true);
31350         
31351         var minX = pos.x;
31352         var minY = pos.y;
31353         
31354         var maxX = pos.right;
31355         
31356         this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31357         
31358         var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31359         
31360         Roo.each(queue, function(box, k){
31361             
31362             Roo.each(box, function(b, kk){
31363                 
31364                 b.el.position('absolute');
31365                 
31366                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31367                 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31368                 
31369                 if(b.size == 'md-left' || b.size == 'md-right'){
31370                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31371                     height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31372                 }
31373                 
31374                 b.el.setWidth(width);
31375                 b.el.setHeight(height);
31376                 
31377             }, this);
31378             
31379             if(!box.length){
31380                 return;
31381             }
31382             
31383             var positions = [];
31384             
31385             switch (box.length){
31386                 case 1 :
31387                     positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31388                     break;
31389                 case 2 :
31390                     positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31391                     break;
31392                 case 3 :
31393                     positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31394                     break;
31395                 case 4 :
31396                     positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31397                     break;
31398                 default :
31399                     break;
31400             }
31401             
31402             Roo.each(box, function(b,kk){
31403                 
31404                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31405                 
31406                 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31407                 
31408             }, this);
31409             
31410         }, this);
31411         
31412     },
31413     
31414     _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31415     {
31416         Roo.each(eItems, function(b,k){
31417             
31418             b.size = (k == 0) ? 'sm' : 'xs';
31419             b.x = (k == 0) ? 2 : 1;
31420             b.y = (k == 0) ? 2 : 1;
31421             
31422             b.el.position('absolute');
31423             
31424             var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31425                 
31426             b.el.setWidth(width);
31427             
31428             var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31429             
31430             b.el.setHeight(height);
31431             
31432         }, this);
31433
31434         var positions = [];
31435         
31436         positions.push({
31437             x : maxX - this.unitWidth * 2 - this.gutter,
31438             y : minY
31439         });
31440         
31441         positions.push({
31442             x : maxX - this.unitWidth,
31443             y : minY + (this.unitWidth + this.gutter) * 2
31444         });
31445         
31446         positions.push({
31447             x : maxX - this.unitWidth * 3 - this.gutter * 2,
31448             y : minY
31449         });
31450         
31451         Roo.each(eItems, function(b,k){
31452             
31453             b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31454
31455         }, this);
31456         
31457     },
31458     
31459     getVerticalOneBoxColPositions : function(x, y, box)
31460     {
31461         var pos = [];
31462         
31463         var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31464         
31465         if(box[0].size == 'md-left'){
31466             rand = 0;
31467         }
31468         
31469         if(box[0].size == 'md-right'){
31470             rand = 1;
31471         }
31472         
31473         pos.push({
31474             x : x + (this.unitWidth + this.gutter) * rand,
31475             y : y
31476         });
31477         
31478         return pos;
31479     },
31480     
31481     getVerticalTwoBoxColPositions : function(x, y, box)
31482     {
31483         var pos = [];
31484         
31485         if(box[0].size == 'xs'){
31486             
31487             pos.push({
31488                 x : x,
31489                 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31490             });
31491
31492             pos.push({
31493                 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31494                 y : y
31495             });
31496             
31497             return pos;
31498             
31499         }
31500         
31501         pos.push({
31502             x : x,
31503             y : y
31504         });
31505
31506         pos.push({
31507             x : x + (this.unitWidth + this.gutter) * 2,
31508             y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31509         });
31510         
31511         return pos;
31512         
31513     },
31514     
31515     getVerticalThreeBoxColPositions : function(x, y, box)
31516     {
31517         var pos = [];
31518         
31519         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31520             
31521             pos.push({
31522                 x : x,
31523                 y : y
31524             });
31525
31526             pos.push({
31527                 x : x + (this.unitWidth + this.gutter) * 1,
31528                 y : y
31529             });
31530             
31531             pos.push({
31532                 x : x + (this.unitWidth + this.gutter) * 2,
31533                 y : y
31534             });
31535             
31536             return pos;
31537             
31538         }
31539         
31540         if(box[0].size == 'xs' && box[1].size == 'xs'){
31541             
31542             pos.push({
31543                 x : x,
31544                 y : y
31545             });
31546
31547             pos.push({
31548                 x : x,
31549                 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31550             });
31551             
31552             pos.push({
31553                 x : x + (this.unitWidth + this.gutter) * 1,
31554                 y : y
31555             });
31556             
31557             return pos;
31558             
31559         }
31560         
31561         pos.push({
31562             x : x,
31563             y : y
31564         });
31565
31566         pos.push({
31567             x : x + (this.unitWidth + this.gutter) * 2,
31568             y : y
31569         });
31570
31571         pos.push({
31572             x : x + (this.unitWidth + this.gutter) * 2,
31573             y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31574         });
31575             
31576         return pos;
31577         
31578     },
31579     
31580     getVerticalFourBoxColPositions : function(x, y, box)
31581     {
31582         var pos = [];
31583         
31584         if(box[0].size == 'xs'){
31585             
31586             pos.push({
31587                 x : x,
31588                 y : y
31589             });
31590
31591             pos.push({
31592                 x : x,
31593                 y : y + (this.unitHeight + this.gutter) * 1
31594             });
31595             
31596             pos.push({
31597                 x : x,
31598                 y : y + (this.unitHeight + this.gutter) * 2
31599             });
31600             
31601             pos.push({
31602                 x : x + (this.unitWidth + this.gutter) * 1,
31603                 y : y
31604             });
31605             
31606             return pos;
31607             
31608         }
31609         
31610         pos.push({
31611             x : x,
31612             y : y
31613         });
31614
31615         pos.push({
31616             x : x + (this.unitWidth + this.gutter) * 2,
31617             y : y
31618         });
31619
31620         pos.push({
31621             x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31622             y : y + (this.unitHeight + this.gutter) * 1
31623         });
31624
31625         pos.push({
31626             x : x + (this.unitWidth + this.gutter) * 2,
31627             y : y + (this.unitWidth + this.gutter) * 2
31628         });
31629
31630         return pos;
31631         
31632     },
31633     
31634     getHorizontalOneBoxColPositions : function(maxX, minY, box)
31635     {
31636         var pos = [];
31637         
31638         if(box[0].size == 'md-left'){
31639             pos.push({
31640                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31641                 y : minY
31642             });
31643             
31644             return pos;
31645         }
31646         
31647         if(box[0].size == 'md-right'){
31648             pos.push({
31649                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31650                 y : minY + (this.unitWidth + this.gutter) * 1
31651             });
31652             
31653             return pos;
31654         }
31655         
31656         var rand = Math.floor(Math.random() * (4 - box[0].y));
31657         
31658         pos.push({
31659             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31660             y : minY + (this.unitWidth + this.gutter) * rand
31661         });
31662         
31663         return pos;
31664         
31665     },
31666     
31667     getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31668     {
31669         var pos = [];
31670         
31671         if(box[0].size == 'xs'){
31672             
31673             pos.push({
31674                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31675                 y : minY
31676             });
31677
31678             pos.push({
31679                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31680                 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31681             });
31682             
31683             return pos;
31684             
31685         }
31686         
31687         pos.push({
31688             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31689             y : minY
31690         });
31691
31692         pos.push({
31693             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31694             y : minY + (this.unitWidth + this.gutter) * 2
31695         });
31696         
31697         return pos;
31698         
31699     },
31700     
31701     getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31702     {
31703         var pos = [];
31704         
31705         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31706             
31707             pos.push({
31708                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31709                 y : minY
31710             });
31711
31712             pos.push({
31713                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31714                 y : minY + (this.unitWidth + this.gutter) * 1
31715             });
31716             
31717             pos.push({
31718                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31719                 y : minY + (this.unitWidth + this.gutter) * 2
31720             });
31721             
31722             return pos;
31723             
31724         }
31725         
31726         if(box[0].size == 'xs' && box[1].size == 'xs'){
31727             
31728             pos.push({
31729                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31730                 y : minY
31731             });
31732
31733             pos.push({
31734                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31735                 y : minY
31736             });
31737             
31738             pos.push({
31739                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31740                 y : minY + (this.unitWidth + this.gutter) * 1
31741             });
31742             
31743             return pos;
31744             
31745         }
31746         
31747         pos.push({
31748             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31749             y : minY
31750         });
31751
31752         pos.push({
31753             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31754             y : minY + (this.unitWidth + this.gutter) * 2
31755         });
31756
31757         pos.push({
31758             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31759             y : minY + (this.unitWidth + this.gutter) * 2
31760         });
31761             
31762         return pos;
31763         
31764     },
31765     
31766     getHorizontalFourBoxColPositions : function(maxX, minY, box)
31767     {
31768         var pos = [];
31769         
31770         if(box[0].size == 'xs'){
31771             
31772             pos.push({
31773                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31774                 y : minY
31775             });
31776
31777             pos.push({
31778                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31779                 y : minY
31780             });
31781             
31782             pos.push({
31783                 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),
31784                 y : minY
31785             });
31786             
31787             pos.push({
31788                 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31789                 y : minY + (this.unitWidth + this.gutter) * 1
31790             });
31791             
31792             return pos;
31793             
31794         }
31795         
31796         pos.push({
31797             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31798             y : minY
31799         });
31800         
31801         pos.push({
31802             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31803             y : minY + (this.unitWidth + this.gutter) * 2
31804         });
31805         
31806         pos.push({
31807             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31808             y : minY + (this.unitWidth + this.gutter) * 2
31809         });
31810         
31811         pos.push({
31812             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),
31813             y : minY + (this.unitWidth + this.gutter) * 2
31814         });
31815
31816         return pos;
31817         
31818     },
31819     
31820     /**
31821     * remove a Masonry Brick
31822     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31823     */
31824     removeBrick : function(brick_id)
31825     {
31826         if (!brick_id) {
31827             return;
31828         }
31829         
31830         for (var i = 0; i<this.bricks.length; i++) {
31831             if (this.bricks[i].id == brick_id) {
31832                 this.bricks.splice(i,1);
31833                 this.el.dom.removeChild(Roo.get(brick_id).dom);
31834                 this.initial();
31835             }
31836         }
31837     },
31838     
31839     /**
31840     * adds a Masonry Brick
31841     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31842     */
31843     addBrick : function(cfg)
31844     {
31845         var cn = new Roo.bootstrap.MasonryBrick(cfg);
31846         //this.register(cn);
31847         cn.parentId = this.id;
31848         cn.onRender(this.el, null);
31849         return cn;
31850     },
31851     
31852     /**
31853     * register a Masonry Brick
31854     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31855     */
31856     
31857     register : function(brick)
31858     {
31859         this.bricks.push(brick);
31860         brick.masonryId = this.id;
31861     },
31862     
31863     /**
31864     * clear all the Masonry Brick
31865     */
31866     clearAll : function()
31867     {
31868         this.bricks = [];
31869         //this.getChildContainer().dom.innerHTML = "";
31870         this.el.dom.innerHTML = '';
31871     },
31872     
31873     getSelected : function()
31874     {
31875         if (!this.selectedBrick) {
31876             return false;
31877         }
31878         
31879         return this.selectedBrick;
31880     }
31881 });
31882
31883 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31884     
31885     groups: {},
31886      /**
31887     * register a Masonry Layout
31888     * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31889     */
31890     
31891     register : function(layout)
31892     {
31893         this.groups[layout.id] = layout;
31894     },
31895     /**
31896     * fetch a  Masonry Layout based on the masonry layout ID
31897     * @param {string} the masonry layout to add
31898     * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31899     */
31900     
31901     get: function(layout_id) {
31902         if (typeof(this.groups[layout_id]) == 'undefined') {
31903             return false;
31904         }
31905         return this.groups[layout_id] ;
31906     }
31907     
31908     
31909     
31910 });
31911
31912  
31913
31914  /**
31915  *
31916  * This is based on 
31917  * http://masonry.desandro.com
31918  *
31919  * The idea is to render all the bricks based on vertical width...
31920  *
31921  * The original code extends 'outlayer' - we might need to use that....
31922  * 
31923  */
31924
31925
31926 /**
31927  * @class Roo.bootstrap.LayoutMasonryAuto
31928  * @extends Roo.bootstrap.Component
31929  * Bootstrap Layout Masonry class
31930  * 
31931  * @constructor
31932  * Create a new Element
31933  * @param {Object} config The config object
31934  */
31935
31936 Roo.bootstrap.LayoutMasonryAuto = function(config){
31937     Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31938 };
31939
31940 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component,  {
31941     
31942       /**
31943      * @cfg {Boolean} isFitWidth  - resize the width..
31944      */   
31945     isFitWidth : false,  // options..
31946     /**
31947      * @cfg {Boolean} isOriginLeft = left align?
31948      */   
31949     isOriginLeft : true,
31950     /**
31951      * @cfg {Boolean} isOriginTop = top align?
31952      */   
31953     isOriginTop : false,
31954     /**
31955      * @cfg {Boolean} isLayoutInstant = no animation?
31956      */   
31957     isLayoutInstant : false, // needed?
31958     /**
31959      * @cfg {Boolean} isResizingContainer = not sure if this is used..
31960      */   
31961     isResizingContainer : true,
31962     /**
31963      * @cfg {Number} columnWidth  width of the columns 
31964      */   
31965     
31966     columnWidth : 0,
31967     
31968     /**
31969      * @cfg {Number} maxCols maximum number of columns
31970      */   
31971     
31972     maxCols: 0,
31973     /**
31974      * @cfg {Number} padHeight padding below box..
31975      */   
31976     
31977     padHeight : 10, 
31978     
31979     /**
31980      * @cfg {Boolean} isAutoInitial defalut true
31981      */   
31982     
31983     isAutoInitial : true, 
31984     
31985     // private?
31986     gutter : 0,
31987     
31988     containerWidth: 0,
31989     initialColumnWidth : 0,
31990     currentSize : null,
31991     
31992     colYs : null, // array.
31993     maxY : 0,
31994     padWidth: 10,
31995     
31996     
31997     tag: 'div',
31998     cls: '',
31999     bricks: null, //CompositeElement
32000     cols : 0, // array?
32001     // element : null, // wrapped now this.el
32002     _isLayoutInited : null, 
32003     
32004     
32005     getAutoCreate : function(){
32006         
32007         var cfg = {
32008             tag: this.tag,
32009             cls: 'blog-masonary-wrapper ' + this.cls,
32010             cn : {
32011                 cls : 'mas-boxes masonary'
32012             }
32013         };
32014         
32015         return cfg;
32016     },
32017     
32018     getChildContainer: function( )
32019     {
32020         if (this.boxesEl) {
32021             return this.boxesEl;
32022         }
32023         
32024         this.boxesEl = this.el.select('.mas-boxes').first();
32025         
32026         return this.boxesEl;
32027     },
32028     
32029     
32030     initEvents : function()
32031     {
32032         var _this = this;
32033         
32034         if(this.isAutoInitial){
32035             Roo.log('hook children rendered');
32036             this.on('childrenrendered', function() {
32037                 Roo.log('children rendered');
32038                 _this.initial();
32039             } ,this);
32040         }
32041         
32042     },
32043     
32044     initial : function()
32045     {
32046         this.reloadItems();
32047
32048         this.currentSize = this.el.getBox(true);
32049
32050         /// was window resize... - let's see if this works..
32051         Roo.EventManager.onWindowResize(this.resize, this); 
32052
32053         if(!this.isAutoInitial){
32054             this.layout();
32055             return;
32056         }
32057         
32058         this.layout.defer(500,this);
32059     },
32060     
32061     reloadItems: function()
32062     {
32063         this.bricks = this.el.select('.masonry-brick', true);
32064         
32065         this.bricks.each(function(b) {
32066             //Roo.log(b.getSize());
32067             if (!b.attr('originalwidth')) {
32068                 b.attr('originalwidth',  b.getSize().width);
32069             }
32070             
32071         });
32072         
32073         Roo.log(this.bricks.elements.length);
32074     },
32075     
32076     resize : function()
32077     {
32078         Roo.log('resize');
32079         var cs = this.el.getBox(true);
32080         
32081         if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32082             Roo.log("no change in with or X");
32083             return;
32084         }
32085         this.currentSize = cs;
32086         this.layout();
32087     },
32088     
32089     layout : function()
32090     {
32091          Roo.log('layout');
32092         this._resetLayout();
32093         //this._manageStamps();
32094       
32095         // don't animate first layout
32096         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32097         this.layoutItems( isInstant );
32098       
32099         // flag for initalized
32100         this._isLayoutInited = true;
32101     },
32102     
32103     layoutItems : function( isInstant )
32104     {
32105         //var items = this._getItemsForLayout( this.items );
32106         // original code supports filtering layout items.. we just ignore it..
32107         
32108         this._layoutItems( this.bricks , isInstant );
32109       
32110         this._postLayout();
32111     },
32112     _layoutItems : function ( items , isInstant)
32113     {
32114        //this.fireEvent( 'layout', this, items );
32115     
32116
32117         if ( !items || !items.elements.length ) {
32118           // no items, emit event with empty array
32119             return;
32120         }
32121
32122         var queue = [];
32123         items.each(function(item) {
32124             Roo.log("layout item");
32125             Roo.log(item);
32126             // get x/y object from method
32127             var position = this._getItemLayoutPosition( item );
32128             // enqueue
32129             position.item = item;
32130             position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32131             queue.push( position );
32132         }, this);
32133       
32134         this._processLayoutQueue( queue );
32135     },
32136     /** Sets position of item in DOM
32137     * @param {Element} item
32138     * @param {Number} x - horizontal position
32139     * @param {Number} y - vertical position
32140     * @param {Boolean} isInstant - disables transitions
32141     */
32142     _processLayoutQueue : function( queue )
32143     {
32144         for ( var i=0, len = queue.length; i < len; i++ ) {
32145             var obj = queue[i];
32146             obj.item.position('absolute');
32147             obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32148         }
32149     },
32150       
32151     
32152     /**
32153     * Any logic you want to do after each layout,
32154     * i.e. size the container
32155     */
32156     _postLayout : function()
32157     {
32158         this.resizeContainer();
32159     },
32160     
32161     resizeContainer : function()
32162     {
32163         if ( !this.isResizingContainer ) {
32164             return;
32165         }
32166         var size = this._getContainerSize();
32167         if ( size ) {
32168             this.el.setSize(size.width,size.height);
32169             this.boxesEl.setSize(size.width,size.height);
32170         }
32171     },
32172     
32173     
32174     
32175     _resetLayout : function()
32176     {
32177         //this.getSize();  // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32178         this.colWidth = this.el.getWidth();
32179         //this.gutter = this.el.getWidth(); 
32180         
32181         this.measureColumns();
32182
32183         // reset column Y
32184         var i = this.cols;
32185         this.colYs = [];
32186         while (i--) {
32187             this.colYs.push( 0 );
32188         }
32189     
32190         this.maxY = 0;
32191     },
32192
32193     measureColumns : function()
32194     {
32195         this.getContainerWidth();
32196       // if columnWidth is 0, default to outerWidth of first item
32197         if ( !this.columnWidth ) {
32198             var firstItem = this.bricks.first();
32199             Roo.log(firstItem);
32200             this.columnWidth  = this.containerWidth;
32201             if (firstItem && firstItem.attr('originalwidth') ) {
32202                 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32203             }
32204             // columnWidth fall back to item of first element
32205             Roo.log("set column width?");
32206                         this.initialColumnWidth = this.columnWidth  ;
32207
32208             // if first elem has no width, default to size of container
32209             
32210         }
32211         
32212         
32213         if (this.initialColumnWidth) {
32214             this.columnWidth = this.initialColumnWidth;
32215         }
32216         
32217         
32218             
32219         // column width is fixed at the top - however if container width get's smaller we should
32220         // reduce it...
32221         
32222         // this bit calcs how man columns..
32223             
32224         var columnWidth = this.columnWidth += this.gutter;
32225       
32226         // calculate columns
32227         var containerWidth = this.containerWidth + this.gutter;
32228         
32229         var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32230         // fix rounding errors, typically with gutters
32231         var excess = columnWidth - containerWidth % columnWidth;
32232         
32233         
32234         // if overshoot is less than a pixel, round up, otherwise floor it
32235         var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32236         cols = Math[ mathMethod ]( cols );
32237         this.cols = Math.max( cols, 1 );
32238         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32239         
32240          // padding positioning..
32241         var totalColWidth = this.cols * this.columnWidth;
32242         var padavail = this.containerWidth - totalColWidth;
32243         // so for 2 columns - we need 3 'pads'
32244         
32245         var padNeeded = (1+this.cols) * this.padWidth;
32246         
32247         var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32248         
32249         this.columnWidth += padExtra
32250         //this.padWidth = Math.floor(padavail /  ( this.cols));
32251         
32252         // adjust colum width so that padding is fixed??
32253         
32254         // we have 3 columns ... total = width * 3
32255         // we have X left over... that should be used by 
32256         
32257         //if (this.expandC) {
32258             
32259         //}
32260         
32261         
32262         
32263     },
32264     
32265     getContainerWidth : function()
32266     {
32267        /* // container is parent if fit width
32268         var container = this.isFitWidth ? this.element.parentNode : this.element;
32269         // check that this.size and size are there
32270         // IE8 triggers resize on body size change, so they might not be
32271         
32272         var size = getSize( container );  //FIXME
32273         this.containerWidth = size && size.innerWidth; //FIXME
32274         */
32275          
32276         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
32277         
32278     },
32279     
32280     _getItemLayoutPosition : function( item )  // what is item?
32281     {
32282         // we resize the item to our columnWidth..
32283       
32284         item.setWidth(this.columnWidth);
32285         item.autoBoxAdjust  = false;
32286         
32287         var sz = item.getSize();
32288  
32289         // how many columns does this brick span
32290         var remainder = this.containerWidth % this.columnWidth;
32291         
32292         var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32293         // round if off by 1 pixel, otherwise use ceil
32294         var colSpan = Math[ mathMethod ]( sz.width  / this.columnWidth );
32295         colSpan = Math.min( colSpan, this.cols );
32296         
32297         // normally this should be '1' as we dont' currently allow multi width columns..
32298         
32299         var colGroup = this._getColGroup( colSpan );
32300         // get the minimum Y value from the columns
32301         var minimumY = Math.min.apply( Math, colGroup );
32302         Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32303         
32304         var shortColIndex = colGroup.indexOf(  minimumY ); // broken on ie8..?? probably...
32305          
32306         // position the brick
32307         var position = {
32308             x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32309             y: this.currentSize.y + minimumY + this.padHeight
32310         };
32311         
32312         Roo.log(position);
32313         // apply setHeight to necessary columns
32314         var setHeight = minimumY + sz.height + this.padHeight;
32315         //Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32316         
32317         var setSpan = this.cols + 1 - colGroup.length;
32318         for ( var i = 0; i < setSpan; i++ ) {
32319           this.colYs[ shortColIndex + i ] = setHeight ;
32320         }
32321       
32322         return position;
32323     },
32324     
32325     /**
32326      * @param {Number} colSpan - number of columns the element spans
32327      * @returns {Array} colGroup
32328      */
32329     _getColGroup : function( colSpan )
32330     {
32331         if ( colSpan < 2 ) {
32332           // if brick spans only one column, use all the column Ys
32333           return this.colYs;
32334         }
32335       
32336         var colGroup = [];
32337         // how many different places could this brick fit horizontally
32338         var groupCount = this.cols + 1 - colSpan;
32339         // for each group potential horizontal position
32340         for ( var i = 0; i < groupCount; i++ ) {
32341           // make an array of colY values for that one group
32342           var groupColYs = this.colYs.slice( i, i + colSpan );
32343           // and get the max value of the array
32344           colGroup[i] = Math.max.apply( Math, groupColYs );
32345         }
32346         return colGroup;
32347     },
32348     /*
32349     _manageStamp : function( stamp )
32350     {
32351         var stampSize =  stamp.getSize();
32352         var offset = stamp.getBox();
32353         // get the columns that this stamp affects
32354         var firstX = this.isOriginLeft ? offset.x : offset.right;
32355         var lastX = firstX + stampSize.width;
32356         var firstCol = Math.floor( firstX / this.columnWidth );
32357         firstCol = Math.max( 0, firstCol );
32358         
32359         var lastCol = Math.floor( lastX / this.columnWidth );
32360         // lastCol should not go over if multiple of columnWidth #425
32361         lastCol -= lastX % this.columnWidth ? 0 : 1;
32362         lastCol = Math.min( this.cols - 1, lastCol );
32363         
32364         // set colYs to bottom of the stamp
32365         var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32366             stampSize.height;
32367             
32368         for ( var i = firstCol; i <= lastCol; i++ ) {
32369           this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32370         }
32371     },
32372     */
32373     
32374     _getContainerSize : function()
32375     {
32376         this.maxY = Math.max.apply( Math, this.colYs );
32377         var size = {
32378             height: this.maxY
32379         };
32380       
32381         if ( this.isFitWidth ) {
32382             size.width = this._getContainerFitWidth();
32383         }
32384       
32385         return size;
32386     },
32387     
32388     _getContainerFitWidth : function()
32389     {
32390         var unusedCols = 0;
32391         // count unused columns
32392         var i = this.cols;
32393         while ( --i ) {
32394           if ( this.colYs[i] !== 0 ) {
32395             break;
32396           }
32397           unusedCols++;
32398         }
32399         // fit container to columns that have been used
32400         return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32401     },
32402     
32403     needsResizeLayout : function()
32404     {
32405         var previousWidth = this.containerWidth;
32406         this.getContainerWidth();
32407         return previousWidth !== this.containerWidth;
32408     }
32409  
32410 });
32411
32412  
32413
32414  /*
32415  * - LGPL
32416  *
32417  * element
32418  * 
32419  */
32420
32421 /**
32422  * @class Roo.bootstrap.MasonryBrick
32423  * @extends Roo.bootstrap.Component
32424  * Bootstrap MasonryBrick class
32425  * 
32426  * @constructor
32427  * Create a new MasonryBrick
32428  * @param {Object} config The config object
32429  */
32430
32431 Roo.bootstrap.MasonryBrick = function(config){
32432     
32433     Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32434     
32435     Roo.bootstrap.MasonryBrick.register(this);
32436     
32437     this.addEvents({
32438         // raw events
32439         /**
32440          * @event click
32441          * When a MasonryBrick is clcik
32442          * @param {Roo.bootstrap.MasonryBrick} this
32443          * @param {Roo.EventObject} e
32444          */
32445         "click" : true
32446     });
32447 };
32448
32449 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component,  {
32450     
32451     /**
32452      * @cfg {String} title
32453      */   
32454     title : '',
32455     /**
32456      * @cfg {String} html
32457      */   
32458     html : '',
32459     /**
32460      * @cfg {String} bgimage
32461      */   
32462     bgimage : '',
32463     /**
32464      * @cfg {String} videourl
32465      */   
32466     videourl : '',
32467     /**
32468      * @cfg {String} cls
32469      */   
32470     cls : '',
32471     /**
32472      * @cfg {String} href
32473      */   
32474     href : '',
32475     /**
32476      * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32477      */   
32478     size : 'xs',
32479     
32480     /**
32481      * @cfg {String} placetitle (center|bottom)
32482      */   
32483     placetitle : '',
32484     
32485     /**
32486      * @cfg {Boolean} isFitContainer defalut true
32487      */   
32488     isFitContainer : true, 
32489     
32490     /**
32491      * @cfg {Boolean} preventDefault defalut false
32492      */   
32493     preventDefault : false, 
32494     
32495     /**
32496      * @cfg {Boolean} inverse defalut false
32497      */   
32498     maskInverse : false, 
32499     
32500     getAutoCreate : function()
32501     {
32502         if(!this.isFitContainer){
32503             return this.getSplitAutoCreate();
32504         }
32505         
32506         var cls = 'masonry-brick masonry-brick-full';
32507         
32508         if(this.href.length){
32509             cls += ' masonry-brick-link';
32510         }
32511         
32512         if(this.bgimage.length){
32513             cls += ' masonry-brick-image';
32514         }
32515         
32516         if(this.maskInverse){
32517             cls += ' mask-inverse';
32518         }
32519         
32520         if(!this.html.length && !this.maskInverse && !this.videourl.length){
32521             cls += ' enable-mask';
32522         }
32523         
32524         if(this.size){
32525             cls += ' masonry-' + this.size + '-brick';
32526         }
32527         
32528         if(this.placetitle.length){
32529             
32530             switch (this.placetitle) {
32531                 case 'center' :
32532                     cls += ' masonry-center-title';
32533                     break;
32534                 case 'bottom' :
32535                     cls += ' masonry-bottom-title';
32536                     break;
32537                 default:
32538                     break;
32539             }
32540             
32541         } else {
32542             if(!this.html.length && !this.bgimage.length){
32543                 cls += ' masonry-center-title';
32544             }
32545
32546             if(!this.html.length && this.bgimage.length){
32547                 cls += ' masonry-bottom-title';
32548             }
32549         }
32550         
32551         if(this.cls){
32552             cls += ' ' + this.cls;
32553         }
32554         
32555         var cfg = {
32556             tag: (this.href.length) ? 'a' : 'div',
32557             cls: cls,
32558             cn: [
32559                 {
32560                     tag: 'div',
32561                     cls: 'masonry-brick-mask'
32562                 },
32563                 {
32564                     tag: 'div',
32565                     cls: 'masonry-brick-paragraph',
32566                     cn: []
32567                 }
32568             ]
32569         };
32570         
32571         if(this.href.length){
32572             cfg.href = this.href;
32573         }
32574         
32575         var cn = cfg.cn[1].cn;
32576         
32577         if(this.title.length){
32578             cn.push({
32579                 tag: 'h4',
32580                 cls: 'masonry-brick-title',
32581                 html: this.title
32582             });
32583         }
32584         
32585         if(this.html.length){
32586             cn.push({
32587                 tag: 'p',
32588                 cls: 'masonry-brick-text',
32589                 html: this.html
32590             });
32591         }
32592         
32593         if (!this.title.length && !this.html.length) {
32594             cfg.cn[1].cls += ' hide';
32595         }
32596         
32597         if(this.bgimage.length){
32598             cfg.cn.push({
32599                 tag: 'img',
32600                 cls: 'masonry-brick-image-view',
32601                 src: this.bgimage
32602             });
32603         }
32604         
32605         if(this.videourl.length){
32606             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32607             // youtube support only?
32608             cfg.cn.push({
32609                 tag: 'iframe',
32610                 cls: 'masonry-brick-image-view',
32611                 src: vurl,
32612                 frameborder : 0,
32613                 allowfullscreen : true
32614             });
32615         }
32616         
32617         return cfg;
32618         
32619     },
32620     
32621     getSplitAutoCreate : function()
32622     {
32623         var cls = 'masonry-brick masonry-brick-split';
32624         
32625         if(this.href.length){
32626             cls += ' masonry-brick-link';
32627         }
32628         
32629         if(this.bgimage.length){
32630             cls += ' masonry-brick-image';
32631         }
32632         
32633         if(this.size){
32634             cls += ' masonry-' + this.size + '-brick';
32635         }
32636         
32637         switch (this.placetitle) {
32638             case 'center' :
32639                 cls += ' masonry-center-title';
32640                 break;
32641             case 'bottom' :
32642                 cls += ' masonry-bottom-title';
32643                 break;
32644             default:
32645                 if(!this.bgimage.length){
32646                     cls += ' masonry-center-title';
32647                 }
32648
32649                 if(this.bgimage.length){
32650                     cls += ' masonry-bottom-title';
32651                 }
32652                 break;
32653         }
32654         
32655         if(this.cls){
32656             cls += ' ' + this.cls;
32657         }
32658         
32659         var cfg = {
32660             tag: (this.href.length) ? 'a' : 'div',
32661             cls: cls,
32662             cn: [
32663                 {
32664                     tag: 'div',
32665                     cls: 'masonry-brick-split-head',
32666                     cn: [
32667                         {
32668                             tag: 'div',
32669                             cls: 'masonry-brick-paragraph',
32670                             cn: []
32671                         }
32672                     ]
32673                 },
32674                 {
32675                     tag: 'div',
32676                     cls: 'masonry-brick-split-body',
32677                     cn: []
32678                 }
32679             ]
32680         };
32681         
32682         if(this.href.length){
32683             cfg.href = this.href;
32684         }
32685         
32686         if(this.title.length){
32687             cfg.cn[0].cn[0].cn.push({
32688                 tag: 'h4',
32689                 cls: 'masonry-brick-title',
32690                 html: this.title
32691             });
32692         }
32693         
32694         if(this.html.length){
32695             cfg.cn[1].cn.push({
32696                 tag: 'p',
32697                 cls: 'masonry-brick-text',
32698                 html: this.html
32699             });
32700         }
32701
32702         if(this.bgimage.length){
32703             cfg.cn[0].cn.push({
32704                 tag: 'img',
32705                 cls: 'masonry-brick-image-view',
32706                 src: this.bgimage
32707             });
32708         }
32709         
32710         if(this.videourl.length){
32711             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32712             // youtube support only?
32713             cfg.cn[0].cn.cn.push({
32714                 tag: 'iframe',
32715                 cls: 'masonry-brick-image-view',
32716                 src: vurl,
32717                 frameborder : 0,
32718                 allowfullscreen : true
32719             });
32720         }
32721         
32722         return cfg;
32723     },
32724     
32725     initEvents: function() 
32726     {
32727         switch (this.size) {
32728             case 'xs' :
32729                 this.x = 1;
32730                 this.y = 1;
32731                 break;
32732             case 'sm' :
32733                 this.x = 2;
32734                 this.y = 2;
32735                 break;
32736             case 'md' :
32737             case 'md-left' :
32738             case 'md-right' :
32739                 this.x = 3;
32740                 this.y = 3;
32741                 break;
32742             case 'tall' :
32743                 this.x = 2;
32744                 this.y = 3;
32745                 break;
32746             case 'wide' :
32747                 this.x = 3;
32748                 this.y = 2;
32749                 break;
32750             case 'wide-thin' :
32751                 this.x = 3;
32752                 this.y = 1;
32753                 break;
32754                         
32755             default :
32756                 break;
32757         }
32758         
32759         if(Roo.isTouch){
32760             this.el.on('touchstart', this.onTouchStart, this);
32761             this.el.on('touchmove', this.onTouchMove, this);
32762             this.el.on('touchend', this.onTouchEnd, this);
32763             this.el.on('contextmenu', this.onContextMenu, this);
32764         } else {
32765             this.el.on('mouseenter'  ,this.enter, this);
32766             this.el.on('mouseleave', this.leave, this);
32767             this.el.on('click', this.onClick, this);
32768         }
32769         
32770         if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32771             this.parent().bricks.push(this);   
32772         }
32773         
32774     },
32775     
32776     onClick: function(e, el)
32777     {
32778         var time = this.endTimer - this.startTimer;
32779         // Roo.log(e.preventDefault());
32780         if(Roo.isTouch){
32781             if(time > 1000){
32782                 e.preventDefault();
32783                 return;
32784             }
32785         }
32786         
32787         if(!this.preventDefault){
32788             return;
32789         }
32790         
32791         e.preventDefault();
32792         
32793         if (this.activeClass != '') {
32794             this.selectBrick();
32795         }
32796         
32797         this.fireEvent('click', this, e);
32798     },
32799     
32800     enter: function(e, el)
32801     {
32802         e.preventDefault();
32803         
32804         if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32805             return;
32806         }
32807         
32808         if(this.bgimage.length && this.html.length){
32809             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32810         }
32811     },
32812     
32813     leave: function(e, el)
32814     {
32815         e.preventDefault();
32816         
32817         if(!this.isFitContainer || this.maskInverse  || this.videourl.length){
32818             return;
32819         }
32820         
32821         if(this.bgimage.length && this.html.length){
32822             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32823         }
32824     },
32825     
32826     onTouchStart: function(e, el)
32827     {
32828 //        e.preventDefault();
32829         
32830         this.touchmoved = false;
32831         
32832         if(!this.isFitContainer){
32833             return;
32834         }
32835         
32836         if(!this.bgimage.length || !this.html.length){
32837             return;
32838         }
32839         
32840         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32841         
32842         this.timer = new Date().getTime();
32843         
32844     },
32845     
32846     onTouchMove: function(e, el)
32847     {
32848         this.touchmoved = true;
32849     },
32850     
32851     onContextMenu : function(e,el)
32852     {
32853         e.preventDefault();
32854         e.stopPropagation();
32855         return false;
32856     },
32857     
32858     onTouchEnd: function(e, el)
32859     {
32860 //        e.preventDefault();
32861         
32862         if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32863         
32864             this.leave(e,el);
32865             
32866             return;
32867         }
32868         
32869         if(!this.bgimage.length || !this.html.length){
32870             
32871             if(this.href.length){
32872                 window.location.href = this.href;
32873             }
32874             
32875             return;
32876         }
32877         
32878         if(!this.isFitContainer){
32879             return;
32880         }
32881         
32882         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32883         
32884         window.location.href = this.href;
32885     },
32886     
32887     //selection on single brick only
32888     selectBrick : function() {
32889         
32890         if (!this.parentId) {
32891             return;
32892         }
32893         
32894         var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32895         var index = m.selectedBrick.indexOf(this.id);
32896         
32897         if ( index > -1) {
32898             m.selectedBrick.splice(index,1);
32899             this.el.removeClass(this.activeClass);
32900             return;
32901         }
32902         
32903         for(var i = 0; i < m.selectedBrick.length; i++) {
32904             var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32905             b.el.removeClass(b.activeClass);
32906         }
32907         
32908         m.selectedBrick = [];
32909         
32910         m.selectedBrick.push(this.id);
32911         this.el.addClass(this.activeClass);
32912         return;
32913     },
32914     
32915     isSelected : function(){
32916         return this.el.hasClass(this.activeClass);
32917         
32918     }
32919 });
32920
32921 Roo.apply(Roo.bootstrap.MasonryBrick, {
32922     
32923     //groups: {},
32924     groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32925      /**
32926     * register a Masonry Brick
32927     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32928     */
32929     
32930     register : function(brick)
32931     {
32932         //this.groups[brick.id] = brick;
32933         this.groups.add(brick.id, brick);
32934     },
32935     /**
32936     * fetch a  masonry brick based on the masonry brick ID
32937     * @param {string} the masonry brick to add
32938     * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32939     */
32940     
32941     get: function(brick_id) 
32942     {
32943         // if (typeof(this.groups[brick_id]) == 'undefined') {
32944         //     return false;
32945         // }
32946         // return this.groups[brick_id] ;
32947         
32948         if(this.groups.key(brick_id)) {
32949             return this.groups.key(brick_id);
32950         }
32951         
32952         return false;
32953     }
32954     
32955     
32956     
32957 });
32958
32959  /*
32960  * - LGPL
32961  *
32962  * element
32963  * 
32964  */
32965
32966 /**
32967  * @class Roo.bootstrap.Brick
32968  * @extends Roo.bootstrap.Component
32969  * Bootstrap Brick class
32970  * 
32971  * @constructor
32972  * Create a new Brick
32973  * @param {Object} config The config object
32974  */
32975
32976 Roo.bootstrap.Brick = function(config){
32977     Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32978     
32979     this.addEvents({
32980         // raw events
32981         /**
32982          * @event click
32983          * When a Brick is click
32984          * @param {Roo.bootstrap.Brick} this
32985          * @param {Roo.EventObject} e
32986          */
32987         "click" : true
32988     });
32989 };
32990
32991 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
32992     
32993     /**
32994      * @cfg {String} title
32995      */   
32996     title : '',
32997     /**
32998      * @cfg {String} html
32999      */   
33000     html : '',
33001     /**
33002      * @cfg {String} bgimage
33003      */   
33004     bgimage : '',
33005     /**
33006      * @cfg {String} cls
33007      */   
33008     cls : '',
33009     /**
33010      * @cfg {String} href
33011      */   
33012     href : '',
33013     /**
33014      * @cfg {String} video
33015      */   
33016     video : '',
33017     /**
33018      * @cfg {Boolean} square
33019      */   
33020     square : true,
33021     
33022     getAutoCreate : function()
33023     {
33024         var cls = 'roo-brick';
33025         
33026         if(this.href.length){
33027             cls += ' roo-brick-link';
33028         }
33029         
33030         if(this.bgimage.length){
33031             cls += ' roo-brick-image';
33032         }
33033         
33034         if(!this.html.length && !this.bgimage.length){
33035             cls += ' roo-brick-center-title';
33036         }
33037         
33038         if(!this.html.length && this.bgimage.length){
33039             cls += ' roo-brick-bottom-title';
33040         }
33041         
33042         if(this.cls){
33043             cls += ' ' + this.cls;
33044         }
33045         
33046         var cfg = {
33047             tag: (this.href.length) ? 'a' : 'div',
33048             cls: cls,
33049             cn: [
33050                 {
33051                     tag: 'div',
33052                     cls: 'roo-brick-paragraph',
33053                     cn: []
33054                 }
33055             ]
33056         };
33057         
33058         if(this.href.length){
33059             cfg.href = this.href;
33060         }
33061         
33062         var cn = cfg.cn[0].cn;
33063         
33064         if(this.title.length){
33065             cn.push({
33066                 tag: 'h4',
33067                 cls: 'roo-brick-title',
33068                 html: this.title
33069             });
33070         }
33071         
33072         if(this.html.length){
33073             cn.push({
33074                 tag: 'p',
33075                 cls: 'roo-brick-text',
33076                 html: this.html
33077             });
33078         } else {
33079             cn.cls += ' hide';
33080         }
33081         
33082         if(this.bgimage.length){
33083             cfg.cn.push({
33084                 tag: 'img',
33085                 cls: 'roo-brick-image-view',
33086                 src: this.bgimage
33087             });
33088         }
33089         
33090         return cfg;
33091     },
33092     
33093     initEvents: function() 
33094     {
33095         if(this.title.length || this.html.length){
33096             this.el.on('mouseenter'  ,this.enter, this);
33097             this.el.on('mouseleave', this.leave, this);
33098         }
33099         
33100         Roo.EventManager.onWindowResize(this.resize, this); 
33101         
33102         if(this.bgimage.length){
33103             this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33104             this.imageEl.on('load', this.onImageLoad, this);
33105             return;
33106         }
33107         
33108         this.resize();
33109     },
33110     
33111     onImageLoad : function()
33112     {
33113         this.resize();
33114     },
33115     
33116     resize : function()
33117     {
33118         var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33119         
33120         paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33121         
33122         if(this.bgimage.length){
33123             var image = this.el.select('.roo-brick-image-view', true).first();
33124             
33125             image.setWidth(paragraph.getWidth());
33126             
33127             if(this.square){
33128                 image.setHeight(paragraph.getWidth());
33129             }
33130             
33131             this.el.setHeight(image.getHeight());
33132             paragraph.setHeight(image.getHeight());
33133             
33134         }
33135         
33136     },
33137     
33138     enter: function(e, el)
33139     {
33140         e.preventDefault();
33141         
33142         if(this.bgimage.length){
33143             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33144             this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33145         }
33146     },
33147     
33148     leave: function(e, el)
33149     {
33150         e.preventDefault();
33151         
33152         if(this.bgimage.length){
33153             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33154             this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33155         }
33156     }
33157     
33158 });
33159
33160  
33161
33162  /*
33163  * - LGPL
33164  *
33165  * Number field 
33166  */
33167
33168 /**
33169  * @class Roo.bootstrap.NumberField
33170  * @extends Roo.bootstrap.Input
33171  * Bootstrap NumberField class
33172  * 
33173  * 
33174  * 
33175  * 
33176  * @constructor
33177  * Create a new NumberField
33178  * @param {Object} config The config object
33179  */
33180
33181 Roo.bootstrap.NumberField = function(config){
33182     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33183 };
33184
33185 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33186     
33187     /**
33188      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33189      */
33190     allowDecimals : true,
33191     /**
33192      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33193      */
33194     decimalSeparator : ".",
33195     /**
33196      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33197      */
33198     decimalPrecision : 2,
33199     /**
33200      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33201      */
33202     allowNegative : true,
33203     
33204     /**
33205      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33206      */
33207     allowZero: true,
33208     /**
33209      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33210      */
33211     minValue : Number.NEGATIVE_INFINITY,
33212     /**
33213      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33214      */
33215     maxValue : Number.MAX_VALUE,
33216     /**
33217      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33218      */
33219     minText : "The minimum value for this field is {0}",
33220     /**
33221      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33222      */
33223     maxText : "The maximum value for this field is {0}",
33224     /**
33225      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
33226      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33227      */
33228     nanText : "{0} is not a valid number",
33229     /**
33230      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33231      */
33232     thousandsDelimiter : false,
33233     /**
33234      * @cfg {String} valueAlign alignment of value
33235      */
33236     valueAlign : "left",
33237
33238     getAutoCreate : function()
33239     {
33240         var hiddenInput = {
33241             tag: 'input',
33242             type: 'hidden',
33243             id: Roo.id(),
33244             cls: 'hidden-number-input'
33245         };
33246         
33247         if (this.name) {
33248             hiddenInput.name = this.name;
33249         }
33250         
33251         this.name = '';
33252         
33253         var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33254         
33255         this.name = hiddenInput.name;
33256         
33257         if(cfg.cn.length > 0) {
33258             cfg.cn.push(hiddenInput);
33259         }
33260         
33261         return cfg;
33262     },
33263
33264     // private
33265     initEvents : function()
33266     {   
33267         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33268         
33269         var allowed = "0123456789";
33270         
33271         if(this.allowDecimals){
33272             allowed += this.decimalSeparator;
33273         }
33274         
33275         if(this.allowNegative){
33276             allowed += "-";
33277         }
33278         
33279         if(this.thousandsDelimiter) {
33280             allowed += ",";
33281         }
33282         
33283         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33284         
33285         var keyPress = function(e){
33286             
33287             var k = e.getKey();
33288             
33289             var c = e.getCharCode();
33290             
33291             if(
33292                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33293                     allowed.indexOf(String.fromCharCode(c)) === -1
33294             ){
33295                 e.stopEvent();
33296                 return;
33297             }
33298             
33299             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33300                 return;
33301             }
33302             
33303             if(allowed.indexOf(String.fromCharCode(c)) === -1){
33304                 e.stopEvent();
33305             }
33306         };
33307         
33308         this.el.on("keypress", keyPress, this);
33309     },
33310     
33311     validateValue : function(value)
33312     {
33313         
33314         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33315             return false;
33316         }
33317         
33318         var num = this.parseValue(value);
33319         
33320         if(isNaN(num)){
33321             this.markInvalid(String.format(this.nanText, value));
33322             return false;
33323         }
33324         
33325         if(num < this.minValue){
33326             this.markInvalid(String.format(this.minText, this.minValue));
33327             return false;
33328         }
33329         
33330         if(num > this.maxValue){
33331             this.markInvalid(String.format(this.maxText, this.maxValue));
33332             return false;
33333         }
33334         
33335         return true;
33336     },
33337
33338     getValue : function()
33339     {
33340         var v = this.hiddenEl().getValue();
33341         
33342         return this.fixPrecision(this.parseValue(v));
33343     },
33344
33345     parseValue : function(value)
33346     {
33347         if(this.thousandsDelimiter) {
33348             value += "";
33349             r = new RegExp(",", "g");
33350             value = value.replace(r, "");
33351         }
33352         
33353         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33354         return isNaN(value) ? '' : value;
33355     },
33356
33357     fixPrecision : function(value)
33358     {
33359         if(this.thousandsDelimiter) {
33360             value += "";
33361             r = new RegExp(",", "g");
33362             value = value.replace(r, "");
33363         }
33364         
33365         var nan = isNaN(value);
33366         
33367         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33368             return nan ? '' : value;
33369         }
33370         return parseFloat(value).toFixed(this.decimalPrecision);
33371     },
33372
33373     setValue : function(v)
33374     {
33375         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33376         
33377         this.value = v;
33378         
33379         if(this.rendered){
33380             
33381             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33382             
33383             this.inputEl().dom.value = (v == '') ? '' :
33384                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33385             
33386             if(!this.allowZero && v === '0') {
33387                 this.hiddenEl().dom.value = '';
33388                 this.inputEl().dom.value = '';
33389             }
33390             
33391             this.validate();
33392         }
33393     },
33394
33395     decimalPrecisionFcn : function(v)
33396     {
33397         return Math.floor(v);
33398     },
33399
33400     beforeBlur : function()
33401     {
33402         var v = this.parseValue(this.getRawValue());
33403         
33404         if(v || v === 0 || v === ''){
33405             this.setValue(v);
33406         }
33407     },
33408     
33409     hiddenEl : function()
33410     {
33411         return this.el.select('input.hidden-number-input',true).first();
33412     }
33413     
33414 });
33415
33416  
33417
33418 /*
33419 * Licence: LGPL
33420 */
33421
33422 /**
33423  * @class Roo.bootstrap.DocumentSlider
33424  * @extends Roo.bootstrap.Component
33425  * Bootstrap DocumentSlider class
33426  * 
33427  * @constructor
33428  * Create a new DocumentViewer
33429  * @param {Object} config The config object
33430  */
33431
33432 Roo.bootstrap.DocumentSlider = function(config){
33433     Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33434     
33435     this.files = [];
33436     
33437     this.addEvents({
33438         /**
33439          * @event initial
33440          * Fire after initEvent
33441          * @param {Roo.bootstrap.DocumentSlider} this
33442          */
33443         "initial" : true,
33444         /**
33445          * @event update
33446          * Fire after update
33447          * @param {Roo.bootstrap.DocumentSlider} this
33448          */
33449         "update" : true,
33450         /**
33451          * @event click
33452          * Fire after click
33453          * @param {Roo.bootstrap.DocumentSlider} this
33454          */
33455         "click" : true
33456     });
33457 };
33458
33459 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
33460     
33461     files : false,
33462     
33463     indicator : 0,
33464     
33465     getAutoCreate : function()
33466     {
33467         var cfg = {
33468             tag : 'div',
33469             cls : 'roo-document-slider',
33470             cn : [
33471                 {
33472                     tag : 'div',
33473                     cls : 'roo-document-slider-header',
33474                     cn : [
33475                         {
33476                             tag : 'div',
33477                             cls : 'roo-document-slider-header-title'
33478                         }
33479                     ]
33480                 },
33481                 {
33482                     tag : 'div',
33483                     cls : 'roo-document-slider-body',
33484                     cn : [
33485                         {
33486                             tag : 'div',
33487                             cls : 'roo-document-slider-prev',
33488                             cn : [
33489                                 {
33490                                     tag : 'i',
33491                                     cls : 'fa fa-chevron-left'
33492                                 }
33493                             ]
33494                         },
33495                         {
33496                             tag : 'div',
33497                             cls : 'roo-document-slider-thumb',
33498                             cn : [
33499                                 {
33500                                     tag : 'img',
33501                                     cls : 'roo-document-slider-image'
33502                                 }
33503                             ]
33504                         },
33505                         {
33506                             tag : 'div',
33507                             cls : 'roo-document-slider-next',
33508                             cn : [
33509                                 {
33510                                     tag : 'i',
33511                                     cls : 'fa fa-chevron-right'
33512                                 }
33513                             ]
33514                         }
33515                     ]
33516                 }
33517             ]
33518         };
33519         
33520         return cfg;
33521     },
33522     
33523     initEvents : function()
33524     {
33525         this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33526         this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33527         
33528         this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33529         this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33530         
33531         this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33532         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33533         
33534         this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33535         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33536         
33537         this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33538         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33539         
33540         this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33541         this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33542         
33543         this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33544         this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33545         
33546         this.thumbEl.on('click', this.onClick, this);
33547         
33548         this.prevIndicator.on('click', this.prev, this);
33549         
33550         this.nextIndicator.on('click', this.next, this);
33551         
33552     },
33553     
33554     initial : function()
33555     {
33556         if(this.files.length){
33557             this.indicator = 1;
33558             this.update()
33559         }
33560         
33561         this.fireEvent('initial', this);
33562     },
33563     
33564     update : function()
33565     {
33566         this.imageEl.attr('src', this.files[this.indicator - 1]);
33567         
33568         this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33569         
33570         this.prevIndicator.show();
33571         
33572         if(this.indicator == 1){
33573             this.prevIndicator.hide();
33574         }
33575         
33576         this.nextIndicator.show();
33577         
33578         if(this.indicator == this.files.length){
33579             this.nextIndicator.hide();
33580         }
33581         
33582         this.thumbEl.scrollTo('top');
33583         
33584         this.fireEvent('update', this);
33585     },
33586     
33587     onClick : function(e)
33588     {
33589         e.preventDefault();
33590         
33591         this.fireEvent('click', this);
33592     },
33593     
33594     prev : function(e)
33595     {
33596         e.preventDefault();
33597         
33598         this.indicator = Math.max(1, this.indicator - 1);
33599         
33600         this.update();
33601     },
33602     
33603     next : function(e)
33604     {
33605         e.preventDefault();
33606         
33607         this.indicator = Math.min(this.files.length, this.indicator + 1);
33608         
33609         this.update();
33610     }
33611 });
33612 /*
33613  * - LGPL
33614  *
33615  * RadioSet
33616  *
33617  *
33618  */
33619
33620 /**
33621  * @class Roo.bootstrap.RadioSet
33622  * @extends Roo.bootstrap.Input
33623  * Bootstrap RadioSet class
33624  * @cfg {String} indicatorpos (left|right) default left
33625  * @cfg {Boolean} inline (true|false) inline the element (default true)
33626  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33627  * @constructor
33628  * Create a new RadioSet
33629  * @param {Object} config The config object
33630  */
33631
33632 Roo.bootstrap.RadioSet = function(config){
33633     
33634     Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33635     
33636     this.radioes = [];
33637     
33638     Roo.bootstrap.RadioSet.register(this);
33639     
33640     this.addEvents({
33641         /**
33642         * @event check
33643         * Fires when the element is checked or unchecked.
33644         * @param {Roo.bootstrap.RadioSet} this This radio
33645         * @param {Roo.bootstrap.Radio} item The checked item
33646         */
33647        check : true,
33648        /**
33649         * @event click
33650         * Fires when the element is click.
33651         * @param {Roo.bootstrap.RadioSet} this This radio set
33652         * @param {Roo.bootstrap.Radio} item The checked item
33653         * @param {Roo.EventObject} e The event object
33654         */
33655        click : true
33656     });
33657     
33658 };
33659
33660 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
33661
33662     radioes : false,
33663     
33664     inline : true,
33665     
33666     weight : '',
33667     
33668     indicatorpos : 'left',
33669     
33670     getAutoCreate : function()
33671     {
33672         var label = {
33673             tag : 'label',
33674             cls : 'roo-radio-set-label',
33675             cn : [
33676                 {
33677                     tag : 'span',
33678                     html : this.fieldLabel
33679                 }
33680             ]
33681         };
33682         
33683         if(this.indicatorpos == 'left'){
33684             label.cn.unshift({
33685                 tag : 'i',
33686                 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33687                 tooltip : 'This field is required'
33688             });
33689         } else {
33690             label.cn.push({
33691                 tag : 'i',
33692                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33693                 tooltip : 'This field is required'
33694             });
33695         }
33696         
33697         var items = {
33698             tag : 'div',
33699             cls : 'roo-radio-set-items'
33700         };
33701         
33702         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33703         
33704         if (align === 'left' && this.fieldLabel.length) {
33705             
33706             items = {
33707                 cls : "roo-radio-set-right", 
33708                 cn: [
33709                     items
33710                 ]
33711             };
33712             
33713             if(this.labelWidth > 12){
33714                 label.style = "width: " + this.labelWidth + 'px';
33715             }
33716             
33717             if(this.labelWidth < 13 && this.labelmd == 0){
33718                 this.labelmd = this.labelWidth;
33719             }
33720             
33721             if(this.labellg > 0){
33722                 label.cls += ' col-lg-' + this.labellg;
33723                 items.cls += ' col-lg-' + (12 - this.labellg);
33724             }
33725             
33726             if(this.labelmd > 0){
33727                 label.cls += ' col-md-' + this.labelmd;
33728                 items.cls += ' col-md-' + (12 - this.labelmd);
33729             }
33730             
33731             if(this.labelsm > 0){
33732                 label.cls += ' col-sm-' + this.labelsm;
33733                 items.cls += ' col-sm-' + (12 - this.labelsm);
33734             }
33735             
33736             if(this.labelxs > 0){
33737                 label.cls += ' col-xs-' + this.labelxs;
33738                 items.cls += ' col-xs-' + (12 - this.labelxs);
33739             }
33740         }
33741         
33742         var cfg = {
33743             tag : 'div',
33744             cls : 'roo-radio-set',
33745             cn : [
33746                 {
33747                     tag : 'input',
33748                     cls : 'roo-radio-set-input',
33749                     type : 'hidden',
33750                     name : this.name,
33751                     value : this.value ? this.value :  ''
33752                 },
33753                 label,
33754                 items
33755             ]
33756         };
33757         
33758         if(this.weight.length){
33759             cfg.cls += ' roo-radio-' + this.weight;
33760         }
33761         
33762         if(this.inline) {
33763             cfg.cls += ' roo-radio-set-inline';
33764         }
33765         
33766         var settings=this;
33767         ['xs','sm','md','lg'].map(function(size){
33768             if (settings[size]) {
33769                 cfg.cls += ' col-' + size + '-' + settings[size];
33770             }
33771         });
33772         
33773         return cfg;
33774         
33775     },
33776
33777     initEvents : function()
33778     {
33779         this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33780         this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33781         
33782         if(!this.fieldLabel.length){
33783             this.labelEl.hide();
33784         }
33785         
33786         this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33787         this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33788         
33789         this.indicator = this.indicatorEl();
33790         
33791         if(this.indicator){
33792             this.indicator.addClass('invisible');
33793         }
33794         
33795         this.originalValue = this.getValue();
33796         
33797     },
33798     
33799     inputEl: function ()
33800     {
33801         return this.el.select('.roo-radio-set-input', true).first();
33802     },
33803     
33804     getChildContainer : function()
33805     {
33806         return this.itemsEl;
33807     },
33808     
33809     register : function(item)
33810     {
33811         this.radioes.push(item);
33812         
33813     },
33814     
33815     validate : function()
33816     {   
33817         if(this.getVisibilityEl().hasClass('hidden')){
33818             return true;
33819         }
33820         
33821         var valid = false;
33822         
33823         Roo.each(this.radioes, function(i){
33824             if(!i.checked){
33825                 return;
33826             }
33827             
33828             valid = true;
33829             return false;
33830         });
33831         
33832         if(this.allowBlank) {
33833             return true;
33834         }
33835         
33836         if(this.disabled || valid){
33837             this.markValid();
33838             return true;
33839         }
33840         
33841         this.markInvalid();
33842         return false;
33843         
33844     },
33845     
33846     markValid : function()
33847     {
33848         if(this.labelEl.isVisible(true)){
33849             this.indicatorEl().removeClass('visible');
33850             this.indicatorEl().addClass('invisible');
33851         }
33852         
33853         this.el.removeClass([this.invalidClass, this.validClass]);
33854         this.el.addClass(this.validClass);
33855         
33856         this.fireEvent('valid', this);
33857     },
33858     
33859     markInvalid : function(msg)
33860     {
33861         if(this.allowBlank || this.disabled){
33862             return;
33863         }
33864         
33865         if(this.labelEl.isVisible(true)){
33866             this.indicatorEl().removeClass('invisible');
33867             this.indicatorEl().addClass('visible');
33868         }
33869         
33870         this.el.removeClass([this.invalidClass, this.validClass]);
33871         this.el.addClass(this.invalidClass);
33872         
33873         this.fireEvent('invalid', this, msg);
33874         
33875     },
33876     
33877     setValue : function(v, suppressEvent)
33878     {   
33879         if(this.value === v){
33880             return;
33881         }
33882         
33883         this.value = v;
33884         
33885         if(this.rendered){
33886             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33887         }
33888         
33889         Roo.each(this.radioes, function(i){
33890             i.checked = false;
33891             i.el.removeClass('checked');
33892         });
33893         
33894         Roo.each(this.radioes, function(i){
33895             
33896             if(i.value === v || i.value.toString() === v.toString()){
33897                 i.checked = true;
33898                 i.el.addClass('checked');
33899                 
33900                 if(suppressEvent !== true){
33901                     this.fireEvent('check', this, i);
33902                 }
33903                 
33904                 return false;
33905             }
33906             
33907         }, this);
33908         
33909         this.validate();
33910     },
33911     
33912     clearInvalid : function(){
33913         
33914         if(!this.el || this.preventMark){
33915             return;
33916         }
33917         
33918         this.el.removeClass([this.invalidClass]);
33919         
33920         this.fireEvent('valid', this);
33921     }
33922     
33923 });
33924
33925 Roo.apply(Roo.bootstrap.RadioSet, {
33926     
33927     groups: {},
33928     
33929     register : function(set)
33930     {
33931         this.groups[set.name] = set;
33932     },
33933     
33934     get: function(name) 
33935     {
33936         if (typeof(this.groups[name]) == 'undefined') {
33937             return false;
33938         }
33939         
33940         return this.groups[name] ;
33941     }
33942     
33943 });
33944 /*
33945  * Based on:
33946  * Ext JS Library 1.1.1
33947  * Copyright(c) 2006-2007, Ext JS, LLC.
33948  *
33949  * Originally Released Under LGPL - original licence link has changed is not relivant.
33950  *
33951  * Fork - LGPL
33952  * <script type="text/javascript">
33953  */
33954
33955
33956 /**
33957  * @class Roo.bootstrap.SplitBar
33958  * @extends Roo.util.Observable
33959  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33960  * <br><br>
33961  * Usage:
33962  * <pre><code>
33963 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33964                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33965 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33966 split.minSize = 100;
33967 split.maxSize = 600;
33968 split.animate = true;
33969 split.on('moved', splitterMoved);
33970 </code></pre>
33971  * @constructor
33972  * Create a new SplitBar
33973  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
33974  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
33975  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33976  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
33977                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33978                         position of the SplitBar).
33979  */
33980 Roo.bootstrap.SplitBar = function(cfg){
33981     
33982     /** @private */
33983     
33984     //{
33985     //  dragElement : elm
33986     //  resizingElement: el,
33987         // optional..
33988     //    orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33989     //    placement : Roo.bootstrap.SplitBar.LEFT  ,
33990         // existingProxy ???
33991     //}
33992     
33993     this.el = Roo.get(cfg.dragElement, true);
33994     this.el.dom.unselectable = "on";
33995     /** @private */
33996     this.resizingEl = Roo.get(cfg.resizingElement, true);
33997
33998     /**
33999      * @private
34000      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34001      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34002      * @type Number
34003      */
34004     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34005     
34006     /**
34007      * The minimum size of the resizing element. (Defaults to 0)
34008      * @type Number
34009      */
34010     this.minSize = 0;
34011     
34012     /**
34013      * The maximum size of the resizing element. (Defaults to 2000)
34014      * @type Number
34015      */
34016     this.maxSize = 2000;
34017     
34018     /**
34019      * Whether to animate the transition to the new size
34020      * @type Boolean
34021      */
34022     this.animate = false;
34023     
34024     /**
34025      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34026      * @type Boolean
34027      */
34028     this.useShim = false;
34029     
34030     /** @private */
34031     this.shim = null;
34032     
34033     if(!cfg.existingProxy){
34034         /** @private */
34035         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34036     }else{
34037         this.proxy = Roo.get(cfg.existingProxy).dom;
34038     }
34039     /** @private */
34040     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34041     
34042     /** @private */
34043     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34044     
34045     /** @private */
34046     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34047     
34048     /** @private */
34049     this.dragSpecs = {};
34050     
34051     /**
34052      * @private The adapter to use to positon and resize elements
34053      */
34054     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34055     this.adapter.init(this);
34056     
34057     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34058         /** @private */
34059         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34060         this.el.addClass("roo-splitbar-h");
34061     }else{
34062         /** @private */
34063         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34064         this.el.addClass("roo-splitbar-v");
34065     }
34066     
34067     this.addEvents({
34068         /**
34069          * @event resize
34070          * Fires when the splitter is moved (alias for {@link #event-moved})
34071          * @param {Roo.bootstrap.SplitBar} this
34072          * @param {Number} newSize the new width or height
34073          */
34074         "resize" : true,
34075         /**
34076          * @event moved
34077          * Fires when the splitter is moved
34078          * @param {Roo.bootstrap.SplitBar} this
34079          * @param {Number} newSize the new width or height
34080          */
34081         "moved" : true,
34082         /**
34083          * @event beforeresize
34084          * Fires before the splitter is dragged
34085          * @param {Roo.bootstrap.SplitBar} this
34086          */
34087         "beforeresize" : true,
34088
34089         "beforeapply" : true
34090     });
34091
34092     Roo.util.Observable.call(this);
34093 };
34094
34095 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34096     onStartProxyDrag : function(x, y){
34097         this.fireEvent("beforeresize", this);
34098         if(!this.overlay){
34099             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "roo-drag-overlay", html: "&#160;"}, true);
34100             o.unselectable();
34101             o.enableDisplayMode("block");
34102             // all splitbars share the same overlay
34103             Roo.bootstrap.SplitBar.prototype.overlay = o;
34104         }
34105         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34106         this.overlay.show();
34107         Roo.get(this.proxy).setDisplayed("block");
34108         var size = this.adapter.getElementSize(this);
34109         this.activeMinSize = this.getMinimumSize();;
34110         this.activeMaxSize = this.getMaximumSize();;
34111         var c1 = size - this.activeMinSize;
34112         var c2 = Math.max(this.activeMaxSize - size, 0);
34113         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34114             this.dd.resetConstraints();
34115             this.dd.setXConstraint(
34116                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
34117                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34118             );
34119             this.dd.setYConstraint(0, 0);
34120         }else{
34121             this.dd.resetConstraints();
34122             this.dd.setXConstraint(0, 0);
34123             this.dd.setYConstraint(
34124                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
34125                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34126             );
34127          }
34128         this.dragSpecs.startSize = size;
34129         this.dragSpecs.startPoint = [x, y];
34130         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34131     },
34132     
34133     /** 
34134      * @private Called after the drag operation by the DDProxy
34135      */
34136     onEndProxyDrag : function(e){
34137         Roo.get(this.proxy).setDisplayed(false);
34138         var endPoint = Roo.lib.Event.getXY(e);
34139         if(this.overlay){
34140             this.overlay.hide();
34141         }
34142         var newSize;
34143         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34144             newSize = this.dragSpecs.startSize + 
34145                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34146                     endPoint[0] - this.dragSpecs.startPoint[0] :
34147                     this.dragSpecs.startPoint[0] - endPoint[0]
34148                 );
34149         }else{
34150             newSize = this.dragSpecs.startSize + 
34151                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34152                     endPoint[1] - this.dragSpecs.startPoint[1] :
34153                     this.dragSpecs.startPoint[1] - endPoint[1]
34154                 );
34155         }
34156         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34157         if(newSize != this.dragSpecs.startSize){
34158             if(this.fireEvent('beforeapply', this, newSize) !== false){
34159                 this.adapter.setElementSize(this, newSize);
34160                 this.fireEvent("moved", this, newSize);
34161                 this.fireEvent("resize", this, newSize);
34162             }
34163         }
34164     },
34165     
34166     /**
34167      * Get the adapter this SplitBar uses
34168      * @return The adapter object
34169      */
34170     getAdapter : function(){
34171         return this.adapter;
34172     },
34173     
34174     /**
34175      * Set the adapter this SplitBar uses
34176      * @param {Object} adapter A SplitBar adapter object
34177      */
34178     setAdapter : function(adapter){
34179         this.adapter = adapter;
34180         this.adapter.init(this);
34181     },
34182     
34183     /**
34184      * Gets the minimum size for the resizing element
34185      * @return {Number} The minimum size
34186      */
34187     getMinimumSize : function(){
34188         return this.minSize;
34189     },
34190     
34191     /**
34192      * Sets the minimum size for the resizing element
34193      * @param {Number} minSize The minimum size
34194      */
34195     setMinimumSize : function(minSize){
34196         this.minSize = minSize;
34197     },
34198     
34199     /**
34200      * Gets the maximum size for the resizing element
34201      * @return {Number} The maximum size
34202      */
34203     getMaximumSize : function(){
34204         return this.maxSize;
34205     },
34206     
34207     /**
34208      * Sets the maximum size for the resizing element
34209      * @param {Number} maxSize The maximum size
34210      */
34211     setMaximumSize : function(maxSize){
34212         this.maxSize = maxSize;
34213     },
34214     
34215     /**
34216      * Sets the initialize size for the resizing element
34217      * @param {Number} size The initial size
34218      */
34219     setCurrentSize : function(size){
34220         var oldAnimate = this.animate;
34221         this.animate = false;
34222         this.adapter.setElementSize(this, size);
34223         this.animate = oldAnimate;
34224     },
34225     
34226     /**
34227      * Destroy this splitbar. 
34228      * @param {Boolean} removeEl True to remove the element
34229      */
34230     destroy : function(removeEl){
34231         if(this.shim){
34232             this.shim.remove();
34233         }
34234         this.dd.unreg();
34235         this.proxy.parentNode.removeChild(this.proxy);
34236         if(removeEl){
34237             this.el.remove();
34238         }
34239     }
34240 });
34241
34242 /**
34243  * @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.
34244  */
34245 Roo.bootstrap.SplitBar.createProxy = function(dir){
34246     var proxy = new Roo.Element(document.createElement("div"));
34247     proxy.unselectable();
34248     var cls = 'roo-splitbar-proxy';
34249     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34250     document.body.appendChild(proxy.dom);
34251     return proxy.dom;
34252 };
34253
34254 /** 
34255  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34256  * Default Adapter. It assumes the splitter and resizing element are not positioned
34257  * elements and only gets/sets the width of the element. Generally used for table based layouts.
34258  */
34259 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34260 };
34261
34262 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34263     // do nothing for now
34264     init : function(s){
34265     
34266     },
34267     /**
34268      * Called before drag operations to get the current size of the resizing element. 
34269      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34270      */
34271      getElementSize : function(s){
34272         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34273             return s.resizingEl.getWidth();
34274         }else{
34275             return s.resizingEl.getHeight();
34276         }
34277     },
34278     
34279     /**
34280      * Called after drag operations to set the size of the resizing element.
34281      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34282      * @param {Number} newSize The new size to set
34283      * @param {Function} onComplete A function to be invoked when resizing is complete
34284      */
34285     setElementSize : function(s, newSize, onComplete){
34286         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34287             if(!s.animate){
34288                 s.resizingEl.setWidth(newSize);
34289                 if(onComplete){
34290                     onComplete(s, newSize);
34291                 }
34292             }else{
34293                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34294             }
34295         }else{
34296             
34297             if(!s.animate){
34298                 s.resizingEl.setHeight(newSize);
34299                 if(onComplete){
34300                     onComplete(s, newSize);
34301                 }
34302             }else{
34303                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34304             }
34305         }
34306     }
34307 };
34308
34309 /** 
34310  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34311  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34312  * Adapter that  moves the splitter element to align with the resized sizing element. 
34313  * Used with an absolute positioned SplitBar.
34314  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34315  * document.body, make sure you assign an id to the body element.
34316  */
34317 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34318     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34319     this.container = Roo.get(container);
34320 };
34321
34322 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34323     init : function(s){
34324         this.basic.init(s);
34325     },
34326     
34327     getElementSize : function(s){
34328         return this.basic.getElementSize(s);
34329     },
34330     
34331     setElementSize : function(s, newSize, onComplete){
34332         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34333     },
34334     
34335     moveSplitter : function(s){
34336         var yes = Roo.bootstrap.SplitBar;
34337         switch(s.placement){
34338             case yes.LEFT:
34339                 s.el.setX(s.resizingEl.getRight());
34340                 break;
34341             case yes.RIGHT:
34342                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34343                 break;
34344             case yes.TOP:
34345                 s.el.setY(s.resizingEl.getBottom());
34346                 break;
34347             case yes.BOTTOM:
34348                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34349                 break;
34350         }
34351     }
34352 };
34353
34354 /**
34355  * Orientation constant - Create a vertical SplitBar
34356  * @static
34357  * @type Number
34358  */
34359 Roo.bootstrap.SplitBar.VERTICAL = 1;
34360
34361 /**
34362  * Orientation constant - Create a horizontal SplitBar
34363  * @static
34364  * @type Number
34365  */
34366 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34367
34368 /**
34369  * Placement constant - The resizing element is to the left of the splitter element
34370  * @static
34371  * @type Number
34372  */
34373 Roo.bootstrap.SplitBar.LEFT = 1;
34374
34375 /**
34376  * Placement constant - The resizing element is to the right of the splitter element
34377  * @static
34378  * @type Number
34379  */
34380 Roo.bootstrap.SplitBar.RIGHT = 2;
34381
34382 /**
34383  * Placement constant - The resizing element is positioned above the splitter element
34384  * @static
34385  * @type Number
34386  */
34387 Roo.bootstrap.SplitBar.TOP = 3;
34388
34389 /**
34390  * Placement constant - The resizing element is positioned under splitter element
34391  * @static
34392  * @type Number
34393  */
34394 Roo.bootstrap.SplitBar.BOTTOM = 4;
34395 Roo.namespace("Roo.bootstrap.layout");/*
34396  * Based on:
34397  * Ext JS Library 1.1.1
34398  * Copyright(c) 2006-2007, Ext JS, LLC.
34399  *
34400  * Originally Released Under LGPL - original licence link has changed is not relivant.
34401  *
34402  * Fork - LGPL
34403  * <script type="text/javascript">
34404  */
34405
34406 /**
34407  * @class Roo.bootstrap.layout.Manager
34408  * @extends Roo.bootstrap.Component
34409  * Base class for layout managers.
34410  */
34411 Roo.bootstrap.layout.Manager = function(config)
34412 {
34413     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34414
34415
34416
34417
34418
34419     /** false to disable window resize monitoring @type Boolean */
34420     this.monitorWindowResize = true;
34421     this.regions = {};
34422     this.addEvents({
34423         /**
34424          * @event layout
34425          * Fires when a layout is performed.
34426          * @param {Roo.LayoutManager} this
34427          */
34428         "layout" : true,
34429         /**
34430          * @event regionresized
34431          * Fires when the user resizes a region.
34432          * @param {Roo.LayoutRegion} region The resized region
34433          * @param {Number} newSize The new size (width for east/west, height for north/south)
34434          */
34435         "regionresized" : true,
34436         /**
34437          * @event regioncollapsed
34438          * Fires when a region is collapsed.
34439          * @param {Roo.LayoutRegion} region The collapsed region
34440          */
34441         "regioncollapsed" : true,
34442         /**
34443          * @event regionexpanded
34444          * Fires when a region is expanded.
34445          * @param {Roo.LayoutRegion} region The expanded region
34446          */
34447         "regionexpanded" : true
34448     });
34449     this.updating = false;
34450
34451     if (config.el) {
34452         this.el = Roo.get(config.el);
34453         this.initEvents();
34454     }
34455
34456 };
34457
34458 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34459
34460
34461     regions : null,
34462
34463     monitorWindowResize : true,
34464
34465
34466     updating : false,
34467
34468
34469     onRender : function(ct, position)
34470     {
34471         if(!this.el){
34472             this.el = Roo.get(ct);
34473             this.initEvents();
34474         }
34475         //this.fireEvent('render',this);
34476     },
34477
34478
34479     initEvents: function()
34480     {
34481
34482
34483         // ie scrollbar fix
34484         if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34485             document.body.scroll = "no";
34486         }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34487             this.el.position('relative');
34488         }
34489         this.id = this.el.id;
34490         this.el.addClass("roo-layout-container");
34491         Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34492         if(this.el.dom != document.body ) {
34493             this.el.on('resize', this.layout,this);
34494             this.el.on('show', this.layout,this);
34495         }
34496
34497     },
34498
34499     /**
34500      * Returns true if this layout is currently being updated
34501      * @return {Boolean}
34502      */
34503     isUpdating : function(){
34504         return this.updating;
34505     },
34506
34507     /**
34508      * Suspend the LayoutManager from doing auto-layouts while
34509      * making multiple add or remove calls
34510      */
34511     beginUpdate : function(){
34512         this.updating = true;
34513     },
34514
34515     /**
34516      * Restore auto-layouts and optionally disable the manager from performing a layout
34517      * @param {Boolean} noLayout true to disable a layout update
34518      */
34519     endUpdate : function(noLayout){
34520         this.updating = false;
34521         if(!noLayout){
34522             this.layout();
34523         }
34524     },
34525
34526     layout: function(){
34527         // abstract...
34528     },
34529
34530     onRegionResized : function(region, newSize){
34531         this.fireEvent("regionresized", region, newSize);
34532         this.layout();
34533     },
34534
34535     onRegionCollapsed : function(region){
34536         this.fireEvent("regioncollapsed", region);
34537     },
34538
34539     onRegionExpanded : function(region){
34540         this.fireEvent("regionexpanded", region);
34541     },
34542
34543     /**
34544      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34545      * performs box-model adjustments.
34546      * @return {Object} The size as an object {width: (the width), height: (the height)}
34547      */
34548     getViewSize : function()
34549     {
34550         var size;
34551         if(this.el.dom != document.body){
34552             size = this.el.getSize();
34553         }else{
34554             size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34555         }
34556         size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34557         size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34558         return size;
34559     },
34560
34561     /**
34562      * Returns the Element this layout is bound to.
34563      * @return {Roo.Element}
34564      */
34565     getEl : function(){
34566         return this.el;
34567     },
34568
34569     /**
34570      * Returns the specified region.
34571      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34572      * @return {Roo.LayoutRegion}
34573      */
34574     getRegion : function(target){
34575         return this.regions[target.toLowerCase()];
34576     },
34577
34578     onWindowResize : function(){
34579         if(this.monitorWindowResize){
34580             this.layout();
34581         }
34582     }
34583 });
34584 /*
34585  * Based on:
34586  * Ext JS Library 1.1.1
34587  * Copyright(c) 2006-2007, Ext JS, LLC.
34588  *
34589  * Originally Released Under LGPL - original licence link has changed is not relivant.
34590  *
34591  * Fork - LGPL
34592  * <script type="text/javascript">
34593  */
34594 /**
34595  * @class Roo.bootstrap.layout.Border
34596  * @extends Roo.bootstrap.layout.Manager
34597  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34598  * please see: examples/bootstrap/nested.html<br><br>
34599  
34600 <b>The container the layout is rendered into can be either the body element or any other element.
34601 If it is not the body element, the container needs to either be an absolute positioned element,
34602 or you will need to add "position:relative" to the css of the container.  You will also need to specify
34603 the container size if it is not the body element.</b>
34604
34605 * @constructor
34606 * Create a new Border
34607 * @param {Object} config Configuration options
34608  */
34609 Roo.bootstrap.layout.Border = function(config){
34610     config = config || {};
34611     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34612     
34613     
34614     
34615     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34616         if(config[region]){
34617             config[region].region = region;
34618             this.addRegion(config[region]);
34619         }
34620     },this);
34621     
34622 };
34623
34624 Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
34625
34626 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34627     /**
34628      * Creates and adds a new region if it doesn't already exist.
34629      * @param {String} target The target region key (north, south, east, west or center).
34630      * @param {Object} config The regions config object
34631      * @return {BorderLayoutRegion} The new region
34632      */
34633     addRegion : function(config)
34634     {
34635         if(!this.regions[config.region]){
34636             var r = this.factory(config);
34637             this.bindRegion(r);
34638         }
34639         return this.regions[config.region];
34640     },
34641
34642     // private (kinda)
34643     bindRegion : function(r){
34644         this.regions[r.config.region] = r;
34645         
34646         r.on("visibilitychange",    this.layout, this);
34647         r.on("paneladded",          this.layout, this);
34648         r.on("panelremoved",        this.layout, this);
34649         r.on("invalidated",         this.layout, this);
34650         r.on("resized",             this.onRegionResized, this);
34651         r.on("collapsed",           this.onRegionCollapsed, this);
34652         r.on("expanded",            this.onRegionExpanded, this);
34653     },
34654
34655     /**
34656      * Performs a layout update.
34657      */
34658     layout : function()
34659     {
34660         if(this.updating) {
34661             return;
34662         }
34663         
34664         // render all the rebions if they have not been done alreayd?
34665         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34666             if(this.regions[region] && !this.regions[region].bodyEl){
34667                 this.regions[region].onRender(this.el)
34668             }
34669         },this);
34670         
34671         var size = this.getViewSize();
34672         var w = size.width;
34673         var h = size.height;
34674         var centerW = w;
34675         var centerH = h;
34676         var centerY = 0;
34677         var centerX = 0;
34678         //var x = 0, y = 0;
34679
34680         var rs = this.regions;
34681         var north = rs["north"];
34682         var south = rs["south"]; 
34683         var west = rs["west"];
34684         var east = rs["east"];
34685         var center = rs["center"];
34686         //if(this.hideOnLayout){ // not supported anymore
34687             //c.el.setStyle("display", "none");
34688         //}
34689         if(north && north.isVisible()){
34690             var b = north.getBox();
34691             var m = north.getMargins();
34692             b.width = w - (m.left+m.right);
34693             b.x = m.left;
34694             b.y = m.top;
34695             centerY = b.height + b.y + m.bottom;
34696             centerH -= centerY;
34697             north.updateBox(this.safeBox(b));
34698         }
34699         if(south && south.isVisible()){
34700             var b = south.getBox();
34701             var m = south.getMargins();
34702             b.width = w - (m.left+m.right);
34703             b.x = m.left;
34704             var totalHeight = (b.height + m.top + m.bottom);
34705             b.y = h - totalHeight + m.top;
34706             centerH -= totalHeight;
34707             south.updateBox(this.safeBox(b));
34708         }
34709         if(west && west.isVisible()){
34710             var b = west.getBox();
34711             var m = west.getMargins();
34712             b.height = centerH - (m.top+m.bottom);
34713             b.x = m.left;
34714             b.y = centerY + m.top;
34715             var totalWidth = (b.width + m.left + m.right);
34716             centerX += totalWidth;
34717             centerW -= totalWidth;
34718             west.updateBox(this.safeBox(b));
34719         }
34720         if(east && east.isVisible()){
34721             var b = east.getBox();
34722             var m = east.getMargins();
34723             b.height = centerH - (m.top+m.bottom);
34724             var totalWidth = (b.width + m.left + m.right);
34725             b.x = w - totalWidth + m.left;
34726             b.y = centerY + m.top;
34727             centerW -= totalWidth;
34728             east.updateBox(this.safeBox(b));
34729         }
34730         if(center){
34731             var m = center.getMargins();
34732             var centerBox = {
34733                 x: centerX + m.left,
34734                 y: centerY + m.top,
34735                 width: centerW - (m.left+m.right),
34736                 height: centerH - (m.top+m.bottom)
34737             };
34738             //if(this.hideOnLayout){
34739                 //center.el.setStyle("display", "block");
34740             //}
34741             center.updateBox(this.safeBox(centerBox));
34742         }
34743         this.el.repaint();
34744         this.fireEvent("layout", this);
34745     },
34746
34747     // private
34748     safeBox : function(box){
34749         box.width = Math.max(0, box.width);
34750         box.height = Math.max(0, box.height);
34751         return box;
34752     },
34753
34754     /**
34755      * Adds a ContentPanel (or subclass) to this layout.
34756      * @param {String} target The target region key (north, south, east, west or center).
34757      * @param {Roo.ContentPanel} panel The panel to add
34758      * @return {Roo.ContentPanel} The added panel
34759      */
34760     add : function(target, panel){
34761          
34762         target = target.toLowerCase();
34763         return this.regions[target].add(panel);
34764     },
34765
34766     /**
34767      * Remove a ContentPanel (or subclass) to this layout.
34768      * @param {String} target The target region key (north, south, east, west or center).
34769      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34770      * @return {Roo.ContentPanel} The removed panel
34771      */
34772     remove : function(target, panel){
34773         target = target.toLowerCase();
34774         return this.regions[target].remove(panel);
34775     },
34776
34777     /**
34778      * Searches all regions for a panel with the specified id
34779      * @param {String} panelId
34780      * @return {Roo.ContentPanel} The panel or null if it wasn't found
34781      */
34782     findPanel : function(panelId){
34783         var rs = this.regions;
34784         for(var target in rs){
34785             if(typeof rs[target] != "function"){
34786                 var p = rs[target].getPanel(panelId);
34787                 if(p){
34788                     return p;
34789                 }
34790             }
34791         }
34792         return null;
34793     },
34794
34795     /**
34796      * Searches all regions for a panel with the specified id and activates (shows) it.
34797      * @param {String/ContentPanel} panelId The panels id or the panel itself
34798      * @return {Roo.ContentPanel} The shown panel or null
34799      */
34800     showPanel : function(panelId) {
34801       var rs = this.regions;
34802       for(var target in rs){
34803          var r = rs[target];
34804          if(typeof r != "function"){
34805             if(r.hasPanel(panelId)){
34806                return r.showPanel(panelId);
34807             }
34808          }
34809       }
34810       return null;
34811    },
34812
34813    /**
34814      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34815      * @param {Roo.state.Provider} provider (optional) An alternate state provider
34816      */
34817    /*
34818     restoreState : function(provider){
34819         if(!provider){
34820             provider = Roo.state.Manager;
34821         }
34822         var sm = new Roo.LayoutStateManager();
34823         sm.init(this, provider);
34824     },
34825 */
34826  
34827  
34828     /**
34829      * Adds a xtype elements to the layout.
34830      * <pre><code>
34831
34832 layout.addxtype({
34833        xtype : 'ContentPanel',
34834        region: 'west',
34835        items: [ .... ]
34836    }
34837 );
34838
34839 layout.addxtype({
34840         xtype : 'NestedLayoutPanel',
34841         region: 'west',
34842         layout: {
34843            center: { },
34844            west: { }   
34845         },
34846         items : [ ... list of content panels or nested layout panels.. ]
34847    }
34848 );
34849 </code></pre>
34850      * @param {Object} cfg Xtype definition of item to add.
34851      */
34852     addxtype : function(cfg)
34853     {
34854         // basically accepts a pannel...
34855         // can accept a layout region..!?!?
34856         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34857         
34858         
34859         // theory?  children can only be panels??
34860         
34861         //if (!cfg.xtype.match(/Panel$/)) {
34862         //    return false;
34863         //}
34864         var ret = false;
34865         
34866         if (typeof(cfg.region) == 'undefined') {
34867             Roo.log("Failed to add Panel, region was not set");
34868             Roo.log(cfg);
34869             return false;
34870         }
34871         var region = cfg.region;
34872         delete cfg.region;
34873         
34874           
34875         var xitems = [];
34876         if (cfg.items) {
34877             xitems = cfg.items;
34878             delete cfg.items;
34879         }
34880         var nb = false;
34881         
34882         switch(cfg.xtype) 
34883         {
34884             case 'Content':  // ContentPanel (el, cfg)
34885             case 'Scroll':  // ContentPanel (el, cfg)
34886             case 'View': 
34887                 cfg.autoCreate = true;
34888                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34889                 //} else {
34890                 //    var el = this.el.createChild();
34891                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34892                 //}
34893                 
34894                 this.add(region, ret);
34895                 break;
34896             
34897             /*
34898             case 'TreePanel': // our new panel!
34899                 cfg.el = this.el.createChild();
34900                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34901                 this.add(region, ret);
34902                 break;
34903             */
34904             
34905             case 'Nest': 
34906                 // create a new Layout (which is  a Border Layout...
34907                 
34908                 var clayout = cfg.layout;
34909                 clayout.el  = this.el.createChild();
34910                 clayout.items   = clayout.items  || [];
34911                 
34912                 delete cfg.layout;
34913                 
34914                 // replace this exitems with the clayout ones..
34915                 xitems = clayout.items;
34916                  
34917                 // force background off if it's in center...
34918                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34919                     cfg.background = false;
34920                 }
34921                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
34922                 
34923                 
34924                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34925                 //console.log('adding nested layout panel '  + cfg.toSource());
34926                 this.add(region, ret);
34927                 nb = {}; /// find first...
34928                 break;
34929             
34930             case 'Grid':
34931                 
34932                 // needs grid and region
34933                 
34934                 //var el = this.getRegion(region).el.createChild();
34935                 /*
34936                  *var el = this.el.createChild();
34937                 // create the grid first...
34938                 cfg.grid.container = el;
34939                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34940                 */
34941                 
34942                 if (region == 'center' && this.active ) {
34943                     cfg.background = false;
34944                 }
34945                 
34946                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34947                 
34948                 this.add(region, ret);
34949                 /*
34950                 if (cfg.background) {
34951                     // render grid on panel activation (if panel background)
34952                     ret.on('activate', function(gp) {
34953                         if (!gp.grid.rendered) {
34954                     //        gp.grid.render(el);
34955                         }
34956                     });
34957                 } else {
34958                   //  cfg.grid.render(el);
34959                 }
34960                 */
34961                 break;
34962            
34963            
34964             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34965                 // it was the old xcomponent building that caused this before.
34966                 // espeically if border is the top element in the tree.
34967                 ret = this;
34968                 break; 
34969                 
34970                     
34971                 
34972                 
34973                 
34974             default:
34975                 /*
34976                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34977                     
34978                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34979                     this.add(region, ret);
34980                 } else {
34981                 */
34982                     Roo.log(cfg);
34983                     throw "Can not add '" + cfg.xtype + "' to Border";
34984                     return null;
34985              
34986                                 
34987              
34988         }
34989         this.beginUpdate();
34990         // add children..
34991         var region = '';
34992         var abn = {};
34993         Roo.each(xitems, function(i)  {
34994             region = nb && i.region ? i.region : false;
34995             
34996             var add = ret.addxtype(i);
34997            
34998             if (region) {
34999                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35000                 if (!i.background) {
35001                     abn[region] = nb[region] ;
35002                 }
35003             }
35004             
35005         });
35006         this.endUpdate();
35007
35008         // make the last non-background panel active..
35009         //if (nb) { Roo.log(abn); }
35010         if (nb) {
35011             
35012             for(var r in abn) {
35013                 region = this.getRegion(r);
35014                 if (region) {
35015                     // tried using nb[r], but it does not work..
35016                      
35017                     region.showPanel(abn[r]);
35018                    
35019                 }
35020             }
35021         }
35022         return ret;
35023         
35024     },
35025     
35026     
35027 // private
35028     factory : function(cfg)
35029     {
35030         
35031         var validRegions = Roo.bootstrap.layout.Border.regions;
35032
35033         var target = cfg.region;
35034         cfg.mgr = this;
35035         
35036         var r = Roo.bootstrap.layout;
35037         Roo.log(target);
35038         switch(target){
35039             case "north":
35040                 return new r.North(cfg);
35041             case "south":
35042                 return new r.South(cfg);
35043             case "east":
35044                 return new r.East(cfg);
35045             case "west":
35046                 return new r.West(cfg);
35047             case "center":
35048                 return new r.Center(cfg);
35049         }
35050         throw 'Layout region "'+target+'" not supported.';
35051     }
35052     
35053     
35054 });
35055  /*
35056  * Based on:
35057  * Ext JS Library 1.1.1
35058  * Copyright(c) 2006-2007, Ext JS, LLC.
35059  *
35060  * Originally Released Under LGPL - original licence link has changed is not relivant.
35061  *
35062  * Fork - LGPL
35063  * <script type="text/javascript">
35064  */
35065  
35066 /**
35067  * @class Roo.bootstrap.layout.Basic
35068  * @extends Roo.util.Observable
35069  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35070  * and does not have a titlebar, tabs or any other features. All it does is size and position 
35071  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35072  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35073  * @cfg {string}   region  the region that it inhabits..
35074  * @cfg {bool}   skipConfig skip config?
35075  * 
35076
35077  */
35078 Roo.bootstrap.layout.Basic = function(config){
35079     
35080     this.mgr = config.mgr;
35081     
35082     this.position = config.region;
35083     
35084     var skipConfig = config.skipConfig;
35085     
35086     this.events = {
35087         /**
35088          * @scope Roo.BasicLayoutRegion
35089          */
35090         
35091         /**
35092          * @event beforeremove
35093          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35094          * @param {Roo.LayoutRegion} this
35095          * @param {Roo.ContentPanel} panel The panel
35096          * @param {Object} e The cancel event object
35097          */
35098         "beforeremove" : true,
35099         /**
35100          * @event invalidated
35101          * Fires when the layout for this region is changed.
35102          * @param {Roo.LayoutRegion} this
35103          */
35104         "invalidated" : true,
35105         /**
35106          * @event visibilitychange
35107          * Fires when this region is shown or hidden 
35108          * @param {Roo.LayoutRegion} this
35109          * @param {Boolean} visibility true or false
35110          */
35111         "visibilitychange" : true,
35112         /**
35113          * @event paneladded
35114          * Fires when a panel is added. 
35115          * @param {Roo.LayoutRegion} this
35116          * @param {Roo.ContentPanel} panel The panel
35117          */
35118         "paneladded" : true,
35119         /**
35120          * @event panelremoved
35121          * Fires when a panel is removed. 
35122          * @param {Roo.LayoutRegion} this
35123          * @param {Roo.ContentPanel} panel The panel
35124          */
35125         "panelremoved" : true,
35126         /**
35127          * @event beforecollapse
35128          * Fires when this region before collapse.
35129          * @param {Roo.LayoutRegion} this
35130          */
35131         "beforecollapse" : true,
35132         /**
35133          * @event collapsed
35134          * Fires when this region is collapsed.
35135          * @param {Roo.LayoutRegion} this
35136          */
35137         "collapsed" : true,
35138         /**
35139          * @event expanded
35140          * Fires when this region is expanded.
35141          * @param {Roo.LayoutRegion} this
35142          */
35143         "expanded" : true,
35144         /**
35145          * @event slideshow
35146          * Fires when this region is slid into view.
35147          * @param {Roo.LayoutRegion} this
35148          */
35149         "slideshow" : true,
35150         /**
35151          * @event slidehide
35152          * Fires when this region slides out of view. 
35153          * @param {Roo.LayoutRegion} this
35154          */
35155         "slidehide" : true,
35156         /**
35157          * @event panelactivated
35158          * Fires when a panel is activated. 
35159          * @param {Roo.LayoutRegion} this
35160          * @param {Roo.ContentPanel} panel The activated panel
35161          */
35162         "panelactivated" : true,
35163         /**
35164          * @event resized
35165          * Fires when the user resizes this region. 
35166          * @param {Roo.LayoutRegion} this
35167          * @param {Number} newSize The new size (width for east/west, height for north/south)
35168          */
35169         "resized" : true
35170     };
35171     /** A collection of panels in this region. @type Roo.util.MixedCollection */
35172     this.panels = new Roo.util.MixedCollection();
35173     this.panels.getKey = this.getPanelId.createDelegate(this);
35174     this.box = null;
35175     this.activePanel = null;
35176     // ensure listeners are added...
35177     
35178     if (config.listeners || config.events) {
35179         Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35180             listeners : config.listeners || {},
35181             events : config.events || {}
35182         });
35183     }
35184     
35185     if(skipConfig !== true){
35186         this.applyConfig(config);
35187     }
35188 };
35189
35190 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35191 {
35192     getPanelId : function(p){
35193         return p.getId();
35194     },
35195     
35196     applyConfig : function(config){
35197         this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35198         this.config = config;
35199         
35200     },
35201     
35202     /**
35203      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
35204      * the width, for horizontal (north, south) the height.
35205      * @param {Number} newSize The new width or height
35206      */
35207     resizeTo : function(newSize){
35208         var el = this.el ? this.el :
35209                  (this.activePanel ? this.activePanel.getEl() : null);
35210         if(el){
35211             switch(this.position){
35212                 case "east":
35213                 case "west":
35214                     el.setWidth(newSize);
35215                     this.fireEvent("resized", this, newSize);
35216                 break;
35217                 case "north":
35218                 case "south":
35219                     el.setHeight(newSize);
35220                     this.fireEvent("resized", this, newSize);
35221                 break;                
35222             }
35223         }
35224     },
35225     
35226     getBox : function(){
35227         return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35228     },
35229     
35230     getMargins : function(){
35231         return this.margins;
35232     },
35233     
35234     updateBox : function(box){
35235         this.box = box;
35236         var el = this.activePanel.getEl();
35237         el.dom.style.left = box.x + "px";
35238         el.dom.style.top = box.y + "px";
35239         this.activePanel.setSize(box.width, box.height);
35240     },
35241     
35242     /**
35243      * Returns the container element for this region.
35244      * @return {Roo.Element}
35245      */
35246     getEl : function(){
35247         return this.activePanel;
35248     },
35249     
35250     /**
35251      * Returns true if this region is currently visible.
35252      * @return {Boolean}
35253      */
35254     isVisible : function(){
35255         return this.activePanel ? true : false;
35256     },
35257     
35258     setActivePanel : function(panel){
35259         panel = this.getPanel(panel);
35260         if(this.activePanel && this.activePanel != panel){
35261             this.activePanel.setActiveState(false);
35262             this.activePanel.getEl().setLeftTop(-10000,-10000);
35263         }
35264         this.activePanel = panel;
35265         panel.setActiveState(true);
35266         if(this.box){
35267             panel.setSize(this.box.width, this.box.height);
35268         }
35269         this.fireEvent("panelactivated", this, panel);
35270         this.fireEvent("invalidated");
35271     },
35272     
35273     /**
35274      * Show the specified panel.
35275      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35276      * @return {Roo.ContentPanel} The shown panel or null
35277      */
35278     showPanel : function(panel){
35279         panel = this.getPanel(panel);
35280         if(panel){
35281             this.setActivePanel(panel);
35282         }
35283         return panel;
35284     },
35285     
35286     /**
35287      * Get the active panel for this region.
35288      * @return {Roo.ContentPanel} The active panel or null
35289      */
35290     getActivePanel : function(){
35291         return this.activePanel;
35292     },
35293     
35294     /**
35295      * Add the passed ContentPanel(s)
35296      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35297      * @return {Roo.ContentPanel} The panel added (if only one was added)
35298      */
35299     add : function(panel){
35300         if(arguments.length > 1){
35301             for(var i = 0, len = arguments.length; i < len; i++) {
35302                 this.add(arguments[i]);
35303             }
35304             return null;
35305         }
35306         if(this.hasPanel(panel)){
35307             this.showPanel(panel);
35308             return panel;
35309         }
35310         var el = panel.getEl();
35311         if(el.dom.parentNode != this.mgr.el.dom){
35312             this.mgr.el.dom.appendChild(el.dom);
35313         }
35314         if(panel.setRegion){
35315             panel.setRegion(this);
35316         }
35317         this.panels.add(panel);
35318         el.setStyle("position", "absolute");
35319         if(!panel.background){
35320             this.setActivePanel(panel);
35321             if(this.config.initialSize && this.panels.getCount()==1){
35322                 this.resizeTo(this.config.initialSize);
35323             }
35324         }
35325         this.fireEvent("paneladded", this, panel);
35326         return panel;
35327     },
35328     
35329     /**
35330      * Returns true if the panel is in this region.
35331      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35332      * @return {Boolean}
35333      */
35334     hasPanel : function(panel){
35335         if(typeof panel == "object"){ // must be panel obj
35336             panel = panel.getId();
35337         }
35338         return this.getPanel(panel) ? true : false;
35339     },
35340     
35341     /**
35342      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35343      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35344      * @param {Boolean} preservePanel Overrides the config preservePanel option
35345      * @return {Roo.ContentPanel} The panel that was removed
35346      */
35347     remove : function(panel, preservePanel){
35348         panel = this.getPanel(panel);
35349         if(!panel){
35350             return null;
35351         }
35352         var e = {};
35353         this.fireEvent("beforeremove", this, panel, e);
35354         if(e.cancel === true){
35355             return null;
35356         }
35357         var panelId = panel.getId();
35358         this.panels.removeKey(panelId);
35359         return panel;
35360     },
35361     
35362     /**
35363      * Returns the panel specified or null if it's not in this region.
35364      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35365      * @return {Roo.ContentPanel}
35366      */
35367     getPanel : function(id){
35368         if(typeof id == "object"){ // must be panel obj
35369             return id;
35370         }
35371         return this.panels.get(id);
35372     },
35373     
35374     /**
35375      * Returns this regions position (north/south/east/west/center).
35376      * @return {String} 
35377      */
35378     getPosition: function(){
35379         return this.position;    
35380     }
35381 });/*
35382  * Based on:
35383  * Ext JS Library 1.1.1
35384  * Copyright(c) 2006-2007, Ext JS, LLC.
35385  *
35386  * Originally Released Under LGPL - original licence link has changed is not relivant.
35387  *
35388  * Fork - LGPL
35389  * <script type="text/javascript">
35390  */
35391  
35392 /**
35393  * @class Roo.bootstrap.layout.Region
35394  * @extends Roo.bootstrap.layout.Basic
35395  * This class represents a region in a layout manager.
35396  
35397  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35398  * @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})
35399  * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
35400  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
35401  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
35402  * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
35403  * @cfg {String}    title           The title for the region (overrides panel titles)
35404  * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
35405  * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35406  * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
35407  * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35408  * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
35409  * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35410  *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
35411  * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
35412  * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
35413  * @cfg {String}    overflow       (hidden|visible) if you have menus in the region, then you need to set this to visible.
35414
35415  * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
35416  * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
35417  * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
35418  * @cfg {Number}    width           For East/West panels
35419  * @cfg {Number}    height          For North/South panels
35420  * @cfg {Boolean}   split           To show the splitter
35421  * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
35422  * 
35423  * @cfg {string}   cls             Extra CSS classes to add to region
35424  * 
35425  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35426  * @cfg {string}   region  the region that it inhabits..
35427  *
35428
35429  * @xxxcfg {Boolean}   collapsible     DISABLED False to disable collapsing (defaults to true)
35430  * @xxxcfg {Boolean}   collapsed       DISABLED True to set the initial display to collapsed (defaults to false)
35431
35432  * @xxxcfg {String}    collapsedTitle  DISABLED Optional string message to display in the collapsed block of a north or south region
35433  * @xxxxcfg {Boolean}   floatable       DISABLED False to disable floating (defaults to true)
35434  * @xxxxcfg {Boolean}   showPin         True to show a pin button NOT SUPPORTED YET
35435  */
35436 Roo.bootstrap.layout.Region = function(config)
35437 {
35438     this.applyConfig(config);
35439
35440     var mgr = config.mgr;
35441     var pos = config.region;
35442     config.skipConfig = true;
35443     Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35444     
35445     if (mgr.el) {
35446         this.onRender(mgr.el);   
35447     }
35448      
35449     this.visible = true;
35450     this.collapsed = false;
35451     this.unrendered_panels = [];
35452 };
35453
35454 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35455
35456     position: '', // set by wrapper (eg. north/south etc..)
35457     unrendered_panels : null,  // unrendered panels.
35458     createBody : function(){
35459         /** This region's body element 
35460         * @type Roo.Element */
35461         this.bodyEl = this.el.createChild({
35462                 tag: "div",
35463                 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35464         });
35465     },
35466
35467     onRender: function(ctr, pos)
35468     {
35469         var dh = Roo.DomHelper;
35470         /** This region's container element 
35471         * @type Roo.Element */
35472         this.el = dh.append(ctr.dom, {
35473                 tag: "div",
35474                 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35475             }, true);
35476         /** This region's title element 
35477         * @type Roo.Element */
35478     
35479         this.titleEl = dh.append(this.el.dom,
35480             {
35481                     tag: "div",
35482                     unselectable: "on",
35483                     cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35484                     children:[
35485                         {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
35486                         {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35487                     ]}, true);
35488         
35489         this.titleEl.enableDisplayMode();
35490         /** This region's title text element 
35491         * @type HTMLElement */
35492         this.titleTextEl = this.titleEl.dom.firstChild;
35493         this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35494         /*
35495         this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35496         this.closeBtn.enableDisplayMode();
35497         this.closeBtn.on("click", this.closeClicked, this);
35498         this.closeBtn.hide();
35499     */
35500         this.createBody(this.config);
35501         if(this.config.hideWhenEmpty){
35502             this.hide();
35503             this.on("paneladded", this.validateVisibility, this);
35504             this.on("panelremoved", this.validateVisibility, this);
35505         }
35506         if(this.autoScroll){
35507             this.bodyEl.setStyle("overflow", "auto");
35508         }else{
35509             this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35510         }
35511         //if(c.titlebar !== false){
35512             if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35513                 this.titleEl.hide();
35514             }else{
35515                 this.titleEl.show();
35516                 if(this.config.title){
35517                     this.titleTextEl.innerHTML = this.config.title;
35518                 }
35519             }
35520         //}
35521         if(this.config.collapsed){
35522             this.collapse(true);
35523         }
35524         if(this.config.hidden){
35525             this.hide();
35526         }
35527         
35528         if (this.unrendered_panels && this.unrendered_panels.length) {
35529             for (var i =0;i< this.unrendered_panels.length; i++) {
35530                 this.add(this.unrendered_panels[i]);
35531             }
35532             this.unrendered_panels = null;
35533             
35534         }
35535         
35536     },
35537     
35538     applyConfig : function(c)
35539     {
35540         /*
35541          *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35542             var dh = Roo.DomHelper;
35543             if(c.titlebar !== false){
35544                 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35545                 this.collapseBtn.on("click", this.collapse, this);
35546                 this.collapseBtn.enableDisplayMode();
35547                 /*
35548                 if(c.showPin === true || this.showPin){
35549                     this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35550                     this.stickBtn.enableDisplayMode();
35551                     this.stickBtn.on("click", this.expand, this);
35552                     this.stickBtn.hide();
35553                 }
35554                 
35555             }
35556             */
35557             /** This region's collapsed element
35558             * @type Roo.Element */
35559             /*
35560              *
35561             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35562                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35563             ]}, true);
35564             
35565             if(c.floatable !== false){
35566                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35567                this.collapsedEl.on("click", this.collapseClick, this);
35568             }
35569
35570             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35571                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35572                    id: "message", unselectable: "on", style:{"float":"left"}});
35573                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35574              }
35575             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35576             this.expandBtn.on("click", this.expand, this);
35577             
35578         }
35579         
35580         if(this.collapseBtn){
35581             this.collapseBtn.setVisible(c.collapsible == true);
35582         }
35583         
35584         this.cmargins = c.cmargins || this.cmargins ||
35585                          (this.position == "west" || this.position == "east" ?
35586                              {top: 0, left: 2, right:2, bottom: 0} :
35587                              {top: 2, left: 0, right:0, bottom: 2});
35588         */
35589         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35590         
35591         
35592         this.bottomTabs = c.tabPosition != "top";
35593         
35594         this.autoScroll = c.autoScroll || false;
35595         
35596         
35597        
35598         
35599         this.duration = c.duration || .30;
35600         this.slideDuration = c.slideDuration || .45;
35601         this.config = c;
35602        
35603     },
35604     /**
35605      * Returns true if this region is currently visible.
35606      * @return {Boolean}
35607      */
35608     isVisible : function(){
35609         return this.visible;
35610     },
35611
35612     /**
35613      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35614      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
35615      */
35616     //setCollapsedTitle : function(title){
35617     //    title = title || "&#160;";
35618      //   if(this.collapsedTitleTextEl){
35619       //      this.collapsedTitleTextEl.innerHTML = title;
35620        // }
35621     //},
35622
35623     getBox : function(){
35624         var b;
35625       //  if(!this.collapsed){
35626             b = this.el.getBox(false, true);
35627        // }else{
35628           //  b = this.collapsedEl.getBox(false, true);
35629         //}
35630         return b;
35631     },
35632
35633     getMargins : function(){
35634         return this.margins;
35635         //return this.collapsed ? this.cmargins : this.margins;
35636     },
35637 /*
35638     highlight : function(){
35639         this.el.addClass("x-layout-panel-dragover");
35640     },
35641
35642     unhighlight : function(){
35643         this.el.removeClass("x-layout-panel-dragover");
35644     },
35645 */
35646     updateBox : function(box)
35647     {
35648         if (!this.bodyEl) {
35649             return; // not rendered yet..
35650         }
35651         
35652         this.box = box;
35653         if(!this.collapsed){
35654             this.el.dom.style.left = box.x + "px";
35655             this.el.dom.style.top = box.y + "px";
35656             this.updateBody(box.width, box.height);
35657         }else{
35658             this.collapsedEl.dom.style.left = box.x + "px";
35659             this.collapsedEl.dom.style.top = box.y + "px";
35660             this.collapsedEl.setSize(box.width, box.height);
35661         }
35662         if(this.tabs){
35663             this.tabs.autoSizeTabs();
35664         }
35665     },
35666
35667     updateBody : function(w, h)
35668     {
35669         if(w !== null){
35670             this.el.setWidth(w);
35671             w -= this.el.getBorderWidth("rl");
35672             if(this.config.adjustments){
35673                 w += this.config.adjustments[0];
35674             }
35675         }
35676         if(h !== null && h > 0){
35677             this.el.setHeight(h);
35678             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35679             h -= this.el.getBorderWidth("tb");
35680             if(this.config.adjustments){
35681                 h += this.config.adjustments[1];
35682             }
35683             this.bodyEl.setHeight(h);
35684             if(this.tabs){
35685                 h = this.tabs.syncHeight(h);
35686             }
35687         }
35688         if(this.panelSize){
35689             w = w !== null ? w : this.panelSize.width;
35690             h = h !== null ? h : this.panelSize.height;
35691         }
35692         if(this.activePanel){
35693             var el = this.activePanel.getEl();
35694             w = w !== null ? w : el.getWidth();
35695             h = h !== null ? h : el.getHeight();
35696             this.panelSize = {width: w, height: h};
35697             this.activePanel.setSize(w, h);
35698         }
35699         if(Roo.isIE && this.tabs){
35700             this.tabs.el.repaint();
35701         }
35702     },
35703
35704     /**
35705      * Returns the container element for this region.
35706      * @return {Roo.Element}
35707      */
35708     getEl : function(){
35709         return this.el;
35710     },
35711
35712     /**
35713      * Hides this region.
35714      */
35715     hide : function(){
35716         //if(!this.collapsed){
35717             this.el.dom.style.left = "-2000px";
35718             this.el.hide();
35719         //}else{
35720          //   this.collapsedEl.dom.style.left = "-2000px";
35721          //   this.collapsedEl.hide();
35722        // }
35723         this.visible = false;
35724         this.fireEvent("visibilitychange", this, false);
35725     },
35726
35727     /**
35728      * Shows this region if it was previously hidden.
35729      */
35730     show : function(){
35731         //if(!this.collapsed){
35732             this.el.show();
35733         //}else{
35734         //    this.collapsedEl.show();
35735        // }
35736         this.visible = true;
35737         this.fireEvent("visibilitychange", this, true);
35738     },
35739 /*
35740     closeClicked : function(){
35741         if(this.activePanel){
35742             this.remove(this.activePanel);
35743         }
35744     },
35745
35746     collapseClick : function(e){
35747         if(this.isSlid){
35748            e.stopPropagation();
35749            this.slideIn();
35750         }else{
35751            e.stopPropagation();
35752            this.slideOut();
35753         }
35754     },
35755 */
35756     /**
35757      * Collapses this region.
35758      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35759      */
35760     /*
35761     collapse : function(skipAnim, skipCheck = false){
35762         if(this.collapsed) {
35763             return;
35764         }
35765         
35766         if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35767             
35768             this.collapsed = true;
35769             if(this.split){
35770                 this.split.el.hide();
35771             }
35772             if(this.config.animate && skipAnim !== true){
35773                 this.fireEvent("invalidated", this);
35774                 this.animateCollapse();
35775             }else{
35776                 this.el.setLocation(-20000,-20000);
35777                 this.el.hide();
35778                 this.collapsedEl.show();
35779                 this.fireEvent("collapsed", this);
35780                 this.fireEvent("invalidated", this);
35781             }
35782         }
35783         
35784     },
35785 */
35786     animateCollapse : function(){
35787         // overridden
35788     },
35789
35790     /**
35791      * Expands this region if it was previously collapsed.
35792      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35793      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35794      */
35795     /*
35796     expand : function(e, skipAnim){
35797         if(e) {
35798             e.stopPropagation();
35799         }
35800         if(!this.collapsed || this.el.hasActiveFx()) {
35801             return;
35802         }
35803         if(this.isSlid){
35804             this.afterSlideIn();
35805             skipAnim = true;
35806         }
35807         this.collapsed = false;
35808         if(this.config.animate && skipAnim !== true){
35809             this.animateExpand();
35810         }else{
35811             this.el.show();
35812             if(this.split){
35813                 this.split.el.show();
35814             }
35815             this.collapsedEl.setLocation(-2000,-2000);
35816             this.collapsedEl.hide();
35817             this.fireEvent("invalidated", this);
35818             this.fireEvent("expanded", this);
35819         }
35820     },
35821 */
35822     animateExpand : function(){
35823         // overridden
35824     },
35825
35826     initTabs : function()
35827     {
35828         //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35829         
35830         var ts = new Roo.bootstrap.panel.Tabs({
35831                 el: this.bodyEl.dom,
35832                 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35833                 disableTooltips: this.config.disableTabTips,
35834                 toolbar : this.config.toolbar
35835             });
35836         
35837         if(this.config.hideTabs){
35838             ts.stripWrap.setDisplayed(false);
35839         }
35840         this.tabs = ts;
35841         ts.resizeTabs = this.config.resizeTabs === true;
35842         ts.minTabWidth = this.config.minTabWidth || 40;
35843         ts.maxTabWidth = this.config.maxTabWidth || 250;
35844         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35845         ts.monitorResize = false;
35846         //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35847         ts.bodyEl.addClass('roo-layout-tabs-body');
35848         this.panels.each(this.initPanelAsTab, this);
35849     },
35850
35851     initPanelAsTab : function(panel){
35852         var ti = this.tabs.addTab(
35853             panel.getEl().id,
35854             panel.getTitle(),
35855             null,
35856             this.config.closeOnTab && panel.isClosable(),
35857             panel.tpl
35858         );
35859         if(panel.tabTip !== undefined){
35860             ti.setTooltip(panel.tabTip);
35861         }
35862         ti.on("activate", function(){
35863               this.setActivePanel(panel);
35864         }, this);
35865         
35866         if(this.config.closeOnTab){
35867             ti.on("beforeclose", function(t, e){
35868                 e.cancel = true;
35869                 this.remove(panel);
35870             }, this);
35871         }
35872         
35873         panel.tabItem = ti;
35874         
35875         return ti;
35876     },
35877
35878     updatePanelTitle : function(panel, title)
35879     {
35880         if(this.activePanel == panel){
35881             this.updateTitle(title);
35882         }
35883         if(this.tabs){
35884             var ti = this.tabs.getTab(panel.getEl().id);
35885             ti.setText(title);
35886             if(panel.tabTip !== undefined){
35887                 ti.setTooltip(panel.tabTip);
35888             }
35889         }
35890     },
35891
35892     updateTitle : function(title){
35893         if(this.titleTextEl && !this.config.title){
35894             this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
35895         }
35896     },
35897
35898     setActivePanel : function(panel)
35899     {
35900         panel = this.getPanel(panel);
35901         if(this.activePanel && this.activePanel != panel){
35902             if(this.activePanel.setActiveState(false) === false){
35903                 return;
35904             }
35905         }
35906         this.activePanel = panel;
35907         panel.setActiveState(true);
35908         if(this.panelSize){
35909             panel.setSize(this.panelSize.width, this.panelSize.height);
35910         }
35911         if(this.closeBtn){
35912             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35913         }
35914         this.updateTitle(panel.getTitle());
35915         if(this.tabs){
35916             this.fireEvent("invalidated", this);
35917         }
35918         this.fireEvent("panelactivated", this, panel);
35919     },
35920
35921     /**
35922      * Shows the specified panel.
35923      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35924      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35925      */
35926     showPanel : function(panel)
35927     {
35928         panel = this.getPanel(panel);
35929         if(panel){
35930             if(this.tabs){
35931                 var tab = this.tabs.getTab(panel.getEl().id);
35932                 if(tab.isHidden()){
35933                     this.tabs.unhideTab(tab.id);
35934                 }
35935                 tab.activate();
35936             }else{
35937                 this.setActivePanel(panel);
35938             }
35939         }
35940         return panel;
35941     },
35942
35943     /**
35944      * Get the active panel for this region.
35945      * @return {Roo.ContentPanel} The active panel or null
35946      */
35947     getActivePanel : function(){
35948         return this.activePanel;
35949     },
35950
35951     validateVisibility : function(){
35952         if(this.panels.getCount() < 1){
35953             this.updateTitle("&#160;");
35954             this.closeBtn.hide();
35955             this.hide();
35956         }else{
35957             if(!this.isVisible()){
35958                 this.show();
35959             }
35960         }
35961     },
35962
35963     /**
35964      * Adds the passed ContentPanel(s) to this region.
35965      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35966      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35967      */
35968     add : function(panel)
35969     {
35970         if(arguments.length > 1){
35971             for(var i = 0, len = arguments.length; i < len; i++) {
35972                 this.add(arguments[i]);
35973             }
35974             return null;
35975         }
35976         
35977         // if we have not been rendered yet, then we can not really do much of this..
35978         if (!this.bodyEl) {
35979             this.unrendered_panels.push(panel);
35980             return panel;
35981         }
35982         
35983         
35984         
35985         
35986         if(this.hasPanel(panel)){
35987             this.showPanel(panel);
35988             return panel;
35989         }
35990         panel.setRegion(this);
35991         this.panels.add(panel);
35992        /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35993             // sinle panel - no tab...?? would it not be better to render it with the tabs,
35994             // and hide them... ???
35995             this.bodyEl.dom.appendChild(panel.getEl().dom);
35996             if(panel.background !== true){
35997                 this.setActivePanel(panel);
35998             }
35999             this.fireEvent("paneladded", this, panel);
36000             return panel;
36001         }
36002         */
36003         if(!this.tabs){
36004             this.initTabs();
36005         }else{
36006             this.initPanelAsTab(panel);
36007         }
36008         
36009         
36010         if(panel.background !== true){
36011             this.tabs.activate(panel.getEl().id);
36012         }
36013         this.fireEvent("paneladded", this, panel);
36014         return panel;
36015     },
36016
36017     /**
36018      * Hides the tab for the specified panel.
36019      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36020      */
36021     hidePanel : function(panel){
36022         if(this.tabs && (panel = this.getPanel(panel))){
36023             this.tabs.hideTab(panel.getEl().id);
36024         }
36025     },
36026
36027     /**
36028      * Unhides the tab for a previously hidden panel.
36029      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36030      */
36031     unhidePanel : function(panel){
36032         if(this.tabs && (panel = this.getPanel(panel))){
36033             this.tabs.unhideTab(panel.getEl().id);
36034         }
36035     },
36036
36037     clearPanels : function(){
36038         while(this.panels.getCount() > 0){
36039              this.remove(this.panels.first());
36040         }
36041     },
36042
36043     /**
36044      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36045      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36046      * @param {Boolean} preservePanel Overrides the config preservePanel option
36047      * @return {Roo.ContentPanel} The panel that was removed
36048      */
36049     remove : function(panel, preservePanel)
36050     {
36051         panel = this.getPanel(panel);
36052         if(!panel){
36053             return null;
36054         }
36055         var e = {};
36056         this.fireEvent("beforeremove", this, panel, e);
36057         if(e.cancel === true){
36058             return null;
36059         }
36060         preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36061         var panelId = panel.getId();
36062         this.panels.removeKey(panelId);
36063         if(preservePanel){
36064             document.body.appendChild(panel.getEl().dom);
36065         }
36066         if(this.tabs){
36067             this.tabs.removeTab(panel.getEl().id);
36068         }else if (!preservePanel){
36069             this.bodyEl.dom.removeChild(panel.getEl().dom);
36070         }
36071         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36072             var p = this.panels.first();
36073             var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36074             tempEl.appendChild(p.getEl().dom);
36075             this.bodyEl.update("");
36076             this.bodyEl.dom.appendChild(p.getEl().dom);
36077             tempEl = null;
36078             this.updateTitle(p.getTitle());
36079             this.tabs = null;
36080             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36081             this.setActivePanel(p);
36082         }
36083         panel.setRegion(null);
36084         if(this.activePanel == panel){
36085             this.activePanel = null;
36086         }
36087         if(this.config.autoDestroy !== false && preservePanel !== true){
36088             try{panel.destroy();}catch(e){}
36089         }
36090         this.fireEvent("panelremoved", this, panel);
36091         return panel;
36092     },
36093
36094     /**
36095      * Returns the TabPanel component used by this region
36096      * @return {Roo.TabPanel}
36097      */
36098     getTabs : function(){
36099         return this.tabs;
36100     },
36101
36102     createTool : function(parentEl, className){
36103         var btn = Roo.DomHelper.append(parentEl, {
36104             tag: "div",
36105             cls: "x-layout-tools-button",
36106             children: [ {
36107                 tag: "div",
36108                 cls: "roo-layout-tools-button-inner " + className,
36109                 html: "&#160;"
36110             }]
36111         }, true);
36112         btn.addClassOnOver("roo-layout-tools-button-over");
36113         return btn;
36114     }
36115 });/*
36116  * Based on:
36117  * Ext JS Library 1.1.1
36118  * Copyright(c) 2006-2007, Ext JS, LLC.
36119  *
36120  * Originally Released Under LGPL - original licence link has changed is not relivant.
36121  *
36122  * Fork - LGPL
36123  * <script type="text/javascript">
36124  */
36125  
36126
36127
36128 /**
36129  * @class Roo.SplitLayoutRegion
36130  * @extends Roo.LayoutRegion
36131  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36132  */
36133 Roo.bootstrap.layout.Split = function(config){
36134     this.cursor = config.cursor;
36135     Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36136 };
36137
36138 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36139 {
36140     splitTip : "Drag to resize.",
36141     collapsibleSplitTip : "Drag to resize. Double click to hide.",
36142     useSplitTips : false,
36143
36144     applyConfig : function(config){
36145         Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36146     },
36147     
36148     onRender : function(ctr,pos) {
36149         
36150         Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36151         if(!this.config.split){
36152             return;
36153         }
36154         if(!this.split){
36155             
36156             var splitEl = Roo.DomHelper.append(ctr.dom,  {
36157                             tag: "div",
36158                             id: this.el.id + "-split",
36159                             cls: "roo-layout-split roo-layout-split-"+this.position,
36160                             html: "&#160;"
36161             });
36162             /** The SplitBar for this region 
36163             * @type Roo.SplitBar */
36164             // does not exist yet...
36165             Roo.log([this.position, this.orientation]);
36166             
36167             this.split = new Roo.bootstrap.SplitBar({
36168                 dragElement : splitEl,
36169                 resizingElement: this.el,
36170                 orientation : this.orientation
36171             });
36172             
36173             this.split.on("moved", this.onSplitMove, this);
36174             this.split.useShim = this.config.useShim === true;
36175             this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36176             if(this.useSplitTips){
36177                 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36178             }
36179             //if(config.collapsible){
36180             //    this.split.el.on("dblclick", this.collapse,  this);
36181             //}
36182         }
36183         if(typeof this.config.minSize != "undefined"){
36184             this.split.minSize = this.config.minSize;
36185         }
36186         if(typeof this.config.maxSize != "undefined"){
36187             this.split.maxSize = this.config.maxSize;
36188         }
36189         if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36190             this.hideSplitter();
36191         }
36192         
36193     },
36194
36195     getHMaxSize : function(){
36196          var cmax = this.config.maxSize || 10000;
36197          var center = this.mgr.getRegion("center");
36198          return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36199     },
36200
36201     getVMaxSize : function(){
36202          var cmax = this.config.maxSize || 10000;
36203          var center = this.mgr.getRegion("center");
36204          return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36205     },
36206
36207     onSplitMove : function(split, newSize){
36208         this.fireEvent("resized", this, newSize);
36209     },
36210     
36211     /** 
36212      * Returns the {@link Roo.SplitBar} for this region.
36213      * @return {Roo.SplitBar}
36214      */
36215     getSplitBar : function(){
36216         return this.split;
36217     },
36218     
36219     hide : function(){
36220         this.hideSplitter();
36221         Roo.bootstrap.layout.Split.superclass.hide.call(this);
36222     },
36223
36224     hideSplitter : function(){
36225         if(this.split){
36226             this.split.el.setLocation(-2000,-2000);
36227             this.split.el.hide();
36228         }
36229     },
36230
36231     show : function(){
36232         if(this.split){
36233             this.split.el.show();
36234         }
36235         Roo.bootstrap.layout.Split.superclass.show.call(this);
36236     },
36237     
36238     beforeSlide: function(){
36239         if(Roo.isGecko){// firefox overflow auto bug workaround
36240             this.bodyEl.clip();
36241             if(this.tabs) {
36242                 this.tabs.bodyEl.clip();
36243             }
36244             if(this.activePanel){
36245                 this.activePanel.getEl().clip();
36246                 
36247                 if(this.activePanel.beforeSlide){
36248                     this.activePanel.beforeSlide();
36249                 }
36250             }
36251         }
36252     },
36253     
36254     afterSlide : function(){
36255         if(Roo.isGecko){// firefox overflow auto bug workaround
36256             this.bodyEl.unclip();
36257             if(this.tabs) {
36258                 this.tabs.bodyEl.unclip();
36259             }
36260             if(this.activePanel){
36261                 this.activePanel.getEl().unclip();
36262                 if(this.activePanel.afterSlide){
36263                     this.activePanel.afterSlide();
36264                 }
36265             }
36266         }
36267     },
36268
36269     initAutoHide : function(){
36270         if(this.autoHide !== false){
36271             if(!this.autoHideHd){
36272                 var st = new Roo.util.DelayedTask(this.slideIn, this);
36273                 this.autoHideHd = {
36274                     "mouseout": function(e){
36275                         if(!e.within(this.el, true)){
36276                             st.delay(500);
36277                         }
36278                     },
36279                     "mouseover" : function(e){
36280                         st.cancel();
36281                     },
36282                     scope : this
36283                 };
36284             }
36285             this.el.on(this.autoHideHd);
36286         }
36287     },
36288
36289     clearAutoHide : function(){
36290         if(this.autoHide !== false){
36291             this.el.un("mouseout", this.autoHideHd.mouseout);
36292             this.el.un("mouseover", this.autoHideHd.mouseover);
36293         }
36294     },
36295
36296     clearMonitor : function(){
36297         Roo.get(document).un("click", this.slideInIf, this);
36298     },
36299
36300     // these names are backwards but not changed for compat
36301     slideOut : function(){
36302         if(this.isSlid || this.el.hasActiveFx()){
36303             return;
36304         }
36305         this.isSlid = true;
36306         if(this.collapseBtn){
36307             this.collapseBtn.hide();
36308         }
36309         this.closeBtnState = this.closeBtn.getStyle('display');
36310         this.closeBtn.hide();
36311         if(this.stickBtn){
36312             this.stickBtn.show();
36313         }
36314         this.el.show();
36315         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36316         this.beforeSlide();
36317         this.el.setStyle("z-index", 10001);
36318         this.el.slideIn(this.getSlideAnchor(), {
36319             callback: function(){
36320                 this.afterSlide();
36321                 this.initAutoHide();
36322                 Roo.get(document).on("click", this.slideInIf, this);
36323                 this.fireEvent("slideshow", this);
36324             },
36325             scope: this,
36326             block: true
36327         });
36328     },
36329
36330     afterSlideIn : function(){
36331         this.clearAutoHide();
36332         this.isSlid = false;
36333         this.clearMonitor();
36334         this.el.setStyle("z-index", "");
36335         if(this.collapseBtn){
36336             this.collapseBtn.show();
36337         }
36338         this.closeBtn.setStyle('display', this.closeBtnState);
36339         if(this.stickBtn){
36340             this.stickBtn.hide();
36341         }
36342         this.fireEvent("slidehide", this);
36343     },
36344
36345     slideIn : function(cb){
36346         if(!this.isSlid || this.el.hasActiveFx()){
36347             Roo.callback(cb);
36348             return;
36349         }
36350         this.isSlid = false;
36351         this.beforeSlide();
36352         this.el.slideOut(this.getSlideAnchor(), {
36353             callback: function(){
36354                 this.el.setLeftTop(-10000, -10000);
36355                 this.afterSlide();
36356                 this.afterSlideIn();
36357                 Roo.callback(cb);
36358             },
36359             scope: this,
36360             block: true
36361         });
36362     },
36363     
36364     slideInIf : function(e){
36365         if(!e.within(this.el)){
36366             this.slideIn();
36367         }
36368     },
36369
36370     animateCollapse : function(){
36371         this.beforeSlide();
36372         this.el.setStyle("z-index", 20000);
36373         var anchor = this.getSlideAnchor();
36374         this.el.slideOut(anchor, {
36375             callback : function(){
36376                 this.el.setStyle("z-index", "");
36377                 this.collapsedEl.slideIn(anchor, {duration:.3});
36378                 this.afterSlide();
36379                 this.el.setLocation(-10000,-10000);
36380                 this.el.hide();
36381                 this.fireEvent("collapsed", this);
36382             },
36383             scope: this,
36384             block: true
36385         });
36386     },
36387
36388     animateExpand : function(){
36389         this.beforeSlide();
36390         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36391         this.el.setStyle("z-index", 20000);
36392         this.collapsedEl.hide({
36393             duration:.1
36394         });
36395         this.el.slideIn(this.getSlideAnchor(), {
36396             callback : function(){
36397                 this.el.setStyle("z-index", "");
36398                 this.afterSlide();
36399                 if(this.split){
36400                     this.split.el.show();
36401                 }
36402                 this.fireEvent("invalidated", this);
36403                 this.fireEvent("expanded", this);
36404             },
36405             scope: this,
36406             block: true
36407         });
36408     },
36409
36410     anchors : {
36411         "west" : "left",
36412         "east" : "right",
36413         "north" : "top",
36414         "south" : "bottom"
36415     },
36416
36417     sanchors : {
36418         "west" : "l",
36419         "east" : "r",
36420         "north" : "t",
36421         "south" : "b"
36422     },
36423
36424     canchors : {
36425         "west" : "tl-tr",
36426         "east" : "tr-tl",
36427         "north" : "tl-bl",
36428         "south" : "bl-tl"
36429     },
36430
36431     getAnchor : function(){
36432         return this.anchors[this.position];
36433     },
36434
36435     getCollapseAnchor : function(){
36436         return this.canchors[this.position];
36437     },
36438
36439     getSlideAnchor : function(){
36440         return this.sanchors[this.position];
36441     },
36442
36443     getAlignAdj : function(){
36444         var cm = this.cmargins;
36445         switch(this.position){
36446             case "west":
36447                 return [0, 0];
36448             break;
36449             case "east":
36450                 return [0, 0];
36451             break;
36452             case "north":
36453                 return [0, 0];
36454             break;
36455             case "south":
36456                 return [0, 0];
36457             break;
36458         }
36459     },
36460
36461     getExpandAdj : function(){
36462         var c = this.collapsedEl, cm = this.cmargins;
36463         switch(this.position){
36464             case "west":
36465                 return [-(cm.right+c.getWidth()+cm.left), 0];
36466             break;
36467             case "east":
36468                 return [cm.right+c.getWidth()+cm.left, 0];
36469             break;
36470             case "north":
36471                 return [0, -(cm.top+cm.bottom+c.getHeight())];
36472             break;
36473             case "south":
36474                 return [0, cm.top+cm.bottom+c.getHeight()];
36475             break;
36476         }
36477     }
36478 });/*
36479  * Based on:
36480  * Ext JS Library 1.1.1
36481  * Copyright(c) 2006-2007, Ext JS, LLC.
36482  *
36483  * Originally Released Under LGPL - original licence link has changed is not relivant.
36484  *
36485  * Fork - LGPL
36486  * <script type="text/javascript">
36487  */
36488 /*
36489  * These classes are private internal classes
36490  */
36491 Roo.bootstrap.layout.Center = function(config){
36492     config.region = "center";
36493     Roo.bootstrap.layout.Region.call(this, config);
36494     this.visible = true;
36495     this.minWidth = config.minWidth || 20;
36496     this.minHeight = config.minHeight || 20;
36497 };
36498
36499 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36500     hide : function(){
36501         // center panel can't be hidden
36502     },
36503     
36504     show : function(){
36505         // center panel can't be hidden
36506     },
36507     
36508     getMinWidth: function(){
36509         return this.minWidth;
36510     },
36511     
36512     getMinHeight: function(){
36513         return this.minHeight;
36514     }
36515 });
36516
36517
36518
36519
36520  
36521
36522
36523
36524
36525
36526 Roo.bootstrap.layout.North = function(config)
36527 {
36528     config.region = 'north';
36529     config.cursor = 'n-resize';
36530     
36531     Roo.bootstrap.layout.Split.call(this, config);
36532     
36533     
36534     if(this.split){
36535         this.split.placement = Roo.bootstrap.SplitBar.TOP;
36536         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36537         this.split.el.addClass("roo-layout-split-v");
36538     }
36539     var size = config.initialSize || config.height;
36540     if(typeof size != "undefined"){
36541         this.el.setHeight(size);
36542     }
36543 };
36544 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36545 {
36546     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36547     
36548     
36549     
36550     getBox : function(){
36551         if(this.collapsed){
36552             return this.collapsedEl.getBox();
36553         }
36554         var box = this.el.getBox();
36555         if(this.split){
36556             box.height += this.split.el.getHeight();
36557         }
36558         return box;
36559     },
36560     
36561     updateBox : function(box){
36562         if(this.split && !this.collapsed){
36563             box.height -= this.split.el.getHeight();
36564             this.split.el.setLeft(box.x);
36565             this.split.el.setTop(box.y+box.height);
36566             this.split.el.setWidth(box.width);
36567         }
36568         if(this.collapsed){
36569             this.updateBody(box.width, null);
36570         }
36571         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36572     }
36573 });
36574
36575
36576
36577
36578
36579 Roo.bootstrap.layout.South = function(config){
36580     config.region = 'south';
36581     config.cursor = 's-resize';
36582     Roo.bootstrap.layout.Split.call(this, config);
36583     if(this.split){
36584         this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36585         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36586         this.split.el.addClass("roo-layout-split-v");
36587     }
36588     var size = config.initialSize || config.height;
36589     if(typeof size != "undefined"){
36590         this.el.setHeight(size);
36591     }
36592 };
36593
36594 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36595     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36596     getBox : function(){
36597         if(this.collapsed){
36598             return this.collapsedEl.getBox();
36599         }
36600         var box = this.el.getBox();
36601         if(this.split){
36602             var sh = this.split.el.getHeight();
36603             box.height += sh;
36604             box.y -= sh;
36605         }
36606         return box;
36607     },
36608     
36609     updateBox : function(box){
36610         if(this.split && !this.collapsed){
36611             var sh = this.split.el.getHeight();
36612             box.height -= sh;
36613             box.y += sh;
36614             this.split.el.setLeft(box.x);
36615             this.split.el.setTop(box.y-sh);
36616             this.split.el.setWidth(box.width);
36617         }
36618         if(this.collapsed){
36619             this.updateBody(box.width, null);
36620         }
36621         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36622     }
36623 });
36624
36625 Roo.bootstrap.layout.East = function(config){
36626     config.region = "east";
36627     config.cursor = "e-resize";
36628     Roo.bootstrap.layout.Split.call(this, config);
36629     if(this.split){
36630         this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36631         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36632         this.split.el.addClass("roo-layout-split-h");
36633     }
36634     var size = config.initialSize || config.width;
36635     if(typeof size != "undefined"){
36636         this.el.setWidth(size);
36637     }
36638 };
36639 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36640     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36641     getBox : function(){
36642         if(this.collapsed){
36643             return this.collapsedEl.getBox();
36644         }
36645         var box = this.el.getBox();
36646         if(this.split){
36647             var sw = this.split.el.getWidth();
36648             box.width += sw;
36649             box.x -= sw;
36650         }
36651         return box;
36652     },
36653
36654     updateBox : function(box){
36655         if(this.split && !this.collapsed){
36656             var sw = this.split.el.getWidth();
36657             box.width -= sw;
36658             this.split.el.setLeft(box.x);
36659             this.split.el.setTop(box.y);
36660             this.split.el.setHeight(box.height);
36661             box.x += sw;
36662         }
36663         if(this.collapsed){
36664             this.updateBody(null, box.height);
36665         }
36666         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36667     }
36668 });
36669
36670 Roo.bootstrap.layout.West = function(config){
36671     config.region = "west";
36672     config.cursor = "w-resize";
36673     
36674     Roo.bootstrap.layout.Split.call(this, config);
36675     if(this.split){
36676         this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36677         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36678         this.split.el.addClass("roo-layout-split-h");
36679     }
36680     
36681 };
36682 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36683     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36684     
36685     onRender: function(ctr, pos)
36686     {
36687         Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36688         var size = this.config.initialSize || this.config.width;
36689         if(typeof size != "undefined"){
36690             this.el.setWidth(size);
36691         }
36692     },
36693     
36694     getBox : function(){
36695         if(this.collapsed){
36696             return this.collapsedEl.getBox();
36697         }
36698         var box = this.el.getBox();
36699         if(this.split){
36700             box.width += this.split.el.getWidth();
36701         }
36702         return box;
36703     },
36704     
36705     updateBox : function(box){
36706         if(this.split && !this.collapsed){
36707             var sw = this.split.el.getWidth();
36708             box.width -= sw;
36709             this.split.el.setLeft(box.x+box.width);
36710             this.split.el.setTop(box.y);
36711             this.split.el.setHeight(box.height);
36712         }
36713         if(this.collapsed){
36714             this.updateBody(null, box.height);
36715         }
36716         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36717     }
36718 });
36719 Roo.namespace("Roo.bootstrap.panel");/*
36720  * Based on:
36721  * Ext JS Library 1.1.1
36722  * Copyright(c) 2006-2007, Ext JS, LLC.
36723  *
36724  * Originally Released Under LGPL - original licence link has changed is not relivant.
36725  *
36726  * Fork - LGPL
36727  * <script type="text/javascript">
36728  */
36729 /**
36730  * @class Roo.ContentPanel
36731  * @extends Roo.util.Observable
36732  * A basic ContentPanel element.
36733  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
36734  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
36735  * @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
36736  * @cfg {Boolean}   closable      True if the panel can be closed/removed
36737  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
36738  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36739  * @cfg {Toolbar}   toolbar       A toolbar for this panel
36740  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
36741  * @cfg {String} title          The title for this panel
36742  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36743  * @cfg {String} url            Calls {@link #setUrl} with this value
36744  * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36745  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
36746  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
36747  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
36748  * @cfg {Boolean} badges render the badges
36749
36750  * @constructor
36751  * Create a new ContentPanel.
36752  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36753  * @param {String/Object} config A string to set only the title or a config object
36754  * @param {String} content (optional) Set the HTML content for this panel
36755  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36756  */
36757 Roo.bootstrap.panel.Content = function( config){
36758     
36759     this.tpl = config.tpl || false;
36760     
36761     var el = config.el;
36762     var content = config.content;
36763
36764     if(config.autoCreate){ // xtype is available if this is called from factory
36765         el = Roo.id();
36766     }
36767     this.el = Roo.get(el);
36768     if(!this.el && config && config.autoCreate){
36769         if(typeof config.autoCreate == "object"){
36770             if(!config.autoCreate.id){
36771                 config.autoCreate.id = config.id||el;
36772             }
36773             this.el = Roo.DomHelper.append(document.body,
36774                         config.autoCreate, true);
36775         }else{
36776             var elcfg =  {   tag: "div",
36777                             cls: "roo-layout-inactive-content",
36778                             id: config.id||el
36779                             };
36780             if (config.html) {
36781                 elcfg.html = config.html;
36782                 
36783             }
36784                         
36785             this.el = Roo.DomHelper.append(document.body, elcfg , true);
36786         }
36787     } 
36788     this.closable = false;
36789     this.loaded = false;
36790     this.active = false;
36791    
36792       
36793     if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36794         
36795         this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36796         
36797         this.wrapEl = this.el; //this.el.wrap();
36798         var ti = [];
36799         if (config.toolbar.items) {
36800             ti = config.toolbar.items ;
36801             delete config.toolbar.items ;
36802         }
36803         
36804         var nitems = [];
36805         this.toolbar.render(this.wrapEl, 'before');
36806         for(var i =0;i < ti.length;i++) {
36807           //  Roo.log(['add child', items[i]]);
36808             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36809         }
36810         this.toolbar.items = nitems;
36811         this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36812         delete config.toolbar;
36813         
36814     }
36815     /*
36816     // xtype created footer. - not sure if will work as we normally have to render first..
36817     if (this.footer && !this.footer.el && this.footer.xtype) {
36818         if (!this.wrapEl) {
36819             this.wrapEl = this.el.wrap();
36820         }
36821     
36822         this.footer.container = this.wrapEl.createChild();
36823          
36824         this.footer = Roo.factory(this.footer, Roo);
36825         
36826     }
36827     */
36828     
36829      if(typeof config == "string"){
36830         this.title = config;
36831     }else{
36832         Roo.apply(this, config);
36833     }
36834     
36835     if(this.resizeEl){
36836         this.resizeEl = Roo.get(this.resizeEl, true);
36837     }else{
36838         this.resizeEl = this.el;
36839     }
36840     // handle view.xtype
36841     
36842  
36843     
36844     
36845     this.addEvents({
36846         /**
36847          * @event activate
36848          * Fires when this panel is activated. 
36849          * @param {Roo.ContentPanel} this
36850          */
36851         "activate" : true,
36852         /**
36853          * @event deactivate
36854          * Fires when this panel is activated. 
36855          * @param {Roo.ContentPanel} this
36856          */
36857         "deactivate" : true,
36858
36859         /**
36860          * @event resize
36861          * Fires when this panel is resized if fitToFrame is true.
36862          * @param {Roo.ContentPanel} this
36863          * @param {Number} width The width after any component adjustments
36864          * @param {Number} height The height after any component adjustments
36865          */
36866         "resize" : true,
36867         
36868          /**
36869          * @event render
36870          * Fires when this tab is created
36871          * @param {Roo.ContentPanel} this
36872          */
36873         "render" : true
36874         
36875         
36876         
36877     });
36878     
36879
36880     
36881     
36882     if(this.autoScroll){
36883         this.resizeEl.setStyle("overflow", "auto");
36884     } else {
36885         // fix randome scrolling
36886         //this.el.on('scroll', function() {
36887         //    Roo.log('fix random scolling');
36888         //    this.scrollTo('top',0); 
36889         //});
36890     }
36891     content = content || this.content;
36892     if(content){
36893         this.setContent(content);
36894     }
36895     if(config && config.url){
36896         this.setUrl(this.url, this.params, this.loadOnce);
36897     }
36898     
36899     
36900     
36901     Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36902     
36903     if (this.view && typeof(this.view.xtype) != 'undefined') {
36904         this.view.el = this.el.appendChild(document.createElement("div"));
36905         this.view = Roo.factory(this.view); 
36906         this.view.render  &&  this.view.render(false, '');  
36907     }
36908     
36909     
36910     this.fireEvent('render', this);
36911 };
36912
36913 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36914     
36915     tabTip : '',
36916     
36917     setRegion : function(region){
36918         this.region = region;
36919         this.setActiveClass(region && !this.background);
36920     },
36921     
36922     
36923     setActiveClass: function(state)
36924     {
36925         if(state){
36926            this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36927            this.el.setStyle('position','relative');
36928         }else{
36929            this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36930            this.el.setStyle('position', 'absolute');
36931         } 
36932     },
36933     
36934     /**
36935      * Returns the toolbar for this Panel if one was configured. 
36936      * @return {Roo.Toolbar} 
36937      */
36938     getToolbar : function(){
36939         return this.toolbar;
36940     },
36941     
36942     setActiveState : function(active)
36943     {
36944         this.active = active;
36945         this.setActiveClass(active);
36946         if(!active){
36947             if(this.fireEvent("deactivate", this) === false){
36948                 return false;
36949             }
36950             return true;
36951         }
36952         this.fireEvent("activate", this);
36953         return true;
36954     },
36955     /**
36956      * Updates this panel's element
36957      * @param {String} content The new content
36958      * @param {Boolean} loadScripts (optional) true to look for and process scripts
36959     */
36960     setContent : function(content, loadScripts){
36961         this.el.update(content, loadScripts);
36962     },
36963
36964     ignoreResize : function(w, h){
36965         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36966             return true;
36967         }else{
36968             this.lastSize = {width: w, height: h};
36969             return false;
36970         }
36971     },
36972     /**
36973      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36974      * @return {Roo.UpdateManager} The UpdateManager
36975      */
36976     getUpdateManager : function(){
36977         return this.el.getUpdateManager();
36978     },
36979      /**
36980      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36981      * @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:
36982 <pre><code>
36983 panel.load({
36984     url: "your-url.php",
36985     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36986     callback: yourFunction,
36987     scope: yourObject, //(optional scope)
36988     discardUrl: false,
36989     nocache: false,
36990     text: "Loading...",
36991     timeout: 30,
36992     scripts: false
36993 });
36994 </code></pre>
36995      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36996      * 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.
36997      * @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}
36998      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36999      * @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.
37000      * @return {Roo.ContentPanel} this
37001      */
37002     load : function(){
37003         var um = this.el.getUpdateManager();
37004         um.update.apply(um, arguments);
37005         return this;
37006     },
37007
37008
37009     /**
37010      * 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.
37011      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37012      * @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)
37013      * @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)
37014      * @return {Roo.UpdateManager} The UpdateManager
37015      */
37016     setUrl : function(url, params, loadOnce){
37017         if(this.refreshDelegate){
37018             this.removeListener("activate", this.refreshDelegate);
37019         }
37020         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37021         this.on("activate", this.refreshDelegate);
37022         return this.el.getUpdateManager();
37023     },
37024     
37025     _handleRefresh : function(url, params, loadOnce){
37026         if(!loadOnce || !this.loaded){
37027             var updater = this.el.getUpdateManager();
37028             updater.update(url, params, this._setLoaded.createDelegate(this));
37029         }
37030     },
37031     
37032     _setLoaded : function(){
37033         this.loaded = true;
37034     }, 
37035     
37036     /**
37037      * Returns this panel's id
37038      * @return {String} 
37039      */
37040     getId : function(){
37041         return this.el.id;
37042     },
37043     
37044     /** 
37045      * Returns this panel's element - used by regiosn to add.
37046      * @return {Roo.Element} 
37047      */
37048     getEl : function(){
37049         return this.wrapEl || this.el;
37050     },
37051     
37052    
37053     
37054     adjustForComponents : function(width, height)
37055     {
37056         //Roo.log('adjustForComponents ');
37057         if(this.resizeEl != this.el){
37058             width -= this.el.getFrameWidth('lr');
37059             height -= this.el.getFrameWidth('tb');
37060         }
37061         if(this.toolbar){
37062             var te = this.toolbar.getEl();
37063             te.setWidth(width);
37064             height -= te.getHeight();
37065         }
37066         if(this.footer){
37067             var te = this.footer.getEl();
37068             te.setWidth(width);
37069             height -= te.getHeight();
37070         }
37071         
37072         
37073         if(this.adjustments){
37074             width += this.adjustments[0];
37075             height += this.adjustments[1];
37076         }
37077         return {"width": width, "height": height};
37078     },
37079     
37080     setSize : function(width, height){
37081         if(this.fitToFrame && !this.ignoreResize(width, height)){
37082             if(this.fitContainer && this.resizeEl != this.el){
37083                 this.el.setSize(width, height);
37084             }
37085             var size = this.adjustForComponents(width, height);
37086             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37087             this.fireEvent('resize', this, size.width, size.height);
37088         }
37089     },
37090     
37091     /**
37092      * Returns this panel's title
37093      * @return {String} 
37094      */
37095     getTitle : function(){
37096         
37097         if (typeof(this.title) != 'object') {
37098             return this.title;
37099         }
37100         
37101         var t = '';
37102         for (var k in this.title) {
37103             if (!this.title.hasOwnProperty(k)) {
37104                 continue;
37105             }
37106             
37107             if (k.indexOf('-') >= 0) {
37108                 var s = k.split('-');
37109                 for (var i = 0; i<s.length; i++) {
37110                     t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37111                 }
37112             } else {
37113                 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37114             }
37115         }
37116         return t;
37117     },
37118     
37119     /**
37120      * Set this panel's title
37121      * @param {String} title
37122      */
37123     setTitle : function(title){
37124         this.title = title;
37125         if(this.region){
37126             this.region.updatePanelTitle(this, title);
37127         }
37128     },
37129     
37130     /**
37131      * Returns true is this panel was configured to be closable
37132      * @return {Boolean} 
37133      */
37134     isClosable : function(){
37135         return this.closable;
37136     },
37137     
37138     beforeSlide : function(){
37139         this.el.clip();
37140         this.resizeEl.clip();
37141     },
37142     
37143     afterSlide : function(){
37144         this.el.unclip();
37145         this.resizeEl.unclip();
37146     },
37147     
37148     /**
37149      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
37150      *   Will fail silently if the {@link #setUrl} method has not been called.
37151      *   This does not activate the panel, just updates its content.
37152      */
37153     refresh : function(){
37154         if(this.refreshDelegate){
37155            this.loaded = false;
37156            this.refreshDelegate();
37157         }
37158     },
37159     
37160     /**
37161      * Destroys this panel
37162      */
37163     destroy : function(){
37164         this.el.removeAllListeners();
37165         var tempEl = document.createElement("span");
37166         tempEl.appendChild(this.el.dom);
37167         tempEl.innerHTML = "";
37168         this.el.remove();
37169         this.el = null;
37170     },
37171     
37172     /**
37173      * form - if the content panel contains a form - this is a reference to it.
37174      * @type {Roo.form.Form}
37175      */
37176     form : false,
37177     /**
37178      * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37179      *    This contains a reference to it.
37180      * @type {Roo.View}
37181      */
37182     view : false,
37183     
37184       /**
37185      * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37186      * <pre><code>
37187
37188 layout.addxtype({
37189        xtype : 'Form',
37190        items: [ .... ]
37191    }
37192 );
37193
37194 </code></pre>
37195      * @param {Object} cfg Xtype definition of item to add.
37196      */
37197     
37198     
37199     getChildContainer: function () {
37200         return this.getEl();
37201     }
37202     
37203     
37204     /*
37205         var  ret = new Roo.factory(cfg);
37206         return ret;
37207         
37208         
37209         // add form..
37210         if (cfg.xtype.match(/^Form$/)) {
37211             
37212             var el;
37213             //if (this.footer) {
37214             //    el = this.footer.container.insertSibling(false, 'before');
37215             //} else {
37216                 el = this.el.createChild();
37217             //}
37218
37219             this.form = new  Roo.form.Form(cfg);
37220             
37221             
37222             if ( this.form.allItems.length) {
37223                 this.form.render(el.dom);
37224             }
37225             return this.form;
37226         }
37227         // should only have one of theses..
37228         if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37229             // views.. should not be just added - used named prop 'view''
37230             
37231             cfg.el = this.el.appendChild(document.createElement("div"));
37232             // factory?
37233             
37234             var ret = new Roo.factory(cfg);
37235              
37236              ret.render && ret.render(false, ''); // render blank..
37237             this.view = ret;
37238             return ret;
37239         }
37240         return false;
37241     }
37242     \*/
37243 });
37244  
37245 /**
37246  * @class Roo.bootstrap.panel.Grid
37247  * @extends Roo.bootstrap.panel.Content
37248  * @constructor
37249  * Create a new GridPanel.
37250  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37251  * @param {Object} config A the config object
37252   
37253  */
37254
37255
37256
37257 Roo.bootstrap.panel.Grid = function(config)
37258 {
37259     
37260       
37261     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37262         {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37263
37264     config.el = this.wrapper;
37265     //this.el = this.wrapper;
37266     
37267       if (config.container) {
37268         // ctor'ed from a Border/panel.grid
37269         
37270         
37271         this.wrapper.setStyle("overflow", "hidden");
37272         this.wrapper.addClass('roo-grid-container');
37273
37274     }
37275     
37276     
37277     if(config.toolbar){
37278         var tool_el = this.wrapper.createChild();    
37279         this.toolbar = Roo.factory(config.toolbar);
37280         var ti = [];
37281         if (config.toolbar.items) {
37282             ti = config.toolbar.items ;
37283             delete config.toolbar.items ;
37284         }
37285         
37286         var nitems = [];
37287         this.toolbar.render(tool_el);
37288         for(var i =0;i < ti.length;i++) {
37289           //  Roo.log(['add child', items[i]]);
37290             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37291         }
37292         this.toolbar.items = nitems;
37293         
37294         delete config.toolbar;
37295     }
37296     
37297     Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37298     config.grid.scrollBody = true;;
37299     config.grid.monitorWindowResize = false; // turn off autosizing
37300     config.grid.autoHeight = false;
37301     config.grid.autoWidth = false;
37302     
37303     this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37304     
37305     if (config.background) {
37306         // render grid on panel activation (if panel background)
37307         this.on('activate', function(gp) {
37308             if (!gp.grid.rendered) {
37309                 gp.grid.render(this.wrapper);
37310                 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");   
37311             }
37312         });
37313             
37314     } else {
37315         this.grid.render(this.wrapper);
37316         this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");               
37317
37318     }
37319     //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37320     // ??? needed ??? config.el = this.wrapper;
37321     
37322     
37323     
37324   
37325     // xtype created footer. - not sure if will work as we normally have to render first..
37326     if (this.footer && !this.footer.el && this.footer.xtype) {
37327         
37328         var ctr = this.grid.getView().getFooterPanel(true);
37329         this.footer.dataSource = this.grid.dataSource;
37330         this.footer = Roo.factory(this.footer, Roo);
37331         this.footer.render(ctr);
37332         
37333     }
37334     
37335     
37336     
37337     
37338      
37339 };
37340
37341 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37342     getId : function(){
37343         return this.grid.id;
37344     },
37345     
37346     /**
37347      * Returns the grid for this panel
37348      * @return {Roo.bootstrap.Table} 
37349      */
37350     getGrid : function(){
37351         return this.grid;    
37352     },
37353     
37354     setSize : function(width, height){
37355         if(!this.ignoreResize(width, height)){
37356             var grid = this.grid;
37357             var size = this.adjustForComponents(width, height);
37358             var gridel = grid.getGridEl();
37359             gridel.setSize(size.width, size.height);
37360             /*
37361             var thd = grid.getGridEl().select('thead',true).first();
37362             var tbd = grid.getGridEl().select('tbody', true).first();
37363             if (tbd) {
37364                 tbd.setSize(width, height - thd.getHeight());
37365             }
37366             */
37367             grid.autoSize();
37368         }
37369     },
37370      
37371     
37372     
37373     beforeSlide : function(){
37374         this.grid.getView().scroller.clip();
37375     },
37376     
37377     afterSlide : function(){
37378         this.grid.getView().scroller.unclip();
37379     },
37380     
37381     destroy : function(){
37382         this.grid.destroy();
37383         delete this.grid;
37384         Roo.bootstrap.panel.Grid.superclass.destroy.call(this); 
37385     }
37386 });
37387
37388 /**
37389  * @class Roo.bootstrap.panel.Nest
37390  * @extends Roo.bootstrap.panel.Content
37391  * @constructor
37392  * Create a new Panel, that can contain a layout.Border.
37393  * 
37394  * 
37395  * @param {Roo.BorderLayout} layout The layout for this panel
37396  * @param {String/Object} config A string to set only the title or a config object
37397  */
37398 Roo.bootstrap.panel.Nest = function(config)
37399 {
37400     // construct with only one argument..
37401     /* FIXME - implement nicer consturctors
37402     if (layout.layout) {
37403         config = layout;
37404         layout = config.layout;
37405         delete config.layout;
37406     }
37407     if (layout.xtype && !layout.getEl) {
37408         // then layout needs constructing..
37409         layout = Roo.factory(layout, Roo);
37410     }
37411     */
37412     
37413     config.el =  config.layout.getEl();
37414     
37415     Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37416     
37417     config.layout.monitorWindowResize = false; // turn off autosizing
37418     this.layout = config.layout;
37419     this.layout.getEl().addClass("roo-layout-nested-layout");
37420     
37421     
37422     
37423     
37424 };
37425
37426 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37427
37428     setSize : function(width, height){
37429         if(!this.ignoreResize(width, height)){
37430             var size = this.adjustForComponents(width, height);
37431             var el = this.layout.getEl();
37432             if (size.height < 1) {
37433                 el.setWidth(size.width);   
37434             } else {
37435                 el.setSize(size.width, size.height);
37436             }
37437             var touch = el.dom.offsetWidth;
37438             this.layout.layout();
37439             // ie requires a double layout on the first pass
37440             if(Roo.isIE && !this.initialized){
37441                 this.initialized = true;
37442                 this.layout.layout();
37443             }
37444         }
37445     },
37446     
37447     // activate all subpanels if not currently active..
37448     
37449     setActiveState : function(active){
37450         this.active = active;
37451         this.setActiveClass(active);
37452         
37453         if(!active){
37454             this.fireEvent("deactivate", this);
37455             return;
37456         }
37457         
37458         this.fireEvent("activate", this);
37459         // not sure if this should happen before or after..
37460         if (!this.layout) {
37461             return; // should not happen..
37462         }
37463         var reg = false;
37464         for (var r in this.layout.regions) {
37465             reg = this.layout.getRegion(r);
37466             if (reg.getActivePanel()) {
37467                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
37468                 reg.setActivePanel(reg.getActivePanel());
37469                 continue;
37470             }
37471             if (!reg.panels.length) {
37472                 continue;
37473             }
37474             reg.showPanel(reg.getPanel(0));
37475         }
37476         
37477         
37478         
37479         
37480     },
37481     
37482     /**
37483      * Returns the nested BorderLayout for this panel
37484      * @return {Roo.BorderLayout} 
37485      */
37486     getLayout : function(){
37487         return this.layout;
37488     },
37489     
37490      /**
37491      * Adds a xtype elements to the layout of the nested panel
37492      * <pre><code>
37493
37494 panel.addxtype({
37495        xtype : 'ContentPanel',
37496        region: 'west',
37497        items: [ .... ]
37498    }
37499 );
37500
37501 panel.addxtype({
37502         xtype : 'NestedLayoutPanel',
37503         region: 'west',
37504         layout: {
37505            center: { },
37506            west: { }   
37507         },
37508         items : [ ... list of content panels or nested layout panels.. ]
37509    }
37510 );
37511 </code></pre>
37512      * @param {Object} cfg Xtype definition of item to add.
37513      */
37514     addxtype : function(cfg) {
37515         return this.layout.addxtype(cfg);
37516     
37517     }
37518 });        /*
37519  * Based on:
37520  * Ext JS Library 1.1.1
37521  * Copyright(c) 2006-2007, Ext JS, LLC.
37522  *
37523  * Originally Released Under LGPL - original licence link has changed is not relivant.
37524  *
37525  * Fork - LGPL
37526  * <script type="text/javascript">
37527  */
37528 /**
37529  * @class Roo.TabPanel
37530  * @extends Roo.util.Observable
37531  * A lightweight tab container.
37532  * <br><br>
37533  * Usage:
37534  * <pre><code>
37535 // basic tabs 1, built from existing content
37536 var tabs = new Roo.TabPanel("tabs1");
37537 tabs.addTab("script", "View Script");
37538 tabs.addTab("markup", "View Markup");
37539 tabs.activate("script");
37540
37541 // more advanced tabs, built from javascript
37542 var jtabs = new Roo.TabPanel("jtabs");
37543 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37544
37545 // set up the UpdateManager
37546 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37547 var updater = tab2.getUpdateManager();
37548 updater.setDefaultUrl("ajax1.htm");
37549 tab2.on('activate', updater.refresh, updater, true);
37550
37551 // Use setUrl for Ajax loading
37552 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37553 tab3.setUrl("ajax2.htm", null, true);
37554
37555 // Disabled tab
37556 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37557 tab4.disable();
37558
37559 jtabs.activate("jtabs-1");
37560  * </code></pre>
37561  * @constructor
37562  * Create a new TabPanel.
37563  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37564  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37565  */
37566 Roo.bootstrap.panel.Tabs = function(config){
37567     /**
37568     * The container element for this TabPanel.
37569     * @type Roo.Element
37570     */
37571     this.el = Roo.get(config.el);
37572     delete config.el;
37573     if(config){
37574         if(typeof config == "boolean"){
37575             this.tabPosition = config ? "bottom" : "top";
37576         }else{
37577             Roo.apply(this, config);
37578         }
37579     }
37580     
37581     if(this.tabPosition == "bottom"){
37582         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37583         this.el.addClass("roo-tabs-bottom");
37584     }
37585     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37586     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37587     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37588     if(Roo.isIE){
37589         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37590     }
37591     if(this.tabPosition != "bottom"){
37592         /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37593          * @type Roo.Element
37594          */
37595         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37596         this.el.addClass("roo-tabs-top");
37597     }
37598     this.items = [];
37599
37600     this.bodyEl.setStyle("position", "relative");
37601
37602     this.active = null;
37603     this.activateDelegate = this.activate.createDelegate(this);
37604
37605     this.addEvents({
37606         /**
37607          * @event tabchange
37608          * Fires when the active tab changes
37609          * @param {Roo.TabPanel} this
37610          * @param {Roo.TabPanelItem} activePanel The new active tab
37611          */
37612         "tabchange": true,
37613         /**
37614          * @event beforetabchange
37615          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37616          * @param {Roo.TabPanel} this
37617          * @param {Object} e Set cancel to true on this object to cancel the tab change
37618          * @param {Roo.TabPanelItem} tab The tab being changed to
37619          */
37620         "beforetabchange" : true
37621     });
37622
37623     Roo.EventManager.onWindowResize(this.onResize, this);
37624     this.cpad = this.el.getPadding("lr");
37625     this.hiddenCount = 0;
37626
37627
37628     // toolbar on the tabbar support...
37629     if (this.toolbar) {
37630         alert("no toolbar support yet");
37631         this.toolbar  = false;
37632         /*
37633         var tcfg = this.toolbar;
37634         tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
37635         this.toolbar = new Roo.Toolbar(tcfg);
37636         if (Roo.isSafari) {
37637             var tbl = tcfg.container.child('table', true);
37638             tbl.setAttribute('width', '100%');
37639         }
37640         */
37641         
37642     }
37643    
37644
37645
37646     Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37647 };
37648
37649 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37650     /*
37651      *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37652      */
37653     tabPosition : "top",
37654     /*
37655      *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37656      */
37657     currentTabWidth : 0,
37658     /*
37659      *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37660      */
37661     minTabWidth : 40,
37662     /*
37663      *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37664      */
37665     maxTabWidth : 250,
37666     /*
37667      *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37668      */
37669     preferredTabWidth : 175,
37670     /*
37671      *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37672      */
37673     resizeTabs : false,
37674     /*
37675      *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37676      */
37677     monitorResize : true,
37678     /*
37679      *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
37680      */
37681     toolbar : false,
37682
37683     /**
37684      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37685      * @param {String} id The id of the div to use <b>or create</b>
37686      * @param {String} text The text for the tab
37687      * @param {String} content (optional) Content to put in the TabPanelItem body
37688      * @param {Boolean} closable (optional) True to create a close icon on the tab
37689      * @return {Roo.TabPanelItem} The created TabPanelItem
37690      */
37691     addTab : function(id, text, content, closable, tpl)
37692     {
37693         var item = new Roo.bootstrap.panel.TabItem({
37694             panel: this,
37695             id : id,
37696             text : text,
37697             closable : closable,
37698             tpl : tpl
37699         });
37700         this.addTabItem(item);
37701         if(content){
37702             item.setContent(content);
37703         }
37704         return item;
37705     },
37706
37707     /**
37708      * Returns the {@link Roo.TabPanelItem} with the specified id/index
37709      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37710      * @return {Roo.TabPanelItem}
37711      */
37712     getTab : function(id){
37713         return this.items[id];
37714     },
37715
37716     /**
37717      * Hides the {@link Roo.TabPanelItem} with the specified id/index
37718      * @param {String/Number} id The id or index of the TabPanelItem to hide.
37719      */
37720     hideTab : function(id){
37721         var t = this.items[id];
37722         if(!t.isHidden()){
37723            t.setHidden(true);
37724            this.hiddenCount++;
37725            this.autoSizeTabs();
37726         }
37727     },
37728
37729     /**
37730      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37731      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37732      */
37733     unhideTab : function(id){
37734         var t = this.items[id];
37735         if(t.isHidden()){
37736            t.setHidden(false);
37737            this.hiddenCount--;
37738            this.autoSizeTabs();
37739         }
37740     },
37741
37742     /**
37743      * Adds an existing {@link Roo.TabPanelItem}.
37744      * @param {Roo.TabPanelItem} item The TabPanelItem to add
37745      */
37746     addTabItem : function(item){
37747         this.items[item.id] = item;
37748         this.items.push(item);
37749       //  if(this.resizeTabs){
37750     //       item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37751   //         this.autoSizeTabs();
37752 //        }else{
37753 //            item.autoSize();
37754        // }
37755     },
37756
37757     /**
37758      * Removes a {@link Roo.TabPanelItem}.
37759      * @param {String/Number} id The id or index of the TabPanelItem to remove.
37760      */
37761     removeTab : function(id){
37762         var items = this.items;
37763         var tab = items[id];
37764         if(!tab) { return; }
37765         var index = items.indexOf(tab);
37766         if(this.active == tab && items.length > 1){
37767             var newTab = this.getNextAvailable(index);
37768             if(newTab) {
37769                 newTab.activate();
37770             }
37771         }
37772         this.stripEl.dom.removeChild(tab.pnode.dom);
37773         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37774             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37775         }
37776         items.splice(index, 1);
37777         delete this.items[tab.id];
37778         tab.fireEvent("close", tab);
37779         tab.purgeListeners();
37780         this.autoSizeTabs();
37781     },
37782
37783     getNextAvailable : function(start){
37784         var items = this.items;
37785         var index = start;
37786         // look for a next tab that will slide over to
37787         // replace the one being removed
37788         while(index < items.length){
37789             var item = items[++index];
37790             if(item && !item.isHidden()){
37791                 return item;
37792             }
37793         }
37794         // if one isn't found select the previous tab (on the left)
37795         index = start;
37796         while(index >= 0){
37797             var item = items[--index];
37798             if(item && !item.isHidden()){
37799                 return item;
37800             }
37801         }
37802         return null;
37803     },
37804
37805     /**
37806      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37807      * @param {String/Number} id The id or index of the TabPanelItem to disable.
37808      */
37809     disableTab : function(id){
37810         var tab = this.items[id];
37811         if(tab && this.active != tab){
37812             tab.disable();
37813         }
37814     },
37815
37816     /**
37817      * Enables a {@link Roo.TabPanelItem} that is disabled.
37818      * @param {String/Number} id The id or index of the TabPanelItem to enable.
37819      */
37820     enableTab : function(id){
37821         var tab = this.items[id];
37822         tab.enable();
37823     },
37824
37825     /**
37826      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37827      * @param {String/Number} id The id or index of the TabPanelItem to activate.
37828      * @return {Roo.TabPanelItem} The TabPanelItem.
37829      */
37830     activate : function(id){
37831         var tab = this.items[id];
37832         if(!tab){
37833             return null;
37834         }
37835         if(tab == this.active || tab.disabled){
37836             return tab;
37837         }
37838         var e = {};
37839         this.fireEvent("beforetabchange", this, e, tab);
37840         if(e.cancel !== true && !tab.disabled){
37841             if(this.active){
37842                 this.active.hide();
37843             }
37844             this.active = this.items[id];
37845             this.active.show();
37846             this.fireEvent("tabchange", this, this.active);
37847         }
37848         return tab;
37849     },
37850
37851     /**
37852      * Gets the active {@link Roo.TabPanelItem}.
37853      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37854      */
37855     getActiveTab : function(){
37856         return this.active;
37857     },
37858
37859     /**
37860      * Updates the tab body element to fit the height of the container element
37861      * for overflow scrolling
37862      * @param {Number} targetHeight (optional) Override the starting height from the elements height
37863      */
37864     syncHeight : function(targetHeight){
37865         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37866         var bm = this.bodyEl.getMargins();
37867         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37868         this.bodyEl.setHeight(newHeight);
37869         return newHeight;
37870     },
37871
37872     onResize : function(){
37873         if(this.monitorResize){
37874             this.autoSizeTabs();
37875         }
37876     },
37877
37878     /**
37879      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37880      */
37881     beginUpdate : function(){
37882         this.updating = true;
37883     },
37884
37885     /**
37886      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37887      */
37888     endUpdate : function(){
37889         this.updating = false;
37890         this.autoSizeTabs();
37891     },
37892
37893     /**
37894      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37895      */
37896     autoSizeTabs : function(){
37897         var count = this.items.length;
37898         var vcount = count - this.hiddenCount;
37899         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37900             return;
37901         }
37902         var w = Math.max(this.el.getWidth() - this.cpad, 10);
37903         var availWidth = Math.floor(w / vcount);
37904         var b = this.stripBody;
37905         if(b.getWidth() > w){
37906             var tabs = this.items;
37907             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37908             if(availWidth < this.minTabWidth){
37909                 /*if(!this.sleft){    // incomplete scrolling code
37910                     this.createScrollButtons();
37911                 }
37912                 this.showScroll();
37913                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37914             }
37915         }else{
37916             if(this.currentTabWidth < this.preferredTabWidth){
37917                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37918             }
37919         }
37920     },
37921
37922     /**
37923      * Returns the number of tabs in this TabPanel.
37924      * @return {Number}
37925      */
37926      getCount : function(){
37927          return this.items.length;
37928      },
37929
37930     /**
37931      * Resizes all the tabs to the passed width
37932      * @param {Number} The new width
37933      */
37934     setTabWidth : function(width){
37935         this.currentTabWidth = width;
37936         for(var i = 0, len = this.items.length; i < len; i++) {
37937                 if(!this.items[i].isHidden()) {
37938                 this.items[i].setWidth(width);
37939             }
37940         }
37941     },
37942
37943     /**
37944      * Destroys this TabPanel
37945      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37946      */
37947     destroy : function(removeEl){
37948         Roo.EventManager.removeResizeListener(this.onResize, this);
37949         for(var i = 0, len = this.items.length; i < len; i++){
37950             this.items[i].purgeListeners();
37951         }
37952         if(removeEl === true){
37953             this.el.update("");
37954             this.el.remove();
37955         }
37956     },
37957     
37958     createStrip : function(container)
37959     {
37960         var strip = document.createElement("nav");
37961         strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37962         container.appendChild(strip);
37963         return strip;
37964     },
37965     
37966     createStripList : function(strip)
37967     {
37968         // div wrapper for retard IE
37969         // returns the "tr" element.
37970         strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37971         //'<div class="x-tabs-strip-wrap">'+
37972           //  '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37973           //  '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37974         return strip.firstChild; //.firstChild.firstChild.firstChild;
37975     },
37976     createBody : function(container)
37977     {
37978         var body = document.createElement("div");
37979         Roo.id(body, "tab-body");
37980         //Roo.fly(body).addClass("x-tabs-body");
37981         Roo.fly(body).addClass("tab-content");
37982         container.appendChild(body);
37983         return body;
37984     },
37985     createItemBody :function(bodyEl, id){
37986         var body = Roo.getDom(id);
37987         if(!body){
37988             body = document.createElement("div");
37989             body.id = id;
37990         }
37991         //Roo.fly(body).addClass("x-tabs-item-body");
37992         Roo.fly(body).addClass("tab-pane");
37993          bodyEl.insertBefore(body, bodyEl.firstChild);
37994         return body;
37995     },
37996     /** @private */
37997     createStripElements :  function(stripEl, text, closable, tpl)
37998     {
37999         var td = document.createElement("li"); // was td..
38000         
38001         
38002         //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38003         
38004         
38005         stripEl.appendChild(td);
38006         /*if(closable){
38007             td.className = "x-tabs-closable";
38008             if(!this.closeTpl){
38009                 this.closeTpl = new Roo.Template(
38010                    '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38011                    '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38012                    '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
38013                 );
38014             }
38015             var el = this.closeTpl.overwrite(td, {"text": text});
38016             var close = el.getElementsByTagName("div")[0];
38017             var inner = el.getElementsByTagName("em")[0];
38018             return {"el": el, "close": close, "inner": inner};
38019         } else {
38020         */
38021         // not sure what this is..
38022 //            if(!this.tabTpl){
38023                 //this.tabTpl = new Roo.Template(
38024                 //   '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38025                 //   '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38026                 //);
38027 //                this.tabTpl = new Roo.Template(
38028 //                   '<a href="#">' +
38029 //                   '<span unselectable="on"' +
38030 //                            (this.disableTooltips ? '' : ' title="{text}"') +
38031 //                            ' >{text}</span></a>'
38032 //                );
38033 //                
38034 //            }
38035
38036
38037             var template = tpl || this.tabTpl || false;
38038             
38039             if(!template){
38040                 
38041                 template = new Roo.Template(
38042                    '<a href="#">' +
38043                    '<span unselectable="on"' +
38044                             (this.disableTooltips ? '' : ' title="{text}"') +
38045                             ' >{text}</span></a>'
38046                 );
38047             }
38048             
38049             switch (typeof(template)) {
38050                 case 'object' :
38051                     break;
38052                 case 'string' :
38053                     template = new Roo.Template(template);
38054                     break;
38055                 default :
38056                     break;
38057             }
38058             
38059             var el = template.overwrite(td, {"text": text});
38060             
38061             var inner = el.getElementsByTagName("span")[0];
38062             
38063             return {"el": el, "inner": inner};
38064             
38065     }
38066         
38067     
38068 });
38069
38070 /**
38071  * @class Roo.TabPanelItem
38072  * @extends Roo.util.Observable
38073  * Represents an individual item (tab plus body) in a TabPanel.
38074  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38075  * @param {String} id The id of this TabPanelItem
38076  * @param {String} text The text for the tab of this TabPanelItem
38077  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38078  */
38079 Roo.bootstrap.panel.TabItem = function(config){
38080     /**
38081      * The {@link Roo.TabPanel} this TabPanelItem belongs to
38082      * @type Roo.TabPanel
38083      */
38084     this.tabPanel = config.panel;
38085     /**
38086      * The id for this TabPanelItem
38087      * @type String
38088      */
38089     this.id = config.id;
38090     /** @private */
38091     this.disabled = false;
38092     /** @private */
38093     this.text = config.text;
38094     /** @private */
38095     this.loaded = false;
38096     this.closable = config.closable;
38097
38098     /**
38099      * The body element for this TabPanelItem.
38100      * @type Roo.Element
38101      */
38102     this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38103     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38104     this.bodyEl.setStyle("display", "block");
38105     this.bodyEl.setStyle("zoom", "1");
38106     //this.hideAction();
38107
38108     var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38109     /** @private */
38110     this.el = Roo.get(els.el);
38111     this.inner = Roo.get(els.inner, true);
38112     this.textEl = Roo.get(this.el.dom.firstChild, true);
38113     this.pnode = Roo.get(els.el.parentNode, true);
38114 //    this.el.on("mousedown", this.onTabMouseDown, this);
38115     this.el.on("click", this.onTabClick, this);
38116     /** @private */
38117     if(config.closable){
38118         var c = Roo.get(els.close, true);
38119         c.dom.title = this.closeText;
38120         c.addClassOnOver("close-over");
38121         c.on("click", this.closeClick, this);
38122      }
38123
38124     this.addEvents({
38125          /**
38126          * @event activate
38127          * Fires when this tab becomes the active tab.
38128          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38129          * @param {Roo.TabPanelItem} this
38130          */
38131         "activate": true,
38132         /**
38133          * @event beforeclose
38134          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38135          * @param {Roo.TabPanelItem} this
38136          * @param {Object} e Set cancel to true on this object to cancel the close.
38137          */
38138         "beforeclose": true,
38139         /**
38140          * @event close
38141          * Fires when this tab is closed.
38142          * @param {Roo.TabPanelItem} this
38143          */
38144          "close": true,
38145         /**
38146          * @event deactivate
38147          * Fires when this tab is no longer the active tab.
38148          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38149          * @param {Roo.TabPanelItem} this
38150          */
38151          "deactivate" : true
38152     });
38153     this.hidden = false;
38154
38155     Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38156 };
38157
38158 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38159            {
38160     purgeListeners : function(){
38161        Roo.util.Observable.prototype.purgeListeners.call(this);
38162        this.el.removeAllListeners();
38163     },
38164     /**
38165      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38166      */
38167     show : function(){
38168         this.pnode.addClass("active");
38169         this.showAction();
38170         if(Roo.isOpera){
38171             this.tabPanel.stripWrap.repaint();
38172         }
38173         this.fireEvent("activate", this.tabPanel, this);
38174     },
38175
38176     /**
38177      * Returns true if this tab is the active tab.
38178      * @return {Boolean}
38179      */
38180     isActive : function(){
38181         return this.tabPanel.getActiveTab() == this;
38182     },
38183
38184     /**
38185      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38186      */
38187     hide : function(){
38188         this.pnode.removeClass("active");
38189         this.hideAction();
38190         this.fireEvent("deactivate", this.tabPanel, this);
38191     },
38192
38193     hideAction : function(){
38194         this.bodyEl.hide();
38195         this.bodyEl.setStyle("position", "absolute");
38196         this.bodyEl.setLeft("-20000px");
38197         this.bodyEl.setTop("-20000px");
38198     },
38199
38200     showAction : function(){
38201         this.bodyEl.setStyle("position", "relative");
38202         this.bodyEl.setTop("");
38203         this.bodyEl.setLeft("");
38204         this.bodyEl.show();
38205     },
38206
38207     /**
38208      * Set the tooltip for the tab.
38209      * @param {String} tooltip The tab's tooltip
38210      */
38211     setTooltip : function(text){
38212         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38213             this.textEl.dom.qtip = text;
38214             this.textEl.dom.removeAttribute('title');
38215         }else{
38216             this.textEl.dom.title = text;
38217         }
38218     },
38219
38220     onTabClick : function(e){
38221         e.preventDefault();
38222         this.tabPanel.activate(this.id);
38223     },
38224
38225     onTabMouseDown : function(e){
38226         e.preventDefault();
38227         this.tabPanel.activate(this.id);
38228     },
38229 /*
38230     getWidth : function(){
38231         return this.inner.getWidth();
38232     },
38233
38234     setWidth : function(width){
38235         var iwidth = width - this.pnode.getPadding("lr");
38236         this.inner.setWidth(iwidth);
38237         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38238         this.pnode.setWidth(width);
38239     },
38240 */
38241     /**
38242      * Show or hide the tab
38243      * @param {Boolean} hidden True to hide or false to show.
38244      */
38245     setHidden : function(hidden){
38246         this.hidden = hidden;
38247         this.pnode.setStyle("display", hidden ? "none" : "");
38248     },
38249
38250     /**
38251      * Returns true if this tab is "hidden"
38252      * @return {Boolean}
38253      */
38254     isHidden : function(){
38255         return this.hidden;
38256     },
38257
38258     /**
38259      * Returns the text for this tab
38260      * @return {String}
38261      */
38262     getText : function(){
38263         return this.text;
38264     },
38265     /*
38266     autoSize : function(){
38267         //this.el.beginMeasure();
38268         this.textEl.setWidth(1);
38269         /*
38270          *  #2804 [new] Tabs in Roojs
38271          *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38272          */
38273         //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38274         //this.el.endMeasure();
38275     //},
38276
38277     /**
38278      * Sets the text for the tab (Note: this also sets the tooltip text)
38279      * @param {String} text The tab's text and tooltip
38280      */
38281     setText : function(text){
38282         this.text = text;
38283         this.textEl.update(text);
38284         this.setTooltip(text);
38285         //if(!this.tabPanel.resizeTabs){
38286         //    this.autoSize();
38287         //}
38288     },
38289     /**
38290      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38291      */
38292     activate : function(){
38293         this.tabPanel.activate(this.id);
38294     },
38295
38296     /**
38297      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38298      */
38299     disable : function(){
38300         if(this.tabPanel.active != this){
38301             this.disabled = true;
38302             this.pnode.addClass("disabled");
38303         }
38304     },
38305
38306     /**
38307      * Enables this TabPanelItem if it was previously disabled.
38308      */
38309     enable : function(){
38310         this.disabled = false;
38311         this.pnode.removeClass("disabled");
38312     },
38313
38314     /**
38315      * Sets the content for this TabPanelItem.
38316      * @param {String} content The content
38317      * @param {Boolean} loadScripts true to look for and load scripts
38318      */
38319     setContent : function(content, loadScripts){
38320         this.bodyEl.update(content, loadScripts);
38321     },
38322
38323     /**
38324      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38325      * @return {Roo.UpdateManager} The UpdateManager
38326      */
38327     getUpdateManager : function(){
38328         return this.bodyEl.getUpdateManager();
38329     },
38330
38331     /**
38332      * Set a URL to be used to load the content for this TabPanelItem.
38333      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38334      * @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)
38335      * @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)
38336      * @return {Roo.UpdateManager} The UpdateManager
38337      */
38338     setUrl : function(url, params, loadOnce){
38339         if(this.refreshDelegate){
38340             this.un('activate', this.refreshDelegate);
38341         }
38342         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38343         this.on("activate", this.refreshDelegate);
38344         return this.bodyEl.getUpdateManager();
38345     },
38346
38347     /** @private */
38348     _handleRefresh : function(url, params, loadOnce){
38349         if(!loadOnce || !this.loaded){
38350             var updater = this.bodyEl.getUpdateManager();
38351             updater.update(url, params, this._setLoaded.createDelegate(this));
38352         }
38353     },
38354
38355     /**
38356      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
38357      *   Will fail silently if the setUrl method has not been called.
38358      *   This does not activate the panel, just updates its content.
38359      */
38360     refresh : function(){
38361         if(this.refreshDelegate){
38362            this.loaded = false;
38363            this.refreshDelegate();
38364         }
38365     },
38366
38367     /** @private */
38368     _setLoaded : function(){
38369         this.loaded = true;
38370     },
38371
38372     /** @private */
38373     closeClick : function(e){
38374         var o = {};
38375         e.stopEvent();
38376         this.fireEvent("beforeclose", this, o);
38377         if(o.cancel !== true){
38378             this.tabPanel.removeTab(this.id);
38379         }
38380     },
38381     /**
38382      * The text displayed in the tooltip for the close icon.
38383      * @type String
38384      */
38385     closeText : "Close this tab"
38386 });
38387 /**
38388 *    This script refer to:
38389 *    Title: International Telephone Input
38390 *    Author: Jack O'Connor
38391 *    Code version:  v12.1.12
38392 *    Availability: https://github.com/jackocnr/intl-tel-input.git
38393 **/
38394
38395 Roo.bootstrap.PhoneInputData = function() {
38396     var d = [
38397       [
38398         "Afghanistan (‫افغانستان‬‎)",
38399         "af",
38400         "93"
38401       ],
38402       [
38403         "Albania (Shqipëri)",
38404         "al",
38405         "355"
38406       ],
38407       [
38408         "Algeria (‫الجزائر‬‎)",
38409         "dz",
38410         "213"
38411       ],
38412       [
38413         "American Samoa",
38414         "as",
38415         "1684"
38416       ],
38417       [
38418         "Andorra",
38419         "ad",
38420         "376"
38421       ],
38422       [
38423         "Angola",
38424         "ao",
38425         "244"
38426       ],
38427       [
38428         "Anguilla",
38429         "ai",
38430         "1264"
38431       ],
38432       [
38433         "Antigua and Barbuda",
38434         "ag",
38435         "1268"
38436       ],
38437       [
38438         "Argentina",
38439         "ar",
38440         "54"
38441       ],
38442       [
38443         "Armenia (Հայաստան)",
38444         "am",
38445         "374"
38446       ],
38447       [
38448         "Aruba",
38449         "aw",
38450         "297"
38451       ],
38452       [
38453         "Australia",
38454         "au",
38455         "61",
38456         0
38457       ],
38458       [
38459         "Austria (Österreich)",
38460         "at",
38461         "43"
38462       ],
38463       [
38464         "Azerbaijan (Azərbaycan)",
38465         "az",
38466         "994"
38467       ],
38468       [
38469         "Bahamas",
38470         "bs",
38471         "1242"
38472       ],
38473       [
38474         "Bahrain (‫البحرين‬‎)",
38475         "bh",
38476         "973"
38477       ],
38478       [
38479         "Bangladesh (বাংলাদেশ)",
38480         "bd",
38481         "880"
38482       ],
38483       [
38484         "Barbados",
38485         "bb",
38486         "1246"
38487       ],
38488       [
38489         "Belarus (Беларусь)",
38490         "by",
38491         "375"
38492       ],
38493       [
38494         "Belgium (België)",
38495         "be",
38496         "32"
38497       ],
38498       [
38499         "Belize",
38500         "bz",
38501         "501"
38502       ],
38503       [
38504         "Benin (Bénin)",
38505         "bj",
38506         "229"
38507       ],
38508       [
38509         "Bermuda",
38510         "bm",
38511         "1441"
38512       ],
38513       [
38514         "Bhutan (འབྲུག)",
38515         "bt",
38516         "975"
38517       ],
38518       [
38519         "Bolivia",
38520         "bo",
38521         "591"
38522       ],
38523       [
38524         "Bosnia and Herzegovina (Босна и Херцеговина)",
38525         "ba",
38526         "387"
38527       ],
38528       [
38529         "Botswana",
38530         "bw",
38531         "267"
38532       ],
38533       [
38534         "Brazil (Brasil)",
38535         "br",
38536         "55"
38537       ],
38538       [
38539         "British Indian Ocean Territory",
38540         "io",
38541         "246"
38542       ],
38543       [
38544         "British Virgin Islands",
38545         "vg",
38546         "1284"
38547       ],
38548       [
38549         "Brunei",
38550         "bn",
38551         "673"
38552       ],
38553       [
38554         "Bulgaria (България)",
38555         "bg",
38556         "359"
38557       ],
38558       [
38559         "Burkina Faso",
38560         "bf",
38561         "226"
38562       ],
38563       [
38564         "Burundi (Uburundi)",
38565         "bi",
38566         "257"
38567       ],
38568       [
38569         "Cambodia (កម្ពុជា)",
38570         "kh",
38571         "855"
38572       ],
38573       [
38574         "Cameroon (Cameroun)",
38575         "cm",
38576         "237"
38577       ],
38578       [
38579         "Canada",
38580         "ca",
38581         "1",
38582         1,
38583         ["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"]
38584       ],
38585       [
38586         "Cape Verde (Kabu Verdi)",
38587         "cv",
38588         "238"
38589       ],
38590       [
38591         "Caribbean Netherlands",
38592         "bq",
38593         "599",
38594         1
38595       ],
38596       [
38597         "Cayman Islands",
38598         "ky",
38599         "1345"
38600       ],
38601       [
38602         "Central African Republic (République centrafricaine)",
38603         "cf",
38604         "236"
38605       ],
38606       [
38607         "Chad (Tchad)",
38608         "td",
38609         "235"
38610       ],
38611       [
38612         "Chile",
38613         "cl",
38614         "56"
38615       ],
38616       [
38617         "China (中国)",
38618         "cn",
38619         "86"
38620       ],
38621       [
38622         "Christmas Island",
38623         "cx",
38624         "61",
38625         2
38626       ],
38627       [
38628         "Cocos (Keeling) Islands",
38629         "cc",
38630         "61",
38631         1
38632       ],
38633       [
38634         "Colombia",
38635         "co",
38636         "57"
38637       ],
38638       [
38639         "Comoros (‫جزر القمر‬‎)",
38640         "km",
38641         "269"
38642       ],
38643       [
38644         "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38645         "cd",
38646         "243"
38647       ],
38648       [
38649         "Congo (Republic) (Congo-Brazzaville)",
38650         "cg",
38651         "242"
38652       ],
38653       [
38654         "Cook Islands",
38655         "ck",
38656         "682"
38657       ],
38658       [
38659         "Costa Rica",
38660         "cr",
38661         "506"
38662       ],
38663       [
38664         "Côte d’Ivoire",
38665         "ci",
38666         "225"
38667       ],
38668       [
38669         "Croatia (Hrvatska)",
38670         "hr",
38671         "385"
38672       ],
38673       [
38674         "Cuba",
38675         "cu",
38676         "53"
38677       ],
38678       [
38679         "Curaçao",
38680         "cw",
38681         "599",
38682         0
38683       ],
38684       [
38685         "Cyprus (Κύπρος)",
38686         "cy",
38687         "357"
38688       ],
38689       [
38690         "Czech Republic (Česká republika)",
38691         "cz",
38692         "420"
38693       ],
38694       [
38695         "Denmark (Danmark)",
38696         "dk",
38697         "45"
38698       ],
38699       [
38700         "Djibouti",
38701         "dj",
38702         "253"
38703       ],
38704       [
38705         "Dominica",
38706         "dm",
38707         "1767"
38708       ],
38709       [
38710         "Dominican Republic (República Dominicana)",
38711         "do",
38712         "1",
38713         2,
38714         ["809", "829", "849"]
38715       ],
38716       [
38717         "Ecuador",
38718         "ec",
38719         "593"
38720       ],
38721       [
38722         "Egypt (‫مصر‬‎)",
38723         "eg",
38724         "20"
38725       ],
38726       [
38727         "El Salvador",
38728         "sv",
38729         "503"
38730       ],
38731       [
38732         "Equatorial Guinea (Guinea Ecuatorial)",
38733         "gq",
38734         "240"
38735       ],
38736       [
38737         "Eritrea",
38738         "er",
38739         "291"
38740       ],
38741       [
38742         "Estonia (Eesti)",
38743         "ee",
38744         "372"
38745       ],
38746       [
38747         "Ethiopia",
38748         "et",
38749         "251"
38750       ],
38751       [
38752         "Falkland Islands (Islas Malvinas)",
38753         "fk",
38754         "500"
38755       ],
38756       [
38757         "Faroe Islands (Føroyar)",
38758         "fo",
38759         "298"
38760       ],
38761       [
38762         "Fiji",
38763         "fj",
38764         "679"
38765       ],
38766       [
38767         "Finland (Suomi)",
38768         "fi",
38769         "358",
38770         0
38771       ],
38772       [
38773         "France",
38774         "fr",
38775         "33"
38776       ],
38777       [
38778         "French Guiana (Guyane française)",
38779         "gf",
38780         "594"
38781       ],
38782       [
38783         "French Polynesia (Polynésie française)",
38784         "pf",
38785         "689"
38786       ],
38787       [
38788         "Gabon",
38789         "ga",
38790         "241"
38791       ],
38792       [
38793         "Gambia",
38794         "gm",
38795         "220"
38796       ],
38797       [
38798         "Georgia (საქართველო)",
38799         "ge",
38800         "995"
38801       ],
38802       [
38803         "Germany (Deutschland)",
38804         "de",
38805         "49"
38806       ],
38807       [
38808         "Ghana (Gaana)",
38809         "gh",
38810         "233"
38811       ],
38812       [
38813         "Gibraltar",
38814         "gi",
38815         "350"
38816       ],
38817       [
38818         "Greece (Ελλάδα)",
38819         "gr",
38820         "30"
38821       ],
38822       [
38823         "Greenland (Kalaallit Nunaat)",
38824         "gl",
38825         "299"
38826       ],
38827       [
38828         "Grenada",
38829         "gd",
38830         "1473"
38831       ],
38832       [
38833         "Guadeloupe",
38834         "gp",
38835         "590",
38836         0
38837       ],
38838       [
38839         "Guam",
38840         "gu",
38841         "1671"
38842       ],
38843       [
38844         "Guatemala",
38845         "gt",
38846         "502"
38847       ],
38848       [
38849         "Guernsey",
38850         "gg",
38851         "44",
38852         1
38853       ],
38854       [
38855         "Guinea (Guinée)",
38856         "gn",
38857         "224"
38858       ],
38859       [
38860         "Guinea-Bissau (Guiné Bissau)",
38861         "gw",
38862         "245"
38863       ],
38864       [
38865         "Guyana",
38866         "gy",
38867         "592"
38868       ],
38869       [
38870         "Haiti",
38871         "ht",
38872         "509"
38873       ],
38874       [
38875         "Honduras",
38876         "hn",
38877         "504"
38878       ],
38879       [
38880         "Hong Kong (香港)",
38881         "hk",
38882         "852"
38883       ],
38884       [
38885         "Hungary (Magyarország)",
38886         "hu",
38887         "36"
38888       ],
38889       [
38890         "Iceland (Ísland)",
38891         "is",
38892         "354"
38893       ],
38894       [
38895         "India (भारत)",
38896         "in",
38897         "91"
38898       ],
38899       [
38900         "Indonesia",
38901         "id",
38902         "62"
38903       ],
38904       [
38905         "Iran (‫ایران‬‎)",
38906         "ir",
38907         "98"
38908       ],
38909       [
38910         "Iraq (‫العراق‬‎)",
38911         "iq",
38912         "964"
38913       ],
38914       [
38915         "Ireland",
38916         "ie",
38917         "353"
38918       ],
38919       [
38920         "Isle of Man",
38921         "im",
38922         "44",
38923         2
38924       ],
38925       [
38926         "Israel (‫ישראל‬‎)",
38927         "il",
38928         "972"
38929       ],
38930       [
38931         "Italy (Italia)",
38932         "it",
38933         "39",
38934         0
38935       ],
38936       [
38937         "Jamaica",
38938         "jm",
38939         "1876"
38940       ],
38941       [
38942         "Japan (日本)",
38943         "jp",
38944         "81"
38945       ],
38946       [
38947         "Jersey",
38948         "je",
38949         "44",
38950         3
38951       ],
38952       [
38953         "Jordan (‫الأردن‬‎)",
38954         "jo",
38955         "962"
38956       ],
38957       [
38958         "Kazakhstan (Казахстан)",
38959         "kz",
38960         "7",
38961         1
38962       ],
38963       [
38964         "Kenya",
38965         "ke",
38966         "254"
38967       ],
38968       [
38969         "Kiribati",
38970         "ki",
38971         "686"
38972       ],
38973       [
38974         "Kosovo",
38975         "xk",
38976         "383"
38977       ],
38978       [
38979         "Kuwait (‫الكويت‬‎)",
38980         "kw",
38981         "965"
38982       ],
38983       [
38984         "Kyrgyzstan (Кыргызстан)",
38985         "kg",
38986         "996"
38987       ],
38988       [
38989         "Laos (ລາວ)",
38990         "la",
38991         "856"
38992       ],
38993       [
38994         "Latvia (Latvija)",
38995         "lv",
38996         "371"
38997       ],
38998       [
38999         "Lebanon (‫لبنان‬‎)",
39000         "lb",
39001         "961"
39002       ],
39003       [
39004         "Lesotho",
39005         "ls",
39006         "266"
39007       ],
39008       [
39009         "Liberia",
39010         "lr",
39011         "231"
39012       ],
39013       [
39014         "Libya (‫ليبيا‬‎)",
39015         "ly",
39016         "218"
39017       ],
39018       [
39019         "Liechtenstein",
39020         "li",
39021         "423"
39022       ],
39023       [
39024         "Lithuania (Lietuva)",
39025         "lt",
39026         "370"
39027       ],
39028       [
39029         "Luxembourg",
39030         "lu",
39031         "352"
39032       ],
39033       [
39034         "Macau (澳門)",
39035         "mo",
39036         "853"
39037       ],
39038       [
39039         "Macedonia (FYROM) (Македонија)",
39040         "mk",
39041         "389"
39042       ],
39043       [
39044         "Madagascar (Madagasikara)",
39045         "mg",
39046         "261"
39047       ],
39048       [
39049         "Malawi",
39050         "mw",
39051         "265"
39052       ],
39053       [
39054         "Malaysia",
39055         "my",
39056         "60"
39057       ],
39058       [
39059         "Maldives",
39060         "mv",
39061         "960"
39062       ],
39063       [
39064         "Mali",
39065         "ml",
39066         "223"
39067       ],
39068       [
39069         "Malta",
39070         "mt",
39071         "356"
39072       ],
39073       [
39074         "Marshall Islands",
39075         "mh",
39076         "692"
39077       ],
39078       [
39079         "Martinique",
39080         "mq",
39081         "596"
39082       ],
39083       [
39084         "Mauritania (‫موريتانيا‬‎)",
39085         "mr",
39086         "222"
39087       ],
39088       [
39089         "Mauritius (Moris)",
39090         "mu",
39091         "230"
39092       ],
39093       [
39094         "Mayotte",
39095         "yt",
39096         "262",
39097         1
39098       ],
39099       [
39100         "Mexico (México)",
39101         "mx",
39102         "52"
39103       ],
39104       [
39105         "Micronesia",
39106         "fm",
39107         "691"
39108       ],
39109       [
39110         "Moldova (Republica Moldova)",
39111         "md",
39112         "373"
39113       ],
39114       [
39115         "Monaco",
39116         "mc",
39117         "377"
39118       ],
39119       [
39120         "Mongolia (Монгол)",
39121         "mn",
39122         "976"
39123       ],
39124       [
39125         "Montenegro (Crna Gora)",
39126         "me",
39127         "382"
39128       ],
39129       [
39130         "Montserrat",
39131         "ms",
39132         "1664"
39133       ],
39134       [
39135         "Morocco (‫المغرب‬‎)",
39136         "ma",
39137         "212",
39138         0
39139       ],
39140       [
39141         "Mozambique (Moçambique)",
39142         "mz",
39143         "258"
39144       ],
39145       [
39146         "Myanmar (Burma) (မြန်မာ)",
39147         "mm",
39148         "95"
39149       ],
39150       [
39151         "Namibia (Namibië)",
39152         "na",
39153         "264"
39154       ],
39155       [
39156         "Nauru",
39157         "nr",
39158         "674"
39159       ],
39160       [
39161         "Nepal (नेपाल)",
39162         "np",
39163         "977"
39164       ],
39165       [
39166         "Netherlands (Nederland)",
39167         "nl",
39168         "31"
39169       ],
39170       [
39171         "New Caledonia (Nouvelle-Calédonie)",
39172         "nc",
39173         "687"
39174       ],
39175       [
39176         "New Zealand",
39177         "nz",
39178         "64"
39179       ],
39180       [
39181         "Nicaragua",
39182         "ni",
39183         "505"
39184       ],
39185       [
39186         "Niger (Nijar)",
39187         "ne",
39188         "227"
39189       ],
39190       [
39191         "Nigeria",
39192         "ng",
39193         "234"
39194       ],
39195       [
39196         "Niue",
39197         "nu",
39198         "683"
39199       ],
39200       [
39201         "Norfolk Island",
39202         "nf",
39203         "672"
39204       ],
39205       [
39206         "North Korea (조선 민주주의 인민 공화국)",
39207         "kp",
39208         "850"
39209       ],
39210       [
39211         "Northern Mariana Islands",
39212         "mp",
39213         "1670"
39214       ],
39215       [
39216         "Norway (Norge)",
39217         "no",
39218         "47",
39219         0
39220       ],
39221       [
39222         "Oman (‫عُمان‬‎)",
39223         "om",
39224         "968"
39225       ],
39226       [
39227         "Pakistan (‫پاکستان‬‎)",
39228         "pk",
39229         "92"
39230       ],
39231       [
39232         "Palau",
39233         "pw",
39234         "680"
39235       ],
39236       [
39237         "Palestine (‫فلسطين‬‎)",
39238         "ps",
39239         "970"
39240       ],
39241       [
39242         "Panama (Panamá)",
39243         "pa",
39244         "507"
39245       ],
39246       [
39247         "Papua New Guinea",
39248         "pg",
39249         "675"
39250       ],
39251       [
39252         "Paraguay",
39253         "py",
39254         "595"
39255       ],
39256       [
39257         "Peru (Perú)",
39258         "pe",
39259         "51"
39260       ],
39261       [
39262         "Philippines",
39263         "ph",
39264         "63"
39265       ],
39266       [
39267         "Poland (Polska)",
39268         "pl",
39269         "48"
39270       ],
39271       [
39272         "Portugal",
39273         "pt",
39274         "351"
39275       ],
39276       [
39277         "Puerto Rico",
39278         "pr",
39279         "1",
39280         3,
39281         ["787", "939"]
39282       ],
39283       [
39284         "Qatar (‫قطر‬‎)",
39285         "qa",
39286         "974"
39287       ],
39288       [
39289         "Réunion (La Réunion)",
39290         "re",
39291         "262",
39292         0
39293       ],
39294       [
39295         "Romania (România)",
39296         "ro",
39297         "40"
39298       ],
39299       [
39300         "Russia (Россия)",
39301         "ru",
39302         "7",
39303         0
39304       ],
39305       [
39306         "Rwanda",
39307         "rw",
39308         "250"
39309       ],
39310       [
39311         "Saint Barthélemy",
39312         "bl",
39313         "590",
39314         1
39315       ],
39316       [
39317         "Saint Helena",
39318         "sh",
39319         "290"
39320       ],
39321       [
39322         "Saint Kitts and Nevis",
39323         "kn",
39324         "1869"
39325       ],
39326       [
39327         "Saint Lucia",
39328         "lc",
39329         "1758"
39330       ],
39331       [
39332         "Saint Martin (Saint-Martin (partie française))",
39333         "mf",
39334         "590",
39335         2
39336       ],
39337       [
39338         "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39339         "pm",
39340         "508"
39341       ],
39342       [
39343         "Saint Vincent and the Grenadines",
39344         "vc",
39345         "1784"
39346       ],
39347       [
39348         "Samoa",
39349         "ws",
39350         "685"
39351       ],
39352       [
39353         "San Marino",
39354         "sm",
39355         "378"
39356       ],
39357       [
39358         "São Tomé and Príncipe (São Tomé e Príncipe)",
39359         "st",
39360         "239"
39361       ],
39362       [
39363         "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
39364         "sa",
39365         "966"
39366       ],
39367       [
39368         "Senegal (Sénégal)",
39369         "sn",
39370         "221"
39371       ],
39372       [
39373         "Serbia (Србија)",
39374         "rs",
39375         "381"
39376       ],
39377       [
39378         "Seychelles",
39379         "sc",
39380         "248"
39381       ],
39382       [
39383         "Sierra Leone",
39384         "sl",
39385         "232"
39386       ],
39387       [
39388         "Singapore",
39389         "sg",
39390         "65"
39391       ],
39392       [
39393         "Sint Maarten",
39394         "sx",
39395         "1721"
39396       ],
39397       [
39398         "Slovakia (Slovensko)",
39399         "sk",
39400         "421"
39401       ],
39402       [
39403         "Slovenia (Slovenija)",
39404         "si",
39405         "386"
39406       ],
39407       [
39408         "Solomon Islands",
39409         "sb",
39410         "677"
39411       ],
39412       [
39413         "Somalia (Soomaaliya)",
39414         "so",
39415         "252"
39416       ],
39417       [
39418         "South Africa",
39419         "za",
39420         "27"
39421       ],
39422       [
39423         "South Korea (대한민국)",
39424         "kr",
39425         "82"
39426       ],
39427       [
39428         "South Sudan (‫جنوب السودان‬‎)",
39429         "ss",
39430         "211"
39431       ],
39432       [
39433         "Spain (España)",
39434         "es",
39435         "34"
39436       ],
39437       [
39438         "Sri Lanka (ශ්‍රී ලංකාව)",
39439         "lk",
39440         "94"
39441       ],
39442       [
39443         "Sudan (‫السودان‬‎)",
39444         "sd",
39445         "249"
39446       ],
39447       [
39448         "Suriname",
39449         "sr",
39450         "597"
39451       ],
39452       [
39453         "Svalbard and Jan Mayen",
39454         "sj",
39455         "47",
39456         1
39457       ],
39458       [
39459         "Swaziland",
39460         "sz",
39461         "268"
39462       ],
39463       [
39464         "Sweden (Sverige)",
39465         "se",
39466         "46"
39467       ],
39468       [
39469         "Switzerland (Schweiz)",
39470         "ch",
39471         "41"
39472       ],
39473       [
39474         "Syria (‫سوريا‬‎)",
39475         "sy",
39476         "963"
39477       ],
39478       [
39479         "Taiwan (台灣)",
39480         "tw",
39481         "886"
39482       ],
39483       [
39484         "Tajikistan",
39485         "tj",
39486         "992"
39487       ],
39488       [
39489         "Tanzania",
39490         "tz",
39491         "255"
39492       ],
39493       [
39494         "Thailand (ไทย)",
39495         "th",
39496         "66"
39497       ],
39498       [
39499         "Timor-Leste",
39500         "tl",
39501         "670"
39502       ],
39503       [
39504         "Togo",
39505         "tg",
39506         "228"
39507       ],
39508       [
39509         "Tokelau",
39510         "tk",
39511         "690"
39512       ],
39513       [
39514         "Tonga",
39515         "to",
39516         "676"
39517       ],
39518       [
39519         "Trinidad and Tobago",
39520         "tt",
39521         "1868"
39522       ],
39523       [
39524         "Tunisia (‫تونس‬‎)",
39525         "tn",
39526         "216"
39527       ],
39528       [
39529         "Turkey (Türkiye)",
39530         "tr",
39531         "90"
39532       ],
39533       [
39534         "Turkmenistan",
39535         "tm",
39536         "993"
39537       ],
39538       [
39539         "Turks and Caicos Islands",
39540         "tc",
39541         "1649"
39542       ],
39543       [
39544         "Tuvalu",
39545         "tv",
39546         "688"
39547       ],
39548       [
39549         "U.S. Virgin Islands",
39550         "vi",
39551         "1340"
39552       ],
39553       [
39554         "Uganda",
39555         "ug",
39556         "256"
39557       ],
39558       [
39559         "Ukraine (Україна)",
39560         "ua",
39561         "380"
39562       ],
39563       [
39564         "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
39565         "ae",
39566         "971"
39567       ],
39568       [
39569         "United Kingdom",
39570         "gb",
39571         "44",
39572         0
39573       ],
39574       [
39575         "United States",
39576         "us",
39577         "1",
39578         0
39579       ],
39580       [
39581         "Uruguay",
39582         "uy",
39583         "598"
39584       ],
39585       [
39586         "Uzbekistan (Oʻzbekiston)",
39587         "uz",
39588         "998"
39589       ],
39590       [
39591         "Vanuatu",
39592         "vu",
39593         "678"
39594       ],
39595       [
39596         "Vatican City (Città del Vaticano)",
39597         "va",
39598         "39",
39599         1
39600       ],
39601       [
39602         "Venezuela",
39603         "ve",
39604         "58"
39605       ],
39606       [
39607         "Vietnam (Việt Nam)",
39608         "vn",
39609         "84"
39610       ],
39611       [
39612         "Wallis and Futuna (Wallis-et-Futuna)",
39613         "wf",
39614         "681"
39615       ],
39616       [
39617         "Western Sahara (‫الصحراء الغربية‬‎)",
39618         "eh",
39619         "212",
39620         1
39621       ],
39622       [
39623         "Yemen (‫اليمن‬‎)",
39624         "ye",
39625         "967"
39626       ],
39627       [
39628         "Zambia",
39629         "zm",
39630         "260"
39631       ],
39632       [
39633         "Zimbabwe",
39634         "zw",
39635         "263"
39636       ],
39637       [
39638         "Åland Islands",
39639         "ax",
39640         "358",
39641         1
39642       ]
39643   ];
39644   
39645   return d;
39646 }/**
39647 *    This script refer to:
39648 *    Title: International Telephone Input
39649 *    Author: Jack O'Connor
39650 *    Code version:  v12.1.12
39651 *    Availability: https://github.com/jackocnr/intl-tel-input.git
39652 **/
39653
39654 /**
39655  * @class Roo.bootstrap.PhoneInput
39656  * @extends Roo.bootstrap.TriggerField
39657  * An input with International dial-code selection
39658  
39659  * @cfg {String} defaultDialCode default '+852'
39660  * @cfg {Array} preferedCountries default []
39661   
39662  * @constructor
39663  * Create a new PhoneInput.
39664  * @param {Object} config Configuration options
39665  */
39666
39667 Roo.bootstrap.PhoneInput = function(config) {
39668     Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39669 };
39670
39671 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39672         
39673         listWidth: undefined,
39674         
39675         selectedClass: 'active',
39676         
39677         invalidClass : "has-warning",
39678         
39679         validClass: 'has-success',
39680         
39681         allowed: '0123456789',
39682         
39683         /**
39684          * @cfg {String} defaultDialCode The default dial code when initializing the input
39685          */
39686         defaultDialCode: '+852',
39687         
39688         /**
39689          * @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
39690          */
39691         preferedCountries: false,
39692         
39693         getAutoCreate : function()
39694         {
39695             var data = Roo.bootstrap.PhoneInputData();
39696             var align = this.labelAlign || this.parentLabelAlign();
39697             var id = Roo.id();
39698             
39699             this.allCountries = [];
39700             this.dialCodeMapping = [];
39701             
39702             for (var i = 0; i < data.length; i++) {
39703               var c = data[i];
39704               this.allCountries[i] = {
39705                 name: c[0],
39706                 iso2: c[1],
39707                 dialCode: c[2],
39708                 priority: c[3] || 0,
39709                 areaCodes: c[4] || null
39710               };
39711               this.dialCodeMapping[c[2]] = {
39712                   name: c[0],
39713                   iso2: c[1],
39714                   priority: c[3] || 0,
39715                   areaCodes: c[4] || null
39716               };
39717             }
39718             
39719             var cfg = {
39720                 cls: 'form-group',
39721                 cn: []
39722             };
39723             
39724             var input =  {
39725                 tag: 'input',
39726                 id : id,
39727                 cls : 'form-control tel-input',
39728                 autocomplete: 'new-password'
39729             };
39730             
39731             var hiddenInput = {
39732                 tag: 'input',
39733                 type: 'hidden',
39734                 cls: 'hidden-tel-input'
39735             };
39736             
39737             if (this.name) {
39738                 hiddenInput.name = this.name;
39739             }
39740             
39741             if (this.disabled) {
39742                 input.disabled = true;
39743             }
39744             
39745             var flag_container = {
39746                 tag: 'div',
39747                 cls: 'flag-box',
39748                 cn: [
39749                     {
39750                         tag: 'div',
39751                         cls: 'flag'
39752                     },
39753                     {
39754                         tag: 'div',
39755                         cls: 'caret'
39756                     }
39757                 ]
39758             };
39759             
39760             var box = {
39761                 tag: 'div',
39762                 cls: this.hasFeedback ? 'has-feedback' : '',
39763                 cn: [
39764                     hiddenInput,
39765                     input,
39766                     {
39767                         tag: 'input',
39768                         cls: 'dial-code-holder',
39769                         disabled: true
39770                     }
39771                 ]
39772             };
39773             
39774             var container = {
39775                 cls: 'roo-select2-container input-group',
39776                 cn: [
39777                     flag_container,
39778                     box
39779                 ]
39780             };
39781             
39782             if (this.fieldLabel.length) {
39783                 var indicator = {
39784                     tag: 'i',
39785                     tooltip: 'This field is required'
39786                 };
39787                 
39788                 var label = {
39789                     tag: 'label',
39790                     'for':  id,
39791                     cls: 'control-label',
39792                     cn: []
39793                 };
39794                 
39795                 var label_text = {
39796                     tag: 'span',
39797                     html: this.fieldLabel
39798                 };
39799                 
39800                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39801                 label.cn = [
39802                     indicator,
39803                     label_text
39804                 ];
39805                 
39806                 if(this.indicatorpos == 'right') {
39807                     indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39808                     label.cn = [
39809                         label_text,
39810                         indicator
39811                     ];
39812                 }
39813                 
39814                 if(align == 'left') {
39815                     container = {
39816                         tag: 'div',
39817                         cn: [
39818                             container
39819                         ]
39820                     };
39821                     
39822                     if(this.labelWidth > 12){
39823                         label.style = "width: " + this.labelWidth + 'px';
39824                     }
39825                     if(this.labelWidth < 13 && this.labelmd == 0){
39826                         this.labelmd = this.labelWidth;
39827                     }
39828                     if(this.labellg > 0){
39829                         label.cls += ' col-lg-' + this.labellg;
39830                         input.cls += ' col-lg-' + (12 - this.labellg);
39831                     }
39832                     if(this.labelmd > 0){
39833                         label.cls += ' col-md-' + this.labelmd;
39834                         container.cls += ' col-md-' + (12 - this.labelmd);
39835                     }
39836                     if(this.labelsm > 0){
39837                         label.cls += ' col-sm-' + this.labelsm;
39838                         container.cls += ' col-sm-' + (12 - this.labelsm);
39839                     }
39840                     if(this.labelxs > 0){
39841                         label.cls += ' col-xs-' + this.labelxs;
39842                         container.cls += ' col-xs-' + (12 - this.labelxs);
39843                     }
39844                 }
39845             }
39846             
39847             cfg.cn = [
39848                 label,
39849                 container
39850             ];
39851             
39852             var settings = this;
39853             
39854             ['xs','sm','md','lg'].map(function(size){
39855                 if (settings[size]) {
39856                     cfg.cls += ' col-' + size + '-' + settings[size];
39857                 }
39858             });
39859             
39860             this.store = new Roo.data.Store({
39861                 proxy : new Roo.data.MemoryProxy({}),
39862                 reader : new Roo.data.JsonReader({
39863                     fields : [
39864                         {
39865                             'name' : 'name',
39866                             'type' : 'string'
39867                         },
39868                         {
39869                             'name' : 'iso2',
39870                             'type' : 'string'
39871                         },
39872                         {
39873                             'name' : 'dialCode',
39874                             'type' : 'string'
39875                         },
39876                         {
39877                             'name' : 'priority',
39878                             'type' : 'string'
39879                         },
39880                         {
39881                             'name' : 'areaCodes',
39882                             'type' : 'string'
39883                         }
39884                     ]
39885                 })
39886             });
39887             
39888             if(!this.preferedCountries) {
39889                 this.preferedCountries = [
39890                     'hk',
39891                     'gb',
39892                     'us'
39893                 ];
39894             }
39895             
39896             var p = this.preferedCountries.reverse();
39897             
39898             if(p) {
39899                 for (var i = 0; i < p.length; i++) {
39900                     for (var j = 0; j < this.allCountries.length; j++) {
39901                         if(this.allCountries[j].iso2 == p[i]) {
39902                             var t = this.allCountries[j];
39903                             this.allCountries.splice(j,1);
39904                             this.allCountries.unshift(t);
39905                         }
39906                     } 
39907                 }
39908             }
39909             
39910             this.store.proxy.data = {
39911                 success: true,
39912                 data: this.allCountries
39913             };
39914             
39915             return cfg;
39916         },
39917         
39918         initEvents : function()
39919         {
39920             this.createList();
39921             Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39922             
39923             this.indicator = this.indicatorEl();
39924             this.flag = this.flagEl();
39925             this.dialCodeHolder = this.dialCodeHolderEl();
39926             
39927             this.trigger = this.el.select('div.flag-box',true).first();
39928             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39929             
39930             var _this = this;
39931             
39932             (function(){
39933                 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39934                 _this.list.setWidth(lw);
39935             }).defer(100);
39936             
39937             this.list.on('mouseover', this.onViewOver, this);
39938             this.list.on('mousemove', this.onViewMove, this);
39939             this.inputEl().on("keyup", this.onKeyUp, this);
39940             
39941             this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39942
39943             this.view = new Roo.View(this.list, this.tpl, {
39944                 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39945             });
39946             
39947             this.view.on('click', this.onViewClick, this);
39948             this.setValue(this.defaultDialCode);
39949         },
39950         
39951         onTriggerClick : function(e)
39952         {
39953             Roo.log('trigger click');
39954             if(this.disabled){
39955                 return;
39956             }
39957             
39958             if(this.isExpanded()){
39959                 this.collapse();
39960                 this.hasFocus = false;
39961             }else {
39962                 this.store.load({});
39963                 this.hasFocus = true;
39964                 this.expand();
39965             }
39966         },
39967         
39968         isExpanded : function()
39969         {
39970             return this.list.isVisible();
39971         },
39972         
39973         collapse : function()
39974         {
39975             if(!this.isExpanded()){
39976                 return;
39977             }
39978             this.list.hide();
39979             Roo.get(document).un('mousedown', this.collapseIf, this);
39980             Roo.get(document).un('mousewheel', this.collapseIf, this);
39981             this.fireEvent('collapse', this);
39982             this.validate();
39983         },
39984         
39985         expand : function()
39986         {
39987             Roo.log('expand');
39988
39989             if(this.isExpanded() || !this.hasFocus){
39990                 return;
39991             }
39992             
39993             var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39994             this.list.setWidth(lw);
39995             
39996             this.list.show();
39997             this.restrictHeight();
39998             
39999             Roo.get(document).on('mousedown', this.collapseIf, this);
40000             Roo.get(document).on('mousewheel', this.collapseIf, this);
40001             
40002             this.fireEvent('expand', this);
40003         },
40004         
40005         restrictHeight : function()
40006         {
40007             this.list.alignTo(this.inputEl(), this.listAlign);
40008             this.list.alignTo(this.inputEl(), this.listAlign);
40009         },
40010         
40011         onViewOver : function(e, t)
40012         {
40013             if(this.inKeyMode){
40014                 return;
40015             }
40016             var item = this.view.findItemFromChild(t);
40017             
40018             if(item){
40019                 var index = this.view.indexOf(item);
40020                 this.select(index, false);
40021             }
40022         },
40023
40024         // private
40025         onViewClick : function(view, doFocus, el, e)
40026         {
40027             var index = this.view.getSelectedIndexes()[0];
40028             
40029             var r = this.store.getAt(index);
40030             
40031             if(r){
40032                 this.onSelect(r, index);
40033             }
40034             if(doFocus !== false && !this.blockFocus){
40035                 this.inputEl().focus();
40036             }
40037         },
40038         
40039         onViewMove : function(e, t)
40040         {
40041             this.inKeyMode = false;
40042         },
40043         
40044         select : function(index, scrollIntoView)
40045         {
40046             this.selectedIndex = index;
40047             this.view.select(index);
40048             if(scrollIntoView !== false){
40049                 var el = this.view.getNode(index);
40050                 if(el){
40051                     this.list.scrollChildIntoView(el, false);
40052                 }
40053             }
40054         },
40055         
40056         createList : function()
40057         {
40058             this.list = Roo.get(document.body).createChild({
40059                 tag: 'ul',
40060                 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40061                 style: 'display:none'
40062             });
40063             
40064             this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40065         },
40066         
40067         collapseIf : function(e)
40068         {
40069             var in_combo  = e.within(this.el);
40070             var in_list =  e.within(this.list);
40071             var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40072             
40073             if (in_combo || in_list || is_list) {
40074                 return;
40075             }
40076             this.collapse();
40077         },
40078         
40079         onSelect : function(record, index)
40080         {
40081             if(this.fireEvent('beforeselect', this, record, index) !== false){
40082                 
40083                 this.setFlagClass(record.data.iso2);
40084                 this.setDialCode(record.data.dialCode);
40085                 this.hasFocus = false;
40086                 this.collapse();
40087                 this.fireEvent('select', this, record, index);
40088             }
40089         },
40090         
40091         flagEl : function()
40092         {
40093             var flag = this.el.select('div.flag',true).first();
40094             if(!flag){
40095                 return false;
40096             }
40097             return flag;
40098         },
40099         
40100         dialCodeHolderEl : function()
40101         {
40102             var d = this.el.select('input.dial-code-holder',true).first();
40103             if(!d){
40104                 return false;
40105             }
40106             return d;
40107         },
40108         
40109         setDialCode : function(v)
40110         {
40111             this.dialCodeHolder.dom.value = '+'+v;
40112         },
40113         
40114         setFlagClass : function(n)
40115         {
40116             this.flag.dom.className = 'flag '+n;
40117         },
40118         
40119         getValue : function()
40120         {
40121             var v = this.inputEl().getValue();
40122             if(this.dialCodeHolder) {
40123                 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40124             }
40125             return v;
40126         },
40127         
40128         setValue : function(v)
40129         {
40130             var d = this.getDialCode(v);
40131             
40132             //invalid dial code
40133             if(v.length == 0 || !d || d.length == 0) {
40134                 if(this.rendered){
40135                     this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40136                     this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40137                 }
40138                 return;
40139             }
40140             
40141             //valid dial code
40142             this.setFlagClass(this.dialCodeMapping[d].iso2);
40143             this.setDialCode(d);
40144             this.inputEl().dom.value = v.replace('+'+d,'');
40145             this.hiddenEl().dom.value = this.getValue();
40146             
40147             this.validate();
40148         },
40149         
40150         getDialCode : function(v)
40151         {
40152             v = v ||  '';
40153             
40154             if (v.length == 0) {
40155                 return this.dialCodeHolder.dom.value;
40156             }
40157             
40158             var dialCode = "";
40159             if (v.charAt(0) != "+") {
40160                 return false;
40161             }
40162             var numericChars = "";
40163             for (var i = 1; i < v.length; i++) {
40164               var c = v.charAt(i);
40165               if (!isNaN(c)) {
40166                 numericChars += c;
40167                 if (this.dialCodeMapping[numericChars]) {
40168                   dialCode = v.substr(1, i);
40169                 }
40170                 if (numericChars.length == 4) {
40171                   break;
40172                 }
40173               }
40174             }
40175             return dialCode;
40176         },
40177         
40178         reset : function()
40179         {
40180             this.setValue(this.defaultDialCode);
40181             this.validate();
40182         },
40183         
40184         hiddenEl : function()
40185         {
40186             return this.el.select('input.hidden-tel-input',true).first();
40187         },
40188         
40189         onKeyUp : function(e){
40190             
40191             var k = e.getKey();
40192             var c = e.getCharCode();
40193             
40194             if(
40195                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40196                     this.allowed.indexOf(String.fromCharCode(c)) === -1
40197             ){
40198                 e.stopEvent();
40199             }
40200             
40201             // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40202             //     return;
40203             // }
40204             if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40205                 e.stopEvent();
40206             }
40207             
40208             this.setValue(this.getValue());
40209         }
40210         
40211 });
40212 /**
40213  * @class Roo.bootstrap.MoneyField
40214  * @extends Roo.bootstrap.ComboBox
40215  * Bootstrap MoneyField class
40216  * 
40217  * @constructor
40218  * Create a new MoneyField.
40219  * @param {Object} config Configuration options
40220  */
40221
40222 Roo.bootstrap.MoneyField = function(config) {
40223     
40224     Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40225     
40226 };
40227
40228 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40229     
40230     /**
40231      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40232      */
40233     allowDecimals : true,
40234     /**
40235      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40236      */
40237     decimalSeparator : ".",
40238     /**
40239      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40240      */
40241     decimalPrecision : 0,
40242     /**
40243      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40244      */
40245     allowNegative : true,
40246     /**
40247      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40248      */
40249     allowZero: true,
40250     /**
40251      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40252      */
40253     minValue : Number.NEGATIVE_INFINITY,
40254     /**
40255      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40256      */
40257     maxValue : Number.MAX_VALUE,
40258     /**
40259      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40260      */
40261     minText : "The minimum value for this field is {0}",
40262     /**
40263      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40264      */
40265     maxText : "The maximum value for this field is {0}",
40266     /**
40267      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
40268      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40269      */
40270     nanText : "{0} is not a valid number",
40271     /**
40272      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40273      */
40274     castInt : true,
40275     /**
40276      * @cfg {String} defaults currency of the MoneyField
40277      * value should be in lkey
40278      */
40279     defaultCurrency : false,
40280     /**
40281      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40282      */
40283     thousandsDelimiter : false,
40284     
40285     
40286     inputlg : 9,
40287     inputmd : 9,
40288     inputsm : 9,
40289     inputxs : 6,
40290     
40291     store : false,
40292     
40293     getAutoCreate : function()
40294     {
40295         var align = this.labelAlign || this.parentLabelAlign();
40296         
40297         var id = Roo.id();
40298
40299         var cfg = {
40300             cls: 'form-group',
40301             cn: []
40302         };
40303
40304         var input =  {
40305             tag: 'input',
40306             id : id,
40307             cls : 'form-control roo-money-amount-input',
40308             autocomplete: 'new-password'
40309         };
40310         
40311         var hiddenInput = {
40312             tag: 'input',
40313             type: 'hidden',
40314             id: Roo.id(),
40315             cls: 'hidden-number-input'
40316         };
40317         
40318         if (this.name) {
40319             hiddenInput.name = this.name;
40320         }
40321
40322         if (this.disabled) {
40323             input.disabled = true;
40324         }
40325
40326         var clg = 12 - this.inputlg;
40327         var cmd = 12 - this.inputmd;
40328         var csm = 12 - this.inputsm;
40329         var cxs = 12 - this.inputxs;
40330         
40331         var container = {
40332             tag : 'div',
40333             cls : 'row roo-money-field',
40334             cn : [
40335                 {
40336                     tag : 'div',
40337                     cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40338                     cn : [
40339                         {
40340                             tag : 'div',
40341                             cls: 'roo-select2-container input-group',
40342                             cn: [
40343                                 {
40344                                     tag : 'input',
40345                                     cls : 'form-control roo-money-currency-input',
40346                                     autocomplete: 'new-password',
40347                                     readOnly : 1,
40348                                     name : this.currencyName
40349                                 },
40350                                 {
40351                                     tag :'span',
40352                                     cls : 'input-group-addon',
40353                                     cn : [
40354                                         {
40355                                             tag: 'span',
40356                                             cls: 'caret'
40357                                         }
40358                                     ]
40359                                 }
40360                             ]
40361                         }
40362                     ]
40363                 },
40364                 {
40365                     tag : 'div',
40366                     cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40367                     cn : [
40368                         {
40369                             tag: 'div',
40370                             cls: this.hasFeedback ? 'has-feedback' : '',
40371                             cn: [
40372                                 input
40373                             ]
40374                         }
40375                     ]
40376                 }
40377             ]
40378             
40379         };
40380         
40381         if (this.fieldLabel.length) {
40382             var indicator = {
40383                 tag: 'i',
40384                 tooltip: 'This field is required'
40385             };
40386
40387             var label = {
40388                 tag: 'label',
40389                 'for':  id,
40390                 cls: 'control-label',
40391                 cn: []
40392             };
40393
40394             var label_text = {
40395                 tag: 'span',
40396                 html: this.fieldLabel
40397             };
40398
40399             indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40400             label.cn = [
40401                 indicator,
40402                 label_text
40403             ];
40404
40405             if(this.indicatorpos == 'right') {
40406                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40407                 label.cn = [
40408                     label_text,
40409                     indicator
40410                 ];
40411             }
40412
40413             if(align == 'left') {
40414                 container = {
40415                     tag: 'div',
40416                     cn: [
40417                         container
40418                     ]
40419                 };
40420
40421                 if(this.labelWidth > 12){
40422                     label.style = "width: " + this.labelWidth + 'px';
40423                 }
40424                 if(this.labelWidth < 13 && this.labelmd == 0){
40425                     this.labelmd = this.labelWidth;
40426                 }
40427                 if(this.labellg > 0){
40428                     label.cls += ' col-lg-' + this.labellg;
40429                     input.cls += ' col-lg-' + (12 - this.labellg);
40430                 }
40431                 if(this.labelmd > 0){
40432                     label.cls += ' col-md-' + this.labelmd;
40433                     container.cls += ' col-md-' + (12 - this.labelmd);
40434                 }
40435                 if(this.labelsm > 0){
40436                     label.cls += ' col-sm-' + this.labelsm;
40437                     container.cls += ' col-sm-' + (12 - this.labelsm);
40438                 }
40439                 if(this.labelxs > 0){
40440                     label.cls += ' col-xs-' + this.labelxs;
40441                     container.cls += ' col-xs-' + (12 - this.labelxs);
40442                 }
40443             }
40444         }
40445
40446         cfg.cn = [
40447             label,
40448             container,
40449             hiddenInput
40450         ];
40451         
40452         var settings = this;
40453
40454         ['xs','sm','md','lg'].map(function(size){
40455             if (settings[size]) {
40456                 cfg.cls += ' col-' + size + '-' + settings[size];
40457             }
40458         });
40459         
40460         return cfg;
40461     },
40462     
40463     initEvents : function()
40464     {
40465         this.indicator = this.indicatorEl();
40466         
40467         this.initCurrencyEvent();
40468         
40469         this.initNumberEvent();
40470     },
40471     
40472     initCurrencyEvent : function()
40473     {
40474         if (!this.store) {
40475             throw "can not find store for combo";
40476         }
40477         
40478         this.store = Roo.factory(this.store, Roo.data);
40479         this.store.parent = this;
40480         
40481         this.createList();
40482         
40483         this.triggerEl = this.el.select('.input-group-addon', true).first();
40484         
40485         this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40486         
40487         var _this = this;
40488         
40489         (function(){
40490             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40491             _this.list.setWidth(lw);
40492         }).defer(100);
40493         
40494         this.list.on('mouseover', this.onViewOver, this);
40495         this.list.on('mousemove', this.onViewMove, this);
40496         this.list.on('scroll', this.onViewScroll, this);
40497         
40498         if(!this.tpl){
40499             this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40500         }
40501         
40502         this.view = new Roo.View(this.list, this.tpl, {
40503             singleSelect:true, store: this.store, selectedClass: this.selectedClass
40504         });
40505         
40506         this.view.on('click', this.onViewClick, this);
40507         
40508         this.store.on('beforeload', this.onBeforeLoad, this);
40509         this.store.on('load', this.onLoad, this);
40510         this.store.on('loadexception', this.onLoadException, this);
40511         
40512         this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40513             "up" : function(e){
40514                 this.inKeyMode = true;
40515                 this.selectPrev();
40516             },
40517
40518             "down" : function(e){
40519                 if(!this.isExpanded()){
40520                     this.onTriggerClick();
40521                 }else{
40522                     this.inKeyMode = true;
40523                     this.selectNext();
40524                 }
40525             },
40526
40527             "enter" : function(e){
40528                 this.collapse();
40529                 
40530                 if(this.fireEvent("specialkey", this, e)){
40531                     this.onViewClick(false);
40532                 }
40533                 
40534                 return true;
40535             },
40536
40537             "esc" : function(e){
40538                 this.collapse();
40539             },
40540
40541             "tab" : function(e){
40542                 this.collapse();
40543                 
40544                 if(this.fireEvent("specialkey", this, e)){
40545                     this.onViewClick(false);
40546                 }
40547                 
40548                 return true;
40549             },
40550
40551             scope : this,
40552
40553             doRelay : function(foo, bar, hname){
40554                 if(hname == 'down' || this.scope.isExpanded()){
40555                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40556                 }
40557                 return true;
40558             },
40559
40560             forceKeyDown: true
40561         });
40562         
40563         this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40564         
40565     },
40566     
40567     initNumberEvent : function(e)
40568     {
40569         this.inputEl().on("keydown" , this.fireKey,  this);
40570         this.inputEl().on("focus", this.onFocus,  this);
40571         this.inputEl().on("blur", this.onBlur,  this);
40572         
40573         this.inputEl().relayEvent('keyup', this);
40574         
40575         if(this.indicator){
40576             this.indicator.addClass('invisible');
40577         }
40578  
40579         this.originalValue = this.getValue();
40580         
40581         if(this.validationEvent == 'keyup'){
40582             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40583             this.inputEl().on('keyup', this.filterValidation, this);
40584         }
40585         else if(this.validationEvent !== false){
40586             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40587         }
40588         
40589         if(this.selectOnFocus){
40590             this.on("focus", this.preFocus, this);
40591             
40592         }
40593         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40594             this.inputEl().on("keypress", this.filterKeys, this);
40595         } else {
40596             this.inputEl().relayEvent('keypress', this);
40597         }
40598         
40599         var allowed = "0123456789";
40600         
40601         if(this.allowDecimals){
40602             allowed += this.decimalSeparator;
40603         }
40604         
40605         if(this.allowNegative){
40606             allowed += "-";
40607         }
40608         
40609         if(this.thousandsDelimiter) {
40610             allowed += ",";
40611         }
40612         
40613         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40614         
40615         var keyPress = function(e){
40616             
40617             var k = e.getKey();
40618             
40619             var c = e.getCharCode();
40620             
40621             if(
40622                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40623                     allowed.indexOf(String.fromCharCode(c)) === -1
40624             ){
40625                 e.stopEvent();
40626                 return;
40627             }
40628             
40629             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40630                 return;
40631             }
40632             
40633             if(allowed.indexOf(String.fromCharCode(c)) === -1){
40634                 e.stopEvent();
40635             }
40636         };
40637         
40638         this.inputEl().on("keypress", keyPress, this);
40639         
40640     },
40641     
40642     onTriggerClick : function(e)
40643     {   
40644         if(this.disabled){
40645             return;
40646         }
40647         
40648         this.page = 0;
40649         this.loadNext = false;
40650         
40651         if(this.isExpanded()){
40652             this.collapse();
40653             return;
40654         }
40655         
40656         this.hasFocus = true;
40657         
40658         if(this.triggerAction == 'all') {
40659             this.doQuery(this.allQuery, true);
40660             return;
40661         }
40662         
40663         this.doQuery(this.getRawValue());
40664     },
40665     
40666     getCurrency : function()
40667     {   
40668         var v = this.currencyEl().getValue();
40669         
40670         return v;
40671     },
40672     
40673     restrictHeight : function()
40674     {
40675         this.list.alignTo(this.currencyEl(), this.listAlign);
40676         this.list.alignTo(this.currencyEl(), this.listAlign);
40677     },
40678     
40679     onViewClick : function(view, doFocus, el, e)
40680     {
40681         var index = this.view.getSelectedIndexes()[0];
40682         
40683         var r = this.store.getAt(index);
40684         
40685         if(r){
40686             this.onSelect(r, index);
40687         }
40688     },
40689     
40690     onSelect : function(record, index){
40691         
40692         if(this.fireEvent('beforeselect', this, record, index) !== false){
40693         
40694             this.setFromCurrencyData(index > -1 ? record.data : false);
40695             
40696             this.collapse();
40697             
40698             this.fireEvent('select', this, record, index);
40699         }
40700     },
40701     
40702     setFromCurrencyData : function(o)
40703     {
40704         var currency = '';
40705         
40706         this.lastCurrency = o;
40707         
40708         if (this.currencyField) {
40709             currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40710         } else {
40711             Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
40712         }
40713         
40714         this.lastSelectionText = currency;
40715         
40716         //setting default currency
40717         if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40718             this.setCurrency(this.defaultCurrency);
40719             return;
40720         }
40721         
40722         this.setCurrency(currency);
40723     },
40724     
40725     setFromData : function(o)
40726     {
40727         var c = {};
40728         
40729         c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40730         
40731         this.setFromCurrencyData(c);
40732         
40733         var value = '';
40734         
40735         if (this.name) {
40736             value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40737         } else {
40738             Roo.log('no value set for '+ (this.name ? this.name : this.id));
40739         }
40740         
40741         this.setValue(value);
40742         
40743     },
40744     
40745     setCurrency : function(v)
40746     {   
40747         this.currencyValue = v;
40748         
40749         if(this.rendered){
40750             this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40751             this.validate();
40752         }
40753     },
40754     
40755     setValue : function(v)
40756     {
40757         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40758         
40759         this.value = v;
40760         
40761         if(this.rendered){
40762             
40763             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40764             
40765             this.inputEl().dom.value = (v == '') ? '' :
40766                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40767             
40768             if(!this.allowZero && v === '0') {
40769                 this.hiddenEl().dom.value = '';
40770                 this.inputEl().dom.value = '';
40771             }
40772             
40773             this.validate();
40774         }
40775     },
40776     
40777     getRawValue : function()
40778     {
40779         var v = this.inputEl().getValue();
40780         
40781         return v;
40782     },
40783     
40784     getValue : function()
40785     {
40786         return this.fixPrecision(this.parseValue(this.getRawValue()));
40787     },
40788     
40789     parseValue : function(value)
40790     {
40791         if(this.thousandsDelimiter) {
40792             value += "";
40793             r = new RegExp(",", "g");
40794             value = value.replace(r, "");
40795         }
40796         
40797         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40798         return isNaN(value) ? '' : value;
40799         
40800     },
40801     
40802     fixPrecision : function(value)
40803     {
40804         if(this.thousandsDelimiter) {
40805             value += "";
40806             r = new RegExp(",", "g");
40807             value = value.replace(r, "");
40808         }
40809         
40810         var nan = isNaN(value);
40811         
40812         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40813             return nan ? '' : value;
40814         }
40815         return parseFloat(value).toFixed(this.decimalPrecision);
40816     },
40817     
40818     decimalPrecisionFcn : function(v)
40819     {
40820         return Math.floor(v);
40821     },
40822     
40823     validateValue : function(value)
40824     {
40825         if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40826             return false;
40827         }
40828         
40829         var num = this.parseValue(value);
40830         
40831         if(isNaN(num)){
40832             this.markInvalid(String.format(this.nanText, value));
40833             return false;
40834         }
40835         
40836         if(num < this.minValue){
40837             this.markInvalid(String.format(this.minText, this.minValue));
40838             return false;
40839         }
40840         
40841         if(num > this.maxValue){
40842             this.markInvalid(String.format(this.maxText, this.maxValue));
40843             return false;
40844         }
40845         
40846         return true;
40847     },
40848     
40849     validate : function()
40850     {
40851         if(this.disabled || this.allowBlank){
40852             this.markValid();
40853             return true;
40854         }
40855         
40856         var currency = this.getCurrency();
40857         
40858         if(this.validateValue(this.getRawValue()) && currency.length){
40859             this.markValid();
40860             return true;
40861         }
40862         
40863         this.markInvalid();
40864         return false;
40865     },
40866     
40867     getName: function()
40868     {
40869         return this.name;
40870     },
40871     
40872     beforeBlur : function()
40873     {
40874         if(!this.castInt){
40875             return;
40876         }
40877         
40878         var v = this.parseValue(this.getRawValue());
40879         
40880         if(v || v == 0){
40881             this.setValue(v);
40882         }
40883     },
40884     
40885     onBlur : function()
40886     {
40887         this.beforeBlur();
40888         
40889         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40890             //this.el.removeClass(this.focusClass);
40891         }
40892         
40893         this.hasFocus = false;
40894         
40895         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40896             this.validate();
40897         }
40898         
40899         var v = this.getValue();
40900         
40901         if(String(v) !== String(this.startValue)){
40902             this.fireEvent('change', this, v, this.startValue);
40903         }
40904         
40905         this.fireEvent("blur", this);
40906     },
40907     
40908     inputEl : function()
40909     {
40910         return this.el.select('.roo-money-amount-input', true).first();
40911     },
40912     
40913     currencyEl : function()
40914     {
40915         return this.el.select('.roo-money-currency-input', true).first();
40916     },
40917     
40918     hiddenEl : function()
40919     {
40920         return this.el.select('input.hidden-number-input',true).first();
40921     }
40922     
40923 });