Roo/bootstrap/Menu.js
[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         
2228         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2229     },
2230      /**
2231      * Displays this menu at a specific xy position
2232      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2233      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2234      */
2235     showAt : function(xy, parentMenu, /* private: */_e){
2236         this.parentMenu = parentMenu;
2237         if(!this.el){
2238             this.render();
2239         }
2240         if(_e !== false){
2241             this.fireEvent("beforeshow", this);
2242             // xy = this.el.adjustForConstraints(xy);
2243         }
2244         
2245         //this.el.show();
2246         this.hideMenuItems();
2247         this.hidden = false;
2248         this.triggerEl.addClass('open');
2249         
2250         xy = this.el.getAlignToXY(this.triggerEl, '?');
2251         
2252         Roo.log(this.el.getWidth());
2253         Roo.log(xy[0]);
2254         Roo.log(Roo.lib.Dom.getViewWidth());
2255         
2256         if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2257             xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2258         }
2259         
2260         // xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2261         
2262         if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2263             this.el.setXY(xy);
2264         }
2265         
2266         this.focus();
2267         this.fireEvent("show", this);
2268     },
2269     
2270     focus : function(){
2271         return;
2272         if(!this.hidden){
2273             this.doFocus.defer(50, this);
2274         }
2275     },
2276
2277     doFocus : function(){
2278         if(!this.hidden){
2279             this.focusEl.focus();
2280         }
2281     },
2282
2283     /**
2284      * Hides this menu and optionally all parent menus
2285      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2286      */
2287     hide : function(deep)
2288     {
2289         
2290         this.hideMenuItems();
2291         if(this.el && this.isVisible()){
2292             this.fireEvent("beforehide", this);
2293             if(this.activeItem){
2294                 this.activeItem.deactivate();
2295                 this.activeItem = null;
2296             }
2297             this.triggerEl.removeClass('open');;
2298             this.hidden = true;
2299             this.fireEvent("hide", this);
2300         }
2301         if(deep === true && this.parentMenu){
2302             this.parentMenu.hide(true);
2303         }
2304     },
2305     
2306     onTriggerClick : function(e)
2307     {
2308         Roo.log('trigger click');
2309         
2310         var target = e.getTarget();
2311         
2312         Roo.log(target.nodeName.toLowerCase());
2313         
2314         if(target.nodeName.toLowerCase() === 'i'){
2315             e.preventDefault();
2316         }
2317         
2318     },
2319     
2320     onTriggerPress  : function(e)
2321     {
2322         Roo.log('trigger press');
2323         //Roo.log(e.getTarget());
2324        // Roo.log(this.triggerEl.dom);
2325        
2326         // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2327         var pel = Roo.get(e.getTarget());
2328         if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2329             Roo.log('is treeview or dropdown?');
2330             return;
2331         }
2332         
2333         if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2334             return;
2335         }
2336         
2337         if (this.isVisible()) {
2338             Roo.log('hide');
2339             this.hide();
2340         } else {
2341             Roo.log('show');
2342             this.show(this.triggerEl, false, false);
2343         }
2344         
2345         if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2346             e.stopEvent();
2347         }
2348         
2349     },
2350        
2351     
2352     hideMenuItems : function()
2353     {
2354         Roo.log("hide Menu Items");
2355         if (!this.el) { 
2356             return;
2357         }
2358         //$(backdrop).remove()
2359         this.el.select('.open',true).each(function(aa) {
2360             
2361             aa.removeClass('open');
2362           //var parent = getParent($(this))
2363           //var relatedTarget = { relatedTarget: this }
2364           
2365            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2366           //if (e.isDefaultPrevented()) return
2367            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2368         });
2369     },
2370     addxtypeChild : function (tree, cntr) {
2371         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2372           
2373         this.menuitems.add(comp);
2374         return comp;
2375
2376     },
2377     getEl : function()
2378     {
2379         Roo.log(this.el);
2380         return this.el;
2381     },
2382     
2383     clear : function()
2384     {
2385         this.getEl().dom.innerHTML = '';
2386         this.menuitems.clear();
2387     }
2388 });
2389
2390  
2391  /*
2392  * - LGPL
2393  *
2394  * menu item
2395  * 
2396  */
2397
2398
2399 /**
2400  * @class Roo.bootstrap.MenuItem
2401  * @extends Roo.bootstrap.Component
2402  * Bootstrap MenuItem class
2403  * @cfg {String} html the menu label
2404  * @cfg {String} href the link
2405  * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2406  * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2407  * @cfg {Boolean} active  used on sidebars to highlight active itesm
2408  * @cfg {String} fa favicon to show on left of menu item.
2409  * @cfg {Roo.bootsrap.Menu} menu the child menu.
2410  * 
2411  * 
2412  * @constructor
2413  * Create a new MenuItem
2414  * @param {Object} config The config object
2415  */
2416
2417
2418 Roo.bootstrap.MenuItem = function(config){
2419     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2420     this.addEvents({
2421         // raw events
2422         /**
2423          * @event click
2424          * The raw click event for the entire grid.
2425          * @param {Roo.bootstrap.MenuItem} this
2426          * @param {Roo.EventObject} e
2427          */
2428         "click" : true
2429     });
2430 };
2431
2432 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
2433     
2434     href : false,
2435     html : false,
2436     preventDefault: false,
2437     isContainer : false,
2438     active : false,
2439     fa: false,
2440     
2441     getAutoCreate : function(){
2442         
2443         if(this.isContainer){
2444             return {
2445                 tag: 'li',
2446                 cls: 'dropdown-menu-item'
2447             };
2448         }
2449         var ctag = {
2450             tag: 'span',
2451             html: 'Link'
2452         };
2453         
2454         var anc = {
2455             tag : 'a',
2456             href : '#',
2457             cn : [  ]
2458         };
2459         
2460         if (this.fa !== false) {
2461             anc.cn.push({
2462                 tag : 'i',
2463                 cls : 'fa fa-' + this.fa
2464             });
2465         }
2466         
2467         anc.cn.push(ctag);
2468         
2469         
2470         var cfg= {
2471             tag: 'li',
2472             cls: 'dropdown-menu-item',
2473             cn: [ anc ]
2474         };
2475         if (this.parent().type == 'treeview') {
2476             cfg.cls = 'treeview-menu';
2477         }
2478         if (this.active) {
2479             cfg.cls += ' active';
2480         }
2481         
2482         
2483         
2484         anc.href = this.href || cfg.cn[0].href ;
2485         ctag.html = this.html || cfg.cn[0].html ;
2486         return cfg;
2487     },
2488     
2489     initEvents: function()
2490     {
2491         if (this.parent().type == 'treeview') {
2492             this.el.select('a').on('click', this.onClick, this);
2493         }
2494         
2495         if (this.menu) {
2496             this.menu.parentType = this.xtype;
2497             this.menu.triggerEl = this.el;
2498             this.menu = this.addxtype(Roo.apply({}, this.menu));
2499         }
2500         
2501     },
2502     onClick : function(e)
2503     {
2504         Roo.log('item on click ');
2505         
2506         if(this.preventDefault){
2507             e.preventDefault();
2508         }
2509         //this.parent().hideMenuItems();
2510         
2511         this.fireEvent('click', this, e);
2512     },
2513     getEl : function()
2514     {
2515         return this.el;
2516     } 
2517 });
2518
2519  
2520
2521  /*
2522  * - LGPL
2523  *
2524  * menu separator
2525  * 
2526  */
2527
2528
2529 /**
2530  * @class Roo.bootstrap.MenuSeparator
2531  * @extends Roo.bootstrap.Component
2532  * Bootstrap MenuSeparator class
2533  * 
2534  * @constructor
2535  * Create a new MenuItem
2536  * @param {Object} config The config object
2537  */
2538
2539
2540 Roo.bootstrap.MenuSeparator = function(config){
2541     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2542 };
2543
2544 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2545     
2546     getAutoCreate : function(){
2547         var cfg = {
2548             cls: 'divider',
2549             tag : 'li'
2550         };
2551         
2552         return cfg;
2553     }
2554    
2555 });
2556
2557  
2558
2559  
2560 /*
2561 * Licence: LGPL
2562 */
2563
2564 /**
2565  * @class Roo.bootstrap.Modal
2566  * @extends Roo.bootstrap.Component
2567  * Bootstrap Modal class
2568  * @cfg {String} title Title of dialog
2569  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2570  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn
2571  * @cfg {Boolean} specificTitle default false
2572  * @cfg {Array} buttons Array of buttons or standard button set..
2573  * @cfg {String} buttonPosition (left|right|center) default right
2574  * @cfg {Boolean} animate default true
2575  * @cfg {Boolean} allow_close default true
2576  * @cfg {Boolean} fitwindow default false
2577  * @cfg {String} size (sm|lg) default empty
2578  *
2579  *
2580  * @constructor
2581  * Create a new Modal Dialog
2582  * @param {Object} config The config object
2583  */
2584
2585 Roo.bootstrap.Modal = function(config){
2586     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2587     this.addEvents({
2588         // raw events
2589         /**
2590          * @event btnclick
2591          * The raw btnclick event for the button
2592          * @param {Roo.EventObject} e
2593          */
2594         "btnclick" : true,
2595         /**
2596          * @event resize
2597          * Fire when dialog resize
2598          * @param {Roo.bootstrap.Modal} this
2599          * @param {Roo.EventObject} e
2600          */
2601         "resize" : true
2602     });
2603     this.buttons = this.buttons || [];
2604
2605     if (this.tmpl) {
2606         this.tmpl = Roo.factory(this.tmpl);
2607     }
2608
2609 };
2610
2611 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2612
2613     title : 'test dialog',
2614
2615     buttons : false,
2616
2617     // set on load...
2618
2619     html: false,
2620
2621     tmp: false,
2622
2623     specificTitle: false,
2624
2625     buttonPosition: 'right',
2626
2627     allow_close : true,
2628
2629     animate : true,
2630
2631     fitwindow: false,
2632
2633
2634      // private
2635     dialogEl: false,
2636     bodyEl:  false,
2637     footerEl:  false,
2638     titleEl:  false,
2639     closeEl:  false,
2640
2641     size: '',
2642
2643
2644     onRender : function(ct, position)
2645     {
2646         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2647
2648         if(!this.el){
2649             var cfg = Roo.apply({},  this.getAutoCreate());
2650             cfg.id = Roo.id();
2651             //if(!cfg.name){
2652             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2653             //}
2654             //if (!cfg.name.length) {
2655             //    delete cfg.name;
2656            // }
2657             if (this.cls) {
2658                 cfg.cls += ' ' + this.cls;
2659             }
2660             if (this.style) {
2661                 cfg.style = this.style;
2662             }
2663             this.el = Roo.get(document.body).createChild(cfg, position);
2664         }
2665         //var type = this.el.dom.type;
2666
2667
2668         if(this.tabIndex !== undefined){
2669             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2670         }
2671
2672         this.dialogEl = this.el.select('.modal-dialog',true).first();
2673         this.bodyEl = this.el.select('.modal-body',true).first();
2674         this.closeEl = this.el.select('.modal-header .close', true).first();
2675         this.headerEl = this.el.select('.modal-header',true).first();
2676         this.titleEl = this.el.select('.modal-title',true).first();
2677         this.footerEl = this.el.select('.modal-footer',true).first();
2678
2679         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2680         
2681         //this.el.addClass("x-dlg-modal");
2682
2683         if (this.buttons.length) {
2684             Roo.each(this.buttons, function(bb) {
2685                 var b = Roo.apply({}, bb);
2686                 b.xns = b.xns || Roo.bootstrap;
2687                 b.xtype = b.xtype || 'Button';
2688                 if (typeof(b.listeners) == 'undefined') {
2689                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2690                 }
2691
2692                 var btn = Roo.factory(b);
2693
2694                 btn.render(this.el.select('.modal-footer div').first());
2695
2696             },this);
2697         }
2698         // render the children.
2699         var nitems = [];
2700
2701         if(typeof(this.items) != 'undefined'){
2702             var items = this.items;
2703             delete this.items;
2704
2705             for(var i =0;i < items.length;i++) {
2706                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2707             }
2708         }
2709
2710         this.items = nitems;
2711
2712         // where are these used - they used to be body/close/footer
2713
2714
2715         this.initEvents();
2716         //this.el.addClass([this.fieldClass, this.cls]);
2717
2718     },
2719
2720     getAutoCreate : function(){
2721
2722
2723         var bdy = {
2724                 cls : 'modal-body',
2725                 html : this.html || ''
2726         };
2727
2728         var title = {
2729             tag: 'h4',
2730             cls : 'modal-title',
2731             html : this.title
2732         };
2733
2734         if(this.specificTitle){
2735             title = this.title;
2736
2737         };
2738
2739         var header = [];
2740         if (this.allow_close) {
2741             header.push({
2742                 tag: 'button',
2743                 cls : 'close',
2744                 html : '&times'
2745             });
2746         }
2747
2748         header.push(title);
2749
2750         var size = '';
2751
2752         if(this.size.length){
2753             size = 'modal-' + this.size;
2754         }
2755
2756         var modal = {
2757             cls: "modal",
2758              cn : [
2759                 {
2760                     cls: "modal-dialog " + size,
2761                     cn : [
2762                         {
2763                             cls : "modal-content",
2764                             cn : [
2765                                 {
2766                                     cls : 'modal-header',
2767                                     cn : header
2768                                 },
2769                                 bdy,
2770                                 {
2771                                     cls : 'modal-footer',
2772                                     cn : [
2773                                         {
2774                                             tag: 'div',
2775                                             cls: 'btn-' + this.buttonPosition
2776                                         }
2777                                     ]
2778
2779                                 }
2780
2781
2782                             ]
2783
2784                         }
2785                     ]
2786
2787                 }
2788             ]
2789         };
2790
2791         if(this.animate){
2792             modal.cls += ' fade';
2793         }
2794
2795         return modal;
2796
2797     },
2798     getChildContainer : function() {
2799
2800          return this.bodyEl;
2801
2802     },
2803     getButtonContainer : function() {
2804          return this.el.select('.modal-footer div',true).first();
2805
2806     },
2807     initEvents : function()
2808     {
2809         if (this.allow_close) {
2810             this.closeEl.on('click', this.hide, this);
2811         }
2812         Roo.EventManager.onWindowResize(this.resize, this, true);
2813
2814
2815     },
2816
2817     resize : function()
2818     {
2819         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),  Roo.lib.Dom.getViewHeight(true));
2820         if (this.fitwindow) {
2821             var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2822             var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2823             this.setSize(w,h);
2824         }
2825     },
2826
2827     setSize : function(w,h)
2828     {
2829         if (!w && !h) {
2830             return;
2831         }
2832         this.resizeTo(w,h);
2833     },
2834
2835     show : function() {
2836
2837         if (!this.rendered) {
2838             this.render();
2839         }
2840
2841         //this.el.setStyle('display', 'block');
2842         this.el.removeClass('hideing');        
2843         this.el.addClass('show');
2844  
2845         if(this.animate){  // element has 'fade'  - so stuff happens after .3s ?- not sure why the delay?
2846             var _this = this;
2847             (function(){
2848                 this.el.addClass('in');
2849             }).defer(50, this);
2850         }else{
2851             this.el.addClass('in');
2852
2853         }
2854
2855         // not sure how we can show data in here..
2856         //if (this.tmpl) {
2857         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2858         //}
2859
2860         Roo.get(document.body).addClass("x-body-masked");
2861         
2862         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),   Roo.lib.Dom.getViewHeight(true));
2863         this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2864         this.maskEl.addClass('show');
2865         
2866         this.resize();
2867         
2868         this.fireEvent('show', this);
2869
2870         // set zindex here - otherwise it appears to be ignored...
2871         this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2872
2873         (function () {
2874             this.items.forEach( function(e) {
2875                 e.layout ? e.layout() : false;
2876
2877             });
2878         }).defer(100,this);
2879
2880     },
2881     hide : function()
2882     {
2883         if(this.fireEvent("beforehide", this) !== false){
2884             this.maskEl.removeClass('show');
2885             Roo.get(document.body).removeClass("x-body-masked");
2886             this.el.removeClass('in');
2887             this.el.select('.modal-dialog', true).first().setStyle('transform','');
2888
2889             if(this.animate){ // why
2890                 this.el.addClass('hideing');
2891                 (function(){
2892                     if (!this.el.hasClass('hideing')) {
2893                         return; // it's been shown again...
2894                     }
2895                     this.el.removeClass('show');
2896                     this.el.removeClass('hideing');
2897                 }).defer(150,this);
2898                 
2899             }else{
2900                  this.el.removeClass('show');
2901             }
2902             this.fireEvent('hide', this);
2903         }
2904     },
2905     isVisible : function()
2906     {
2907         
2908         return this.el.hasClass('show') && !this.el.hasClass('hideing');
2909         
2910     },
2911
2912     addButton : function(str, cb)
2913     {
2914
2915
2916         var b = Roo.apply({}, { html : str } );
2917         b.xns = b.xns || Roo.bootstrap;
2918         b.xtype = b.xtype || 'Button';
2919         if (typeof(b.listeners) == 'undefined') {
2920             b.listeners = { click : cb.createDelegate(this)  };
2921         }
2922
2923         var btn = Roo.factory(b);
2924
2925         btn.render(this.el.select('.modal-footer div').first());
2926
2927         return btn;
2928
2929     },
2930
2931     setDefaultButton : function(btn)
2932     {
2933         //this.el.select('.modal-footer').()
2934     },
2935     diff : false,
2936
2937     resizeTo: function(w,h)
2938     {
2939         // skip.. ?? why??
2940
2941         this.dialogEl.setWidth(w);
2942         if (this.diff === false) {
2943             this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2944         }
2945
2946         this.bodyEl.setHeight(h-this.diff);
2947
2948         this.fireEvent('resize', this);
2949
2950     },
2951     setContentSize  : function(w, h)
2952     {
2953
2954     },
2955     onButtonClick: function(btn,e)
2956     {
2957         //Roo.log([a,b,c]);
2958         this.fireEvent('btnclick', btn.name, e);
2959     },
2960      /**
2961      * Set the title of the Dialog
2962      * @param {String} str new Title
2963      */
2964     setTitle: function(str) {
2965         this.titleEl.dom.innerHTML = str;
2966     },
2967     /**
2968      * Set the body of the Dialog
2969      * @param {String} str new Title
2970      */
2971     setBody: function(str) {
2972         this.bodyEl.dom.innerHTML = str;
2973     },
2974     /**
2975      * Set the body of the Dialog using the template
2976      * @param {Obj} data - apply this data to the template and replace the body contents.
2977      */
2978     applyBody: function(obj)
2979     {
2980         if (!this.tmpl) {
2981             Roo.log("Error - using apply Body without a template");
2982             //code
2983         }
2984         this.tmpl.overwrite(this.bodyEl, obj);
2985     }
2986
2987 });
2988
2989
2990 Roo.apply(Roo.bootstrap.Modal,  {
2991     /**
2992          * Button config that displays a single OK button
2993          * @type Object
2994          */
2995         OK :  [{
2996             name : 'ok',
2997             weight : 'primary',
2998             html : 'OK'
2999         }],
3000         /**
3001          * Button config that displays Yes and No buttons
3002          * @type Object
3003          */
3004         YESNO : [
3005             {
3006                 name  : 'no',
3007                 html : 'No'
3008             },
3009             {
3010                 name  :'yes',
3011                 weight : 'primary',
3012                 html : 'Yes'
3013             }
3014         ],
3015
3016         /**
3017          * Button config that displays OK and Cancel buttons
3018          * @type Object
3019          */
3020         OKCANCEL : [
3021             {
3022                name : 'cancel',
3023                 html : 'Cancel'
3024             },
3025             {
3026                 name : 'ok',
3027                 weight : 'primary',
3028                 html : 'OK'
3029             }
3030         ],
3031         /**
3032          * Button config that displays Yes, No and Cancel buttons
3033          * @type Object
3034          */
3035         YESNOCANCEL : [
3036             {
3037                 name : 'yes',
3038                 weight : 'primary',
3039                 html : 'Yes'
3040             },
3041             {
3042                 name : 'no',
3043                 html : 'No'
3044             },
3045             {
3046                 name : 'cancel',
3047                 html : 'Cancel'
3048             }
3049         ],
3050         
3051         zIndex : 10001
3052 });
3053 /*
3054  * - LGPL
3055  *
3056  * messagebox - can be used as a replace
3057  * 
3058  */
3059 /**
3060  * @class Roo.MessageBox
3061  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
3062  * Example usage:
3063  *<pre><code>
3064 // Basic alert:
3065 Roo.Msg.alert('Status', 'Changes saved successfully.');
3066
3067 // Prompt for user data:
3068 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3069     if (btn == 'ok'){
3070         // process text value...
3071     }
3072 });
3073
3074 // Show a dialog using config options:
3075 Roo.Msg.show({
3076    title:'Save Changes?',
3077    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3078    buttons: Roo.Msg.YESNOCANCEL,
3079    fn: processResult,
3080    animEl: 'elId'
3081 });
3082 </code></pre>
3083  * @singleton
3084  */
3085 Roo.bootstrap.MessageBox = function(){
3086     var dlg, opt, mask, waitTimer;
3087     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3088     var buttons, activeTextEl, bwidth;
3089
3090     
3091     // private
3092     var handleButton = function(button){
3093         dlg.hide();
3094         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3095     };
3096
3097     // private
3098     var handleHide = function(){
3099         if(opt && opt.cls){
3100             dlg.el.removeClass(opt.cls);
3101         }
3102         //if(waitTimer){
3103         //    Roo.TaskMgr.stop(waitTimer);
3104         //    waitTimer = null;
3105         //}
3106     };
3107
3108     // private
3109     var updateButtons = function(b){
3110         var width = 0;
3111         if(!b){
3112             buttons["ok"].hide();
3113             buttons["cancel"].hide();
3114             buttons["yes"].hide();
3115             buttons["no"].hide();
3116             //dlg.footer.dom.style.display = 'none';
3117             return width;
3118         }
3119         dlg.footerEl.dom.style.display = '';
3120         for(var k in buttons){
3121             if(typeof buttons[k] != "function"){
3122                 if(b[k]){
3123                     buttons[k].show();
3124                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3125                     width += buttons[k].el.getWidth()+15;
3126                 }else{
3127                     buttons[k].hide();
3128                 }
3129             }
3130         }
3131         return width;
3132     };
3133
3134     // private
3135     var handleEsc = function(d, k, e){
3136         if(opt && opt.closable !== false){
3137             dlg.hide();
3138         }
3139         if(e){
3140             e.stopEvent();
3141         }
3142     };
3143
3144     return {
3145         /**
3146          * Returns a reference to the underlying {@link Roo.BasicDialog} element
3147          * @return {Roo.BasicDialog} The BasicDialog element
3148          */
3149         getDialog : function(){
3150            if(!dlg){
3151                 dlg = new Roo.bootstrap.Modal( {
3152                     //draggable: true,
3153                     //resizable:false,
3154                     //constraintoviewport:false,
3155                     //fixedcenter:true,
3156                     //collapsible : false,
3157                     //shim:true,
3158                     //modal: true,
3159                 //    width: 'auto',
3160                   //  height:100,
3161                     //buttonAlign:"center",
3162                     closeClick : function(){
3163                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3164                             handleButton("no");
3165                         }else{
3166                             handleButton("cancel");
3167                         }
3168                     }
3169                 });
3170                 dlg.render();
3171                 dlg.on("hide", handleHide);
3172                 mask = dlg.mask;
3173                 //dlg.addKeyListener(27, handleEsc);
3174                 buttons = {};
3175                 this.buttons = buttons;
3176                 var bt = this.buttonText;
3177                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3178                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3179                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3180                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3181                 //Roo.log(buttons);
3182                 bodyEl = dlg.bodyEl.createChild({
3183
3184                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3185                         '<textarea class="roo-mb-textarea"></textarea>' +
3186                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
3187                 });
3188                 msgEl = bodyEl.dom.firstChild;
3189                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3190                 textboxEl.enableDisplayMode();
3191                 textboxEl.addKeyListener([10,13], function(){
3192                     if(dlg.isVisible() && opt && opt.buttons){
3193                         if(opt.buttons.ok){
3194                             handleButton("ok");
3195                         }else if(opt.buttons.yes){
3196                             handleButton("yes");
3197                         }
3198                     }
3199                 });
3200                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3201                 textareaEl.enableDisplayMode();
3202                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3203                 progressEl.enableDisplayMode();
3204                 
3205                 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3206                 var pf = progressEl.dom.firstChild;
3207                 if (pf) {
3208                     pp = Roo.get(pf.firstChild);
3209                     pp.setHeight(pf.offsetHeight);
3210                 }
3211                 
3212             }
3213             return dlg;
3214         },
3215
3216         /**
3217          * Updates the message box body text
3218          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3219          * the XHTML-compliant non-breaking space character '&amp;#160;')
3220          * @return {Roo.MessageBox} This message box
3221          */
3222         updateText : function(text)
3223         {
3224             if(!dlg.isVisible() && !opt.width){
3225                 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3226                 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3227             }
3228             msgEl.innerHTML = text || '&#160;';
3229       
3230             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3231             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3232             var w = Math.max(
3233                     Math.min(opt.width || cw , this.maxWidth), 
3234                     Math.max(opt.minWidth || this.minWidth, bwidth)
3235             );
3236             if(opt.prompt){
3237                 activeTextEl.setWidth(w);
3238             }
3239             if(dlg.isVisible()){
3240                 dlg.fixedcenter = false;
3241             }
3242             // to big, make it scroll. = But as usual stupid IE does not support
3243             // !important..
3244             
3245             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3246                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3247                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3248             } else {
3249                 bodyEl.dom.style.height = '';
3250                 bodyEl.dom.style.overflowY = '';
3251             }
3252             if (cw > w) {
3253                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3254             } else {
3255                 bodyEl.dom.style.overflowX = '';
3256             }
3257             
3258             dlg.setContentSize(w, bodyEl.getHeight());
3259             if(dlg.isVisible()){
3260                 dlg.fixedcenter = true;
3261             }
3262             return this;
3263         },
3264
3265         /**
3266          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
3267          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3268          * @param {Number} value Any number between 0 and 1 (e.g., .5)
3269          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3270          * @return {Roo.MessageBox} This message box
3271          */
3272         updateProgress : function(value, text){
3273             if(text){
3274                 this.updateText(text);
3275             }
3276             
3277             if (pp) { // weird bug on my firefox - for some reason this is not defined
3278                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3279                 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3280             }
3281             return this;
3282         },        
3283
3284         /**
3285          * Returns true if the message box is currently displayed
3286          * @return {Boolean} True if the message box is visible, else false
3287          */
3288         isVisible : function(){
3289             return dlg && dlg.isVisible();  
3290         },
3291
3292         /**
3293          * Hides the message box if it is displayed
3294          */
3295         hide : function(){
3296             if(this.isVisible()){
3297                 dlg.hide();
3298             }  
3299         },
3300
3301         /**
3302          * Displays a new message box, or reinitializes an existing message box, based on the config options
3303          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3304          * The following config object properties are supported:
3305          * <pre>
3306 Property    Type             Description
3307 ----------  ---------------  ------------------------------------------------------------------------------------
3308 animEl            String/Element   An id or Element from which the message box should animate as it opens and
3309                                    closes (defaults to undefined)
3310 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3311                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
3312 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
3313                                    progress and wait dialogs will ignore this property and always hide the
3314                                    close button as they can only be closed programmatically.
3315 cls               String           A custom CSS class to apply to the message box element
3316 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
3317                                    displayed (defaults to 75)
3318 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
3319                                    function will be btn (the name of the button that was clicked, if applicable,
3320                                    e.g. "ok"), and text (the value of the active text field, if applicable).
3321                                    Progress and wait dialogs will ignore this option since they do not respond to
3322                                    user actions and can only be closed programmatically, so any required function
3323                                    should be called by the same code after it closes the dialog.
3324 icon              String           A CSS class that provides a background image to be used as an icon for
3325                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3326 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
3327 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
3328 modal             Boolean          False to allow user interaction with the page while the message box is
3329                                    displayed (defaults to true)
3330 msg               String           A string that will replace the existing message box body text (defaults
3331                                    to the XHTML-compliant non-breaking space character '&#160;')
3332 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
3333 progress          Boolean          True to display a progress bar (defaults to false)
3334 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
3335 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
3336 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
3337 title             String           The title text
3338 value             String           The string value to set into the active textbox element if displayed
3339 wait              Boolean          True to display a progress bar (defaults to false)
3340 width             Number           The width of the dialog in pixels
3341 </pre>
3342          *
3343          * Example usage:
3344          * <pre><code>
3345 Roo.Msg.show({
3346    title: 'Address',
3347    msg: 'Please enter your address:',
3348    width: 300,
3349    buttons: Roo.MessageBox.OKCANCEL,
3350    multiline: true,
3351    fn: saveAddress,
3352    animEl: 'addAddressBtn'
3353 });
3354 </code></pre>
3355          * @param {Object} config Configuration options
3356          * @return {Roo.MessageBox} This message box
3357          */
3358         show : function(options)
3359         {
3360             
3361             // this causes nightmares if you show one dialog after another
3362             // especially on callbacks..
3363              
3364             if(this.isVisible()){
3365                 
3366                 this.hide();
3367                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3368                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
3369                 Roo.log("New Dialog Message:" +  options.msg )
3370                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3371                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3372                 
3373             }
3374             var d = this.getDialog();
3375             opt = options;
3376             d.setTitle(opt.title || "&#160;");
3377             d.closeEl.setDisplayed(opt.closable !== false);
3378             activeTextEl = textboxEl;
3379             opt.prompt = opt.prompt || (opt.multiline ? true : false);
3380             if(opt.prompt){
3381                 if(opt.multiline){
3382                     textboxEl.hide();
3383                     textareaEl.show();
3384                     textareaEl.setHeight(typeof opt.multiline == "number" ?
3385                         opt.multiline : this.defaultTextHeight);
3386                     activeTextEl = textareaEl;
3387                 }else{
3388                     textboxEl.show();
3389                     textareaEl.hide();
3390                 }
3391             }else{
3392                 textboxEl.hide();
3393                 textareaEl.hide();
3394             }
3395             progressEl.setDisplayed(opt.progress === true);
3396             this.updateProgress(0);
3397             activeTextEl.dom.value = opt.value || "";
3398             if(opt.prompt){
3399                 dlg.setDefaultButton(activeTextEl);
3400             }else{
3401                 var bs = opt.buttons;
3402                 var db = null;
3403                 if(bs && bs.ok){
3404                     db = buttons["ok"];
3405                 }else if(bs && bs.yes){
3406                     db = buttons["yes"];
3407                 }
3408                 dlg.setDefaultButton(db);
3409             }
3410             bwidth = updateButtons(opt.buttons);
3411             this.updateText(opt.msg);
3412             if(opt.cls){
3413                 d.el.addClass(opt.cls);
3414             }
3415             d.proxyDrag = opt.proxyDrag === true;
3416             d.modal = opt.modal !== false;
3417             d.mask = opt.modal !== false ? mask : false;
3418             if(!d.isVisible()){
3419                 // force it to the end of the z-index stack so it gets a cursor in FF
3420                 document.body.appendChild(dlg.el.dom);
3421                 d.animateTarget = null;
3422                 d.show(options.animEl);
3423             }
3424             return this;
3425         },
3426
3427         /**
3428          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
3429          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3430          * and closing the message box when the process is complete.
3431          * @param {String} title The title bar text
3432          * @param {String} msg The message box body text
3433          * @return {Roo.MessageBox} This message box
3434          */
3435         progress : function(title, msg){
3436             this.show({
3437                 title : title,
3438                 msg : msg,
3439                 buttons: false,
3440                 progress:true,
3441                 closable:false,
3442                 minWidth: this.minProgressWidth,
3443                 modal : true
3444             });
3445             return this;
3446         },
3447
3448         /**
3449          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3450          * If a callback function is passed it will be called after the user clicks the button, and the
3451          * id of the button that was clicked will be passed as the only parameter to the callback
3452          * (could also be the top-right close button).
3453          * @param {String} title The title bar text
3454          * @param {String} msg The message box body text
3455          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3456          * @param {Object} scope (optional) The scope of the callback function
3457          * @return {Roo.MessageBox} This message box
3458          */
3459         alert : function(title, msg, fn, scope)
3460         {
3461             this.show({
3462                 title : title,
3463                 msg : msg,
3464                 buttons: this.OK,
3465                 fn: fn,
3466                 closable : false,
3467                 scope : scope,
3468                 modal : true
3469             });
3470             return this;
3471         },
3472
3473         /**
3474          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
3475          * interaction while waiting for a long-running process to complete that does not have defined intervals.
3476          * You are responsible for closing the message box when the process is complete.
3477          * @param {String} msg The message box body text
3478          * @param {String} title (optional) The title bar text
3479          * @return {Roo.MessageBox} This message box
3480          */
3481         wait : function(msg, title){
3482             this.show({
3483                 title : title,
3484                 msg : msg,
3485                 buttons: false,
3486                 closable:false,
3487                 progress:true,
3488                 modal:true,
3489                 width:300,
3490                 wait:true
3491             });
3492             waitTimer = Roo.TaskMgr.start({
3493                 run: function(i){
3494                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3495                 },
3496                 interval: 1000
3497             });
3498             return this;
3499         },
3500
3501         /**
3502          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3503          * If a callback function is passed it will be called after the user clicks either button, and the id of the
3504          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3505          * @param {String} title The title bar text
3506          * @param {String} msg The message box body text
3507          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3508          * @param {Object} scope (optional) The scope of the callback function
3509          * @return {Roo.MessageBox} This message box
3510          */
3511         confirm : function(title, msg, fn, scope){
3512             this.show({
3513                 title : title,
3514                 msg : msg,
3515                 buttons: this.YESNO,
3516                 fn: fn,
3517                 scope : scope,
3518                 modal : true
3519             });
3520             return this;
3521         },
3522
3523         /**
3524          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3525          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
3526          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3527          * (could also be the top-right close button) and the text that was entered will be passed as the two
3528          * parameters to the callback.
3529          * @param {String} title The title bar text
3530          * @param {String} msg The message box body text
3531          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3532          * @param {Object} scope (optional) The scope of the callback function
3533          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3534          * property, or the height in pixels to create the textbox (defaults to false / single-line)
3535          * @return {Roo.MessageBox} This message box
3536          */
3537         prompt : function(title, msg, fn, scope, multiline){
3538             this.show({
3539                 title : title,
3540                 msg : msg,
3541                 buttons: this.OKCANCEL,
3542                 fn: fn,
3543                 minWidth:250,
3544                 scope : scope,
3545                 prompt:true,
3546                 multiline: multiline,
3547                 modal : true
3548             });
3549             return this;
3550         },
3551
3552         /**
3553          * Button config that displays a single OK button
3554          * @type Object
3555          */
3556         OK : {ok:true},
3557         /**
3558          * Button config that displays Yes and No buttons
3559          * @type Object
3560          */
3561         YESNO : {yes:true, no:true},
3562         /**
3563          * Button config that displays OK and Cancel buttons
3564          * @type Object
3565          */
3566         OKCANCEL : {ok:true, cancel:true},
3567         /**
3568          * Button config that displays Yes, No and Cancel buttons
3569          * @type Object
3570          */
3571         YESNOCANCEL : {yes:true, no:true, cancel:true},
3572
3573         /**
3574          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3575          * @type Number
3576          */
3577         defaultTextHeight : 75,
3578         /**
3579          * The maximum width in pixels of the message box (defaults to 600)
3580          * @type Number
3581          */
3582         maxWidth : 600,
3583         /**
3584          * The minimum width in pixels of the message box (defaults to 100)
3585          * @type Number
3586          */
3587         minWidth : 100,
3588         /**
3589          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
3590          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3591          * @type Number
3592          */
3593         minProgressWidth : 250,
3594         /**
3595          * An object containing the default button text strings that can be overriden for localized language support.
3596          * Supported properties are: ok, cancel, yes and no.
3597          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3598          * @type Object
3599          */
3600         buttonText : {
3601             ok : "OK",
3602             cancel : "Cancel",
3603             yes : "Yes",
3604             no : "No"
3605         }
3606     };
3607 }();
3608
3609 /**
3610  * Shorthand for {@link Roo.MessageBox}
3611  */
3612 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3613 Roo.Msg = Roo.Msg || Roo.MessageBox;
3614 /*
3615  * - LGPL
3616  *
3617  * navbar
3618  * 
3619  */
3620
3621 /**
3622  * @class Roo.bootstrap.Navbar
3623  * @extends Roo.bootstrap.Component
3624  * Bootstrap Navbar class
3625
3626  * @constructor
3627  * Create a new Navbar
3628  * @param {Object} config The config object
3629  */
3630
3631
3632 Roo.bootstrap.Navbar = function(config){
3633     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3634     this.addEvents({
3635         // raw events
3636         /**
3637          * @event beforetoggle
3638          * Fire before toggle the menu
3639          * @param {Roo.EventObject} e
3640          */
3641         "beforetoggle" : true
3642     });
3643 };
3644
3645 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3646     
3647     
3648    
3649     // private
3650     navItems : false,
3651     loadMask : false,
3652     
3653     
3654     getAutoCreate : function(){
3655         
3656         
3657         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3658         
3659     },
3660     
3661     initEvents :function ()
3662     {
3663         //Roo.log(this.el.select('.navbar-toggle',true));
3664         this.el.select('.navbar-toggle',true).on('click', function() {
3665             if(this.fireEvent('beforetoggle', this) !== false){
3666                this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3667             }
3668             
3669         }, this);
3670         
3671         var mark = {
3672             tag: "div",
3673             cls:"x-dlg-mask"
3674         };
3675         
3676         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3677         
3678         var size = this.el.getSize();
3679         this.maskEl.setSize(size.width, size.height);
3680         this.maskEl.enableDisplayMode("block");
3681         this.maskEl.hide();
3682         
3683         if(this.loadMask){
3684             this.maskEl.show();
3685         }
3686     },
3687     
3688     
3689     getChildContainer : function()
3690     {
3691         if (this.el.select('.collapse').getCount()) {
3692             return this.el.select('.collapse',true).first();
3693         }
3694         
3695         return this.el;
3696     },
3697     
3698     mask : function()
3699     {
3700         this.maskEl.show();
3701     },
3702     
3703     unmask : function()
3704     {
3705         this.maskEl.hide();
3706     } 
3707     
3708     
3709     
3710     
3711 });
3712
3713
3714
3715  
3716
3717  /*
3718  * - LGPL
3719  *
3720  * navbar
3721  * 
3722  */
3723
3724 /**
3725  * @class Roo.bootstrap.NavSimplebar
3726  * @extends Roo.bootstrap.Navbar
3727  * Bootstrap Sidebar class
3728  *
3729  * @cfg {Boolean} inverse is inverted color
3730  * 
3731  * @cfg {String} type (nav | pills | tabs)
3732  * @cfg {Boolean} arrangement stacked | justified
3733  * @cfg {String} align (left | right) alignment
3734  * 
3735  * @cfg {Boolean} main (true|false) main nav bar? default false
3736  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3737  * 
3738  * @cfg {String} tag (header|footer|nav|div) default is nav 
3739
3740  * 
3741  * 
3742  * 
3743  * @constructor
3744  * Create a new Sidebar
3745  * @param {Object} config The config object
3746  */
3747
3748
3749 Roo.bootstrap.NavSimplebar = function(config){
3750     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3751 };
3752
3753 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3754     
3755     inverse: false,
3756     
3757     type: false,
3758     arrangement: '',
3759     align : false,
3760     
3761     
3762     
3763     main : false,
3764     
3765     
3766     tag : false,
3767     
3768     
3769     getAutoCreate : function(){
3770         
3771         
3772         var cfg = {
3773             tag : this.tag || 'div',
3774             cls : 'navbar'
3775         };
3776           
3777         
3778         cfg.cn = [
3779             {
3780                 cls: 'nav',
3781                 tag : 'ul'
3782             }
3783         ];
3784         
3785          
3786         this.type = this.type || 'nav';
3787         if (['tabs','pills'].indexOf(this.type)!==-1) {
3788             cfg.cn[0].cls += ' nav-' + this.type
3789         
3790         
3791         } else {
3792             if (this.type!=='nav') {
3793                 Roo.log('nav type must be nav/tabs/pills')
3794             }
3795             cfg.cn[0].cls += ' navbar-nav'
3796         }
3797         
3798         
3799         
3800         
3801         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3802             cfg.cn[0].cls += ' nav-' + this.arrangement;
3803         }
3804         
3805         
3806         if (this.align === 'right') {
3807             cfg.cn[0].cls += ' navbar-right';
3808         }
3809         
3810         if (this.inverse) {
3811             cfg.cls += ' navbar-inverse';
3812             
3813         }
3814         
3815         
3816         return cfg;
3817     
3818         
3819     }
3820     
3821     
3822     
3823 });
3824
3825
3826
3827  
3828
3829  
3830        /*
3831  * - LGPL
3832  *
3833  * navbar
3834  * 
3835  */
3836
3837 /**
3838  * @class Roo.bootstrap.NavHeaderbar
3839  * @extends Roo.bootstrap.NavSimplebar
3840  * Bootstrap Sidebar class
3841  *
3842  * @cfg {String} brand what is brand
3843  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3844  * @cfg {String} brand_href href of the brand
3845  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3846  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3847  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3848  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3849  * 
3850  * @constructor
3851  * Create a new Sidebar
3852  * @param {Object} config The config object
3853  */
3854
3855
3856 Roo.bootstrap.NavHeaderbar = function(config){
3857     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3858       
3859 };
3860
3861 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3862     
3863     position: '',
3864     brand: '',
3865     brand_href: false,
3866     srButton : true,
3867     autohide : false,
3868     desktopCenter : false,
3869    
3870     
3871     getAutoCreate : function(){
3872         
3873         var   cfg = {
3874             tag: this.nav || 'nav',
3875             cls: 'navbar',
3876             role: 'navigation',
3877             cn: []
3878         };
3879         
3880         var cn = cfg.cn;
3881         if (this.desktopCenter) {
3882             cn.push({cls : 'container', cn : []});
3883             cn = cn[0].cn;
3884         }
3885         
3886         if(this.srButton){
3887             cn.push({
3888                 tag: 'div',
3889                 cls: 'navbar-header',
3890                 cn: [
3891                     {
3892                         tag: 'button',
3893                         type: 'button',
3894                         cls: 'navbar-toggle',
3895                         'data-toggle': 'collapse',
3896                         cn: [
3897                             {
3898                                 tag: 'span',
3899                                 cls: 'sr-only',
3900                                 html: 'Toggle navigation'
3901                             },
3902                             {
3903                                 tag: 'span',
3904                                 cls: 'icon-bar'
3905                             },
3906                             {
3907                                 tag: 'span',
3908                                 cls: 'icon-bar'
3909                             },
3910                             {
3911                                 tag: 'span',
3912                                 cls: 'icon-bar'
3913                             }
3914                         ]
3915                     }
3916                 ]
3917             });
3918         }
3919         
3920         cn.push({
3921             tag: 'div',
3922             cls: 'collapse navbar-collapse',
3923             cn : []
3924         });
3925         
3926         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3927         
3928         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3929             cfg.cls += ' navbar-' + this.position;
3930             
3931             // tag can override this..
3932             
3933             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3934         }
3935         
3936         if (this.brand !== '') {
3937             cn[0].cn.push({
3938                 tag: 'a',
3939                 href: this.brand_href ? this.brand_href : '#',
3940                 cls: 'navbar-brand',
3941                 cn: [
3942                 this.brand
3943                 ]
3944             });
3945         }
3946         
3947         if(this.main){
3948             cfg.cls += ' main-nav';
3949         }
3950         
3951         
3952         return cfg;
3953
3954         
3955     },
3956     getHeaderChildContainer : function()
3957     {
3958         if (this.srButton && this.el.select('.navbar-header').getCount()) {
3959             return this.el.select('.navbar-header',true).first();
3960         }
3961         
3962         return this.getChildContainer();
3963     },
3964     
3965     
3966     initEvents : function()
3967     {
3968         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3969         
3970         if (this.autohide) {
3971             
3972             var prevScroll = 0;
3973             var ft = this.el;
3974             
3975             Roo.get(document).on('scroll',function(e) {
3976                 var ns = Roo.get(document).getScroll().top;
3977                 var os = prevScroll;
3978                 prevScroll = ns;
3979                 
3980                 if(ns > os){
3981                     ft.removeClass('slideDown');
3982                     ft.addClass('slideUp');
3983                     return;
3984                 }
3985                 ft.removeClass('slideUp');
3986                 ft.addClass('slideDown');
3987                  
3988               
3989           },this);
3990         }
3991     }    
3992     
3993 });
3994
3995
3996
3997  
3998
3999  /*
4000  * - LGPL
4001  *
4002  * navbar
4003  * 
4004  */
4005
4006 /**
4007  * @class Roo.bootstrap.NavSidebar
4008  * @extends Roo.bootstrap.Navbar
4009  * Bootstrap Sidebar class
4010  * 
4011  * @constructor
4012  * Create a new Sidebar
4013  * @param {Object} config The config object
4014  */
4015
4016
4017 Roo.bootstrap.NavSidebar = function(config){
4018     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4019 };
4020
4021 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
4022     
4023     sidebar : true, // used by Navbar Item and NavbarGroup at present...
4024     
4025     getAutoCreate : function(){
4026         
4027         
4028         return  {
4029             tag: 'div',
4030             cls: 'sidebar sidebar-nav'
4031         };
4032     
4033         
4034     }
4035     
4036     
4037     
4038 });
4039
4040
4041
4042  
4043
4044  /*
4045  * - LGPL
4046  *
4047  * nav group
4048  * 
4049  */
4050
4051 /**
4052  * @class Roo.bootstrap.NavGroup
4053  * @extends Roo.bootstrap.Component
4054  * Bootstrap NavGroup class
4055  * @cfg {String} align (left|right)
4056  * @cfg {Boolean} inverse
4057  * @cfg {String} type (nav|pills|tab) default nav
4058  * @cfg {String} navId - reference Id for navbar.
4059
4060  * 
4061  * @constructor
4062  * Create a new nav group
4063  * @param {Object} config The config object
4064  */
4065
4066 Roo.bootstrap.NavGroup = function(config){
4067     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4068     this.navItems = [];
4069    
4070     Roo.bootstrap.NavGroup.register(this);
4071      this.addEvents({
4072         /**
4073              * @event changed
4074              * Fires when the active item changes
4075              * @param {Roo.bootstrap.NavGroup} this
4076              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4077              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
4078          */
4079         'changed': true
4080      });
4081     
4082 };
4083
4084 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
4085     
4086     align: '',
4087     inverse: false,
4088     form: false,
4089     type: 'nav',
4090     navId : '',
4091     // private
4092     
4093     navItems : false, 
4094     
4095     getAutoCreate : function()
4096     {
4097         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4098         
4099         cfg = {
4100             tag : 'ul',
4101             cls: 'nav' 
4102         };
4103         
4104         if (['tabs','pills'].indexOf(this.type)!==-1) {
4105             cfg.cls += ' nav-' + this.type
4106         } else {
4107             if (this.type!=='nav') {
4108                 Roo.log('nav type must be nav/tabs/pills')
4109             }
4110             cfg.cls += ' navbar-nav'
4111         }
4112         
4113         if (this.parent() && this.parent().sidebar) {
4114             cfg = {
4115                 tag: 'ul',
4116                 cls: 'dashboard-menu sidebar-menu'
4117             };
4118             
4119             return cfg;
4120         }
4121         
4122         if (this.form === true) {
4123             cfg = {
4124                 tag: 'form',
4125                 cls: 'navbar-form'
4126             };
4127             
4128             if (this.align === 'right') {
4129                 cfg.cls += ' navbar-right';
4130             } else {
4131                 cfg.cls += ' navbar-left';
4132             }
4133         }
4134         
4135         if (this.align === 'right') {
4136             cfg.cls += ' navbar-right';
4137         }
4138         
4139         if (this.inverse) {
4140             cfg.cls += ' navbar-inverse';
4141             
4142         }
4143         
4144         
4145         return cfg;
4146     },
4147     /**
4148     * sets the active Navigation item
4149     * @param {Roo.bootstrap.NavItem} the new current navitem
4150     */
4151     setActiveItem : function(item)
4152     {
4153         var prev = false;
4154         Roo.each(this.navItems, function(v){
4155             if (v == item) {
4156                 return ;
4157             }
4158             if (v.isActive()) {
4159                 v.setActive(false, true);
4160                 prev = v;
4161                 
4162             }
4163             
4164         });
4165
4166         item.setActive(true, true);
4167         this.fireEvent('changed', this, item, prev);
4168         
4169         
4170     },
4171     /**
4172     * gets the active Navigation item
4173     * @return {Roo.bootstrap.NavItem} the current navitem
4174     */
4175     getActive : function()
4176     {
4177         
4178         var prev = false;
4179         Roo.each(this.navItems, function(v){
4180             
4181             if (v.isActive()) {
4182                 prev = v;
4183                 
4184             }
4185             
4186         });
4187         return prev;
4188     },
4189     
4190     indexOfNav : function()
4191     {
4192         
4193         var prev = false;
4194         Roo.each(this.navItems, function(v,i){
4195             
4196             if (v.isActive()) {
4197                 prev = i;
4198                 
4199             }
4200             
4201         });
4202         return prev;
4203     },
4204     /**
4205     * adds a Navigation item
4206     * @param {Roo.bootstrap.NavItem} the navitem to add
4207     */
4208     addItem : function(cfg)
4209     {
4210         var cn = new Roo.bootstrap.NavItem(cfg);
4211         this.register(cn);
4212         cn.parentId = this.id;
4213         cn.onRender(this.el, null);
4214         return cn;
4215     },
4216     /**
4217     * register a Navigation item
4218     * @param {Roo.bootstrap.NavItem} the navitem to add
4219     */
4220     register : function(item)
4221     {
4222         this.navItems.push( item);
4223         item.navId = this.navId;
4224     
4225     },
4226     
4227     /**
4228     * clear all the Navigation item
4229     */
4230    
4231     clearAll : function()
4232     {
4233         this.navItems = [];
4234         this.el.dom.innerHTML = '';
4235     },
4236     
4237     getNavItem: function(tabId)
4238     {
4239         var ret = false;
4240         Roo.each(this.navItems, function(e) {
4241             if (e.tabId == tabId) {
4242                ret =  e;
4243                return false;
4244             }
4245             return true;
4246             
4247         });
4248         return ret;
4249     },
4250     
4251     setActiveNext : function()
4252     {
4253         var i = this.indexOfNav(this.getActive());
4254         if (i > this.navItems.length) {
4255             return;
4256         }
4257         this.setActiveItem(this.navItems[i+1]);
4258     },
4259     setActivePrev : function()
4260     {
4261         var i = this.indexOfNav(this.getActive());
4262         if (i  < 1) {
4263             return;
4264         }
4265         this.setActiveItem(this.navItems[i-1]);
4266     },
4267     clearWasActive : function(except) {
4268         Roo.each(this.navItems, function(e) {
4269             if (e.tabId != except.tabId && e.was_active) {
4270                e.was_active = false;
4271                return false;
4272             }
4273             return true;
4274             
4275         });
4276     },
4277     getWasActive : function ()
4278     {
4279         var r = false;
4280         Roo.each(this.navItems, function(e) {
4281             if (e.was_active) {
4282                r = e;
4283                return false;
4284             }
4285             return true;
4286             
4287         });
4288         return r;
4289     }
4290     
4291     
4292 });
4293
4294  
4295 Roo.apply(Roo.bootstrap.NavGroup, {
4296     
4297     groups: {},
4298      /**
4299     * register a Navigation Group
4300     * @param {Roo.bootstrap.NavGroup} the navgroup to add
4301     */
4302     register : function(navgrp)
4303     {
4304         this.groups[navgrp.navId] = navgrp;
4305         
4306     },
4307     /**
4308     * fetch a Navigation Group based on the navigation ID
4309     * @param {string} the navgroup to add
4310     * @returns {Roo.bootstrap.NavGroup} the navgroup 
4311     */
4312     get: function(navId) {
4313         if (typeof(this.groups[navId]) == 'undefined') {
4314             return false;
4315             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4316         }
4317         return this.groups[navId] ;
4318     }
4319     
4320     
4321     
4322 });
4323
4324  /*
4325  * - LGPL
4326  *
4327  * row
4328  * 
4329  */
4330
4331 /**
4332  * @class Roo.bootstrap.NavItem
4333  * @extends Roo.bootstrap.Component
4334  * Bootstrap Navbar.NavItem class
4335  * @cfg {String} href  link to
4336  * @cfg {String} html content of button
4337  * @cfg {String} badge text inside badge
4338  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4339  * @cfg {String} glyphicon name of glyphicon
4340  * @cfg {String} icon name of font awesome icon
4341  * @cfg {Boolean} active Is item active
4342  * @cfg {Boolean} disabled Is item disabled
4343  
4344  * @cfg {Boolean} preventDefault (true | false) default false
4345  * @cfg {String} tabId the tab that this item activates.
4346  * @cfg {String} tagtype (a|span) render as a href or span?
4347  * @cfg {Boolean} animateRef (true|false) link to element default false  
4348   
4349  * @constructor
4350  * Create a new Navbar Item
4351  * @param {Object} config The config object
4352  */
4353 Roo.bootstrap.NavItem = function(config){
4354     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4355     this.addEvents({
4356         // raw events
4357         /**
4358          * @event click
4359          * The raw click event for the entire grid.
4360          * @param {Roo.EventObject} e
4361          */
4362         "click" : true,
4363          /**
4364             * @event changed
4365             * Fires when the active item active state changes
4366             * @param {Roo.bootstrap.NavItem} this
4367             * @param {boolean} state the new state
4368              
4369          */
4370         'changed': true,
4371         /**
4372             * @event scrollto
4373             * Fires when scroll to element
4374             * @param {Roo.bootstrap.NavItem} this
4375             * @param {Object} options
4376             * @param {Roo.EventObject} e
4377              
4378          */
4379         'scrollto': true
4380     });
4381    
4382 };
4383
4384 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
4385     
4386     href: false,
4387     html: '',
4388     badge: '',
4389     icon: false,
4390     glyphicon: false,
4391     active: false,
4392     preventDefault : false,
4393     tabId : false,
4394     tagtype : 'a',
4395     disabled : false,
4396     animateRef : false,
4397     was_active : false,
4398     
4399     getAutoCreate : function(){
4400          
4401         var cfg = {
4402             tag: 'li',
4403             cls: 'nav-item'
4404             
4405         };
4406         
4407         if (this.active) {
4408             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4409         }
4410         if (this.disabled) {
4411             cfg.cls += ' disabled';
4412         }
4413         
4414         if (this.href || this.html || this.glyphicon || this.icon) {
4415             cfg.cn = [
4416                 {
4417                     tag: this.tagtype,
4418                     href : this.href || "#",
4419                     html: this.html || ''
4420                 }
4421             ];
4422             
4423             if (this.icon) {
4424                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4425             }
4426
4427             if(this.glyphicon) {
4428                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
4429             }
4430             
4431             if (this.menu) {
4432                 
4433                 cfg.cn[0].html += " <span class='caret'></span>";
4434              
4435             }
4436             
4437             if (this.badge !== '') {
4438                  
4439                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4440             }
4441         }
4442         
4443         
4444         
4445         return cfg;
4446     },
4447     initEvents: function() 
4448     {
4449         if (typeof (this.menu) != 'undefined') {
4450             this.menu.parentType = this.xtype;
4451             this.menu.triggerEl = this.el;
4452             this.menu = this.addxtype(Roo.apply({}, this.menu));
4453         }
4454         
4455         this.el.select('a',true).on('click', this.onClick, this);
4456         
4457         if(this.tagtype == 'span'){
4458             this.el.select('span',true).on('click', this.onClick, this);
4459         }
4460        
4461         // at this point parent should be available..
4462         this.parent().register(this);
4463     },
4464     
4465     onClick : function(e)
4466     {
4467         if (e.getTarget('.dropdown-menu-item')) {
4468             // did you click on a menu itemm.... - then don't trigger onclick..
4469             return;
4470         }
4471         
4472         if(
4473                 this.preventDefault || 
4474                 this.href == '#' 
4475         ){
4476             Roo.log("NavItem - prevent Default?");
4477             e.preventDefault();
4478         }
4479         
4480         if (this.disabled) {
4481             return;
4482         }
4483         
4484         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4485         if (tg && tg.transition) {
4486             Roo.log("waiting for the transitionend");
4487             return;
4488         }
4489         
4490         
4491         
4492         //Roo.log("fire event clicked");
4493         if(this.fireEvent('click', this, e) === false){
4494             return;
4495         };
4496         
4497         if(this.tagtype == 'span'){
4498             return;
4499         }
4500         
4501         //Roo.log(this.href);
4502         var ael = this.el.select('a',true).first();
4503         //Roo.log(ael);
4504         
4505         if(ael && this.animateRef && this.href.indexOf('#') > -1){
4506             //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4507             if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4508                 return; // ignore... - it's a 'hash' to another page.
4509             }
4510             Roo.log("NavItem - prevent Default?");
4511             e.preventDefault();
4512             this.scrollToElement(e);
4513         }
4514         
4515         
4516         var p =  this.parent();
4517    
4518         if (['tabs','pills'].indexOf(p.type)!==-1) {
4519             if (typeof(p.setActiveItem) !== 'undefined') {
4520                 p.setActiveItem(this);
4521             }
4522         }
4523         
4524         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4525         if (p.parentType == 'NavHeaderbar' && !this.menu) {
4526             // remove the collapsed menu expand...
4527             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
4528         }
4529     },
4530     
4531     isActive: function () {
4532         return this.active
4533     },
4534     setActive : function(state, fire, is_was_active)
4535     {
4536         if (this.active && !state && this.navId) {
4537             this.was_active = true;
4538             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4539             if (nv) {
4540                 nv.clearWasActive(this);
4541             }
4542             
4543         }
4544         this.active = state;
4545         
4546         if (!state ) {
4547             this.el.removeClass('active');
4548         } else if (!this.el.hasClass('active')) {
4549             this.el.addClass('active');
4550         }
4551         if (fire) {
4552             this.fireEvent('changed', this, state);
4553         }
4554         
4555         // show a panel if it's registered and related..
4556         
4557         if (!this.navId || !this.tabId || !state || is_was_active) {
4558             return;
4559         }
4560         
4561         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4562         if (!tg) {
4563             return;
4564         }
4565         var pan = tg.getPanelByName(this.tabId);
4566         if (!pan) {
4567             return;
4568         }
4569         // if we can not flip to new panel - go back to old nav highlight..
4570         if (false == tg.showPanel(pan)) {
4571             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4572             if (nv) {
4573                 var onav = nv.getWasActive();
4574                 if (onav) {
4575                     onav.setActive(true, false, true);
4576                 }
4577             }
4578             
4579         }
4580         
4581         
4582         
4583     },
4584      // this should not be here...
4585     setDisabled : function(state)
4586     {
4587         this.disabled = state;
4588         if (!state ) {
4589             this.el.removeClass('disabled');
4590         } else if (!this.el.hasClass('disabled')) {
4591             this.el.addClass('disabled');
4592         }
4593         
4594     },
4595     
4596     /**
4597      * Fetch the element to display the tooltip on.
4598      * @return {Roo.Element} defaults to this.el
4599      */
4600     tooltipEl : function()
4601     {
4602         return this.el.select('' + this.tagtype + '', true).first();
4603     },
4604     
4605     scrollToElement : function(e)
4606     {
4607         var c = document.body;
4608         
4609         /*
4610          * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4611          */
4612         if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4613             c = document.documentElement;
4614         }
4615         
4616         var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4617         
4618         if(!target){
4619             return;
4620         }
4621
4622         var o = target.calcOffsetsTo(c);
4623         
4624         var options = {
4625             target : target,
4626             value : o[1]
4627         };
4628         
4629         this.fireEvent('scrollto', this, options, e);
4630         
4631         Roo.get(c).scrollTo('top', options.value, true);
4632         
4633         return;
4634     }
4635 });
4636  
4637
4638  /*
4639  * - LGPL
4640  *
4641  * sidebar item
4642  *
4643  *  li
4644  *    <span> icon </span>
4645  *    <span> text </span>
4646  *    <span>badge </span>
4647  */
4648
4649 /**
4650  * @class Roo.bootstrap.NavSidebarItem
4651  * @extends Roo.bootstrap.NavItem
4652  * Bootstrap Navbar.NavSidebarItem class
4653  * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4654  * {Boolean} open is the menu open
4655  * {Boolean} buttonView use button as the tigger el rather that a (default false)
4656  * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4657  * {String} buttonSize (sm|md|lg)the extra classes for the button
4658  * {Boolean} showArrow show arrow next to the text (default true)
4659  * @constructor
4660  * Create a new Navbar Button
4661  * @param {Object} config The config object
4662  */
4663 Roo.bootstrap.NavSidebarItem = function(config){
4664     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4665     this.addEvents({
4666         // raw events
4667         /**
4668          * @event click
4669          * The raw click event for the entire grid.
4670          * @param {Roo.EventObject} e
4671          */
4672         "click" : true,
4673          /**
4674             * @event changed
4675             * Fires when the active item active state changes
4676             * @param {Roo.bootstrap.NavSidebarItem} this
4677             * @param {boolean} state the new state
4678              
4679          */
4680         'changed': true
4681     });
4682    
4683 };
4684
4685 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4686     
4687     badgeWeight : 'default',
4688     
4689     open: false,
4690     
4691     buttonView : false,
4692     
4693     buttonWeight : 'default',
4694     
4695     buttonSize : 'md',
4696     
4697     showArrow : true,
4698     
4699     getAutoCreate : function(){
4700         
4701         
4702         var a = {
4703                 tag: 'a',
4704                 href : this.href || '#',
4705                 cls: '',
4706                 html : '',
4707                 cn : []
4708         };
4709         
4710         if(this.buttonView){
4711             a = {
4712                 tag: 'button',
4713                 href : this.href || '#',
4714                 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4715                 html : this.html,
4716                 cn : []
4717             };
4718         }
4719         
4720         var cfg = {
4721             tag: 'li',
4722             cls: '',
4723             cn: [ a ]
4724         };
4725         
4726         if (this.active) {
4727             cfg.cls += ' active';
4728         }
4729         
4730         if (this.disabled) {
4731             cfg.cls += ' disabled';
4732         }
4733         if (this.open) {
4734             cfg.cls += ' open x-open';
4735         }
4736         // left icon..
4737         if (this.glyphicon || this.icon) {
4738             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4739             a.cn.push({ tag : 'i', cls : c }) ;
4740         }
4741         
4742         if(!this.buttonView){
4743             var span = {
4744                 tag: 'span',
4745                 html : this.html || ''
4746             };
4747
4748             a.cn.push(span);
4749             
4750         }
4751         
4752         if (this.badge !== '') {
4753             a.cn.push({ tag: 'span',  cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge }); 
4754         }
4755         
4756         if (this.menu) {
4757             
4758             if(this.showArrow){
4759                 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4760             }
4761             
4762             a.cls += ' dropdown-toggle treeview' ;
4763         }
4764         
4765         return cfg;
4766     },
4767     
4768     initEvents : function()
4769     { 
4770         if (typeof (this.menu) != 'undefined') {
4771             this.menu.parentType = this.xtype;
4772             this.menu.triggerEl = this.el;
4773             this.menu = this.addxtype(Roo.apply({}, this.menu));
4774         }
4775         
4776         this.el.on('click', this.onClick, this);
4777         
4778         if(this.badge !== ''){
4779             this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4780         }
4781         
4782     },
4783     
4784     onClick : function(e)
4785     {
4786         if(this.disabled){
4787             e.preventDefault();
4788             return;
4789         }
4790         
4791         if(this.preventDefault){
4792             e.preventDefault();
4793         }
4794         
4795         this.fireEvent('click', this);
4796     },
4797     
4798     disable : function()
4799     {
4800         this.setDisabled(true);
4801     },
4802     
4803     enable : function()
4804     {
4805         this.setDisabled(false);
4806     },
4807     
4808     setDisabled : function(state)
4809     {
4810         if(this.disabled == state){
4811             return;
4812         }
4813         
4814         this.disabled = state;
4815         
4816         if (state) {
4817             this.el.addClass('disabled');
4818             return;
4819         }
4820         
4821         this.el.removeClass('disabled');
4822         
4823         return;
4824     },
4825     
4826     setActive : function(state)
4827     {
4828         if(this.active == state){
4829             return;
4830         }
4831         
4832         this.active = state;
4833         
4834         if (state) {
4835             this.el.addClass('active');
4836             return;
4837         }
4838         
4839         this.el.removeClass('active');
4840         
4841         return;
4842     },
4843     
4844     isActive: function () 
4845     {
4846         return this.active;
4847     },
4848     
4849     setBadge : function(str)
4850     {
4851         if(!this.badgeEl){
4852             return;
4853         }
4854         
4855         this.badgeEl.dom.innerHTML = str;
4856     }
4857     
4858    
4859      
4860  
4861 });
4862  
4863
4864  /*
4865  * - LGPL
4866  *
4867  * row
4868  * 
4869  */
4870
4871 /**
4872  * @class Roo.bootstrap.Row
4873  * @extends Roo.bootstrap.Component
4874  * Bootstrap Row class (contains columns...)
4875  * 
4876  * @constructor
4877  * Create a new Row
4878  * @param {Object} config The config object
4879  */
4880
4881 Roo.bootstrap.Row = function(config){
4882     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4883 };
4884
4885 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4886     
4887     getAutoCreate : function(){
4888        return {
4889             cls: 'row clearfix'
4890        };
4891     }
4892     
4893     
4894 });
4895
4896  
4897
4898  /*
4899  * - LGPL
4900  *
4901  * element
4902  * 
4903  */
4904
4905 /**
4906  * @class Roo.bootstrap.Element
4907  * @extends Roo.bootstrap.Component
4908  * Bootstrap Element class
4909  * @cfg {String} html contents of the element
4910  * @cfg {String} tag tag of the element
4911  * @cfg {String} cls class of the element
4912  * @cfg {Boolean} preventDefault (true|false) default false
4913  * @cfg {Boolean} clickable (true|false) default false
4914  * 
4915  * @constructor
4916  * Create a new Element
4917  * @param {Object} config The config object
4918  */
4919
4920 Roo.bootstrap.Element = function(config){
4921     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4922     
4923     this.addEvents({
4924         // raw events
4925         /**
4926          * @event click
4927          * When a element is chick
4928          * @param {Roo.bootstrap.Element} this
4929          * @param {Roo.EventObject} e
4930          */
4931         "click" : true
4932     });
4933 };
4934
4935 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4936     
4937     tag: 'div',
4938     cls: '',
4939     html: '',
4940     preventDefault: false, 
4941     clickable: false,
4942     
4943     getAutoCreate : function(){
4944         
4945         var cfg = {
4946             tag: this.tag,
4947             // cls: this.cls, double assign in parent class Component.js :: onRender
4948             html: this.html
4949         };
4950         
4951         return cfg;
4952     },
4953     
4954     initEvents: function() 
4955     {
4956         Roo.bootstrap.Element.superclass.initEvents.call(this);
4957         
4958         if(this.clickable){
4959             this.el.on('click', this.onClick, this);
4960         }
4961         
4962     },
4963     
4964     onClick : function(e)
4965     {
4966         if(this.preventDefault){
4967             e.preventDefault();
4968         }
4969         
4970         this.fireEvent('click', this, e);
4971     },
4972     
4973     getValue : function()
4974     {
4975         return this.el.dom.innerHTML;
4976     },
4977     
4978     setValue : function(value)
4979     {
4980         this.el.dom.innerHTML = value;
4981     }
4982    
4983 });
4984
4985  
4986
4987  /*
4988  * - LGPL
4989  *
4990  * pagination
4991  * 
4992  */
4993
4994 /**
4995  * @class Roo.bootstrap.Pagination
4996  * @extends Roo.bootstrap.Component
4997  * Bootstrap Pagination class
4998  * @cfg {String} size xs | sm | md | lg
4999  * @cfg {Boolean} inverse false | true
5000  * 
5001  * @constructor
5002  * Create a new Pagination
5003  * @param {Object} config The config object
5004  */
5005
5006 Roo.bootstrap.Pagination = function(config){
5007     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5008 };
5009
5010 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
5011     
5012     cls: false,
5013     size: false,
5014     inverse: false,
5015     
5016     getAutoCreate : function(){
5017         var cfg = {
5018             tag: 'ul',
5019                 cls: 'pagination'
5020         };
5021         if (this.inverse) {
5022             cfg.cls += ' inverse';
5023         }
5024         if (this.html) {
5025             cfg.html=this.html;
5026         }
5027         if (this.cls) {
5028             cfg.cls += " " + this.cls;
5029         }
5030         return cfg;
5031     }
5032    
5033 });
5034
5035  
5036
5037  /*
5038  * - LGPL
5039  *
5040  * Pagination item
5041  * 
5042  */
5043
5044
5045 /**
5046  * @class Roo.bootstrap.PaginationItem
5047  * @extends Roo.bootstrap.Component
5048  * Bootstrap PaginationItem class
5049  * @cfg {String} html text
5050  * @cfg {String} href the link
5051  * @cfg {Boolean} preventDefault (true | false) default true
5052  * @cfg {Boolean} active (true | false) default false
5053  * @cfg {Boolean} disabled default false
5054  * 
5055  * 
5056  * @constructor
5057  * Create a new PaginationItem
5058  * @param {Object} config The config object
5059  */
5060
5061
5062 Roo.bootstrap.PaginationItem = function(config){
5063     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5064     this.addEvents({
5065         // raw events
5066         /**
5067          * @event click
5068          * The raw click event for the entire grid.
5069          * @param {Roo.EventObject} e
5070          */
5071         "click" : true
5072     });
5073 };
5074
5075 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
5076     
5077     href : false,
5078     html : false,
5079     preventDefault: true,
5080     active : false,
5081     cls : false,
5082     disabled: false,
5083     
5084     getAutoCreate : function(){
5085         var cfg= {
5086             tag: 'li',
5087             cn: [
5088                 {
5089                     tag : 'a',
5090                     href : this.href ? this.href : '#',
5091                     html : this.html ? this.html : ''
5092                 }
5093             ]
5094         };
5095         
5096         if(this.cls){
5097             cfg.cls = this.cls;
5098         }
5099         
5100         if(this.disabled){
5101             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5102         }
5103         
5104         if(this.active){
5105             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5106         }
5107         
5108         return cfg;
5109     },
5110     
5111     initEvents: function() {
5112         
5113         this.el.on('click', this.onClick, this);
5114         
5115     },
5116     onClick : function(e)
5117     {
5118         Roo.log('PaginationItem on click ');
5119         if(this.preventDefault){
5120             e.preventDefault();
5121         }
5122         
5123         if(this.disabled){
5124             return;
5125         }
5126         
5127         this.fireEvent('click', this, e);
5128     }
5129    
5130 });
5131
5132  
5133
5134  /*
5135  * - LGPL
5136  *
5137  * slider
5138  * 
5139  */
5140
5141
5142 /**
5143  * @class Roo.bootstrap.Slider
5144  * @extends Roo.bootstrap.Component
5145  * Bootstrap Slider class
5146  *    
5147  * @constructor
5148  * Create a new Slider
5149  * @param {Object} config The config object
5150  */
5151
5152 Roo.bootstrap.Slider = function(config){
5153     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5154 };
5155
5156 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
5157     
5158     getAutoCreate : function(){
5159         
5160         var cfg = {
5161             tag: 'div',
5162             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5163             cn: [
5164                 {
5165                     tag: 'a',
5166                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
5167                 }
5168             ]
5169         };
5170         
5171         return cfg;
5172     }
5173    
5174 });
5175
5176  /*
5177  * Based on:
5178  * Ext JS Library 1.1.1
5179  * Copyright(c) 2006-2007, Ext JS, LLC.
5180  *
5181  * Originally Released Under LGPL - original licence link has changed is not relivant.
5182  *
5183  * Fork - LGPL
5184  * <script type="text/javascript">
5185  */
5186  
5187
5188 /**
5189  * @class Roo.grid.ColumnModel
5190  * @extends Roo.util.Observable
5191  * This is the default implementation of a ColumnModel used by the Grid. It defines
5192  * the columns in the grid.
5193  * <br>Usage:<br>
5194  <pre><code>
5195  var colModel = new Roo.grid.ColumnModel([
5196         {header: "Ticker", width: 60, sortable: true, locked: true},
5197         {header: "Company Name", width: 150, sortable: true},
5198         {header: "Market Cap.", width: 100, sortable: true},
5199         {header: "$ Sales", width: 100, sortable: true, renderer: money},
5200         {header: "Employees", width: 100, sortable: true, resizable: false}
5201  ]);
5202  </code></pre>
5203  * <p>
5204  
5205  * The config options listed for this class are options which may appear in each
5206  * individual column definition.
5207  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5208  * @constructor
5209  * @param {Object} config An Array of column config objects. See this class's
5210  * config objects for details.
5211 */
5212 Roo.grid.ColumnModel = function(config){
5213         /**
5214      * The config passed into the constructor
5215      */
5216     this.config = config;
5217     this.lookup = {};
5218
5219     // if no id, create one
5220     // if the column does not have a dataIndex mapping,
5221     // map it to the order it is in the config
5222     for(var i = 0, len = config.length; i < len; i++){
5223         var c = config[i];
5224         if(typeof c.dataIndex == "undefined"){
5225             c.dataIndex = i;
5226         }
5227         if(typeof c.renderer == "string"){
5228             c.renderer = Roo.util.Format[c.renderer];
5229         }
5230         if(typeof c.id == "undefined"){
5231             c.id = Roo.id();
5232         }
5233         if(c.editor && c.editor.xtype){
5234             c.editor  = Roo.factory(c.editor, Roo.grid);
5235         }
5236         if(c.editor && c.editor.isFormField){
5237             c.editor = new Roo.grid.GridEditor(c.editor);
5238         }
5239         this.lookup[c.id] = c;
5240     }
5241
5242     /**
5243      * The width of columns which have no width specified (defaults to 100)
5244      * @type Number
5245      */
5246     this.defaultWidth = 100;
5247
5248     /**
5249      * Default sortable of columns which have no sortable specified (defaults to false)
5250      * @type Boolean
5251      */
5252     this.defaultSortable = false;
5253
5254     this.addEvents({
5255         /**
5256              * @event widthchange
5257              * Fires when the width of a column changes.
5258              * @param {ColumnModel} this
5259              * @param {Number} columnIndex The column index
5260              * @param {Number} newWidth The new width
5261              */
5262             "widthchange": true,
5263         /**
5264              * @event headerchange
5265              * Fires when the text of a header changes.
5266              * @param {ColumnModel} this
5267              * @param {Number} columnIndex The column index
5268              * @param {Number} newText The new header text
5269              */
5270             "headerchange": true,
5271         /**
5272              * @event hiddenchange
5273              * Fires when a column is hidden or "unhidden".
5274              * @param {ColumnModel} this
5275              * @param {Number} columnIndex The column index
5276              * @param {Boolean} hidden true if hidden, false otherwise
5277              */
5278             "hiddenchange": true,
5279             /**
5280          * @event columnmoved
5281          * Fires when a column is moved.
5282          * @param {ColumnModel} this
5283          * @param {Number} oldIndex
5284          * @param {Number} newIndex
5285          */
5286         "columnmoved" : true,
5287         /**
5288          * @event columlockchange
5289          * Fires when a column's locked state is changed
5290          * @param {ColumnModel} this
5291          * @param {Number} colIndex
5292          * @param {Boolean} locked true if locked
5293          */
5294         "columnlockchange" : true
5295     });
5296     Roo.grid.ColumnModel.superclass.constructor.call(this);
5297 };
5298 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5299     /**
5300      * @cfg {String} header The header text to display in the Grid view.
5301      */
5302     /**
5303      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5304      * {@link Roo.data.Record} definition from which to draw the column's value. If not
5305      * specified, the column's index is used as an index into the Record's data Array.
5306      */
5307     /**
5308      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5309      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5310      */
5311     /**
5312      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5313      * Defaults to the value of the {@link #defaultSortable} property.
5314      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5315      */
5316     /**
5317      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
5318      */
5319     /**
5320      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
5321      */
5322     /**
5323      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5324      */
5325     /**
5326      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5327      */
5328     /**
5329      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5330      * given the cell's data value. See {@link #setRenderer}. If not specified, the
5331      * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5332      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5333      */
5334        /**
5335      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
5336      */
5337     /**
5338      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
5339      */
5340     /**
5341      * @cfg {String} cursor (Optional)
5342      */
5343     /**
5344      * @cfg {String} tooltip (Optional)
5345      */
5346     /**
5347      * @cfg {Number} xs (Optional)
5348      */
5349     /**
5350      * @cfg {Number} sm (Optional)
5351      */
5352     /**
5353      * @cfg {Number} md (Optional)
5354      */
5355     /**
5356      * @cfg {Number} lg (Optional)
5357      */
5358     /**
5359      * Returns the id of the column at the specified index.
5360      * @param {Number} index The column index
5361      * @return {String} the id
5362      */
5363     getColumnId : function(index){
5364         return this.config[index].id;
5365     },
5366
5367     /**
5368      * Returns the column for a specified id.
5369      * @param {String} id The column id
5370      * @return {Object} the column
5371      */
5372     getColumnById : function(id){
5373         return this.lookup[id];
5374     },
5375
5376     
5377     /**
5378      * Returns the column for a specified dataIndex.
5379      * @param {String} dataIndex The column dataIndex
5380      * @return {Object|Boolean} the column or false if not found
5381      */
5382     getColumnByDataIndex: function(dataIndex){
5383         var index = this.findColumnIndex(dataIndex);
5384         return index > -1 ? this.config[index] : false;
5385     },
5386     
5387     /**
5388      * Returns the index for a specified column id.
5389      * @param {String} id The column id
5390      * @return {Number} the index, or -1 if not found
5391      */
5392     getIndexById : function(id){
5393         for(var i = 0, len = this.config.length; i < len; i++){
5394             if(this.config[i].id == id){
5395                 return i;
5396             }
5397         }
5398         return -1;
5399     },
5400     
5401     /**
5402      * Returns the index for a specified column dataIndex.
5403      * @param {String} dataIndex The column dataIndex
5404      * @return {Number} the index, or -1 if not found
5405      */
5406     
5407     findColumnIndex : function(dataIndex){
5408         for(var i = 0, len = this.config.length; i < len; i++){
5409             if(this.config[i].dataIndex == dataIndex){
5410                 return i;
5411             }
5412         }
5413         return -1;
5414     },
5415     
5416     
5417     moveColumn : function(oldIndex, newIndex){
5418         var c = this.config[oldIndex];
5419         this.config.splice(oldIndex, 1);
5420         this.config.splice(newIndex, 0, c);
5421         this.dataMap = null;
5422         this.fireEvent("columnmoved", this, oldIndex, newIndex);
5423     },
5424
5425     isLocked : function(colIndex){
5426         return this.config[colIndex].locked === true;
5427     },
5428
5429     setLocked : function(colIndex, value, suppressEvent){
5430         if(this.isLocked(colIndex) == value){
5431             return;
5432         }
5433         this.config[colIndex].locked = value;
5434         if(!suppressEvent){
5435             this.fireEvent("columnlockchange", this, colIndex, value);
5436         }
5437     },
5438
5439     getTotalLockedWidth : function(){
5440         var totalWidth = 0;
5441         for(var i = 0; i < this.config.length; i++){
5442             if(this.isLocked(i) && !this.isHidden(i)){
5443                 this.totalWidth += this.getColumnWidth(i);
5444             }
5445         }
5446         return totalWidth;
5447     },
5448
5449     getLockedCount : function(){
5450         for(var i = 0, len = this.config.length; i < len; i++){
5451             if(!this.isLocked(i)){
5452                 return i;
5453             }
5454         }
5455         
5456         return this.config.length;
5457     },
5458
5459     /**
5460      * Returns the number of columns.
5461      * @return {Number}
5462      */
5463     getColumnCount : function(visibleOnly){
5464         if(visibleOnly === true){
5465             var c = 0;
5466             for(var i = 0, len = this.config.length; i < len; i++){
5467                 if(!this.isHidden(i)){
5468                     c++;
5469                 }
5470             }
5471             return c;
5472         }
5473         return this.config.length;
5474     },
5475
5476     /**
5477      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5478      * @param {Function} fn
5479      * @param {Object} scope (optional)
5480      * @return {Array} result
5481      */
5482     getColumnsBy : function(fn, scope){
5483         var r = [];
5484         for(var i = 0, len = this.config.length; i < len; i++){
5485             var c = this.config[i];
5486             if(fn.call(scope||this, c, i) === true){
5487                 r[r.length] = c;
5488             }
5489         }
5490         return r;
5491     },
5492
5493     /**
5494      * Returns true if the specified column is sortable.
5495      * @param {Number} col The column index
5496      * @return {Boolean}
5497      */
5498     isSortable : function(col){
5499         if(typeof this.config[col].sortable == "undefined"){
5500             return this.defaultSortable;
5501         }
5502         return this.config[col].sortable;
5503     },
5504
5505     /**
5506      * Returns the rendering (formatting) function defined for the column.
5507      * @param {Number} col The column index.
5508      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5509      */
5510     getRenderer : function(col){
5511         if(!this.config[col].renderer){
5512             return Roo.grid.ColumnModel.defaultRenderer;
5513         }
5514         return this.config[col].renderer;
5515     },
5516
5517     /**
5518      * Sets the rendering (formatting) function for a column.
5519      * @param {Number} col The column index
5520      * @param {Function} fn The function to use to process the cell's raw data
5521      * to return HTML markup for the grid view. The render function is called with
5522      * the following parameters:<ul>
5523      * <li>Data value.</li>
5524      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5525      * <li>css A CSS style string to apply to the table cell.</li>
5526      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5527      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5528      * <li>Row index</li>
5529      * <li>Column index</li>
5530      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5531      */
5532     setRenderer : function(col, fn){
5533         this.config[col].renderer = fn;
5534     },
5535
5536     /**
5537      * Returns the width for the specified column.
5538      * @param {Number} col The column index
5539      * @return {Number}
5540      */
5541     getColumnWidth : function(col){
5542         return this.config[col].width * 1 || this.defaultWidth;
5543     },
5544
5545     /**
5546      * Sets the width for a column.
5547      * @param {Number} col The column index
5548      * @param {Number} width The new width
5549      */
5550     setColumnWidth : function(col, width, suppressEvent){
5551         this.config[col].width = width;
5552         this.totalWidth = null;
5553         if(!suppressEvent){
5554              this.fireEvent("widthchange", this, col, width);
5555         }
5556     },
5557
5558     /**
5559      * Returns the total width of all columns.
5560      * @param {Boolean} includeHidden True to include hidden column widths
5561      * @return {Number}
5562      */
5563     getTotalWidth : function(includeHidden){
5564         if(!this.totalWidth){
5565             this.totalWidth = 0;
5566             for(var i = 0, len = this.config.length; i < len; i++){
5567                 if(includeHidden || !this.isHidden(i)){
5568                     this.totalWidth += this.getColumnWidth(i);
5569                 }
5570             }
5571         }
5572         return this.totalWidth;
5573     },
5574
5575     /**
5576      * Returns the header for the specified column.
5577      * @param {Number} col The column index
5578      * @return {String}
5579      */
5580     getColumnHeader : function(col){
5581         return this.config[col].header;
5582     },
5583
5584     /**
5585      * Sets the header for a column.
5586      * @param {Number} col The column index
5587      * @param {String} header The new header
5588      */
5589     setColumnHeader : function(col, header){
5590         this.config[col].header = header;
5591         this.fireEvent("headerchange", this, col, header);
5592     },
5593
5594     /**
5595      * Returns the tooltip for the specified column.
5596      * @param {Number} col The column index
5597      * @return {String}
5598      */
5599     getColumnTooltip : function(col){
5600             return this.config[col].tooltip;
5601     },
5602     /**
5603      * Sets the tooltip for a column.
5604      * @param {Number} col The column index
5605      * @param {String} tooltip The new tooltip
5606      */
5607     setColumnTooltip : function(col, tooltip){
5608             this.config[col].tooltip = tooltip;
5609     },
5610
5611     /**
5612      * Returns the dataIndex for the specified column.
5613      * @param {Number} col The column index
5614      * @return {Number}
5615      */
5616     getDataIndex : function(col){
5617         return this.config[col].dataIndex;
5618     },
5619
5620     /**
5621      * Sets the dataIndex for a column.
5622      * @param {Number} col The column index
5623      * @param {Number} dataIndex The new dataIndex
5624      */
5625     setDataIndex : function(col, dataIndex){
5626         this.config[col].dataIndex = dataIndex;
5627     },
5628
5629     
5630     
5631     /**
5632      * Returns true if the cell is editable.
5633      * @param {Number} colIndex The column index
5634      * @param {Number} rowIndex The row index - this is nto actually used..?
5635      * @return {Boolean}
5636      */
5637     isCellEditable : function(colIndex, rowIndex){
5638         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5639     },
5640
5641     /**
5642      * Returns the editor defined for the cell/column.
5643      * return false or null to disable editing.
5644      * @param {Number} colIndex The column index
5645      * @param {Number} rowIndex The row index
5646      * @return {Object}
5647      */
5648     getCellEditor : function(colIndex, rowIndex){
5649         return this.config[colIndex].editor;
5650     },
5651
5652     /**
5653      * Sets if a column is editable.
5654      * @param {Number} col The column index
5655      * @param {Boolean} editable True if the column is editable
5656      */
5657     setEditable : function(col, editable){
5658         this.config[col].editable = editable;
5659     },
5660
5661
5662     /**
5663      * Returns true if the column is hidden.
5664      * @param {Number} colIndex The column index
5665      * @return {Boolean}
5666      */
5667     isHidden : function(colIndex){
5668         return this.config[colIndex].hidden;
5669     },
5670
5671
5672     /**
5673      * Returns true if the column width cannot be changed
5674      */
5675     isFixed : function(colIndex){
5676         return this.config[colIndex].fixed;
5677     },
5678
5679     /**
5680      * Returns true if the column can be resized
5681      * @return {Boolean}
5682      */
5683     isResizable : function(colIndex){
5684         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5685     },
5686     /**
5687      * Sets if a column is hidden.
5688      * @param {Number} colIndex The column index
5689      * @param {Boolean} hidden True if the column is hidden
5690      */
5691     setHidden : function(colIndex, hidden){
5692         this.config[colIndex].hidden = hidden;
5693         this.totalWidth = null;
5694         this.fireEvent("hiddenchange", this, colIndex, hidden);
5695     },
5696
5697     /**
5698      * Sets the editor for a column.
5699      * @param {Number} col The column index
5700      * @param {Object} editor The editor object
5701      */
5702     setEditor : function(col, editor){
5703         this.config[col].editor = editor;
5704     }
5705 });
5706
5707 Roo.grid.ColumnModel.defaultRenderer = function(value)
5708 {
5709     if(typeof value == "object") {
5710         return value;
5711     }
5712         if(typeof value == "string" && value.length < 1){
5713             return "&#160;";
5714         }
5715     
5716         return String.format("{0}", value);
5717 };
5718
5719 // Alias for backwards compatibility
5720 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5721 /*
5722  * Based on:
5723  * Ext JS Library 1.1.1
5724  * Copyright(c) 2006-2007, Ext JS, LLC.
5725  *
5726  * Originally Released Under LGPL - original licence link has changed is not relivant.
5727  *
5728  * Fork - LGPL
5729  * <script type="text/javascript">
5730  */
5731  
5732 /**
5733  * @class Roo.LoadMask
5734  * A simple utility class for generically masking elements while loading data.  If the element being masked has
5735  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5736  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
5737  * element's UpdateManager load indicator and will be destroyed after the initial load.
5738  * @constructor
5739  * Create a new LoadMask
5740  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5741  * @param {Object} config The config object
5742  */
5743 Roo.LoadMask = function(el, config){
5744     this.el = Roo.get(el);
5745     Roo.apply(this, config);
5746     if(this.store){
5747         this.store.on('beforeload', this.onBeforeLoad, this);
5748         this.store.on('load', this.onLoad, this);
5749         this.store.on('loadexception', this.onLoadException, this);
5750         this.removeMask = false;
5751     }else{
5752         var um = this.el.getUpdateManager();
5753         um.showLoadIndicator = false; // disable the default indicator
5754         um.on('beforeupdate', this.onBeforeLoad, this);
5755         um.on('update', this.onLoad, this);
5756         um.on('failure', this.onLoad, this);
5757         this.removeMask = true;
5758     }
5759 };
5760
5761 Roo.LoadMask.prototype = {
5762     /**
5763      * @cfg {Boolean} removeMask
5764      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5765      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
5766      */
5767     /**
5768      * @cfg {String} msg
5769      * The text to display in a centered loading message box (defaults to 'Loading...')
5770      */
5771     msg : 'Loading...',
5772     /**
5773      * @cfg {String} msgCls
5774      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5775      */
5776     msgCls : 'x-mask-loading',
5777
5778     /**
5779      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5780      * @type Boolean
5781      */
5782     disabled: false,
5783
5784     /**
5785      * Disables the mask to prevent it from being displayed
5786      */
5787     disable : function(){
5788        this.disabled = true;
5789     },
5790
5791     /**
5792      * Enables the mask so that it can be displayed
5793      */
5794     enable : function(){
5795         this.disabled = false;
5796     },
5797     
5798     onLoadException : function()
5799     {
5800         Roo.log(arguments);
5801         
5802         if (typeof(arguments[3]) != 'undefined') {
5803             Roo.MessageBox.alert("Error loading",arguments[3]);
5804         } 
5805         /*
5806         try {
5807             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5808                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5809             }   
5810         } catch(e) {
5811             
5812         }
5813         */
5814     
5815         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5816     },
5817     // private
5818     onLoad : function()
5819     {
5820         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5821     },
5822
5823     // private
5824     onBeforeLoad : function(){
5825         if(!this.disabled){
5826             (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5827         }
5828     },
5829
5830     // private
5831     destroy : function(){
5832         if(this.store){
5833             this.store.un('beforeload', this.onBeforeLoad, this);
5834             this.store.un('load', this.onLoad, this);
5835             this.store.un('loadexception', this.onLoadException, this);
5836         }else{
5837             var um = this.el.getUpdateManager();
5838             um.un('beforeupdate', this.onBeforeLoad, this);
5839             um.un('update', this.onLoad, this);
5840             um.un('failure', this.onLoad, this);
5841         }
5842     }
5843 };/*
5844  * - LGPL
5845  *
5846  * table
5847  * 
5848  */
5849
5850 /**
5851  * @class Roo.bootstrap.Table
5852  * @extends Roo.bootstrap.Component
5853  * Bootstrap Table class
5854  * @cfg {String} cls table class
5855  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5856  * @cfg {String} bgcolor Specifies the background color for a table
5857  * @cfg {Number} border Specifies whether the table cells should have borders or not
5858  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5859  * @cfg {Number} cellspacing Specifies the space between cells
5860  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5861  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5862  * @cfg {String} sortable Specifies that the table should be sortable
5863  * @cfg {String} summary Specifies a summary of the content of a table
5864  * @cfg {Number} width Specifies the width of a table
5865  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5866  * 
5867  * @cfg {boolean} striped Should the rows be alternative striped
5868  * @cfg {boolean} bordered Add borders to the table
5869  * @cfg {boolean} hover Add hover highlighting
5870  * @cfg {boolean} condensed Format condensed
5871  * @cfg {boolean} responsive Format condensed
5872  * @cfg {Boolean} loadMask (true|false) default false
5873  * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5874  * @cfg {Boolean} headerShow (true|false) generate thead, default true
5875  * @cfg {Boolean} rowSelection (true|false) default false
5876  * @cfg {Boolean} cellSelection (true|false) default false
5877  * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5878  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5879  * @cfg {Boolean} lazyLoad  auto load data while scrolling to the end (default false)
5880  
5881  * 
5882  * @constructor
5883  * Create a new Table
5884  * @param {Object} config The config object
5885  */
5886
5887 Roo.bootstrap.Table = function(config){
5888     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5889     
5890   
5891     
5892     // BC...
5893     this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5894     this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5895     this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5896     this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5897     
5898     this.sm = this.sm || {xtype: 'RowSelectionModel'};
5899     if (this.sm) {
5900         this.sm.grid = this;
5901         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5902         this.sm = this.selModel;
5903         this.sm.xmodule = this.xmodule || false;
5904     }
5905     
5906     if (this.cm && typeof(this.cm.config) == 'undefined') {
5907         this.colModel = new Roo.grid.ColumnModel(this.cm);
5908         this.cm = this.colModel;
5909         this.cm.xmodule = this.xmodule || false;
5910     }
5911     if (this.store) {
5912         this.store= Roo.factory(this.store, Roo.data);
5913         this.ds = this.store;
5914         this.ds.xmodule = this.xmodule || false;
5915          
5916     }
5917     if (this.footer && this.store) {
5918         this.footer.dataSource = this.ds;
5919         this.footer = Roo.factory(this.footer);
5920     }
5921     
5922     /** @private */
5923     this.addEvents({
5924         /**
5925          * @event cellclick
5926          * Fires when a cell is clicked
5927          * @param {Roo.bootstrap.Table} this
5928          * @param {Roo.Element} el
5929          * @param {Number} rowIndex
5930          * @param {Number} columnIndex
5931          * @param {Roo.EventObject} e
5932          */
5933         "cellclick" : true,
5934         /**
5935          * @event celldblclick
5936          * Fires when a cell is double clicked
5937          * @param {Roo.bootstrap.Table} this
5938          * @param {Roo.Element} el
5939          * @param {Number} rowIndex
5940          * @param {Number} columnIndex
5941          * @param {Roo.EventObject} e
5942          */
5943         "celldblclick" : true,
5944         /**
5945          * @event rowclick
5946          * Fires when a row is clicked
5947          * @param {Roo.bootstrap.Table} this
5948          * @param {Roo.Element} el
5949          * @param {Number} rowIndex
5950          * @param {Roo.EventObject} e
5951          */
5952         "rowclick" : true,
5953         /**
5954          * @event rowdblclick
5955          * Fires when a row is double clicked
5956          * @param {Roo.bootstrap.Table} this
5957          * @param {Roo.Element} el
5958          * @param {Number} rowIndex
5959          * @param {Roo.EventObject} e
5960          */
5961         "rowdblclick" : true,
5962         /**
5963          * @event mouseover
5964          * Fires when a mouseover occur
5965          * @param {Roo.bootstrap.Table} this
5966          * @param {Roo.Element} el
5967          * @param {Number} rowIndex
5968          * @param {Number} columnIndex
5969          * @param {Roo.EventObject} e
5970          */
5971         "mouseover" : true,
5972         /**
5973          * @event mouseout
5974          * Fires when a mouseout occur
5975          * @param {Roo.bootstrap.Table} this
5976          * @param {Roo.Element} el
5977          * @param {Number} rowIndex
5978          * @param {Number} columnIndex
5979          * @param {Roo.EventObject} e
5980          */
5981         "mouseout" : true,
5982         /**
5983          * @event rowclass
5984          * Fires when a row is rendered, so you can change add a style to it.
5985          * @param {Roo.bootstrap.Table} this
5986          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5987          */
5988         'rowclass' : true,
5989           /**
5990          * @event rowsrendered
5991          * Fires when all the  rows have been rendered
5992          * @param {Roo.bootstrap.Table} this
5993          */
5994         'rowsrendered' : true,
5995         /**
5996          * @event contextmenu
5997          * The raw contextmenu event for the entire grid.
5998          * @param {Roo.EventObject} e
5999          */
6000         "contextmenu" : true,
6001         /**
6002          * @event rowcontextmenu
6003          * Fires when a row is right clicked
6004          * @param {Roo.bootstrap.Table} this
6005          * @param {Number} rowIndex
6006          * @param {Roo.EventObject} e
6007          */
6008         "rowcontextmenu" : true,
6009         /**
6010          * @event cellcontextmenu
6011          * Fires when a cell is right clicked
6012          * @param {Roo.bootstrap.Table} this
6013          * @param {Number} rowIndex
6014          * @param {Number} cellIndex
6015          * @param {Roo.EventObject} e
6016          */
6017          "cellcontextmenu" : true,
6018          /**
6019          * @event headercontextmenu
6020          * Fires when a header is right clicked
6021          * @param {Roo.bootstrap.Table} this
6022          * @param {Number} columnIndex
6023          * @param {Roo.EventObject} e
6024          */
6025         "headercontextmenu" : true
6026     });
6027 };
6028
6029 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
6030     
6031     cls: false,
6032     align: false,
6033     bgcolor: false,
6034     border: false,
6035     cellpadding: false,
6036     cellspacing: false,
6037     frame: false,
6038     rules: false,
6039     sortable: false,
6040     summary: false,
6041     width: false,
6042     striped : false,
6043     scrollBody : false,
6044     bordered: false,
6045     hover:  false,
6046     condensed : false,
6047     responsive : false,
6048     sm : false,
6049     cm : false,
6050     store : false,
6051     loadMask : false,
6052     footerShow : true,
6053     headerShow : true,
6054   
6055     rowSelection : false,
6056     cellSelection : false,
6057     layout : false,
6058     
6059     // Roo.Element - the tbody
6060     mainBody: false,
6061     // Roo.Element - thead element
6062     mainHead: false,
6063     
6064     container: false, // used by gridpanel...
6065     
6066     lazyLoad : false,
6067     
6068     CSS : Roo.util.CSS,
6069     
6070     getAutoCreate : function()
6071     {
6072         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6073         
6074         cfg = {
6075             tag: 'table',
6076             cls : 'table',
6077             cn : []
6078         };
6079         if (this.scrollBody) {
6080             cfg.cls += ' table-body-fixed';
6081         }    
6082         if (this.striped) {
6083             cfg.cls += ' table-striped';
6084         }
6085         
6086         if (this.hover) {
6087             cfg.cls += ' table-hover';
6088         }
6089         if (this.bordered) {
6090             cfg.cls += ' table-bordered';
6091         }
6092         if (this.condensed) {
6093             cfg.cls += ' table-condensed';
6094         }
6095         if (this.responsive) {
6096             cfg.cls += ' table-responsive';
6097         }
6098         
6099         if (this.cls) {
6100             cfg.cls+=  ' ' +this.cls;
6101         }
6102         
6103         // this lot should be simplifed...
6104         
6105         if (this.align) {
6106             cfg.align=this.align;
6107         }
6108         if (this.bgcolor) {
6109             cfg.bgcolor=this.bgcolor;
6110         }
6111         if (this.border) {
6112             cfg.border=this.border;
6113         }
6114         if (this.cellpadding) {
6115             cfg.cellpadding=this.cellpadding;
6116         }
6117         if (this.cellspacing) {
6118             cfg.cellspacing=this.cellspacing;
6119         }
6120         if (this.frame) {
6121             cfg.frame=this.frame;
6122         }
6123         if (this.rules) {
6124             cfg.rules=this.rules;
6125         }
6126         if (this.sortable) {
6127             cfg.sortable=this.sortable;
6128         }
6129         if (this.summary) {
6130             cfg.summary=this.summary;
6131         }
6132         if (this.width) {
6133             cfg.width=this.width;
6134         }
6135         if (this.layout) {
6136             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6137         }
6138         
6139         if(this.store || this.cm){
6140             if(this.headerShow){
6141                 cfg.cn.push(this.renderHeader());
6142             }
6143             
6144             cfg.cn.push(this.renderBody());
6145             
6146             if(this.footerShow){
6147                 cfg.cn.push(this.renderFooter());
6148             }
6149             // where does this come from?
6150             //cfg.cls+=  ' TableGrid';
6151         }
6152         
6153         return { cn : [ cfg ] };
6154     },
6155     
6156     initEvents : function()
6157     {   
6158         if(!this.store || !this.cm){
6159             return;
6160         }
6161         if (this.selModel) {
6162             this.selModel.initEvents();
6163         }
6164         
6165         
6166         //Roo.log('initEvents with ds!!!!');
6167         
6168         this.mainBody = this.el.select('tbody', true).first();
6169         this.mainHead = this.el.select('thead', true).first();
6170         
6171         
6172         
6173         
6174         var _this = this;
6175         
6176         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6177             e.on('click', _this.sort, _this);
6178         });
6179         
6180         this.mainBody.on("click", this.onClick, this);
6181         this.mainBody.on("dblclick", this.onDblClick, this);
6182         
6183         // why is this done????? = it breaks dialogs??
6184         //this.parent().el.setStyle('position', 'relative');
6185         
6186         
6187         if (this.footer) {
6188             this.footer.parentId = this.id;
6189             this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6190             
6191             if(this.lazyLoad){
6192                 this.el.select('tfoot tr td').first().addClass('hide');
6193             }
6194         } 
6195         
6196         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6197         
6198         this.store.on('load', this.onLoad, this);
6199         this.store.on('beforeload', this.onBeforeLoad, this);
6200         this.store.on('update', this.onUpdate, this);
6201         this.store.on('add', this.onAdd, this);
6202         this.store.on("clear", this.clear, this);
6203         
6204         this.el.on("contextmenu", this.onContextMenu, this);
6205         
6206         this.mainBody.on('scroll', this.onBodyScroll, this);
6207         
6208         this.cm.on("headerchange", this.onHeaderChange, this);
6209         
6210         this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6211         
6212     },
6213     
6214     onContextMenu : function(e, t)
6215     {
6216         this.processEvent("contextmenu", e);
6217     },
6218     
6219     processEvent : function(name, e)
6220     {
6221         if (name != 'touchstart' ) {
6222             this.fireEvent(name, e);    
6223         }
6224         
6225         var t = e.getTarget();
6226         
6227         var cell = Roo.get(t);
6228         
6229         if(!cell){
6230             return;
6231         }
6232         
6233         if(cell.findParent('tfoot', false, true)){
6234             return;
6235         }
6236         
6237         if(cell.findParent('thead', false, true)){
6238             
6239             if(e.getTarget().nodeName.toLowerCase() != 'th'){
6240                 cell = Roo.get(t).findParent('th', false, true);
6241                 if (!cell) {
6242                     Roo.log("failed to find th in thead?");
6243                     Roo.log(e.getTarget());
6244                     return;
6245                 }
6246             }
6247             
6248             var cellIndex = cell.dom.cellIndex;
6249             
6250             var ename = name == 'touchstart' ? 'click' : name;
6251             this.fireEvent("header" + ename, this, cellIndex, e);
6252             
6253             return;
6254         }
6255         
6256         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6257             cell = Roo.get(t).findParent('td', false, true);
6258             if (!cell) {
6259                 Roo.log("failed to find th in tbody?");
6260                 Roo.log(e.getTarget());
6261                 return;
6262             }
6263         }
6264         
6265         var row = cell.findParent('tr', false, true);
6266         var cellIndex = cell.dom.cellIndex;
6267         var rowIndex = row.dom.rowIndex - 1;
6268         
6269         if(row !== false){
6270             
6271             this.fireEvent("row" + name, this, rowIndex, e);
6272             
6273             if(cell !== false){
6274             
6275                 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6276             }
6277         }
6278         
6279     },
6280     
6281     onMouseover : function(e, el)
6282     {
6283         var cell = Roo.get(el);
6284         
6285         if(!cell){
6286             return;
6287         }
6288         
6289         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6290             cell = cell.findParent('td', false, true);
6291         }
6292         
6293         var row = cell.findParent('tr', false, true);
6294         var cellIndex = cell.dom.cellIndex;
6295         var rowIndex = row.dom.rowIndex - 1; // start from 0
6296         
6297         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6298         
6299     },
6300     
6301     onMouseout : function(e, el)
6302     {
6303         var cell = Roo.get(el);
6304         
6305         if(!cell){
6306             return;
6307         }
6308         
6309         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6310             cell = cell.findParent('td', false, true);
6311         }
6312         
6313         var row = cell.findParent('tr', false, true);
6314         var cellIndex = cell.dom.cellIndex;
6315         var rowIndex = row.dom.rowIndex - 1; // start from 0
6316         
6317         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6318         
6319     },
6320     
6321     onClick : function(e, el)
6322     {
6323         var cell = Roo.get(el);
6324         
6325         if(!cell || (!this.cellSelection && !this.rowSelection)){
6326             return;
6327         }
6328         
6329         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6330             cell = cell.findParent('td', false, true);
6331         }
6332         
6333         if(!cell || typeof(cell) == 'undefined'){
6334             return;
6335         }
6336         
6337         var row = cell.findParent('tr', false, true);
6338         
6339         if(!row || typeof(row) == 'undefined'){
6340             return;
6341         }
6342         
6343         var cellIndex = cell.dom.cellIndex;
6344         var rowIndex = this.getRowIndex(row);
6345         
6346         // why??? - should these not be based on SelectionModel?
6347         if(this.cellSelection){
6348             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6349         }
6350         
6351         if(this.rowSelection){
6352             this.fireEvent('rowclick', this, row, rowIndex, e);
6353         }
6354         
6355         
6356     },
6357         
6358     onDblClick : function(e,el)
6359     {
6360         var cell = Roo.get(el);
6361         
6362         if(!cell || (!this.cellSelection && !this.rowSelection)){
6363             return;
6364         }
6365         
6366         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6367             cell = cell.findParent('td', false, true);
6368         }
6369         
6370         if(!cell || typeof(cell) == 'undefined'){
6371             return;
6372         }
6373         
6374         var row = cell.findParent('tr', false, true);
6375         
6376         if(!row || typeof(row) == 'undefined'){
6377             return;
6378         }
6379         
6380         var cellIndex = cell.dom.cellIndex;
6381         var rowIndex = this.getRowIndex(row);
6382         
6383         if(this.cellSelection){
6384             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6385         }
6386         
6387         if(this.rowSelection){
6388             this.fireEvent('rowdblclick', this, row, rowIndex, e);
6389         }
6390     },
6391     
6392     sort : function(e,el)
6393     {
6394         var col = Roo.get(el);
6395         
6396         if(!col.hasClass('sortable')){
6397             return;
6398         }
6399         
6400         var sort = col.attr('sort');
6401         var dir = 'ASC';
6402         
6403         if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6404             dir = 'DESC';
6405         }
6406         
6407         this.store.sortInfo = {field : sort, direction : dir};
6408         
6409         if (this.footer) {
6410             Roo.log("calling footer first");
6411             this.footer.onClick('first');
6412         } else {
6413         
6414             this.store.load({ params : { start : 0 } });
6415         }
6416     },
6417     
6418     renderHeader : function()
6419     {
6420         var header = {
6421             tag: 'thead',
6422             cn : []
6423         };
6424         
6425         var cm = this.cm;
6426         this.totalWidth = 0;
6427         
6428         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6429             
6430             var config = cm.config[i];
6431             
6432             var c = {
6433                 tag: 'th',
6434                 cls : 'x-hcol-' + i,
6435                 style : '',
6436                 html: cm.getColumnHeader(i)
6437             };
6438             
6439             var hh = '';
6440             
6441             if(typeof(config.sortable) != 'undefined' && config.sortable){
6442                 c.cls = 'sortable';
6443                 c.html = '<i class="glyphicon"></i>' + c.html;
6444             }
6445             
6446             if(typeof(config.lgHeader) != 'undefined'){
6447                 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6448             }
6449             
6450             if(typeof(config.mdHeader) != 'undefined'){
6451                 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6452             }
6453             
6454             if(typeof(config.smHeader) != 'undefined'){
6455                 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6456             }
6457             
6458             if(typeof(config.xsHeader) != 'undefined'){
6459                 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6460             }
6461             
6462             if(hh.length){
6463                 c.html = hh;
6464             }
6465             
6466             if(typeof(config.tooltip) != 'undefined'){
6467                 c.tooltip = config.tooltip;
6468             }
6469             
6470             if(typeof(config.colspan) != 'undefined'){
6471                 c.colspan = config.colspan;
6472             }
6473             
6474             if(typeof(config.hidden) != 'undefined' && config.hidden){
6475                 c.style += ' display:none;';
6476             }
6477             
6478             if(typeof(config.dataIndex) != 'undefined'){
6479                 c.sort = config.dataIndex;
6480             }
6481             
6482            
6483             
6484             if(typeof(config.align) != 'undefined' && config.align.length){
6485                 c.style += ' text-align:' + config.align + ';';
6486             }
6487             
6488             if(typeof(config.width) != 'undefined'){
6489                 c.style += ' width:' + config.width + 'px;';
6490                 this.totalWidth += config.width;
6491             } else {
6492                 this.totalWidth += 100; // assume minimum of 100 per column?
6493             }
6494             
6495             if(typeof(config.cls) != 'undefined'){
6496                 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6497             }
6498             
6499             ['xs','sm','md','lg'].map(function(size){
6500                 
6501                 if(typeof(config[size]) == 'undefined'){
6502                     return;
6503                 }
6504                 
6505                 if (!config[size]) { // 0 = hidden
6506                     c.cls += ' hidden-' + size;
6507                     return;
6508                 }
6509                 
6510                 c.cls += ' col-' + size + '-' + config[size];
6511
6512             });
6513             
6514             header.cn.push(c)
6515         }
6516         
6517         return header;
6518     },
6519     
6520     renderBody : function()
6521     {
6522         var body = {
6523             tag: 'tbody',
6524             cn : [
6525                 {
6526                     tag: 'tr',
6527                     cn : [
6528                         {
6529                             tag : 'td',
6530                             colspan :  this.cm.getColumnCount()
6531                         }
6532                     ]
6533                 }
6534             ]
6535         };
6536         
6537         return body;
6538     },
6539     
6540     renderFooter : function()
6541     {
6542         var footer = {
6543             tag: 'tfoot',
6544             cn : [
6545                 {
6546                     tag: 'tr',
6547                     cn : [
6548                         {
6549                             tag : 'td',
6550                             colspan :  this.cm.getColumnCount()
6551                         }
6552                     ]
6553                 }
6554             ]
6555         };
6556         
6557         return footer;
6558     },
6559     
6560     
6561     
6562     onLoad : function()
6563     {
6564 //        Roo.log('ds onload');
6565         this.clear();
6566         
6567         var _this = this;
6568         var cm = this.cm;
6569         var ds = this.store;
6570         
6571         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6572             e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6573             if (_this.store.sortInfo) {
6574                     
6575                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6576                     e.select('i', true).addClass(['glyphicon-arrow-up']);
6577                 }
6578                 
6579                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6580                     e.select('i', true).addClass(['glyphicon-arrow-down']);
6581                 }
6582             }
6583         });
6584         
6585         var tbody =  this.mainBody;
6586               
6587         if(ds.getCount() > 0){
6588             ds.data.each(function(d,rowIndex){
6589                 var row =  this.renderRow(cm, ds, rowIndex);
6590                 
6591                 tbody.createChild(row);
6592                 
6593                 var _this = this;
6594                 
6595                 if(row.cellObjects.length){
6596                     Roo.each(row.cellObjects, function(r){
6597                         _this.renderCellObject(r);
6598                     })
6599                 }
6600                 
6601             }, this);
6602         }
6603         
6604         Roo.each(this.el.select('tbody td', true).elements, function(e){
6605             e.on('mouseover', _this.onMouseover, _this);
6606         });
6607         
6608         Roo.each(this.el.select('tbody td', true).elements, function(e){
6609             e.on('mouseout', _this.onMouseout, _this);
6610         });
6611         this.fireEvent('rowsrendered', this);
6612         //if(this.loadMask){
6613         //    this.maskEl.hide();
6614         //}
6615         
6616         this.autoSize();
6617     },
6618     
6619     
6620     onUpdate : function(ds,record)
6621     {
6622         this.refreshRow(record);
6623         this.autoSize();
6624     },
6625     
6626     onRemove : function(ds, record, index, isUpdate){
6627         if(isUpdate !== true){
6628             this.fireEvent("beforerowremoved", this, index, record);
6629         }
6630         var bt = this.mainBody.dom;
6631         
6632         var rows = this.el.select('tbody > tr', true).elements;
6633         
6634         if(typeof(rows[index]) != 'undefined'){
6635             bt.removeChild(rows[index].dom);
6636         }
6637         
6638 //        if(bt.rows[index]){
6639 //            bt.removeChild(bt.rows[index]);
6640 //        }
6641         
6642         if(isUpdate !== true){
6643             //this.stripeRows(index);
6644             //this.syncRowHeights(index, index);
6645             //this.layout();
6646             this.fireEvent("rowremoved", this, index, record);
6647         }
6648     },
6649     
6650     onAdd : function(ds, records, rowIndex)
6651     {
6652         //Roo.log('on Add called');
6653         // - note this does not handle multiple adding very well..
6654         var bt = this.mainBody.dom;
6655         for (var i =0 ; i < records.length;i++) {
6656             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6657             //Roo.log(records[i]);
6658             //Roo.log(this.store.getAt(rowIndex+i));
6659             this.insertRow(this.store, rowIndex + i, false);
6660             return;
6661         }
6662         
6663     },
6664     
6665     
6666     refreshRow : function(record){
6667         var ds = this.store, index;
6668         if(typeof record == 'number'){
6669             index = record;
6670             record = ds.getAt(index);
6671         }else{
6672             index = ds.indexOf(record);
6673         }
6674         this.insertRow(ds, index, true);
6675         this.autoSize();
6676         this.onRemove(ds, record, index+1, true);
6677         this.autoSize();
6678         //this.syncRowHeights(index, index);
6679         //this.layout();
6680         this.fireEvent("rowupdated", this, index, record);
6681     },
6682     
6683     insertRow : function(dm, rowIndex, isUpdate){
6684         
6685         if(!isUpdate){
6686             this.fireEvent("beforerowsinserted", this, rowIndex);
6687         }
6688             //var s = this.getScrollState();
6689         var row = this.renderRow(this.cm, this.store, rowIndex);
6690         // insert before rowIndex..
6691         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6692         
6693         var _this = this;
6694                 
6695         if(row.cellObjects.length){
6696             Roo.each(row.cellObjects, function(r){
6697                 _this.renderCellObject(r);
6698             })
6699         }
6700             
6701         if(!isUpdate){
6702             this.fireEvent("rowsinserted", this, rowIndex);
6703             //this.syncRowHeights(firstRow, lastRow);
6704             //this.stripeRows(firstRow);
6705             //this.layout();
6706         }
6707         
6708     },
6709     
6710     
6711     getRowDom : function(rowIndex)
6712     {
6713         var rows = this.el.select('tbody > tr', true).elements;
6714         
6715         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6716         
6717     },
6718     // returns the object tree for a tr..
6719   
6720     
6721     renderRow : function(cm, ds, rowIndex) 
6722     {
6723         var d = ds.getAt(rowIndex);
6724         
6725         var row = {
6726             tag : 'tr',
6727             cls : 'x-row-' + rowIndex,
6728             cn : []
6729         };
6730             
6731         var cellObjects = [];
6732         
6733         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6734             var config = cm.config[i];
6735             
6736             var renderer = cm.getRenderer(i);
6737             var value = '';
6738             var id = false;
6739             
6740             if(typeof(renderer) !== 'undefined'){
6741                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6742             }
6743             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6744             // and are rendered into the cells after the row is rendered - using the id for the element.
6745             
6746             if(typeof(value) === 'object'){
6747                 id = Roo.id();
6748                 cellObjects.push({
6749                     container : id,
6750                     cfg : value 
6751                 })
6752             }
6753             
6754             var rowcfg = {
6755                 record: d,
6756                 rowIndex : rowIndex,
6757                 colIndex : i,
6758                 rowClass : ''
6759             };
6760
6761             this.fireEvent('rowclass', this, rowcfg);
6762             
6763             var td = {
6764                 tag: 'td',
6765                 cls : rowcfg.rowClass + ' x-col-' + i,
6766                 style: '',
6767                 html: (typeof(value) === 'object') ? '' : value
6768             };
6769             
6770             if (id) {
6771                 td.id = id;
6772             }
6773             
6774             if(typeof(config.colspan) != 'undefined'){
6775                 td.colspan = config.colspan;
6776             }
6777             
6778             if(typeof(config.hidden) != 'undefined' && config.hidden){
6779                 td.style += ' display:none;';
6780             }
6781             
6782             if(typeof(config.align) != 'undefined' && config.align.length){
6783                 td.style += ' text-align:' + config.align + ';';
6784             }
6785             
6786             if(typeof(config.width) != 'undefined'){
6787                 td.style += ' width:' +  config.width + 'px;';
6788             }
6789             
6790             if(typeof(config.cursor) != 'undefined'){
6791                 td.style += ' cursor:' +  config.cursor + ';';
6792             }
6793             
6794             if(typeof(config.cls) != 'undefined'){
6795                 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6796             }
6797             
6798             ['xs','sm','md','lg'].map(function(size){
6799                 
6800                 if(typeof(config[size]) == 'undefined'){
6801                     return;
6802                 }
6803                 
6804                 if (!config[size]) { // 0 = hidden
6805                     td.cls += ' hidden-' + size;
6806                     return;
6807                 }
6808                 
6809                 td.cls += ' col-' + size + '-' + config[size];
6810
6811             });
6812             
6813             row.cn.push(td);
6814            
6815         }
6816         
6817         row.cellObjects = cellObjects;
6818         
6819         return row;
6820           
6821     },
6822     
6823     
6824     
6825     onBeforeLoad : function()
6826     {
6827         //Roo.log('ds onBeforeLoad');
6828         
6829         //this.clear();
6830         
6831         //if(this.loadMask){
6832         //    this.maskEl.show();
6833         //}
6834     },
6835      /**
6836      * Remove all rows
6837      */
6838     clear : function()
6839     {
6840         this.el.select('tbody', true).first().dom.innerHTML = '';
6841     },
6842     /**
6843      * Show or hide a row.
6844      * @param {Number} rowIndex to show or hide
6845      * @param {Boolean} state hide
6846      */
6847     setRowVisibility : function(rowIndex, state)
6848     {
6849         var bt = this.mainBody.dom;
6850         
6851         var rows = this.el.select('tbody > tr', true).elements;
6852         
6853         if(typeof(rows[rowIndex]) == 'undefined'){
6854             return;
6855         }
6856         rows[rowIndex].dom.style.display = state ? '' : 'none';
6857     },
6858     
6859     
6860     getSelectionModel : function(){
6861         if(!this.selModel){
6862             this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6863         }
6864         return this.selModel;
6865     },
6866     /*
6867      * Render the Roo.bootstrap object from renderder
6868      */
6869     renderCellObject : function(r)
6870     {
6871         var _this = this;
6872         
6873         r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6874         
6875         var t = r.cfg.render(r.container);
6876         
6877         if(r.cfg.cn){
6878             Roo.each(r.cfg.cn, function(c){
6879                 var child = {
6880                     container: t.getChildContainer(),
6881                     cfg: c
6882                 };
6883                 _this.renderCellObject(child);
6884             })
6885         }
6886     },
6887     
6888     getRowIndex : function(row)
6889     {
6890         var rowIndex = -1;
6891         
6892         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6893             if(el != row){
6894                 return;
6895             }
6896             
6897             rowIndex = index;
6898         });
6899         
6900         return rowIndex;
6901     },
6902      /**
6903      * Returns the grid's underlying element = used by panel.Grid
6904      * @return {Element} The element
6905      */
6906     getGridEl : function(){
6907         return this.el;
6908     },
6909      /**
6910      * Forces a resize - used by panel.Grid
6911      * @return {Element} The element
6912      */
6913     autoSize : function()
6914     {
6915         //var ctr = Roo.get(this.container.dom.parentElement);
6916         var ctr = Roo.get(this.el.dom);
6917         
6918         var thd = this.getGridEl().select('thead',true).first();
6919         var tbd = this.getGridEl().select('tbody', true).first();
6920         var tfd = this.getGridEl().select('tfoot', true).first();
6921         
6922         var cw = ctr.getWidth();
6923         
6924         if (tbd) {
6925             
6926             tbd.setSize(ctr.getWidth(),
6927                         ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6928             );
6929             var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6930             cw -= barsize;
6931         }
6932         cw = Math.max(cw, this.totalWidth);
6933         this.getGridEl().select('tr',true).setWidth(cw);
6934         // resize 'expandable coloumn?
6935         
6936         return; // we doe not have a view in this design..
6937         
6938     },
6939     onBodyScroll: function()
6940     {
6941         //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6942         if(this.mainHead){
6943             this.mainHead.setStyle({
6944                 'position' : 'relative',
6945                 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6946             });
6947         }
6948         
6949         if(this.lazyLoad){
6950             
6951             var scrollHeight = this.mainBody.dom.scrollHeight;
6952             
6953             var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6954             
6955             var height = this.mainBody.getHeight();
6956             
6957             if(scrollHeight - height == scrollTop) {
6958                 
6959                 var total = this.ds.getTotalCount();
6960                 
6961                 if(this.footer.cursor + this.footer.pageSize < total){
6962                     
6963                     this.footer.ds.load({
6964                         params : {
6965                             start : this.footer.cursor + this.footer.pageSize,
6966                             limit : this.footer.pageSize
6967                         },
6968                         add : true
6969                     });
6970                 }
6971             }
6972             
6973         }
6974     },
6975     
6976     onHeaderChange : function()
6977     {
6978         var header = this.renderHeader();
6979         var table = this.el.select('table', true).first();
6980         
6981         this.mainHead.remove();
6982         this.mainHead = table.createChild(header, this.mainBody, false);
6983     },
6984     
6985     onHiddenChange : function(colModel, colIndex, hidden)
6986     {
6987         var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
6988         var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
6989         
6990         this.CSS.updateRule(thSelector, "display", "");
6991         this.CSS.updateRule(tdSelector, "display", "");
6992         
6993         if(hidden){
6994             this.CSS.updateRule(thSelector, "display", "none");
6995             this.CSS.updateRule(tdSelector, "display", "none");
6996         }
6997         
6998         this.onHeaderChange();
6999         this.onLoad();
7000         
7001     }
7002     
7003 });
7004
7005  
7006
7007  /*
7008  * - LGPL
7009  *
7010  * table cell
7011  * 
7012  */
7013
7014 /**
7015  * @class Roo.bootstrap.TableCell
7016  * @extends Roo.bootstrap.Component
7017  * Bootstrap TableCell class
7018  * @cfg {String} html cell contain text
7019  * @cfg {String} cls cell class
7020  * @cfg {String} tag cell tag (td|th) default td
7021  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7022  * @cfg {String} align Aligns the content in a cell
7023  * @cfg {String} axis Categorizes cells
7024  * @cfg {String} bgcolor Specifies the background color of a cell
7025  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7026  * @cfg {Number} colspan Specifies the number of columns a cell should span
7027  * @cfg {String} headers Specifies one or more header cells a cell is related to
7028  * @cfg {Number} height Sets the height of a cell
7029  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7030  * @cfg {Number} rowspan Sets the number of rows a cell should span
7031  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7032  * @cfg {String} valign Vertical aligns the content in a cell
7033  * @cfg {Number} width Specifies the width of a cell
7034  * 
7035  * @constructor
7036  * Create a new TableCell
7037  * @param {Object} config The config object
7038  */
7039
7040 Roo.bootstrap.TableCell = function(config){
7041     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7042 };
7043
7044 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
7045     
7046     html: false,
7047     cls: false,
7048     tag: false,
7049     abbr: false,
7050     align: false,
7051     axis: false,
7052     bgcolor: false,
7053     charoff: false,
7054     colspan: false,
7055     headers: false,
7056     height: false,
7057     nowrap: false,
7058     rowspan: false,
7059     scope: false,
7060     valign: false,
7061     width: false,
7062     
7063     
7064     getAutoCreate : function(){
7065         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7066         
7067         cfg = {
7068             tag: 'td'
7069         };
7070         
7071         if(this.tag){
7072             cfg.tag = this.tag;
7073         }
7074         
7075         if (this.html) {
7076             cfg.html=this.html
7077         }
7078         if (this.cls) {
7079             cfg.cls=this.cls
7080         }
7081         if (this.abbr) {
7082             cfg.abbr=this.abbr
7083         }
7084         if (this.align) {
7085             cfg.align=this.align
7086         }
7087         if (this.axis) {
7088             cfg.axis=this.axis
7089         }
7090         if (this.bgcolor) {
7091             cfg.bgcolor=this.bgcolor
7092         }
7093         if (this.charoff) {
7094             cfg.charoff=this.charoff
7095         }
7096         if (this.colspan) {
7097             cfg.colspan=this.colspan
7098         }
7099         if (this.headers) {
7100             cfg.headers=this.headers
7101         }
7102         if (this.height) {
7103             cfg.height=this.height
7104         }
7105         if (this.nowrap) {
7106             cfg.nowrap=this.nowrap
7107         }
7108         if (this.rowspan) {
7109             cfg.rowspan=this.rowspan
7110         }
7111         if (this.scope) {
7112             cfg.scope=this.scope
7113         }
7114         if (this.valign) {
7115             cfg.valign=this.valign
7116         }
7117         if (this.width) {
7118             cfg.width=this.width
7119         }
7120         
7121         
7122         return cfg;
7123     }
7124    
7125 });
7126
7127  
7128
7129  /*
7130  * - LGPL
7131  *
7132  * table row
7133  * 
7134  */
7135
7136 /**
7137  * @class Roo.bootstrap.TableRow
7138  * @extends Roo.bootstrap.Component
7139  * Bootstrap TableRow class
7140  * @cfg {String} cls row class
7141  * @cfg {String} align Aligns the content in a table row
7142  * @cfg {String} bgcolor Specifies a background color for a table row
7143  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7144  * @cfg {String} valign Vertical aligns the content in a table row
7145  * 
7146  * @constructor
7147  * Create a new TableRow
7148  * @param {Object} config The config object
7149  */
7150
7151 Roo.bootstrap.TableRow = function(config){
7152     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7153 };
7154
7155 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
7156     
7157     cls: false,
7158     align: false,
7159     bgcolor: false,
7160     charoff: false,
7161     valign: false,
7162     
7163     getAutoCreate : function(){
7164         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7165         
7166         cfg = {
7167             tag: 'tr'
7168         };
7169             
7170         if(this.cls){
7171             cfg.cls = this.cls;
7172         }
7173         if(this.align){
7174             cfg.align = this.align;
7175         }
7176         if(this.bgcolor){
7177             cfg.bgcolor = this.bgcolor;
7178         }
7179         if(this.charoff){
7180             cfg.charoff = this.charoff;
7181         }
7182         if(this.valign){
7183             cfg.valign = this.valign;
7184         }
7185         
7186         return cfg;
7187     }
7188    
7189 });
7190
7191  
7192
7193  /*
7194  * - LGPL
7195  *
7196  * table body
7197  * 
7198  */
7199
7200 /**
7201  * @class Roo.bootstrap.TableBody
7202  * @extends Roo.bootstrap.Component
7203  * Bootstrap TableBody class
7204  * @cfg {String} cls element class
7205  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7206  * @cfg {String} align Aligns the content inside the element
7207  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7208  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7209  * 
7210  * @constructor
7211  * Create a new TableBody
7212  * @param {Object} config The config object
7213  */
7214
7215 Roo.bootstrap.TableBody = function(config){
7216     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7217 };
7218
7219 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
7220     
7221     cls: false,
7222     tag: false,
7223     align: false,
7224     charoff: false,
7225     valign: false,
7226     
7227     getAutoCreate : function(){
7228         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7229         
7230         cfg = {
7231             tag: 'tbody'
7232         };
7233             
7234         if (this.cls) {
7235             cfg.cls=this.cls
7236         }
7237         if(this.tag){
7238             cfg.tag = this.tag;
7239         }
7240         
7241         if(this.align){
7242             cfg.align = this.align;
7243         }
7244         if(this.charoff){
7245             cfg.charoff = this.charoff;
7246         }
7247         if(this.valign){
7248             cfg.valign = this.valign;
7249         }
7250         
7251         return cfg;
7252     }
7253     
7254     
7255 //    initEvents : function()
7256 //    {
7257 //        
7258 //        if(!this.store){
7259 //            return;
7260 //        }
7261 //        
7262 //        this.store = Roo.factory(this.store, Roo.data);
7263 //        this.store.on('load', this.onLoad, this);
7264 //        
7265 //        this.store.load();
7266 //        
7267 //    },
7268 //    
7269 //    onLoad: function () 
7270 //    {   
7271 //        this.fireEvent('load', this);
7272 //    }
7273 //    
7274 //   
7275 });
7276
7277  
7278
7279  /*
7280  * Based on:
7281  * Ext JS Library 1.1.1
7282  * Copyright(c) 2006-2007, Ext JS, LLC.
7283  *
7284  * Originally Released Under LGPL - original licence link has changed is not relivant.
7285  *
7286  * Fork - LGPL
7287  * <script type="text/javascript">
7288  */
7289
7290 // as we use this in bootstrap.
7291 Roo.namespace('Roo.form');
7292  /**
7293  * @class Roo.form.Action
7294  * Internal Class used to handle form actions
7295  * @constructor
7296  * @param {Roo.form.BasicForm} el The form element or its id
7297  * @param {Object} config Configuration options
7298  */
7299
7300  
7301  
7302 // define the action interface
7303 Roo.form.Action = function(form, options){
7304     this.form = form;
7305     this.options = options || {};
7306 };
7307 /**
7308  * Client Validation Failed
7309  * @const 
7310  */
7311 Roo.form.Action.CLIENT_INVALID = 'client';
7312 /**
7313  * Server Validation Failed
7314  * @const 
7315  */
7316 Roo.form.Action.SERVER_INVALID = 'server';
7317  /**
7318  * Connect to Server Failed
7319  * @const 
7320  */
7321 Roo.form.Action.CONNECT_FAILURE = 'connect';
7322 /**
7323  * Reading Data from Server Failed
7324  * @const 
7325  */
7326 Roo.form.Action.LOAD_FAILURE = 'load';
7327
7328 Roo.form.Action.prototype = {
7329     type : 'default',
7330     failureType : undefined,
7331     response : undefined,
7332     result : undefined,
7333
7334     // interface method
7335     run : function(options){
7336
7337     },
7338
7339     // interface method
7340     success : function(response){
7341
7342     },
7343
7344     // interface method
7345     handleResponse : function(response){
7346
7347     },
7348
7349     // default connection failure
7350     failure : function(response){
7351         
7352         this.response = response;
7353         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7354         this.form.afterAction(this, false);
7355     },
7356
7357     processResponse : function(response){
7358         this.response = response;
7359         if(!response.responseText){
7360             return true;
7361         }
7362         this.result = this.handleResponse(response);
7363         return this.result;
7364     },
7365
7366     // utility functions used internally
7367     getUrl : function(appendParams){
7368         var url = this.options.url || this.form.url || this.form.el.dom.action;
7369         if(appendParams){
7370             var p = this.getParams();
7371             if(p){
7372                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7373             }
7374         }
7375         return url;
7376     },
7377
7378     getMethod : function(){
7379         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7380     },
7381
7382     getParams : function(){
7383         var bp = this.form.baseParams;
7384         var p = this.options.params;
7385         if(p){
7386             if(typeof p == "object"){
7387                 p = Roo.urlEncode(Roo.applyIf(p, bp));
7388             }else if(typeof p == 'string' && bp){
7389                 p += '&' + Roo.urlEncode(bp);
7390             }
7391         }else if(bp){
7392             p = Roo.urlEncode(bp);
7393         }
7394         return p;
7395     },
7396
7397     createCallback : function(){
7398         return {
7399             success: this.success,
7400             failure: this.failure,
7401             scope: this,
7402             timeout: (this.form.timeout*1000),
7403             upload: this.form.fileUpload ? this.success : undefined
7404         };
7405     }
7406 };
7407
7408 Roo.form.Action.Submit = function(form, options){
7409     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7410 };
7411
7412 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7413     type : 'submit',
7414
7415     haveProgress : false,
7416     uploadComplete : false,
7417     
7418     // uploadProgress indicator.
7419     uploadProgress : function()
7420     {
7421         if (!this.form.progressUrl) {
7422             return;
7423         }
7424         
7425         if (!this.haveProgress) {
7426             Roo.MessageBox.progress("Uploading", "Uploading");
7427         }
7428         if (this.uploadComplete) {
7429            Roo.MessageBox.hide();
7430            return;
7431         }
7432         
7433         this.haveProgress = true;
7434    
7435         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7436         
7437         var c = new Roo.data.Connection();
7438         c.request({
7439             url : this.form.progressUrl,
7440             params: {
7441                 id : uid
7442             },
7443             method: 'GET',
7444             success : function(req){
7445                //console.log(data);
7446                 var rdata = false;
7447                 var edata;
7448                 try  {
7449                    rdata = Roo.decode(req.responseText)
7450                 } catch (e) {
7451                     Roo.log("Invalid data from server..");
7452                     Roo.log(edata);
7453                     return;
7454                 }
7455                 if (!rdata || !rdata.success) {
7456                     Roo.log(rdata);
7457                     Roo.MessageBox.alert(Roo.encode(rdata));
7458                     return;
7459                 }
7460                 var data = rdata.data;
7461                 
7462                 if (this.uploadComplete) {
7463                    Roo.MessageBox.hide();
7464                    return;
7465                 }
7466                    
7467                 if (data){
7468                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7469                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7470                     );
7471                 }
7472                 this.uploadProgress.defer(2000,this);
7473             },
7474        
7475             failure: function(data) {
7476                 Roo.log('progress url failed ');
7477                 Roo.log(data);
7478             },
7479             scope : this
7480         });
7481            
7482     },
7483     
7484     
7485     run : function()
7486     {
7487         // run get Values on the form, so it syncs any secondary forms.
7488         this.form.getValues();
7489         
7490         var o = this.options;
7491         var method = this.getMethod();
7492         var isPost = method == 'POST';
7493         if(o.clientValidation === false || this.form.isValid()){
7494             
7495             if (this.form.progressUrl) {
7496                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7497                     (new Date() * 1) + '' + Math.random());
7498                     
7499             } 
7500             
7501             
7502             Roo.Ajax.request(Roo.apply(this.createCallback(), {
7503                 form:this.form.el.dom,
7504                 url:this.getUrl(!isPost),
7505                 method: method,
7506                 params:isPost ? this.getParams() : null,
7507                 isUpload: this.form.fileUpload
7508             }));
7509             
7510             this.uploadProgress();
7511
7512         }else if (o.clientValidation !== false){ // client validation failed
7513             this.failureType = Roo.form.Action.CLIENT_INVALID;
7514             this.form.afterAction(this, false);
7515         }
7516     },
7517
7518     success : function(response)
7519     {
7520         this.uploadComplete= true;
7521         if (this.haveProgress) {
7522             Roo.MessageBox.hide();
7523         }
7524         
7525         
7526         var result = this.processResponse(response);
7527         if(result === true || result.success){
7528             this.form.afterAction(this, true);
7529             return;
7530         }
7531         if(result.errors){
7532             this.form.markInvalid(result.errors);
7533             this.failureType = Roo.form.Action.SERVER_INVALID;
7534         }
7535         this.form.afterAction(this, false);
7536     },
7537     failure : function(response)
7538     {
7539         this.uploadComplete= true;
7540         if (this.haveProgress) {
7541             Roo.MessageBox.hide();
7542         }
7543         
7544         this.response = response;
7545         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7546         this.form.afterAction(this, false);
7547     },
7548     
7549     handleResponse : function(response){
7550         if(this.form.errorReader){
7551             var rs = this.form.errorReader.read(response);
7552             var errors = [];
7553             if(rs.records){
7554                 for(var i = 0, len = rs.records.length; i < len; i++) {
7555                     var r = rs.records[i];
7556                     errors[i] = r.data;
7557                 }
7558             }
7559             if(errors.length < 1){
7560                 errors = null;
7561             }
7562             return {
7563                 success : rs.success,
7564                 errors : errors
7565             };
7566         }
7567         var ret = false;
7568         try {
7569             ret = Roo.decode(response.responseText);
7570         } catch (e) {
7571             ret = {
7572                 success: false,
7573                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7574                 errors : []
7575             };
7576         }
7577         return ret;
7578         
7579     }
7580 });
7581
7582
7583 Roo.form.Action.Load = function(form, options){
7584     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7585     this.reader = this.form.reader;
7586 };
7587
7588 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7589     type : 'load',
7590
7591     run : function(){
7592         
7593         Roo.Ajax.request(Roo.apply(
7594                 this.createCallback(), {
7595                     method:this.getMethod(),
7596                     url:this.getUrl(false),
7597                     params:this.getParams()
7598         }));
7599     },
7600
7601     success : function(response){
7602         
7603         var result = this.processResponse(response);
7604         if(result === true || !result.success || !result.data){
7605             this.failureType = Roo.form.Action.LOAD_FAILURE;
7606             this.form.afterAction(this, false);
7607             return;
7608         }
7609         this.form.clearInvalid();
7610         this.form.setValues(result.data);
7611         this.form.afterAction(this, true);
7612     },
7613
7614     handleResponse : function(response){
7615         if(this.form.reader){
7616             var rs = this.form.reader.read(response);
7617             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7618             return {
7619                 success : rs.success,
7620                 data : data
7621             };
7622         }
7623         return Roo.decode(response.responseText);
7624     }
7625 });
7626
7627 Roo.form.Action.ACTION_TYPES = {
7628     'load' : Roo.form.Action.Load,
7629     'submit' : Roo.form.Action.Submit
7630 };/*
7631  * - LGPL
7632  *
7633  * form
7634  *
7635  */
7636
7637 /**
7638  * @class Roo.bootstrap.Form
7639  * @extends Roo.bootstrap.Component
7640  * Bootstrap Form class
7641  * @cfg {String} method  GET | POST (default POST)
7642  * @cfg {String} labelAlign top | left (default top)
7643  * @cfg {String} align left  | right - for navbars
7644  * @cfg {Boolean} loadMask load mask when submit (default true)
7645
7646  *
7647  * @constructor
7648  * Create a new Form
7649  * @param {Object} config The config object
7650  */
7651
7652
7653 Roo.bootstrap.Form = function(config){
7654     
7655     Roo.bootstrap.Form.superclass.constructor.call(this, config);
7656     
7657     Roo.bootstrap.Form.popover.apply();
7658     
7659     this.addEvents({
7660         /**
7661          * @event clientvalidation
7662          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7663          * @param {Form} this
7664          * @param {Boolean} valid true if the form has passed client-side validation
7665          */
7666         clientvalidation: true,
7667         /**
7668          * @event beforeaction
7669          * Fires before any action is performed. Return false to cancel the action.
7670          * @param {Form} this
7671          * @param {Action} action The action to be performed
7672          */
7673         beforeaction: true,
7674         /**
7675          * @event actionfailed
7676          * Fires when an action fails.
7677          * @param {Form} this
7678          * @param {Action} action The action that failed
7679          */
7680         actionfailed : true,
7681         /**
7682          * @event actioncomplete
7683          * Fires when an action is completed.
7684          * @param {Form} this
7685          * @param {Action} action The action that completed
7686          */
7687         actioncomplete : true
7688     });
7689 };
7690
7691 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
7692
7693      /**
7694      * @cfg {String} method
7695      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7696      */
7697     method : 'POST',
7698     /**
7699      * @cfg {String} url
7700      * The URL to use for form actions if one isn't supplied in the action options.
7701      */
7702     /**
7703      * @cfg {Boolean} fileUpload
7704      * Set to true if this form is a file upload.
7705      */
7706
7707     /**
7708      * @cfg {Object} baseParams
7709      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7710      */
7711
7712     /**
7713      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7714      */
7715     timeout: 30,
7716     /**
7717      * @cfg {Sting} align (left|right) for navbar forms
7718      */
7719     align : 'left',
7720
7721     // private
7722     activeAction : null,
7723
7724     /**
7725      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7726      * element by passing it or its id or mask the form itself by passing in true.
7727      * @type Mixed
7728      */
7729     waitMsgTarget : false,
7730
7731     loadMask : true,
7732     
7733     /**
7734      * @cfg {Boolean} errorMask (true|false) default false
7735      */
7736     errorMask : false,
7737     
7738     /**
7739      * @cfg {Number} maskOffset Default 100
7740      */
7741     maskOffset : 100,
7742     
7743     /**
7744      * @cfg {Boolean} maskBody
7745      */
7746     maskBody : false,
7747
7748     getAutoCreate : function(){
7749
7750         var cfg = {
7751             tag: 'form',
7752             method : this.method || 'POST',
7753             id : this.id || Roo.id(),
7754             cls : ''
7755         };
7756         if (this.parent().xtype.match(/^Nav/)) {
7757             cfg.cls = 'navbar-form navbar-' + this.align;
7758
7759         }
7760
7761         if (this.labelAlign == 'left' ) {
7762             cfg.cls += ' form-horizontal';
7763         }
7764
7765
7766         return cfg;
7767     },
7768     initEvents : function()
7769     {
7770         this.el.on('submit', this.onSubmit, this);
7771         // this was added as random key presses on the form where triggering form submit.
7772         this.el.on('keypress', function(e) {
7773             if (e.getCharCode() != 13) {
7774                 return true;
7775             }
7776             // we might need to allow it for textareas.. and some other items.
7777             // check e.getTarget().
7778
7779             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7780                 return true;
7781             }
7782
7783             Roo.log("keypress blocked");
7784
7785             e.preventDefault();
7786             return false;
7787         });
7788         
7789     },
7790     // private
7791     onSubmit : function(e){
7792         e.stopEvent();
7793     },
7794
7795      /**
7796      * Returns true if client-side validation on the form is successful.
7797      * @return Boolean
7798      */
7799     isValid : function(){
7800         var items = this.getItems();
7801         var valid = true;
7802         var target = false;
7803         
7804         items.each(function(f){
7805             
7806             if(f.validate()){
7807                 return;
7808             }
7809             valid = false;
7810
7811             if(!target && f.el.isVisible(true)){
7812                 target = f;
7813             }
7814            
7815         });
7816         
7817         if(this.errorMask && !valid){
7818             Roo.bootstrap.Form.popover.mask(this, target);
7819         }
7820         
7821         return valid;
7822     },
7823     
7824     /**
7825      * Returns true if any fields in this form have changed since their original load.
7826      * @return Boolean
7827      */
7828     isDirty : function(){
7829         var dirty = false;
7830         var items = this.getItems();
7831         items.each(function(f){
7832            if(f.isDirty()){
7833                dirty = true;
7834                return false;
7835            }
7836            return true;
7837         });
7838         return dirty;
7839     },
7840      /**
7841      * Performs a predefined action (submit or load) or custom actions you define on this form.
7842      * @param {String} actionName The name of the action type
7843      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
7844      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7845      * accept other config options):
7846      * <pre>
7847 Property          Type             Description
7848 ----------------  ---------------  ----------------------------------------------------------------------------------
7849 url               String           The url for the action (defaults to the form's url)
7850 method            String           The form method to use (defaults to the form's method, or POST if not defined)
7851 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
7852 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
7853                                    validate the form on the client (defaults to false)
7854      * </pre>
7855      * @return {BasicForm} this
7856      */
7857     doAction : function(action, options){
7858         if(typeof action == 'string'){
7859             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7860         }
7861         if(this.fireEvent('beforeaction', this, action) !== false){
7862             this.beforeAction(action);
7863             action.run.defer(100, action);
7864         }
7865         return this;
7866     },
7867
7868     // private
7869     beforeAction : function(action){
7870         var o = action.options;
7871         
7872         if(this.loadMask){
7873             
7874             if(this.maskBody){
7875                 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7876             } else {
7877                 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7878             }
7879         }
7880         // not really supported yet.. ??
7881
7882         //if(this.waitMsgTarget === true){
7883         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7884         //}else if(this.waitMsgTarget){
7885         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7886         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7887         //}else {
7888         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7889        // }
7890
7891     },
7892
7893     // private
7894     afterAction : function(action, success){
7895         this.activeAction = null;
7896         var o = action.options;
7897
7898         if(this.loadMask){
7899             
7900             if(this.maskBody){
7901                 Roo.get(document.body).unmask();
7902             } else {
7903                 this.el.unmask();
7904             }
7905         }
7906         
7907         //if(this.waitMsgTarget === true){
7908 //            this.el.unmask();
7909         //}else if(this.waitMsgTarget){
7910         //    this.waitMsgTarget.unmask();
7911         //}else{
7912         //    Roo.MessageBox.updateProgress(1);
7913         //    Roo.MessageBox.hide();
7914        // }
7915         //
7916         if(success){
7917             if(o.reset){
7918                 this.reset();
7919             }
7920             Roo.callback(o.success, o.scope, [this, action]);
7921             this.fireEvent('actioncomplete', this, action);
7922
7923         }else{
7924
7925             // failure condition..
7926             // we have a scenario where updates need confirming.
7927             // eg. if a locking scenario exists..
7928             // we look for { errors : { needs_confirm : true }} in the response.
7929             if (
7930                 (typeof(action.result) != 'undefined')  &&
7931                 (typeof(action.result.errors) != 'undefined')  &&
7932                 (typeof(action.result.errors.needs_confirm) != 'undefined')
7933            ){
7934                 var _t = this;
7935                 Roo.log("not supported yet");
7936                  /*
7937
7938                 Roo.MessageBox.confirm(
7939                     "Change requires confirmation",
7940                     action.result.errorMsg,
7941                     function(r) {
7942                         if (r != 'yes') {
7943                             return;
7944                         }
7945                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
7946                     }
7947
7948                 );
7949                 */
7950
7951
7952                 return;
7953             }
7954
7955             Roo.callback(o.failure, o.scope, [this, action]);
7956             // show an error message if no failed handler is set..
7957             if (!this.hasListener('actionfailed')) {
7958                 Roo.log("need to add dialog support");
7959                 /*
7960                 Roo.MessageBox.alert("Error",
7961                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7962                         action.result.errorMsg :
7963                         "Saving Failed, please check your entries or try again"
7964                 );
7965                 */
7966             }
7967
7968             this.fireEvent('actionfailed', this, action);
7969         }
7970
7971     },
7972     /**
7973      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7974      * @param {String} id The value to search for
7975      * @return Field
7976      */
7977     findField : function(id){
7978         var items = this.getItems();
7979         var field = items.get(id);
7980         if(!field){
7981              items.each(function(f){
7982                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7983                     field = f;
7984                     return false;
7985                 }
7986                 return true;
7987             });
7988         }
7989         return field || null;
7990     },
7991      /**
7992      * Mark fields in this form invalid in bulk.
7993      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7994      * @return {BasicForm} this
7995      */
7996     markInvalid : function(errors){
7997         if(errors instanceof Array){
7998             for(var i = 0, len = errors.length; i < len; i++){
7999                 var fieldError = errors[i];
8000                 var f = this.findField(fieldError.id);
8001                 if(f){
8002                     f.markInvalid(fieldError.msg);
8003                 }
8004             }
8005         }else{
8006             var field, id;
8007             for(id in errors){
8008                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8009                     field.markInvalid(errors[id]);
8010                 }
8011             }
8012         }
8013         //Roo.each(this.childForms || [], function (f) {
8014         //    f.markInvalid(errors);
8015         //});
8016
8017         return this;
8018     },
8019
8020     /**
8021      * Set values for fields in this form in bulk.
8022      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8023      * @return {BasicForm} this
8024      */
8025     setValues : function(values){
8026         if(values instanceof Array){ // array of objects
8027             for(var i = 0, len = values.length; i < len; i++){
8028                 var v = values[i];
8029                 var f = this.findField(v.id);
8030                 if(f){
8031                     f.setValue(v.value);
8032                     if(this.trackResetOnLoad){
8033                         f.originalValue = f.getValue();
8034                     }
8035                 }
8036             }
8037         }else{ // object hash
8038             var field, id;
8039             for(id in values){
8040                 if(typeof values[id] != 'function' && (field = this.findField(id))){
8041
8042                     if (field.setFromData &&
8043                         field.valueField &&
8044                         field.displayField &&
8045                         // combos' with local stores can
8046                         // be queried via setValue()
8047                         // to set their value..
8048                         (field.store && !field.store.isLocal)
8049                         ) {
8050                         // it's a combo
8051                         var sd = { };
8052                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8053                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8054                         field.setFromData(sd);
8055
8056                     } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8057                         
8058                         field.setFromData(values);
8059                         
8060                     } else {
8061                         field.setValue(values[id]);
8062                     }
8063
8064
8065                     if(this.trackResetOnLoad){
8066                         field.originalValue = field.getValue();
8067                     }
8068                 }
8069             }
8070         }
8071
8072         //Roo.each(this.childForms || [], function (f) {
8073         //    f.setValues(values);
8074         //});
8075
8076         return this;
8077     },
8078
8079     /**
8080      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8081      * they are returned as an array.
8082      * @param {Boolean} asString
8083      * @return {Object}
8084      */
8085     getValues : function(asString){
8086         //if (this.childForms) {
8087             // copy values from the child forms
8088         //    Roo.each(this.childForms, function (f) {
8089         //        this.setValues(f.getValues());
8090         //    }, this);
8091         //}
8092
8093
8094
8095         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8096         if(asString === true){
8097             return fs;
8098         }
8099         return Roo.urlDecode(fs);
8100     },
8101
8102     /**
8103      * Returns the fields in this form as an object with key/value pairs.
8104      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8105      * @return {Object}
8106      */
8107     getFieldValues : function(with_hidden)
8108     {
8109         var items = this.getItems();
8110         var ret = {};
8111         items.each(function(f){
8112             
8113             if (!f.getName()) {
8114                 return;
8115             }
8116             
8117             var v = f.getValue();
8118             
8119             if (f.inputType =='radio') {
8120                 if (typeof(ret[f.getName()]) == 'undefined') {
8121                     ret[f.getName()] = ''; // empty..
8122                 }
8123
8124                 if (!f.el.dom.checked) {
8125                     return;
8126
8127                 }
8128                 v = f.el.dom.value;
8129
8130             }
8131             
8132             if(f.xtype == 'MoneyField'){
8133                 ret[f.currencyName] = f.getCurrency();
8134             }
8135
8136             // not sure if this supported any more..
8137             if ((typeof(v) == 'object') && f.getRawValue) {
8138                 v = f.getRawValue() ; // dates..
8139             }
8140             // combo boxes where name != hiddenName...
8141             if (f.name !== false && f.name != '' && f.name != f.getName()) {
8142                 ret[f.name] = f.getRawValue();
8143             }
8144             ret[f.getName()] = v;
8145         });
8146
8147         return ret;
8148     },
8149
8150     /**
8151      * Clears all invalid messages in this form.
8152      * @return {BasicForm} this
8153      */
8154     clearInvalid : function(){
8155         var items = this.getItems();
8156
8157         items.each(function(f){
8158            f.clearInvalid();
8159         });
8160
8161         return this;
8162     },
8163
8164     /**
8165      * Resets this form.
8166      * @return {BasicForm} this
8167      */
8168     reset : function(){
8169         var items = this.getItems();
8170         items.each(function(f){
8171             f.reset();
8172         });
8173
8174         Roo.each(this.childForms || [], function (f) {
8175             f.reset();
8176         });
8177
8178
8179         return this;
8180     },
8181     
8182     getItems : function()
8183     {
8184         var r=new Roo.util.MixedCollection(false, function(o){
8185             return o.id || (o.id = Roo.id());
8186         });
8187         var iter = function(el) {
8188             if (el.inputEl) {
8189                 r.add(el);
8190             }
8191             if (!el.items) {
8192                 return;
8193             }
8194             Roo.each(el.items,function(e) {
8195                 iter(e);
8196             });
8197         };
8198
8199         iter(this);
8200         return r;
8201     },
8202     
8203     hideFields : function(items)
8204     {
8205         Roo.each(items, function(i){
8206             
8207             var f = this.findField(i);
8208             
8209             if(!f){
8210                 return;
8211             }
8212             
8213             if(f.xtype == 'DateField'){
8214                 f.setVisible(false);
8215                 return;
8216             }
8217             
8218             f.hide();
8219             
8220         }, this);
8221     },
8222     
8223     showFields : function(items)
8224     {
8225         Roo.each(items, function(i){
8226             
8227             var f = this.findField(i);
8228             
8229             if(!f){
8230                 return;
8231             }
8232             
8233             if(f.xtype == 'DateField'){
8234                 f.setVisible(true);
8235                 return;
8236             }
8237             
8238             f.show();
8239             
8240         }, this);
8241     }
8242
8243 });
8244
8245 Roo.apply(Roo.bootstrap.Form, {
8246     
8247     popover : {
8248         
8249         padding : 5,
8250         
8251         isApplied : false,
8252         
8253         isMasked : false,
8254         
8255         form : false,
8256         
8257         target : false,
8258         
8259         toolTip : false,
8260         
8261         intervalID : false,
8262         
8263         maskEl : false,
8264         
8265         apply : function()
8266         {
8267             if(this.isApplied){
8268                 return;
8269             }
8270             
8271             this.maskEl = {
8272                 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8273                 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8274                 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8275                 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8276             };
8277             
8278             this.maskEl.top.enableDisplayMode("block");
8279             this.maskEl.left.enableDisplayMode("block");
8280             this.maskEl.bottom.enableDisplayMode("block");
8281             this.maskEl.right.enableDisplayMode("block");
8282             
8283             this.toolTip = new Roo.bootstrap.Tooltip({
8284                 cls : 'roo-form-error-popover',
8285                 alignment : {
8286                     'left' : ['r-l', [-2,0], 'right'],
8287                     'right' : ['l-r', [2,0], 'left'],
8288                     'bottom' : ['tl-bl', [0,2], 'top'],
8289                     'top' : [ 'bl-tl', [0,-2], 'bottom']
8290                 }
8291             });
8292             
8293             this.toolTip.render(Roo.get(document.body));
8294
8295             this.toolTip.el.enableDisplayMode("block");
8296             
8297             Roo.get(document.body).on('click', function(){
8298                 this.unmask();
8299             }, this);
8300             
8301             Roo.get(document.body).on('touchstart', function(){
8302                 this.unmask();
8303             }, this);
8304             
8305             this.isApplied = true
8306         },
8307         
8308         mask : function(form, target)
8309         {
8310             this.form = form;
8311             
8312             this.target = target;
8313             
8314             if(!this.form.errorMask || !target.el){
8315                 return;
8316             }
8317             
8318             var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8319             
8320             Roo.log(scrollable);
8321             
8322             var ot = this.target.el.calcOffsetsTo(scrollable);
8323             
8324             var scrollTo = ot[1] - this.form.maskOffset;
8325             
8326             scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8327             
8328             scrollable.scrollTo('top', scrollTo);
8329             
8330             var box = this.target.el.getBox();
8331             Roo.log(box);
8332             var zIndex = Roo.bootstrap.Modal.zIndex++;
8333
8334             
8335             this.maskEl.top.setStyle('position', 'absolute');
8336             this.maskEl.top.setStyle('z-index', zIndex);
8337             this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8338             this.maskEl.top.setLeft(0);
8339             this.maskEl.top.setTop(0);
8340             this.maskEl.top.show();
8341             
8342             this.maskEl.left.setStyle('position', 'absolute');
8343             this.maskEl.left.setStyle('z-index', zIndex);
8344             this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8345             this.maskEl.left.setLeft(0);
8346             this.maskEl.left.setTop(box.y - this.padding);
8347             this.maskEl.left.show();
8348
8349             this.maskEl.bottom.setStyle('position', 'absolute');
8350             this.maskEl.bottom.setStyle('z-index', zIndex);
8351             this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8352             this.maskEl.bottom.setLeft(0);
8353             this.maskEl.bottom.setTop(box.bottom + this.padding);
8354             this.maskEl.bottom.show();
8355
8356             this.maskEl.right.setStyle('position', 'absolute');
8357             this.maskEl.right.setStyle('z-index', zIndex);
8358             this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8359             this.maskEl.right.setLeft(box.right + this.padding);
8360             this.maskEl.right.setTop(box.y - this.padding);
8361             this.maskEl.right.show();
8362
8363             this.toolTip.bindEl = this.target.el;
8364
8365             this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8366
8367             var tip = this.target.blankText;
8368
8369             if(this.target.getValue() !== '' ) {
8370                 
8371                 if (this.target.invalidText.length) {
8372                     tip = this.target.invalidText;
8373                 } else if (this.target.regexText.length){
8374                     tip = this.target.regexText;
8375                 }
8376             }
8377
8378             this.toolTip.show(tip);
8379
8380             this.intervalID = window.setInterval(function() {
8381                 Roo.bootstrap.Form.popover.unmask();
8382             }, 10000);
8383
8384             window.onwheel = function(){ return false;};
8385             
8386             (function(){ this.isMasked = true; }).defer(500, this);
8387             
8388         },
8389         
8390         unmask : function()
8391         {
8392             if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8393                 return;
8394             }
8395             
8396             this.maskEl.top.setStyle('position', 'absolute');
8397             this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8398             this.maskEl.top.hide();
8399
8400             this.maskEl.left.setStyle('position', 'absolute');
8401             this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8402             this.maskEl.left.hide();
8403
8404             this.maskEl.bottom.setStyle('position', 'absolute');
8405             this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8406             this.maskEl.bottom.hide();
8407
8408             this.maskEl.right.setStyle('position', 'absolute');
8409             this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8410             this.maskEl.right.hide();
8411             
8412             this.toolTip.hide();
8413             
8414             this.toolTip.el.hide();
8415             
8416             window.onwheel = function(){ return true;};
8417             
8418             if(this.intervalID){
8419                 window.clearInterval(this.intervalID);
8420                 this.intervalID = false;
8421             }
8422             
8423             this.isMasked = false;
8424             
8425         }
8426         
8427     }
8428     
8429 });
8430
8431 /*
8432  * Based on:
8433  * Ext JS Library 1.1.1
8434  * Copyright(c) 2006-2007, Ext JS, LLC.
8435  *
8436  * Originally Released Under LGPL - original licence link has changed is not relivant.
8437  *
8438  * Fork - LGPL
8439  * <script type="text/javascript">
8440  */
8441 /**
8442  * @class Roo.form.VTypes
8443  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8444  * @singleton
8445  */
8446 Roo.form.VTypes = function(){
8447     // closure these in so they are only created once.
8448     var alpha = /^[a-zA-Z_]+$/;
8449     var alphanum = /^[a-zA-Z0-9_]+$/;
8450     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8451     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8452
8453     // All these messages and functions are configurable
8454     return {
8455         /**
8456          * The function used to validate email addresses
8457          * @param {String} value The email address
8458          */
8459         'email' : function(v){
8460             return email.test(v);
8461         },
8462         /**
8463          * The error text to display when the email validation function returns false
8464          * @type String
8465          */
8466         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8467         /**
8468          * The keystroke filter mask to be applied on email input
8469          * @type RegExp
8470          */
8471         'emailMask' : /[a-z0-9_\.\-@]/i,
8472
8473         /**
8474          * The function used to validate URLs
8475          * @param {String} value The URL
8476          */
8477         'url' : function(v){
8478             return url.test(v);
8479         },
8480         /**
8481          * The error text to display when the url validation function returns false
8482          * @type String
8483          */
8484         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8485         
8486         /**
8487          * The function used to validate alpha values
8488          * @param {String} value The value
8489          */
8490         'alpha' : function(v){
8491             return alpha.test(v);
8492         },
8493         /**
8494          * The error text to display when the alpha validation function returns false
8495          * @type String
8496          */
8497         'alphaText' : 'This field should only contain letters and _',
8498         /**
8499          * The keystroke filter mask to be applied on alpha input
8500          * @type RegExp
8501          */
8502         'alphaMask' : /[a-z_]/i,
8503
8504         /**
8505          * The function used to validate alphanumeric values
8506          * @param {String} value The value
8507          */
8508         'alphanum' : function(v){
8509             return alphanum.test(v);
8510         },
8511         /**
8512          * The error text to display when the alphanumeric validation function returns false
8513          * @type String
8514          */
8515         'alphanumText' : 'This field should only contain letters, numbers and _',
8516         /**
8517          * The keystroke filter mask to be applied on alphanumeric input
8518          * @type RegExp
8519          */
8520         'alphanumMask' : /[a-z0-9_]/i
8521     };
8522 }();/*
8523  * - LGPL
8524  *
8525  * Input
8526  * 
8527  */
8528
8529 /**
8530  * @class Roo.bootstrap.Input
8531  * @extends Roo.bootstrap.Component
8532  * Bootstrap Input class
8533  * @cfg {Boolean} disabled is it disabled
8534  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8535  * @cfg {String} name name of the input
8536  * @cfg {string} fieldLabel - the label associated
8537  * @cfg {string} placeholder - placeholder to put in text.
8538  * @cfg {string}  before - input group add on before
8539  * @cfg {string} after - input group add on after
8540  * @cfg {string} size - (lg|sm) or leave empty..
8541  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8542  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8543  * @cfg {Number} md colspan out of 12 for computer-sized screens
8544  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8545  * @cfg {string} value default value of the input
8546  * @cfg {Number} labelWidth set the width of label 
8547  * @cfg {Number} labellg set the width of label (1-12)
8548  * @cfg {Number} labelmd set the width of label (1-12)
8549  * @cfg {Number} labelsm set the width of label (1-12)
8550  * @cfg {Number} labelxs set the width of label (1-12)
8551  * @cfg {String} labelAlign (top|left)
8552  * @cfg {Boolean} readOnly Specifies that the field should be read-only
8553  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8554  * @cfg {String} indicatorpos (left|right) default left
8555  * @cfg {String} capture (user|camera) use for file input only. (default empty)
8556  * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8557
8558  * @cfg {String} align (left|center|right) Default left
8559  * @cfg {Boolean} forceFeedback (true|false) Default false
8560  * 
8561  * @constructor
8562  * Create a new Input
8563  * @param {Object} config The config object
8564  */
8565
8566 Roo.bootstrap.Input = function(config){
8567     
8568     Roo.bootstrap.Input.superclass.constructor.call(this, config);
8569     
8570     this.addEvents({
8571         /**
8572          * @event focus
8573          * Fires when this field receives input focus.
8574          * @param {Roo.form.Field} this
8575          */
8576         focus : true,
8577         /**
8578          * @event blur
8579          * Fires when this field loses input focus.
8580          * @param {Roo.form.Field} this
8581          */
8582         blur : true,
8583         /**
8584          * @event specialkey
8585          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
8586          * {@link Roo.EventObject#getKey} to determine which key was pressed.
8587          * @param {Roo.form.Field} this
8588          * @param {Roo.EventObject} e The event object
8589          */
8590         specialkey : true,
8591         /**
8592          * @event change
8593          * Fires just before the field blurs if the field value has changed.
8594          * @param {Roo.form.Field} this
8595          * @param {Mixed} newValue The new value
8596          * @param {Mixed} oldValue The original value
8597          */
8598         change : true,
8599         /**
8600          * @event invalid
8601          * Fires after the field has been marked as invalid.
8602          * @param {Roo.form.Field} this
8603          * @param {String} msg The validation message
8604          */
8605         invalid : true,
8606         /**
8607          * @event valid
8608          * Fires after the field has been validated with no errors.
8609          * @param {Roo.form.Field} this
8610          */
8611         valid : true,
8612          /**
8613          * @event keyup
8614          * Fires after the key up
8615          * @param {Roo.form.Field} this
8616          * @param {Roo.EventObject}  e The event Object
8617          */
8618         keyup : true
8619     });
8620 };
8621
8622 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
8623      /**
8624      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8625       automatic validation (defaults to "keyup").
8626      */
8627     validationEvent : "keyup",
8628      /**
8629      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8630      */
8631     validateOnBlur : true,
8632     /**
8633      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8634      */
8635     validationDelay : 250,
8636      /**
8637      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8638      */
8639     focusClass : "x-form-focus",  // not needed???
8640     
8641        
8642     /**
8643      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8644      */
8645     invalidClass : "has-warning",
8646     
8647     /**
8648      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8649      */
8650     validClass : "has-success",
8651     
8652     /**
8653      * @cfg {Boolean} hasFeedback (true|false) default true
8654      */
8655     hasFeedback : true,
8656     
8657     /**
8658      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8659      */
8660     invalidFeedbackClass : "glyphicon-warning-sign",
8661     
8662     /**
8663      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8664      */
8665     validFeedbackClass : "glyphicon-ok",
8666     
8667     /**
8668      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8669      */
8670     selectOnFocus : false,
8671     
8672      /**
8673      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8674      */
8675     maskRe : null,
8676        /**
8677      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8678      */
8679     vtype : null,
8680     
8681       /**
8682      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8683      */
8684     disableKeyFilter : false,
8685     
8686        /**
8687      * @cfg {Boolean} disabled True to disable the field (defaults to false).
8688      */
8689     disabled : false,
8690      /**
8691      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8692      */
8693     allowBlank : true,
8694     /**
8695      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8696      */
8697     blankText : "Please complete this mandatory field",
8698     
8699      /**
8700      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8701      */
8702     minLength : 0,
8703     /**
8704      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8705      */
8706     maxLength : Number.MAX_VALUE,
8707     /**
8708      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8709      */
8710     minLengthText : "The minimum length for this field is {0}",
8711     /**
8712      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8713      */
8714     maxLengthText : "The maximum length for this field is {0}",
8715   
8716     
8717     /**
8718      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8719      * If available, this function will be called only after the basic validators all return true, and will be passed the
8720      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8721      */
8722     validator : null,
8723     /**
8724      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8725      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8726      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
8727      */
8728     regex : null,
8729     /**
8730      * @cfg {String} regexText -- Depricated - use Invalid Text
8731      */
8732     regexText : "",
8733     
8734     /**
8735      * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8736      */
8737     invalidText : "",
8738     
8739     
8740     
8741     autocomplete: false,
8742     
8743     
8744     fieldLabel : '',
8745     inputType : 'text',
8746     
8747     name : false,
8748     placeholder: false,
8749     before : false,
8750     after : false,
8751     size : false,
8752     hasFocus : false,
8753     preventMark: false,
8754     isFormField : true,
8755     value : '',
8756     labelWidth : 2,
8757     labelAlign : false,
8758     readOnly : false,
8759     align : false,
8760     formatedValue : false,
8761     forceFeedback : false,
8762     
8763     indicatorpos : 'left',
8764     
8765     labellg : 0,
8766     labelmd : 0,
8767     labelsm : 0,
8768     labelxs : 0,
8769     
8770     capture : '',
8771     accept : '',
8772     
8773     parentLabelAlign : function()
8774     {
8775         var parent = this;
8776         while (parent.parent()) {
8777             parent = parent.parent();
8778             if (typeof(parent.labelAlign) !='undefined') {
8779                 return parent.labelAlign;
8780             }
8781         }
8782         return 'left';
8783         
8784     },
8785     
8786     getAutoCreate : function()
8787     {
8788         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8789         
8790         var id = Roo.id();
8791         
8792         var cfg = {};
8793         
8794         if(this.inputType != 'hidden'){
8795             cfg.cls = 'form-group' //input-group
8796         }
8797         
8798         var input =  {
8799             tag: 'input',
8800             id : id,
8801             type : this.inputType,
8802             value : this.value,
8803             cls : 'form-control',
8804             placeholder : this.placeholder || '',
8805             autocomplete : this.autocomplete || 'new-password'
8806         };
8807         
8808         if(this.capture.length){
8809             input.capture = this.capture;
8810         }
8811         
8812         if(this.accept.length){
8813             input.accept = this.accept + "/*";
8814         }
8815         
8816         if(this.align){
8817             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8818         }
8819         
8820         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8821             input.maxLength = this.maxLength;
8822         }
8823         
8824         if (this.disabled) {
8825             input.disabled=true;
8826         }
8827         
8828         if (this.readOnly) {
8829             input.readonly=true;
8830         }
8831         
8832         if (this.name) {
8833             input.name = this.name;
8834         }
8835         
8836         if (this.size) {
8837             input.cls += ' input-' + this.size;
8838         }
8839         
8840         var settings=this;
8841         ['xs','sm','md','lg'].map(function(size){
8842             if (settings[size]) {
8843                 cfg.cls += ' col-' + size + '-' + settings[size];
8844             }
8845         });
8846         
8847         var inputblock = input;
8848         
8849         var feedback = {
8850             tag: 'span',
8851             cls: 'glyphicon form-control-feedback'
8852         };
8853             
8854         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8855             
8856             inputblock = {
8857                 cls : 'has-feedback',
8858                 cn :  [
8859                     input,
8860                     feedback
8861                 ] 
8862             };  
8863         }
8864         
8865         if (this.before || this.after) {
8866             
8867             inputblock = {
8868                 cls : 'input-group',
8869                 cn :  [] 
8870             };
8871             
8872             if (this.before && typeof(this.before) == 'string') {
8873                 
8874                 inputblock.cn.push({
8875                     tag :'span',
8876                     cls : 'roo-input-before input-group-addon',
8877                     html : this.before
8878                 });
8879             }
8880             if (this.before && typeof(this.before) == 'object') {
8881                 this.before = Roo.factory(this.before);
8882                 
8883                 inputblock.cn.push({
8884                     tag :'span',
8885                     cls : 'roo-input-before input-group-' +
8886                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8887                 });
8888             }
8889             
8890             inputblock.cn.push(input);
8891             
8892             if (this.after && typeof(this.after) == 'string') {
8893                 inputblock.cn.push({
8894                     tag :'span',
8895                     cls : 'roo-input-after input-group-addon',
8896                     html : this.after
8897                 });
8898             }
8899             if (this.after && typeof(this.after) == 'object') {
8900                 this.after = Roo.factory(this.after);
8901                 
8902                 inputblock.cn.push({
8903                     tag :'span',
8904                     cls : 'roo-input-after input-group-' +
8905                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8906                 });
8907             }
8908             
8909             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8910                 inputblock.cls += ' has-feedback';
8911                 inputblock.cn.push(feedback);
8912             }
8913         };
8914         
8915         if (align ==='left' && this.fieldLabel.length) {
8916             
8917             cfg.cls += ' roo-form-group-label-left';
8918             
8919             cfg.cn = [
8920                 {
8921                     tag : 'i',
8922                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8923                     tooltip : 'This field is required'
8924                 },
8925                 {
8926                     tag: 'label',
8927                     'for' :  id,
8928                     cls : 'control-label',
8929                     html : this.fieldLabel
8930
8931                 },
8932                 {
8933                     cls : "", 
8934                     cn: [
8935                         inputblock
8936                     ]
8937                 }
8938             ];
8939             
8940             var labelCfg = cfg.cn[1];
8941             var contentCfg = cfg.cn[2];
8942             
8943             if(this.indicatorpos == 'right'){
8944                 cfg.cn = [
8945                     {
8946                         tag: 'label',
8947                         'for' :  id,
8948                         cls : 'control-label',
8949                         cn : [
8950                             {
8951                                 tag : 'span',
8952                                 html : this.fieldLabel
8953                             },
8954                             {
8955                                 tag : 'i',
8956                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8957                                 tooltip : 'This field is required'
8958                             }
8959                         ]
8960                     },
8961                     {
8962                         cls : "",
8963                         cn: [
8964                             inputblock
8965                         ]
8966                     }
8967
8968                 ];
8969                 
8970                 labelCfg = cfg.cn[0];
8971                 contentCfg = cfg.cn[1];
8972             
8973             }
8974             
8975             if(this.labelWidth > 12){
8976                 labelCfg.style = "width: " + this.labelWidth + 'px';
8977             }
8978             
8979             if(this.labelWidth < 13 && this.labelmd == 0){
8980                 this.labelmd = this.labelWidth;
8981             }
8982             
8983             if(this.labellg > 0){
8984                 labelCfg.cls += ' col-lg-' + this.labellg;
8985                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8986             }
8987             
8988             if(this.labelmd > 0){
8989                 labelCfg.cls += ' col-md-' + this.labelmd;
8990                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8991             }
8992             
8993             if(this.labelsm > 0){
8994                 labelCfg.cls += ' col-sm-' + this.labelsm;
8995                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8996             }
8997             
8998             if(this.labelxs > 0){
8999                 labelCfg.cls += ' col-xs-' + this.labelxs;
9000                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9001             }
9002             
9003             
9004         } else if ( this.fieldLabel.length) {
9005                 
9006             cfg.cn = [
9007                 {
9008                     tag : 'i',
9009                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9010                     tooltip : 'This field is required'
9011                 },
9012                 {
9013                     tag: 'label',
9014                    //cls : 'input-group-addon',
9015                     html : this.fieldLabel
9016
9017                 },
9018
9019                inputblock
9020
9021            ];
9022            
9023            if(this.indicatorpos == 'right'){
9024                 
9025                 cfg.cn = [
9026                     {
9027                         tag: 'label',
9028                        //cls : 'input-group-addon',
9029                         html : this.fieldLabel
9030
9031                     },
9032                     {
9033                         tag : 'i',
9034                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9035                         tooltip : 'This field is required'
9036                     },
9037
9038                    inputblock
9039
9040                ];
9041
9042             }
9043
9044         } else {
9045             
9046             cfg.cn = [
9047
9048                     inputblock
9049
9050             ];
9051                 
9052                 
9053         };
9054         
9055         if (this.parentType === 'Navbar' &&  this.parent().bar) {
9056            cfg.cls += ' navbar-form';
9057         }
9058         
9059         if (this.parentType === 'NavGroup') {
9060            cfg.cls += ' navbar-form';
9061            cfg.tag = 'li';
9062         }
9063         
9064         return cfg;
9065         
9066     },
9067     /**
9068      * return the real input element.
9069      */
9070     inputEl: function ()
9071     {
9072         return this.el.select('input.form-control',true).first();
9073     },
9074     
9075     tooltipEl : function()
9076     {
9077         return this.inputEl();
9078     },
9079     
9080     indicatorEl : function()
9081     {
9082         var indicator = this.el.select('i.roo-required-indicator',true).first();
9083         
9084         if(!indicator){
9085             return false;
9086         }
9087         
9088         return indicator;
9089         
9090     },
9091     
9092     setDisabled : function(v)
9093     {
9094         var i  = this.inputEl().dom;
9095         if (!v) {
9096             i.removeAttribute('disabled');
9097             return;
9098             
9099         }
9100         i.setAttribute('disabled','true');
9101     },
9102     initEvents : function()
9103     {
9104           
9105         this.inputEl().on("keydown" , this.fireKey,  this);
9106         this.inputEl().on("focus", this.onFocus,  this);
9107         this.inputEl().on("blur", this.onBlur,  this);
9108         
9109         this.inputEl().relayEvent('keyup', this);
9110         
9111         this.indicator = this.indicatorEl();
9112         
9113         if(this.indicator){
9114             this.indicator.addClass('invisible');
9115         }
9116  
9117         // reference to original value for reset
9118         this.originalValue = this.getValue();
9119         //Roo.form.TextField.superclass.initEvents.call(this);
9120         if(this.validationEvent == 'keyup'){
9121             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9122             this.inputEl().on('keyup', this.filterValidation, this);
9123         }
9124         else if(this.validationEvent !== false){
9125             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9126         }
9127         
9128         if(this.selectOnFocus){
9129             this.on("focus", this.preFocus, this);
9130             
9131         }
9132         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9133             this.inputEl().on("keypress", this.filterKeys, this);
9134         } else {
9135             this.inputEl().relayEvent('keypress', this);
9136         }
9137        /* if(this.grow){
9138             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
9139             this.el.on("click", this.autoSize,  this);
9140         }
9141         */
9142         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9143             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9144         }
9145         
9146         if (typeof(this.before) == 'object') {
9147             this.before.render(this.el.select('.roo-input-before',true).first());
9148         }
9149         if (typeof(this.after) == 'object') {
9150             this.after.render(this.el.select('.roo-input-after',true).first());
9151         }
9152         
9153         this.inputEl().on('change', this.onChange, this);
9154         
9155     },
9156     filterValidation : function(e){
9157         if(!e.isNavKeyPress()){
9158             this.validationTask.delay(this.validationDelay);
9159         }
9160     },
9161      /**
9162      * Validates the field value
9163      * @return {Boolean} True if the value is valid, else false
9164      */
9165     validate : function(){
9166         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9167         if(this.disabled || this.validateValue(this.getRawValue())){
9168             this.markValid();
9169             return true;
9170         }
9171         
9172         this.markInvalid();
9173         return false;
9174     },
9175     
9176     
9177     /**
9178      * Validates a value according to the field's validation rules and marks the field as invalid
9179      * if the validation fails
9180      * @param {Mixed} value The value to validate
9181      * @return {Boolean} True if the value is valid, else false
9182      */
9183     validateValue : function(value)
9184     {
9185         if(this.getVisibilityEl().hasClass('hidden')){
9186             return true;
9187         }
9188         
9189         if(value.length < 1)  { // if it's blank
9190             if(this.allowBlank){
9191                 return true;
9192             }
9193             return false;
9194         }
9195         
9196         if(value.length < this.minLength){
9197             return false;
9198         }
9199         if(value.length > this.maxLength){
9200             return false;
9201         }
9202         if(this.vtype){
9203             var vt = Roo.form.VTypes;
9204             if(!vt[this.vtype](value, this)){
9205                 return false;
9206             }
9207         }
9208         if(typeof this.validator == "function"){
9209             var msg = this.validator(value);
9210             if(msg !== true){
9211                 return false;
9212             }
9213             if (typeof(msg) == 'string') {
9214                 this.invalidText = msg;
9215             }
9216         }
9217         
9218         if(this.regex && !this.regex.test(value)){
9219             return false;
9220         }
9221         
9222         return true;
9223     },
9224     
9225      // private
9226     fireKey : function(e){
9227         //Roo.log('field ' + e.getKey());
9228         if(e.isNavKeyPress()){
9229             this.fireEvent("specialkey", this, e);
9230         }
9231     },
9232     focus : function (selectText){
9233         if(this.rendered){
9234             this.inputEl().focus();
9235             if(selectText === true){
9236                 this.inputEl().dom.select();
9237             }
9238         }
9239         return this;
9240     } ,
9241     
9242     onFocus : function(){
9243         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9244            // this.el.addClass(this.focusClass);
9245         }
9246         if(!this.hasFocus){
9247             this.hasFocus = true;
9248             this.startValue = this.getValue();
9249             this.fireEvent("focus", this);
9250         }
9251     },
9252     
9253     beforeBlur : Roo.emptyFn,
9254
9255     
9256     // private
9257     onBlur : function(){
9258         this.beforeBlur();
9259         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9260             //this.el.removeClass(this.focusClass);
9261         }
9262         this.hasFocus = false;
9263         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9264             this.validate();
9265         }
9266         var v = this.getValue();
9267         if(String(v) !== String(this.startValue)){
9268             this.fireEvent('change', this, v, this.startValue);
9269         }
9270         this.fireEvent("blur", this);
9271     },
9272     
9273     onChange : function(e)
9274     {
9275         var v = this.getValue();
9276         if(String(v) !== String(this.startValue)){
9277             this.fireEvent('change', this, v, this.startValue);
9278         }
9279         
9280     },
9281     
9282     /**
9283      * Resets the current field value to the originally loaded value and clears any validation messages
9284      */
9285     reset : function(){
9286         this.setValue(this.originalValue);
9287         this.validate();
9288     },
9289      /**
9290      * Returns the name of the field
9291      * @return {Mixed} name The name field
9292      */
9293     getName: function(){
9294         return this.name;
9295     },
9296      /**
9297      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
9298      * @return {Mixed} value The field value
9299      */
9300     getValue : function(){
9301         
9302         var v = this.inputEl().getValue();
9303         
9304         return v;
9305     },
9306     /**
9307      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
9308      * @return {Mixed} value The field value
9309      */
9310     getRawValue : function(){
9311         var v = this.inputEl().getValue();
9312         
9313         return v;
9314     },
9315     
9316     /**
9317      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
9318      * @param {Mixed} value The value to set
9319      */
9320     setRawValue : function(v){
9321         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9322     },
9323     
9324     selectText : function(start, end){
9325         var v = this.getRawValue();
9326         if(v.length > 0){
9327             start = start === undefined ? 0 : start;
9328             end = end === undefined ? v.length : end;
9329             var d = this.inputEl().dom;
9330             if(d.setSelectionRange){
9331                 d.setSelectionRange(start, end);
9332             }else if(d.createTextRange){
9333                 var range = d.createTextRange();
9334                 range.moveStart("character", start);
9335                 range.moveEnd("character", v.length-end);
9336                 range.select();
9337             }
9338         }
9339     },
9340     
9341     /**
9342      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
9343      * @param {Mixed} value The value to set
9344      */
9345     setValue : function(v){
9346         this.value = v;
9347         if(this.rendered){
9348             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9349             this.validate();
9350         }
9351     },
9352     
9353     /*
9354     processValue : function(value){
9355         if(this.stripCharsRe){
9356             var newValue = value.replace(this.stripCharsRe, '');
9357             if(newValue !== value){
9358                 this.setRawValue(newValue);
9359                 return newValue;
9360             }
9361         }
9362         return value;
9363     },
9364   */
9365     preFocus : function(){
9366         
9367         if(this.selectOnFocus){
9368             this.inputEl().dom.select();
9369         }
9370     },
9371     filterKeys : function(e){
9372         var k = e.getKey();
9373         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9374             return;
9375         }
9376         var c = e.getCharCode(), cc = String.fromCharCode(c);
9377         if(Roo.isIE && (e.isSpecialKey() || !cc)){
9378             return;
9379         }
9380         if(!this.maskRe.test(cc)){
9381             e.stopEvent();
9382         }
9383     },
9384      /**
9385      * Clear any invalid styles/messages for this field
9386      */
9387     clearInvalid : function(){
9388         
9389         if(!this.el || this.preventMark){ // not rendered
9390             return;
9391         }
9392         
9393      
9394         this.el.removeClass(this.invalidClass);
9395         
9396         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9397             
9398             var feedback = this.el.select('.form-control-feedback', true).first();
9399             
9400             if(feedback){
9401                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9402             }
9403             
9404         }
9405         
9406         this.fireEvent('valid', this);
9407     },
9408     
9409      /**
9410      * Mark this field as valid
9411      */
9412     markValid : function()
9413     {
9414         if(!this.el  || this.preventMark){ // not rendered...
9415             return;
9416         }
9417         
9418         this.el.removeClass([this.invalidClass, this.validClass]);
9419         
9420         var feedback = this.el.select('.form-control-feedback', true).first();
9421             
9422         if(feedback){
9423             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9424         }
9425         
9426         if(this.indicator){
9427             this.indicator.removeClass('visible');
9428             this.indicator.addClass('invisible');
9429         }
9430         
9431         if(this.disabled){
9432             return;
9433         }
9434         
9435         if(this.allowBlank && !this.getRawValue().length){
9436             return;
9437         }
9438         
9439         this.el.addClass(this.validClass);
9440         
9441         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9442             
9443             var feedback = this.el.select('.form-control-feedback', true).first();
9444             
9445             if(feedback){
9446                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9447                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9448             }
9449             
9450         }
9451         
9452         this.fireEvent('valid', this);
9453     },
9454     
9455      /**
9456      * Mark this field as invalid
9457      * @param {String} msg The validation message
9458      */
9459     markInvalid : function(msg)
9460     {
9461         if(!this.el  || this.preventMark){ // not rendered
9462             return;
9463         }
9464         
9465         this.el.removeClass([this.invalidClass, this.validClass]);
9466         
9467         var feedback = this.el.select('.form-control-feedback', true).first();
9468             
9469         if(feedback){
9470             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9471         }
9472
9473         if(this.disabled){
9474             return;
9475         }
9476         
9477         if(this.allowBlank && !this.getRawValue().length){
9478             return;
9479         }
9480         
9481         if(this.indicator){
9482             this.indicator.removeClass('invisible');
9483             this.indicator.addClass('visible');
9484         }
9485         
9486         this.el.addClass(this.invalidClass);
9487         
9488         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9489             
9490             var feedback = this.el.select('.form-control-feedback', true).first();
9491             
9492             if(feedback){
9493                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9494                 
9495                 if(this.getValue().length || this.forceFeedback){
9496                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9497                 }
9498                 
9499             }
9500             
9501         }
9502         
9503         this.fireEvent('invalid', this, msg);
9504     },
9505     // private
9506     SafariOnKeyDown : function(event)
9507     {
9508         // this is a workaround for a password hang bug on chrome/ webkit.
9509         if (this.inputEl().dom.type != 'password') {
9510             return;
9511         }
9512         
9513         var isSelectAll = false;
9514         
9515         if(this.inputEl().dom.selectionEnd > 0){
9516             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9517         }
9518         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9519             event.preventDefault();
9520             this.setValue('');
9521             return;
9522         }
9523         
9524         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9525             
9526             event.preventDefault();
9527             // this is very hacky as keydown always get's upper case.
9528             //
9529             var cc = String.fromCharCode(event.getCharCode());
9530             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
9531             
9532         }
9533     },
9534     adjustWidth : function(tag, w){
9535         tag = tag.toLowerCase();
9536         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9537             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9538                 if(tag == 'input'){
9539                     return w + 2;
9540                 }
9541                 if(tag == 'textarea'){
9542                     return w-2;
9543                 }
9544             }else if(Roo.isOpera){
9545                 if(tag == 'input'){
9546                     return w + 2;
9547                 }
9548                 if(tag == 'textarea'){
9549                     return w-2;
9550                 }
9551             }
9552         }
9553         return w;
9554     },
9555     
9556     setFieldLabel : function(v)
9557     {
9558         if(!this.rendered){
9559             return;
9560         }
9561         
9562         if(this.indicator){
9563             var ar = this.el.select('label > span',true);
9564             
9565             if (ar.elements.length) {
9566                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9567                 this.fieldLabel = v;
9568                 return;
9569             }
9570             
9571             var br = this.el.select('label',true);
9572             
9573             if(br.elements.length) {
9574                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9575                 this.fieldLabel = v;
9576                 return;
9577             }
9578             
9579             Roo.log('Cannot Found any of label > span || label in input');
9580             return;
9581         }
9582         
9583         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9584         this.fieldLabel = v;
9585         
9586         
9587     }
9588 });
9589
9590  
9591 /*
9592  * - LGPL
9593  *
9594  * Input
9595  * 
9596  */
9597
9598 /**
9599  * @class Roo.bootstrap.TextArea
9600  * @extends Roo.bootstrap.Input
9601  * Bootstrap TextArea class
9602  * @cfg {Number} cols Specifies the visible width of a text area
9603  * @cfg {Number} rows Specifies the visible number of lines in a text area
9604  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9605  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9606  * @cfg {string} html text
9607  * 
9608  * @constructor
9609  * Create a new TextArea
9610  * @param {Object} config The config object
9611  */
9612
9613 Roo.bootstrap.TextArea = function(config){
9614     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9615    
9616 };
9617
9618 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
9619      
9620     cols : false,
9621     rows : 5,
9622     readOnly : false,
9623     warp : 'soft',
9624     resize : false,
9625     value: false,
9626     html: false,
9627     
9628     getAutoCreate : function(){
9629         
9630         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9631         
9632         var id = Roo.id();
9633         
9634         var cfg = {};
9635         
9636         if(this.inputType != 'hidden'){
9637             cfg.cls = 'form-group' //input-group
9638         }
9639         
9640         var input =  {
9641             tag: 'textarea',
9642             id : id,
9643             warp : this.warp,
9644             rows : this.rows,
9645             value : this.value || '',
9646             html: this.html || '',
9647             cls : 'form-control',
9648             placeholder : this.placeholder || '' 
9649             
9650         };
9651         
9652         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9653             input.maxLength = this.maxLength;
9654         }
9655         
9656         if(this.resize){
9657             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9658         }
9659         
9660         if(this.cols){
9661             input.cols = this.cols;
9662         }
9663         
9664         if (this.readOnly) {
9665             input.readonly = true;
9666         }
9667         
9668         if (this.name) {
9669             input.name = this.name;
9670         }
9671         
9672         if (this.size) {
9673             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9674         }
9675         
9676         var settings=this;
9677         ['xs','sm','md','lg'].map(function(size){
9678             if (settings[size]) {
9679                 cfg.cls += ' col-' + size + '-' + settings[size];
9680             }
9681         });
9682         
9683         var inputblock = input;
9684         
9685         if(this.hasFeedback && !this.allowBlank){
9686             
9687             var feedback = {
9688                 tag: 'span',
9689                 cls: 'glyphicon form-control-feedback'
9690             };
9691
9692             inputblock = {
9693                 cls : 'has-feedback',
9694                 cn :  [
9695                     input,
9696                     feedback
9697                 ] 
9698             };  
9699         }
9700         
9701         
9702         if (this.before || this.after) {
9703             
9704             inputblock = {
9705                 cls : 'input-group',
9706                 cn :  [] 
9707             };
9708             if (this.before) {
9709                 inputblock.cn.push({
9710                     tag :'span',
9711                     cls : 'input-group-addon',
9712                     html : this.before
9713                 });
9714             }
9715             
9716             inputblock.cn.push(input);
9717             
9718             if(this.hasFeedback && !this.allowBlank){
9719                 inputblock.cls += ' has-feedback';
9720                 inputblock.cn.push(feedback);
9721             }
9722             
9723             if (this.after) {
9724                 inputblock.cn.push({
9725                     tag :'span',
9726                     cls : 'input-group-addon',
9727                     html : this.after
9728                 });
9729             }
9730             
9731         }
9732         
9733         if (align ==='left' && this.fieldLabel.length) {
9734             cfg.cn = [
9735                 {
9736                     tag: 'label',
9737                     'for' :  id,
9738                     cls : 'control-label',
9739                     html : this.fieldLabel
9740                 },
9741                 {
9742                     cls : "",
9743                     cn: [
9744                         inputblock
9745                     ]
9746                 }
9747
9748             ];
9749             
9750             if(this.labelWidth > 12){
9751                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9752             }
9753
9754             if(this.labelWidth < 13 && this.labelmd == 0){
9755                 this.labelmd = this.labelWidth;
9756             }
9757
9758             if(this.labellg > 0){
9759                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9760                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9761             }
9762
9763             if(this.labelmd > 0){
9764                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9765                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9766             }
9767
9768             if(this.labelsm > 0){
9769                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9770                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9771             }
9772
9773             if(this.labelxs > 0){
9774                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9775                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9776             }
9777             
9778         } else if ( this.fieldLabel.length) {
9779             cfg.cn = [
9780
9781                {
9782                    tag: 'label',
9783                    //cls : 'input-group-addon',
9784                    html : this.fieldLabel
9785
9786                },
9787
9788                inputblock
9789
9790            ];
9791
9792         } else {
9793
9794             cfg.cn = [
9795
9796                 inputblock
9797
9798             ];
9799                 
9800         }
9801         
9802         if (this.disabled) {
9803             input.disabled=true;
9804         }
9805         
9806         return cfg;
9807         
9808     },
9809     /**
9810      * return the real textarea element.
9811      */
9812     inputEl: function ()
9813     {
9814         return this.el.select('textarea.form-control',true).first();
9815     },
9816     
9817     /**
9818      * Clear any invalid styles/messages for this field
9819      */
9820     clearInvalid : function()
9821     {
9822         
9823         if(!this.el || this.preventMark){ // not rendered
9824             return;
9825         }
9826         
9827         var label = this.el.select('label', true).first();
9828         var icon = this.el.select('i.fa-star', true).first();
9829         
9830         if(label && icon){
9831             icon.remove();
9832         }
9833         
9834         this.el.removeClass(this.invalidClass);
9835         
9836         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9837             
9838             var feedback = this.el.select('.form-control-feedback', true).first();
9839             
9840             if(feedback){
9841                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9842             }
9843             
9844         }
9845         
9846         this.fireEvent('valid', this);
9847     },
9848     
9849      /**
9850      * Mark this field as valid
9851      */
9852     markValid : function()
9853     {
9854         if(!this.el  || this.preventMark){ // not rendered
9855             return;
9856         }
9857         
9858         this.el.removeClass([this.invalidClass, this.validClass]);
9859         
9860         var feedback = this.el.select('.form-control-feedback', true).first();
9861             
9862         if(feedback){
9863             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9864         }
9865
9866         if(this.disabled || this.allowBlank){
9867             return;
9868         }
9869         
9870         var label = this.el.select('label', true).first();
9871         var icon = this.el.select('i.fa-star', true).first();
9872         
9873         if(label && icon){
9874             icon.remove();
9875         }
9876         
9877         this.el.addClass(this.validClass);
9878         
9879         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9880             
9881             var feedback = this.el.select('.form-control-feedback', true).first();
9882             
9883             if(feedback){
9884                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9885                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9886             }
9887             
9888         }
9889         
9890         this.fireEvent('valid', this);
9891     },
9892     
9893      /**
9894      * Mark this field as invalid
9895      * @param {String} msg The validation message
9896      */
9897     markInvalid : function(msg)
9898     {
9899         if(!this.el  || this.preventMark){ // not rendered
9900             return;
9901         }
9902         
9903         this.el.removeClass([this.invalidClass, this.validClass]);
9904         
9905         var feedback = this.el.select('.form-control-feedback', true).first();
9906             
9907         if(feedback){
9908             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9909         }
9910
9911         if(this.disabled || this.allowBlank){
9912             return;
9913         }
9914         
9915         var label = this.el.select('label', true).first();
9916         var icon = this.el.select('i.fa-star', true).first();
9917         
9918         if(!this.getValue().length && label && !icon){
9919             this.el.createChild({
9920                 tag : 'i',
9921                 cls : 'text-danger fa fa-lg fa-star',
9922                 tooltip : 'This field is required',
9923                 style : 'margin-right:5px;'
9924             }, label, true);
9925         }
9926
9927         this.el.addClass(this.invalidClass);
9928         
9929         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9930             
9931             var feedback = this.el.select('.form-control-feedback', true).first();
9932             
9933             if(feedback){
9934                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9935                 
9936                 if(this.getValue().length || this.forceFeedback){
9937                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9938                 }
9939                 
9940             }
9941             
9942         }
9943         
9944         this.fireEvent('invalid', this, msg);
9945     }
9946 });
9947
9948  
9949 /*
9950  * - LGPL
9951  *
9952  * trigger field - base class for combo..
9953  * 
9954  */
9955  
9956 /**
9957  * @class Roo.bootstrap.TriggerField
9958  * @extends Roo.bootstrap.Input
9959  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9960  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9961  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9962  * for which you can provide a custom implementation.  For example:
9963  * <pre><code>
9964 var trigger = new Roo.bootstrap.TriggerField();
9965 trigger.onTriggerClick = myTriggerFn;
9966 trigger.applyTo('my-field');
9967 </code></pre>
9968  *
9969  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9970  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9971  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
9972  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9973  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9974
9975  * @constructor
9976  * Create a new TriggerField.
9977  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9978  * to the base TextField)
9979  */
9980 Roo.bootstrap.TriggerField = function(config){
9981     this.mimicing = false;
9982     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9983 };
9984
9985 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
9986     /**
9987      * @cfg {String} triggerClass A CSS class to apply to the trigger
9988      */
9989      /**
9990      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9991      */
9992     hideTrigger:false,
9993
9994     /**
9995      * @cfg {Boolean} removable (true|false) special filter default false
9996      */
9997     removable : false,
9998     
9999     /** @cfg {Boolean} grow @hide */
10000     /** @cfg {Number} growMin @hide */
10001     /** @cfg {Number} growMax @hide */
10002
10003     /**
10004      * @hide 
10005      * @method
10006      */
10007     autoSize: Roo.emptyFn,
10008     // private
10009     monitorTab : true,
10010     // private
10011     deferHeight : true,
10012
10013     
10014     actionMode : 'wrap',
10015     
10016     caret : false,
10017     
10018     
10019     getAutoCreate : function(){
10020        
10021         var align = this.labelAlign || this.parentLabelAlign();
10022         
10023         var id = Roo.id();
10024         
10025         var cfg = {
10026             cls: 'form-group' //input-group
10027         };
10028         
10029         
10030         var input =  {
10031             tag: 'input',
10032             id : id,
10033             type : this.inputType,
10034             cls : 'form-control',
10035             autocomplete: 'new-password',
10036             placeholder : this.placeholder || '' 
10037             
10038         };
10039         if (this.name) {
10040             input.name = this.name;
10041         }
10042         if (this.size) {
10043             input.cls += ' input-' + this.size;
10044         }
10045         
10046         if (this.disabled) {
10047             input.disabled=true;
10048         }
10049         
10050         var inputblock = input;
10051         
10052         if(this.hasFeedback && !this.allowBlank){
10053             
10054             var feedback = {
10055                 tag: 'span',
10056                 cls: 'glyphicon form-control-feedback'
10057             };
10058             
10059             if(this.removable && !this.editable && !this.tickable){
10060                 inputblock = {
10061                     cls : 'has-feedback',
10062                     cn :  [
10063                         inputblock,
10064                         {
10065                             tag: 'button',
10066                             html : 'x',
10067                             cls : 'roo-combo-removable-btn close'
10068                         },
10069                         feedback
10070                     ] 
10071                 };
10072             } else {
10073                 inputblock = {
10074                     cls : 'has-feedback',
10075                     cn :  [
10076                         inputblock,
10077                         feedback
10078                     ] 
10079                 };
10080             }
10081
10082         } else {
10083             if(this.removable && !this.editable && !this.tickable){
10084                 inputblock = {
10085                     cls : 'roo-removable',
10086                     cn :  [
10087                         inputblock,
10088                         {
10089                             tag: 'button',
10090                             html : 'x',
10091                             cls : 'roo-combo-removable-btn close'
10092                         }
10093                     ] 
10094                 };
10095             }
10096         }
10097         
10098         if (this.before || this.after) {
10099             
10100             inputblock = {
10101                 cls : 'input-group',
10102                 cn :  [] 
10103             };
10104             if (this.before) {
10105                 inputblock.cn.push({
10106                     tag :'span',
10107                     cls : 'input-group-addon',
10108                     html : this.before
10109                 });
10110             }
10111             
10112             inputblock.cn.push(input);
10113             
10114             if(this.hasFeedback && !this.allowBlank){
10115                 inputblock.cls += ' has-feedback';
10116                 inputblock.cn.push(feedback);
10117             }
10118             
10119             if (this.after) {
10120                 inputblock.cn.push({
10121                     tag :'span',
10122                     cls : 'input-group-addon',
10123                     html : this.after
10124                 });
10125             }
10126             
10127         };
10128         
10129         var box = {
10130             tag: 'div',
10131             cn: [
10132                 {
10133                     tag: 'input',
10134                     type : 'hidden',
10135                     cls: 'form-hidden-field'
10136                 },
10137                 inputblock
10138             ]
10139             
10140         };
10141         
10142         if(this.multiple){
10143             box = {
10144                 tag: 'div',
10145                 cn: [
10146                     {
10147                         tag: 'input',
10148                         type : 'hidden',
10149                         cls: 'form-hidden-field'
10150                     },
10151                     {
10152                         tag: 'ul',
10153                         cls: 'roo-select2-choices',
10154                         cn:[
10155                             {
10156                                 tag: 'li',
10157                                 cls: 'roo-select2-search-field',
10158                                 cn: [
10159
10160                                     inputblock
10161                                 ]
10162                             }
10163                         ]
10164                     }
10165                 ]
10166             }
10167         };
10168         
10169         var combobox = {
10170             cls: 'roo-select2-container input-group',
10171             cn: [
10172                 box
10173 //                {
10174 //                    tag: 'ul',
10175 //                    cls: 'typeahead typeahead-long dropdown-menu',
10176 //                    style: 'display:none'
10177 //                }
10178             ]
10179         };
10180         
10181         if(!this.multiple && this.showToggleBtn){
10182             
10183             var caret = {
10184                         tag: 'span',
10185                         cls: 'caret'
10186              };
10187             if (this.caret != false) {
10188                 caret = {
10189                      tag: 'i',
10190                      cls: 'fa fa-' + this.caret
10191                 };
10192                 
10193             }
10194             
10195             combobox.cn.push({
10196                 tag :'span',
10197                 cls : 'input-group-addon btn dropdown-toggle',
10198                 cn : [
10199                     caret,
10200                     {
10201                         tag: 'span',
10202                         cls: 'combobox-clear',
10203                         cn  : [
10204                             {
10205                                 tag : 'i',
10206                                 cls: 'icon-remove'
10207                             }
10208                         ]
10209                     }
10210                 ]
10211
10212             })
10213         }
10214         
10215         if(this.multiple){
10216             combobox.cls += ' roo-select2-container-multi';
10217         }
10218         
10219         if (align ==='left' && this.fieldLabel.length) {
10220             
10221             cfg.cls += ' roo-form-group-label-left';
10222
10223             cfg.cn = [
10224                 {
10225                     tag : 'i',
10226                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10227                     tooltip : 'This field is required'
10228                 },
10229                 {
10230                     tag: 'label',
10231                     'for' :  id,
10232                     cls : 'control-label',
10233                     html : this.fieldLabel
10234
10235                 },
10236                 {
10237                     cls : "", 
10238                     cn: [
10239                         combobox
10240                     ]
10241                 }
10242
10243             ];
10244             
10245             var labelCfg = cfg.cn[1];
10246             var contentCfg = cfg.cn[2];
10247             
10248             if(this.indicatorpos == 'right'){
10249                 cfg.cn = [
10250                     {
10251                         tag: 'label',
10252                         'for' :  id,
10253                         cls : 'control-label',
10254                         cn : [
10255                             {
10256                                 tag : 'span',
10257                                 html : this.fieldLabel
10258                             },
10259                             {
10260                                 tag : 'i',
10261                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10262                                 tooltip : 'This field is required'
10263                             }
10264                         ]
10265                     },
10266                     {
10267                         cls : "", 
10268                         cn: [
10269                             combobox
10270                         ]
10271                     }
10272
10273                 ];
10274                 
10275                 labelCfg = cfg.cn[0];
10276                 contentCfg = cfg.cn[1];
10277             }
10278             
10279             if(this.labelWidth > 12){
10280                 labelCfg.style = "width: " + this.labelWidth + 'px';
10281             }
10282             
10283             if(this.labelWidth < 13 && this.labelmd == 0){
10284                 this.labelmd = this.labelWidth;
10285             }
10286             
10287             if(this.labellg > 0){
10288                 labelCfg.cls += ' col-lg-' + this.labellg;
10289                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10290             }
10291             
10292             if(this.labelmd > 0){
10293                 labelCfg.cls += ' col-md-' + this.labelmd;
10294                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10295             }
10296             
10297             if(this.labelsm > 0){
10298                 labelCfg.cls += ' col-sm-' + this.labelsm;
10299                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10300             }
10301             
10302             if(this.labelxs > 0){
10303                 labelCfg.cls += ' col-xs-' + this.labelxs;
10304                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10305             }
10306             
10307         } else if ( this.fieldLabel.length) {
10308 //                Roo.log(" label");
10309             cfg.cn = [
10310                 {
10311                    tag : 'i',
10312                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10313                    tooltip : 'This field is required'
10314                },
10315                {
10316                    tag: 'label',
10317                    //cls : 'input-group-addon',
10318                    html : this.fieldLabel
10319
10320                },
10321
10322                combobox
10323
10324             ];
10325             
10326             if(this.indicatorpos == 'right'){
10327                 
10328                 cfg.cn = [
10329                     {
10330                        tag: 'label',
10331                        cn : [
10332                            {
10333                                tag : 'span',
10334                                html : this.fieldLabel
10335                            },
10336                            {
10337                               tag : 'i',
10338                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10339                               tooltip : 'This field is required'
10340                            }
10341                        ]
10342
10343                     },
10344                     combobox
10345
10346                 ];
10347
10348             }
10349
10350         } else {
10351             
10352 //                Roo.log(" no label && no align");
10353                 cfg = combobox
10354                      
10355                 
10356         }
10357         
10358         var settings=this;
10359         ['xs','sm','md','lg'].map(function(size){
10360             if (settings[size]) {
10361                 cfg.cls += ' col-' + size + '-' + settings[size];
10362             }
10363         });
10364         
10365         return cfg;
10366         
10367     },
10368     
10369     
10370     
10371     // private
10372     onResize : function(w, h){
10373 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10374 //        if(typeof w == 'number'){
10375 //            var x = w - this.trigger.getWidth();
10376 //            this.inputEl().setWidth(this.adjustWidth('input', x));
10377 //            this.trigger.setStyle('left', x+'px');
10378 //        }
10379     },
10380
10381     // private
10382     adjustSize : Roo.BoxComponent.prototype.adjustSize,
10383
10384     // private
10385     getResizeEl : function(){
10386         return this.inputEl();
10387     },
10388
10389     // private
10390     getPositionEl : function(){
10391         return this.inputEl();
10392     },
10393
10394     // private
10395     alignErrorIcon : function(){
10396         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10397     },
10398
10399     // private
10400     initEvents : function(){
10401         
10402         this.createList();
10403         
10404         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10405         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10406         if(!this.multiple && this.showToggleBtn){
10407             this.trigger = this.el.select('span.dropdown-toggle',true).first();
10408             if(this.hideTrigger){
10409                 this.trigger.setDisplayed(false);
10410             }
10411             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10412         }
10413         
10414         if(this.multiple){
10415             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10416         }
10417         
10418         if(this.removable && !this.editable && !this.tickable){
10419             var close = this.closeTriggerEl();
10420             
10421             if(close){
10422                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10423                 close.on('click', this.removeBtnClick, this, close);
10424             }
10425         }
10426         
10427         //this.trigger.addClassOnOver('x-form-trigger-over');
10428         //this.trigger.addClassOnClick('x-form-trigger-click');
10429         
10430         //if(!this.width){
10431         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10432         //}
10433     },
10434     
10435     closeTriggerEl : function()
10436     {
10437         var close = this.el.select('.roo-combo-removable-btn', true).first();
10438         return close ? close : false;
10439     },
10440     
10441     removeBtnClick : function(e, h, el)
10442     {
10443         e.preventDefault();
10444         
10445         if(this.fireEvent("remove", this) !== false){
10446             this.reset();
10447             this.fireEvent("afterremove", this)
10448         }
10449     },
10450     
10451     createList : function()
10452     {
10453         this.list = Roo.get(document.body).createChild({
10454             tag: 'ul',
10455             cls: 'typeahead typeahead-long dropdown-menu',
10456             style: 'display:none'
10457         });
10458         
10459         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10460         
10461     },
10462
10463     // private
10464     initTrigger : function(){
10465        
10466     },
10467
10468     // private
10469     onDestroy : function(){
10470         if(this.trigger){
10471             this.trigger.removeAllListeners();
10472           //  this.trigger.remove();
10473         }
10474         //if(this.wrap){
10475         //    this.wrap.remove();
10476         //}
10477         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10478     },
10479
10480     // private
10481     onFocus : function(){
10482         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10483         /*
10484         if(!this.mimicing){
10485             this.wrap.addClass('x-trigger-wrap-focus');
10486             this.mimicing = true;
10487             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10488             if(this.monitorTab){
10489                 this.el.on("keydown", this.checkTab, this);
10490             }
10491         }
10492         */
10493     },
10494
10495     // private
10496     checkTab : function(e){
10497         if(e.getKey() == e.TAB){
10498             this.triggerBlur();
10499         }
10500     },
10501
10502     // private
10503     onBlur : function(){
10504         // do nothing
10505     },
10506
10507     // private
10508     mimicBlur : function(e, t){
10509         /*
10510         if(!this.wrap.contains(t) && this.validateBlur()){
10511             this.triggerBlur();
10512         }
10513         */
10514     },
10515
10516     // private
10517     triggerBlur : function(){
10518         this.mimicing = false;
10519         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10520         if(this.monitorTab){
10521             this.el.un("keydown", this.checkTab, this);
10522         }
10523         //this.wrap.removeClass('x-trigger-wrap-focus');
10524         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10525     },
10526
10527     // private
10528     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10529     validateBlur : function(e, t){
10530         return true;
10531     },
10532
10533     // private
10534     onDisable : function(){
10535         this.inputEl().dom.disabled = true;
10536         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10537         //if(this.wrap){
10538         //    this.wrap.addClass('x-item-disabled');
10539         //}
10540     },
10541
10542     // private
10543     onEnable : function(){
10544         this.inputEl().dom.disabled = false;
10545         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10546         //if(this.wrap){
10547         //    this.el.removeClass('x-item-disabled');
10548         //}
10549     },
10550
10551     // private
10552     onShow : function(){
10553         var ae = this.getActionEl();
10554         
10555         if(ae){
10556             ae.dom.style.display = '';
10557             ae.dom.style.visibility = 'visible';
10558         }
10559     },
10560
10561     // private
10562     
10563     onHide : function(){
10564         var ae = this.getActionEl();
10565         ae.dom.style.display = 'none';
10566     },
10567
10568     /**
10569      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
10570      * by an implementing function.
10571      * @method
10572      * @param {EventObject} e
10573      */
10574     onTriggerClick : Roo.emptyFn
10575 });
10576  /*
10577  * Based on:
10578  * Ext JS Library 1.1.1
10579  * Copyright(c) 2006-2007, Ext JS, LLC.
10580  *
10581  * Originally Released Under LGPL - original licence link has changed is not relivant.
10582  *
10583  * Fork - LGPL
10584  * <script type="text/javascript">
10585  */
10586
10587
10588 /**
10589  * @class Roo.data.SortTypes
10590  * @singleton
10591  * Defines the default sorting (casting?) comparison functions used when sorting data.
10592  */
10593 Roo.data.SortTypes = {
10594     /**
10595      * Default sort that does nothing
10596      * @param {Mixed} s The value being converted
10597      * @return {Mixed} The comparison value
10598      */
10599     none : function(s){
10600         return s;
10601     },
10602     
10603     /**
10604      * The regular expression used to strip tags
10605      * @type {RegExp}
10606      * @property
10607      */
10608     stripTagsRE : /<\/?[^>]+>/gi,
10609     
10610     /**
10611      * Strips all HTML tags to sort on text only
10612      * @param {Mixed} s The value being converted
10613      * @return {String} The comparison value
10614      */
10615     asText : function(s){
10616         return String(s).replace(this.stripTagsRE, "");
10617     },
10618     
10619     /**
10620      * Strips all HTML tags to sort on text only - Case insensitive
10621      * @param {Mixed} s The value being converted
10622      * @return {String} The comparison value
10623      */
10624     asUCText : function(s){
10625         return String(s).toUpperCase().replace(this.stripTagsRE, "");
10626     },
10627     
10628     /**
10629      * Case insensitive string
10630      * @param {Mixed} s The value being converted
10631      * @return {String} The comparison value
10632      */
10633     asUCString : function(s) {
10634         return String(s).toUpperCase();
10635     },
10636     
10637     /**
10638      * Date sorting
10639      * @param {Mixed} s The value being converted
10640      * @return {Number} The comparison value
10641      */
10642     asDate : function(s) {
10643         if(!s){
10644             return 0;
10645         }
10646         if(s instanceof Date){
10647             return s.getTime();
10648         }
10649         return Date.parse(String(s));
10650     },
10651     
10652     /**
10653      * Float sorting
10654      * @param {Mixed} s The value being converted
10655      * @return {Float} The comparison value
10656      */
10657     asFloat : function(s) {
10658         var val = parseFloat(String(s).replace(/,/g, ""));
10659         if(isNaN(val)) {
10660             val = 0;
10661         }
10662         return val;
10663     },
10664     
10665     /**
10666      * Integer sorting
10667      * @param {Mixed} s The value being converted
10668      * @return {Number} The comparison value
10669      */
10670     asInt : function(s) {
10671         var val = parseInt(String(s).replace(/,/g, ""));
10672         if(isNaN(val)) {
10673             val = 0;
10674         }
10675         return val;
10676     }
10677 };/*
10678  * Based on:
10679  * Ext JS Library 1.1.1
10680  * Copyright(c) 2006-2007, Ext JS, LLC.
10681  *
10682  * Originally Released Under LGPL - original licence link has changed is not relivant.
10683  *
10684  * Fork - LGPL
10685  * <script type="text/javascript">
10686  */
10687
10688 /**
10689 * @class Roo.data.Record
10690  * Instances of this class encapsulate both record <em>definition</em> information, and record
10691  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10692  * to access Records cached in an {@link Roo.data.Store} object.<br>
10693  * <p>
10694  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10695  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10696  * objects.<br>
10697  * <p>
10698  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10699  * @constructor
10700  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10701  * {@link #create}. The parameters are the same.
10702  * @param {Array} data An associative Array of data values keyed by the field name.
10703  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10704  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10705  * not specified an integer id is generated.
10706  */
10707 Roo.data.Record = function(data, id){
10708     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10709     this.data = data;
10710 };
10711
10712 /**
10713  * Generate a constructor for a specific record layout.
10714  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10715  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10716  * Each field definition object may contain the following properties: <ul>
10717  * <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,
10718  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10719  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10720  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10721  * is being used, then this is a string containing the javascript expression to reference the data relative to 
10722  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10723  * to the data item relative to the record element. If the mapping expression is the same as the field name,
10724  * this may be omitted.</p></li>
10725  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10726  * <ul><li>auto (Default, implies no conversion)</li>
10727  * <li>string</li>
10728  * <li>int</li>
10729  * <li>float</li>
10730  * <li>boolean</li>
10731  * <li>date</li></ul></p></li>
10732  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10733  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10734  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10735  * by the Reader into an object that will be stored in the Record. It is passed the
10736  * following parameters:<ul>
10737  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10738  * </ul></p></li>
10739  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10740  * </ul>
10741  * <br>usage:<br><pre><code>
10742 var TopicRecord = Roo.data.Record.create(
10743     {name: 'title', mapping: 'topic_title'},
10744     {name: 'author', mapping: 'username'},
10745     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10746     {name: 'lastPost', mapping: 'post_time', type: 'date'},
10747     {name: 'lastPoster', mapping: 'user2'},
10748     {name: 'excerpt', mapping: 'post_text'}
10749 );
10750
10751 var myNewRecord = new TopicRecord({
10752     title: 'Do my job please',
10753     author: 'noobie',
10754     totalPosts: 1,
10755     lastPost: new Date(),
10756     lastPoster: 'Animal',
10757     excerpt: 'No way dude!'
10758 });
10759 myStore.add(myNewRecord);
10760 </code></pre>
10761  * @method create
10762  * @static
10763  */
10764 Roo.data.Record.create = function(o){
10765     var f = function(){
10766         f.superclass.constructor.apply(this, arguments);
10767     };
10768     Roo.extend(f, Roo.data.Record);
10769     var p = f.prototype;
10770     p.fields = new Roo.util.MixedCollection(false, function(field){
10771         return field.name;
10772     });
10773     for(var i = 0, len = o.length; i < len; i++){
10774         p.fields.add(new Roo.data.Field(o[i]));
10775     }
10776     f.getField = function(name){
10777         return p.fields.get(name);  
10778     };
10779     return f;
10780 };
10781
10782 Roo.data.Record.AUTO_ID = 1000;
10783 Roo.data.Record.EDIT = 'edit';
10784 Roo.data.Record.REJECT = 'reject';
10785 Roo.data.Record.COMMIT = 'commit';
10786
10787 Roo.data.Record.prototype = {
10788     /**
10789      * Readonly flag - true if this record has been modified.
10790      * @type Boolean
10791      */
10792     dirty : false,
10793     editing : false,
10794     error: null,
10795     modified: null,
10796
10797     // private
10798     join : function(store){
10799         this.store = store;
10800     },
10801
10802     /**
10803      * Set the named field to the specified value.
10804      * @param {String} name The name of the field to set.
10805      * @param {Object} value The value to set the field to.
10806      */
10807     set : function(name, value){
10808         if(this.data[name] == value){
10809             return;
10810         }
10811         this.dirty = true;
10812         if(!this.modified){
10813             this.modified = {};
10814         }
10815         if(typeof this.modified[name] == 'undefined'){
10816             this.modified[name] = this.data[name];
10817         }
10818         this.data[name] = value;
10819         if(!this.editing && this.store){
10820             this.store.afterEdit(this);
10821         }       
10822     },
10823
10824     /**
10825      * Get the value of the named field.
10826      * @param {String} name The name of the field to get the value of.
10827      * @return {Object} The value of the field.
10828      */
10829     get : function(name){
10830         return this.data[name]; 
10831     },
10832
10833     // private
10834     beginEdit : function(){
10835         this.editing = true;
10836         this.modified = {}; 
10837     },
10838
10839     // private
10840     cancelEdit : function(){
10841         this.editing = false;
10842         delete this.modified;
10843     },
10844
10845     // private
10846     endEdit : function(){
10847         this.editing = false;
10848         if(this.dirty && this.store){
10849             this.store.afterEdit(this);
10850         }
10851     },
10852
10853     /**
10854      * Usually called by the {@link Roo.data.Store} which owns the Record.
10855      * Rejects all changes made to the Record since either creation, or the last commit operation.
10856      * Modified fields are reverted to their original values.
10857      * <p>
10858      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10859      * of reject operations.
10860      */
10861     reject : function(){
10862         var m = this.modified;
10863         for(var n in m){
10864             if(typeof m[n] != "function"){
10865                 this.data[n] = m[n];
10866             }
10867         }
10868         this.dirty = false;
10869         delete this.modified;
10870         this.editing = false;
10871         if(this.store){
10872             this.store.afterReject(this);
10873         }
10874     },
10875
10876     /**
10877      * Usually called by the {@link Roo.data.Store} which owns the Record.
10878      * Commits all changes made to the Record since either creation, or the last commit operation.
10879      * <p>
10880      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10881      * of commit operations.
10882      */
10883     commit : function(){
10884         this.dirty = false;
10885         delete this.modified;
10886         this.editing = false;
10887         if(this.store){
10888             this.store.afterCommit(this);
10889         }
10890     },
10891
10892     // private
10893     hasError : function(){
10894         return this.error != null;
10895     },
10896
10897     // private
10898     clearError : function(){
10899         this.error = null;
10900     },
10901
10902     /**
10903      * Creates a copy of this record.
10904      * @param {String} id (optional) A new record id if you don't want to use this record's id
10905      * @return {Record}
10906      */
10907     copy : function(newId) {
10908         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10909     }
10910 };/*
10911  * Based on:
10912  * Ext JS Library 1.1.1
10913  * Copyright(c) 2006-2007, Ext JS, LLC.
10914  *
10915  * Originally Released Under LGPL - original licence link has changed is not relivant.
10916  *
10917  * Fork - LGPL
10918  * <script type="text/javascript">
10919  */
10920
10921
10922
10923 /**
10924  * @class Roo.data.Store
10925  * @extends Roo.util.Observable
10926  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10927  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10928  * <p>
10929  * 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
10930  * has no knowledge of the format of the data returned by the Proxy.<br>
10931  * <p>
10932  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10933  * instances from the data object. These records are cached and made available through accessor functions.
10934  * @constructor
10935  * Creates a new Store.
10936  * @param {Object} config A config object containing the objects needed for the Store to access data,
10937  * and read the data into Records.
10938  */
10939 Roo.data.Store = function(config){
10940     this.data = new Roo.util.MixedCollection(false);
10941     this.data.getKey = function(o){
10942         return o.id;
10943     };
10944     this.baseParams = {};
10945     // private
10946     this.paramNames = {
10947         "start" : "start",
10948         "limit" : "limit",
10949         "sort" : "sort",
10950         "dir" : "dir",
10951         "multisort" : "_multisort"
10952     };
10953
10954     if(config && config.data){
10955         this.inlineData = config.data;
10956         delete config.data;
10957     }
10958
10959     Roo.apply(this, config);
10960     
10961     if(this.reader){ // reader passed
10962         this.reader = Roo.factory(this.reader, Roo.data);
10963         this.reader.xmodule = this.xmodule || false;
10964         if(!this.recordType){
10965             this.recordType = this.reader.recordType;
10966         }
10967         if(this.reader.onMetaChange){
10968             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10969         }
10970     }
10971
10972     if(this.recordType){
10973         this.fields = this.recordType.prototype.fields;
10974     }
10975     this.modified = [];
10976
10977     this.addEvents({
10978         /**
10979          * @event datachanged
10980          * Fires when the data cache has changed, and a widget which is using this Store
10981          * as a Record cache should refresh its view.
10982          * @param {Store} this
10983          */
10984         datachanged : true,
10985         /**
10986          * @event metachange
10987          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10988          * @param {Store} this
10989          * @param {Object} meta The JSON metadata
10990          */
10991         metachange : true,
10992         /**
10993          * @event add
10994          * Fires when Records have been added to the Store
10995          * @param {Store} this
10996          * @param {Roo.data.Record[]} records The array of Records added
10997          * @param {Number} index The index at which the record(s) were added
10998          */
10999         add : true,
11000         /**
11001          * @event remove
11002          * Fires when a Record has been removed from the Store
11003          * @param {Store} this
11004          * @param {Roo.data.Record} record The Record that was removed
11005          * @param {Number} index The index at which the record was removed
11006          */
11007         remove : true,
11008         /**
11009          * @event update
11010          * Fires when a Record has been updated
11011          * @param {Store} this
11012          * @param {Roo.data.Record} record The Record that was updated
11013          * @param {String} operation The update operation being performed.  Value may be one of:
11014          * <pre><code>
11015  Roo.data.Record.EDIT
11016  Roo.data.Record.REJECT
11017  Roo.data.Record.COMMIT
11018          * </code></pre>
11019          */
11020         update : true,
11021         /**
11022          * @event clear
11023          * Fires when the data cache has been cleared.
11024          * @param {Store} this
11025          */
11026         clear : true,
11027         /**
11028          * @event beforeload
11029          * Fires before a request is made for a new data object.  If the beforeload handler returns false
11030          * the load action will be canceled.
11031          * @param {Store} this
11032          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11033          */
11034         beforeload : true,
11035         /**
11036          * @event beforeloadadd
11037          * Fires after a new set of Records has been loaded.
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          */
11042         beforeloadadd : true,
11043         /**
11044          * @event load
11045          * Fires after a new set of Records has been loaded, before they are added to the store.
11046          * @param {Store} this
11047          * @param {Roo.data.Record[]} records The Records that were loaded
11048          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11049          * @params {Object} return from reader
11050          */
11051         load : true,
11052         /**
11053          * @event loadexception
11054          * Fires if an exception occurs in the Proxy during loading.
11055          * Called with the signature of the Proxy's "loadexception" event.
11056          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11057          * 
11058          * @param {Proxy} 
11059          * @param {Object} return from JsonData.reader() - success, totalRecords, records
11060          * @param {Object} load options 
11061          * @param {Object} jsonData from your request (normally this contains the Exception)
11062          */
11063         loadexception : true
11064     });
11065     
11066     if(this.proxy){
11067         this.proxy = Roo.factory(this.proxy, Roo.data);
11068         this.proxy.xmodule = this.xmodule || false;
11069         this.relayEvents(this.proxy,  ["loadexception"]);
11070     }
11071     this.sortToggle = {};
11072     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11073
11074     Roo.data.Store.superclass.constructor.call(this);
11075
11076     if(this.inlineData){
11077         this.loadData(this.inlineData);
11078         delete this.inlineData;
11079     }
11080 };
11081
11082 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11083      /**
11084     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
11085     * without a remote query - used by combo/forms at present.
11086     */
11087     
11088     /**
11089     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11090     */
11091     /**
11092     * @cfg {Array} data Inline data to be loaded when the store is initialized.
11093     */
11094     /**
11095     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11096     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11097     */
11098     /**
11099     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11100     * on any HTTP request
11101     */
11102     /**
11103     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11104     */
11105     /**
11106     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11107     */
11108     multiSort: false,
11109     /**
11110     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11111     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11112     */
11113     remoteSort : false,
11114
11115     /**
11116     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11117      * loaded or when a record is removed. (defaults to false).
11118     */
11119     pruneModifiedRecords : false,
11120
11121     // private
11122     lastOptions : null,
11123
11124     /**
11125      * Add Records to the Store and fires the add event.
11126      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11127      */
11128     add : function(records){
11129         records = [].concat(records);
11130         for(var i = 0, len = records.length; i < len; i++){
11131             records[i].join(this);
11132         }
11133         var index = this.data.length;
11134         this.data.addAll(records);
11135         this.fireEvent("add", this, records, index);
11136     },
11137
11138     /**
11139      * Remove a Record from the Store and fires the remove event.
11140      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11141      */
11142     remove : function(record){
11143         var index = this.data.indexOf(record);
11144         this.data.removeAt(index);
11145  
11146         if(this.pruneModifiedRecords){
11147             this.modified.remove(record);
11148         }
11149         this.fireEvent("remove", this, record, index);
11150     },
11151
11152     /**
11153      * Remove all Records from the Store and fires the clear event.
11154      */
11155     removeAll : function(){
11156         this.data.clear();
11157         if(this.pruneModifiedRecords){
11158             this.modified = [];
11159         }
11160         this.fireEvent("clear", this);
11161     },
11162
11163     /**
11164      * Inserts Records to the Store at the given index and fires the add event.
11165      * @param {Number} index The start index at which to insert the passed Records.
11166      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11167      */
11168     insert : function(index, records){
11169         records = [].concat(records);
11170         for(var i = 0, len = records.length; i < len; i++){
11171             this.data.insert(index, records[i]);
11172             records[i].join(this);
11173         }
11174         this.fireEvent("add", this, records, index);
11175     },
11176
11177     /**
11178      * Get the index within the cache of the passed Record.
11179      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11180      * @return {Number} The index of the passed Record. Returns -1 if not found.
11181      */
11182     indexOf : function(record){
11183         return this.data.indexOf(record);
11184     },
11185
11186     /**
11187      * Get the index within the cache of the Record with the passed id.
11188      * @param {String} id The id of the Record to find.
11189      * @return {Number} The index of the Record. Returns -1 if not found.
11190      */
11191     indexOfId : function(id){
11192         return this.data.indexOfKey(id);
11193     },
11194
11195     /**
11196      * Get the Record with the specified id.
11197      * @param {String} id The id of the Record to find.
11198      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11199      */
11200     getById : function(id){
11201         return this.data.key(id);
11202     },
11203
11204     /**
11205      * Get the Record at the specified index.
11206      * @param {Number} index The index of the Record to find.
11207      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11208      */
11209     getAt : function(index){
11210         return this.data.itemAt(index);
11211     },
11212
11213     /**
11214      * Returns a range of Records between specified indices.
11215      * @param {Number} startIndex (optional) The starting index (defaults to 0)
11216      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11217      * @return {Roo.data.Record[]} An array of Records
11218      */
11219     getRange : function(start, end){
11220         return this.data.getRange(start, end);
11221     },
11222
11223     // private
11224     storeOptions : function(o){
11225         o = Roo.apply({}, o);
11226         delete o.callback;
11227         delete o.scope;
11228         this.lastOptions = o;
11229     },
11230
11231     /**
11232      * Loads the Record cache from the configured Proxy using the configured Reader.
11233      * <p>
11234      * If using remote paging, then the first load call must specify the <em>start</em>
11235      * and <em>limit</em> properties in the options.params property to establish the initial
11236      * position within the dataset, and the number of Records to cache on each read from the Proxy.
11237      * <p>
11238      * <strong>It is important to note that for remote data sources, loading is asynchronous,
11239      * and this call will return before the new data has been loaded. Perform any post-processing
11240      * in a callback function, or in a "load" event handler.</strong>
11241      * <p>
11242      * @param {Object} options An object containing properties which control loading options:<ul>
11243      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11244      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11245      * passed the following arguments:<ul>
11246      * <li>r : Roo.data.Record[]</li>
11247      * <li>options: Options object from the load call</li>
11248      * <li>success: Boolean success indicator</li></ul></li>
11249      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11250      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11251      * </ul>
11252      */
11253     load : function(options){
11254         options = options || {};
11255         if(this.fireEvent("beforeload", this, options) !== false){
11256             this.storeOptions(options);
11257             var p = Roo.apply(options.params || {}, this.baseParams);
11258             // if meta was not loaded from remote source.. try requesting it.
11259             if (!this.reader.metaFromRemote) {
11260                 p._requestMeta = 1;
11261             }
11262             if(this.sortInfo && this.remoteSort){
11263                 var pn = this.paramNames;
11264                 p[pn["sort"]] = this.sortInfo.field;
11265                 p[pn["dir"]] = this.sortInfo.direction;
11266             }
11267             if (this.multiSort) {
11268                 var pn = this.paramNames;
11269                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11270             }
11271             
11272             this.proxy.load(p, this.reader, this.loadRecords, this, options);
11273         }
11274     },
11275
11276     /**
11277      * Reloads the Record cache from the configured Proxy using the configured Reader and
11278      * the options from the last load operation performed.
11279      * @param {Object} options (optional) An object containing properties which may override the options
11280      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11281      * the most recently used options are reused).
11282      */
11283     reload : function(options){
11284         this.load(Roo.applyIf(options||{}, this.lastOptions));
11285     },
11286
11287     // private
11288     // Called as a callback by the Reader during a load operation.
11289     loadRecords : function(o, options, success){
11290         if(!o || success === false){
11291             if(success !== false){
11292                 this.fireEvent("load", this, [], options, o);
11293             }
11294             if(options.callback){
11295                 options.callback.call(options.scope || this, [], options, false);
11296             }
11297             return;
11298         }
11299         // if data returned failure - throw an exception.
11300         if (o.success === false) {
11301             // show a message if no listener is registered.
11302             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11303                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11304             }
11305             // loadmask wil be hooked into this..
11306             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11307             return;
11308         }
11309         var r = o.records, t = o.totalRecords || r.length;
11310         
11311         this.fireEvent("beforeloadadd", this, r, options, o);
11312         
11313         if(!options || options.add !== true){
11314             if(this.pruneModifiedRecords){
11315                 this.modified = [];
11316             }
11317             for(var i = 0, len = r.length; i < len; i++){
11318                 r[i].join(this);
11319             }
11320             if(this.snapshot){
11321                 this.data = this.snapshot;
11322                 delete this.snapshot;
11323             }
11324             this.data.clear();
11325             this.data.addAll(r);
11326             this.totalLength = t;
11327             this.applySort();
11328             this.fireEvent("datachanged", this);
11329         }else{
11330             this.totalLength = Math.max(t, this.data.length+r.length);
11331             this.add(r);
11332         }
11333         
11334         if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11335                 
11336             var e = new Roo.data.Record({});
11337
11338             e.set(this.parent.displayField, this.parent.emptyTitle);
11339             e.set(this.parent.valueField, '');
11340
11341             this.insert(0, e);
11342         }
11343             
11344         this.fireEvent("load", this, r, options, o);
11345         if(options.callback){
11346             options.callback.call(options.scope || this, r, options, true);
11347         }
11348     },
11349
11350
11351     /**
11352      * Loads data from a passed data block. A Reader which understands the format of the data
11353      * must have been configured in the constructor.
11354      * @param {Object} data The data block from which to read the Records.  The format of the data expected
11355      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11356      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11357      */
11358     loadData : function(o, append){
11359         var r = this.reader.readRecords(o);
11360         this.loadRecords(r, {add: append}, true);
11361     },
11362
11363     /**
11364      * Gets the number of cached records.
11365      * <p>
11366      * <em>If using paging, this may not be the total size of the dataset. If the data object
11367      * used by the Reader contains the dataset size, then the getTotalCount() function returns
11368      * the data set size</em>
11369      */
11370     getCount : function(){
11371         return this.data.length || 0;
11372     },
11373
11374     /**
11375      * Gets the total number of records in the dataset as returned by the server.
11376      * <p>
11377      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11378      * the dataset size</em>
11379      */
11380     getTotalCount : function(){
11381         return this.totalLength || 0;
11382     },
11383
11384     /**
11385      * Returns the sort state of the Store as an object with two properties:
11386      * <pre><code>
11387  field {String} The name of the field by which the Records are sorted
11388  direction {String} The sort order, "ASC" or "DESC"
11389      * </code></pre>
11390      */
11391     getSortState : function(){
11392         return this.sortInfo;
11393     },
11394
11395     // private
11396     applySort : function(){
11397         if(this.sortInfo && !this.remoteSort){
11398             var s = this.sortInfo, f = s.field;
11399             var st = this.fields.get(f).sortType;
11400             var fn = function(r1, r2){
11401                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11402                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11403             };
11404             this.data.sort(s.direction, fn);
11405             if(this.snapshot && this.snapshot != this.data){
11406                 this.snapshot.sort(s.direction, fn);
11407             }
11408         }
11409     },
11410
11411     /**
11412      * Sets the default sort column and order to be used by the next load operation.
11413      * @param {String} fieldName The name of the field to sort by.
11414      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11415      */
11416     setDefaultSort : function(field, dir){
11417         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11418     },
11419
11420     /**
11421      * Sort the Records.
11422      * If remote sorting is used, the sort is performed on the server, and the cache is
11423      * reloaded. If local sorting is used, the cache is sorted internally.
11424      * @param {String} fieldName The name of the field to sort by.
11425      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11426      */
11427     sort : function(fieldName, dir){
11428         var f = this.fields.get(fieldName);
11429         if(!dir){
11430             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11431             
11432             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11433                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11434             }else{
11435                 dir = f.sortDir;
11436             }
11437         }
11438         this.sortToggle[f.name] = dir;
11439         this.sortInfo = {field: f.name, direction: dir};
11440         if(!this.remoteSort){
11441             this.applySort();
11442             this.fireEvent("datachanged", this);
11443         }else{
11444             this.load(this.lastOptions);
11445         }
11446     },
11447
11448     /**
11449      * Calls the specified function for each of the Records in the cache.
11450      * @param {Function} fn The function to call. The Record is passed as the first parameter.
11451      * Returning <em>false</em> aborts and exits the iteration.
11452      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11453      */
11454     each : function(fn, scope){
11455         this.data.each(fn, scope);
11456     },
11457
11458     /**
11459      * Gets all records modified since the last commit.  Modified records are persisted across load operations
11460      * (e.g., during paging).
11461      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11462      */
11463     getModifiedRecords : function(){
11464         return this.modified;
11465     },
11466
11467     // private
11468     createFilterFn : function(property, value, anyMatch){
11469         if(!value.exec){ // not a regex
11470             value = String(value);
11471             if(value.length == 0){
11472                 return false;
11473             }
11474             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11475         }
11476         return function(r){
11477             return value.test(r.data[property]);
11478         };
11479     },
11480
11481     /**
11482      * Sums the value of <i>property</i> for each record between start and end and returns the result.
11483      * @param {String} property A field on your records
11484      * @param {Number} start The record index to start at (defaults to 0)
11485      * @param {Number} end The last record index to include (defaults to length - 1)
11486      * @return {Number} The sum
11487      */
11488     sum : function(property, start, end){
11489         var rs = this.data.items, v = 0;
11490         start = start || 0;
11491         end = (end || end === 0) ? end : rs.length-1;
11492
11493         for(var i = start; i <= end; i++){
11494             v += (rs[i].data[property] || 0);
11495         }
11496         return v;
11497     },
11498
11499     /**
11500      * Filter the records by a specified property.
11501      * @param {String} field A field on your records
11502      * @param {String/RegExp} value Either a string that the field
11503      * should start with or a RegExp to test against the field
11504      * @param {Boolean} anyMatch True to match any part not just the beginning
11505      */
11506     filter : function(property, value, anyMatch){
11507         var fn = this.createFilterFn(property, value, anyMatch);
11508         return fn ? this.filterBy(fn) : this.clearFilter();
11509     },
11510
11511     /**
11512      * Filter by a function. The specified function will be called with each
11513      * record in this data source. If the function returns true the record is included,
11514      * otherwise it is filtered.
11515      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11516      * @param {Object} scope (optional) The scope of the function (defaults to this)
11517      */
11518     filterBy : function(fn, scope){
11519         this.snapshot = this.snapshot || this.data;
11520         this.data = this.queryBy(fn, scope||this);
11521         this.fireEvent("datachanged", this);
11522     },
11523
11524     /**
11525      * Query the records by a specified property.
11526      * @param {String} field A field on your records
11527      * @param {String/RegExp} value Either a string that the field
11528      * should start with or a RegExp to test against the field
11529      * @param {Boolean} anyMatch True to match any part not just the beginning
11530      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11531      */
11532     query : function(property, value, anyMatch){
11533         var fn = this.createFilterFn(property, value, anyMatch);
11534         return fn ? this.queryBy(fn) : this.data.clone();
11535     },
11536
11537     /**
11538      * Query by a function. The specified function will be called with each
11539      * record in this data source. If the function returns true the record is included
11540      * in the results.
11541      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11542      * @param {Object} scope (optional) The scope of the function (defaults to this)
11543       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11544      **/
11545     queryBy : function(fn, scope){
11546         var data = this.snapshot || this.data;
11547         return data.filterBy(fn, scope||this);
11548     },
11549
11550     /**
11551      * Collects unique values for a particular dataIndex from this store.
11552      * @param {String} dataIndex The property to collect
11553      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11554      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11555      * @return {Array} An array of the unique values
11556      **/
11557     collect : function(dataIndex, allowNull, bypassFilter){
11558         var d = (bypassFilter === true && this.snapshot) ?
11559                 this.snapshot.items : this.data.items;
11560         var v, sv, r = [], l = {};
11561         for(var i = 0, len = d.length; i < len; i++){
11562             v = d[i].data[dataIndex];
11563             sv = String(v);
11564             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11565                 l[sv] = true;
11566                 r[r.length] = v;
11567             }
11568         }
11569         return r;
11570     },
11571
11572     /**
11573      * Revert to a view of the Record cache with no filtering applied.
11574      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11575      */
11576     clearFilter : function(suppressEvent){
11577         if(this.snapshot && this.snapshot != this.data){
11578             this.data = this.snapshot;
11579             delete this.snapshot;
11580             if(suppressEvent !== true){
11581                 this.fireEvent("datachanged", this);
11582             }
11583         }
11584     },
11585
11586     // private
11587     afterEdit : function(record){
11588         if(this.modified.indexOf(record) == -1){
11589             this.modified.push(record);
11590         }
11591         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11592     },
11593     
11594     // private
11595     afterReject : function(record){
11596         this.modified.remove(record);
11597         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11598     },
11599
11600     // private
11601     afterCommit : function(record){
11602         this.modified.remove(record);
11603         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11604     },
11605
11606     /**
11607      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11608      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11609      */
11610     commitChanges : function(){
11611         var m = this.modified.slice(0);
11612         this.modified = [];
11613         for(var i = 0, len = m.length; i < len; i++){
11614             m[i].commit();
11615         }
11616     },
11617
11618     /**
11619      * Cancel outstanding changes on all changed records.
11620      */
11621     rejectChanges : function(){
11622         var m = this.modified.slice(0);
11623         this.modified = [];
11624         for(var i = 0, len = m.length; i < len; i++){
11625             m[i].reject();
11626         }
11627     },
11628
11629     onMetaChange : function(meta, rtype, o){
11630         this.recordType = rtype;
11631         this.fields = rtype.prototype.fields;
11632         delete this.snapshot;
11633         this.sortInfo = meta.sortInfo || this.sortInfo;
11634         this.modified = [];
11635         this.fireEvent('metachange', this, this.reader.meta);
11636     },
11637     
11638     moveIndex : function(data, type)
11639     {
11640         var index = this.indexOf(data);
11641         
11642         var newIndex = index + type;
11643         
11644         this.remove(data);
11645         
11646         this.insert(newIndex, data);
11647         
11648     }
11649 });/*
11650  * Based on:
11651  * Ext JS Library 1.1.1
11652  * Copyright(c) 2006-2007, Ext JS, LLC.
11653  *
11654  * Originally Released Under LGPL - original licence link has changed is not relivant.
11655  *
11656  * Fork - LGPL
11657  * <script type="text/javascript">
11658  */
11659
11660 /**
11661  * @class Roo.data.SimpleStore
11662  * @extends Roo.data.Store
11663  * Small helper class to make creating Stores from Array data easier.
11664  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11665  * @cfg {Array} fields An array of field definition objects, or field name strings.
11666  * @cfg {Array} data The multi-dimensional array of data
11667  * @constructor
11668  * @param {Object} config
11669  */
11670 Roo.data.SimpleStore = function(config){
11671     Roo.data.SimpleStore.superclass.constructor.call(this, {
11672         isLocal : true,
11673         reader: new Roo.data.ArrayReader({
11674                 id: config.id
11675             },
11676             Roo.data.Record.create(config.fields)
11677         ),
11678         proxy : new Roo.data.MemoryProxy(config.data)
11679     });
11680     this.load();
11681 };
11682 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11683  * Based on:
11684  * Ext JS Library 1.1.1
11685  * Copyright(c) 2006-2007, Ext JS, LLC.
11686  *
11687  * Originally Released Under LGPL - original licence link has changed is not relivant.
11688  *
11689  * Fork - LGPL
11690  * <script type="text/javascript">
11691  */
11692
11693 /**
11694 /**
11695  * @extends Roo.data.Store
11696  * @class Roo.data.JsonStore
11697  * Small helper class to make creating Stores for JSON data easier. <br/>
11698 <pre><code>
11699 var store = new Roo.data.JsonStore({
11700     url: 'get-images.php',
11701     root: 'images',
11702     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11703 });
11704 </code></pre>
11705  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11706  * JsonReader and HttpProxy (unless inline data is provided).</b>
11707  * @cfg {Array} fields An array of field definition objects, or field name strings.
11708  * @constructor
11709  * @param {Object} config
11710  */
11711 Roo.data.JsonStore = function(c){
11712     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11713         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11714         reader: new Roo.data.JsonReader(c, c.fields)
11715     }));
11716 };
11717 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11718  * Based on:
11719  * Ext JS Library 1.1.1
11720  * Copyright(c) 2006-2007, Ext JS, LLC.
11721  *
11722  * Originally Released Under LGPL - original licence link has changed is not relivant.
11723  *
11724  * Fork - LGPL
11725  * <script type="text/javascript">
11726  */
11727
11728  
11729 Roo.data.Field = function(config){
11730     if(typeof config == "string"){
11731         config = {name: config};
11732     }
11733     Roo.apply(this, config);
11734     
11735     if(!this.type){
11736         this.type = "auto";
11737     }
11738     
11739     var st = Roo.data.SortTypes;
11740     // named sortTypes are supported, here we look them up
11741     if(typeof this.sortType == "string"){
11742         this.sortType = st[this.sortType];
11743     }
11744     
11745     // set default sortType for strings and dates
11746     if(!this.sortType){
11747         switch(this.type){
11748             case "string":
11749                 this.sortType = st.asUCString;
11750                 break;
11751             case "date":
11752                 this.sortType = st.asDate;
11753                 break;
11754             default:
11755                 this.sortType = st.none;
11756         }
11757     }
11758
11759     // define once
11760     var stripRe = /[\$,%]/g;
11761
11762     // prebuilt conversion function for this field, instead of
11763     // switching every time we're reading a value
11764     if(!this.convert){
11765         var cv, dateFormat = this.dateFormat;
11766         switch(this.type){
11767             case "":
11768             case "auto":
11769             case undefined:
11770                 cv = function(v){ return v; };
11771                 break;
11772             case "string":
11773                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11774                 break;
11775             case "int":
11776                 cv = function(v){
11777                     return v !== undefined && v !== null && v !== '' ?
11778                            parseInt(String(v).replace(stripRe, ""), 10) : '';
11779                     };
11780                 break;
11781             case "float":
11782                 cv = function(v){
11783                     return v !== undefined && v !== null && v !== '' ?
11784                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
11785                     };
11786                 break;
11787             case "bool":
11788             case "boolean":
11789                 cv = function(v){ return v === true || v === "true" || v == 1; };
11790                 break;
11791             case "date":
11792                 cv = function(v){
11793                     if(!v){
11794                         return '';
11795                     }
11796                     if(v instanceof Date){
11797                         return v;
11798                     }
11799                     if(dateFormat){
11800                         if(dateFormat == "timestamp"){
11801                             return new Date(v*1000);
11802                         }
11803                         return Date.parseDate(v, dateFormat);
11804                     }
11805                     var parsed = Date.parse(v);
11806                     return parsed ? new Date(parsed) : null;
11807                 };
11808              break;
11809             
11810         }
11811         this.convert = cv;
11812     }
11813 };
11814
11815 Roo.data.Field.prototype = {
11816     dateFormat: null,
11817     defaultValue: "",
11818     mapping: null,
11819     sortType : null,
11820     sortDir : "ASC"
11821 };/*
11822  * Based on:
11823  * Ext JS Library 1.1.1
11824  * Copyright(c) 2006-2007, Ext JS, LLC.
11825  *
11826  * Originally Released Under LGPL - original licence link has changed is not relivant.
11827  *
11828  * Fork - LGPL
11829  * <script type="text/javascript">
11830  */
11831  
11832 // Base class for reading structured data from a data source.  This class is intended to be
11833 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11834
11835 /**
11836  * @class Roo.data.DataReader
11837  * Base class for reading structured data from a data source.  This class is intended to be
11838  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11839  */
11840
11841 Roo.data.DataReader = function(meta, recordType){
11842     
11843     this.meta = meta;
11844     
11845     this.recordType = recordType instanceof Array ? 
11846         Roo.data.Record.create(recordType) : recordType;
11847 };
11848
11849 Roo.data.DataReader.prototype = {
11850      /**
11851      * Create an empty record
11852      * @param {Object} data (optional) - overlay some values
11853      * @return {Roo.data.Record} record created.
11854      */
11855     newRow :  function(d) {
11856         var da =  {};
11857         this.recordType.prototype.fields.each(function(c) {
11858             switch( c.type) {
11859                 case 'int' : da[c.name] = 0; break;
11860                 case 'date' : da[c.name] = new Date(); break;
11861                 case 'float' : da[c.name] = 0.0; break;
11862                 case 'boolean' : da[c.name] = false; break;
11863                 default : da[c.name] = ""; break;
11864             }
11865             
11866         });
11867         return new this.recordType(Roo.apply(da, d));
11868     }
11869     
11870 };/*
11871  * Based on:
11872  * Ext JS Library 1.1.1
11873  * Copyright(c) 2006-2007, Ext JS, LLC.
11874  *
11875  * Originally Released Under LGPL - original licence link has changed is not relivant.
11876  *
11877  * Fork - LGPL
11878  * <script type="text/javascript">
11879  */
11880
11881 /**
11882  * @class Roo.data.DataProxy
11883  * @extends Roo.data.Observable
11884  * This class is an abstract base class for implementations which provide retrieval of
11885  * unformatted data objects.<br>
11886  * <p>
11887  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11888  * (of the appropriate type which knows how to parse the data object) to provide a block of
11889  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11890  * <p>
11891  * Custom implementations must implement the load method as described in
11892  * {@link Roo.data.HttpProxy#load}.
11893  */
11894 Roo.data.DataProxy = function(){
11895     this.addEvents({
11896         /**
11897          * @event beforeload
11898          * Fires before a network request is made to retrieve a data object.
11899          * @param {Object} This DataProxy object.
11900          * @param {Object} params The params parameter to the load function.
11901          */
11902         beforeload : true,
11903         /**
11904          * @event load
11905          * Fires before the load method's callback is called.
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          */
11910         load : true,
11911         /**
11912          * @event loadexception
11913          * Fires if an Exception occurs during data retrieval.
11914          * @param {Object} This DataProxy object.
11915          * @param {Object} o The data object.
11916          * @param {Object} arg The callback argument object passed to the load function.
11917          * @param {Object} e The Exception.
11918          */
11919         loadexception : true
11920     });
11921     Roo.data.DataProxy.superclass.constructor.call(this);
11922 };
11923
11924 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11925
11926     /**
11927      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11928      */
11929 /*
11930  * Based on:
11931  * Ext JS Library 1.1.1
11932  * Copyright(c) 2006-2007, Ext JS, LLC.
11933  *
11934  * Originally Released Under LGPL - original licence link has changed is not relivant.
11935  *
11936  * Fork - LGPL
11937  * <script type="text/javascript">
11938  */
11939 /**
11940  * @class Roo.data.MemoryProxy
11941  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11942  * to the Reader when its load method is called.
11943  * @constructor
11944  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11945  */
11946 Roo.data.MemoryProxy = function(data){
11947     if (data.data) {
11948         data = data.data;
11949     }
11950     Roo.data.MemoryProxy.superclass.constructor.call(this);
11951     this.data = data;
11952 };
11953
11954 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11955     
11956     /**
11957      * Load data from the requested source (in this case an in-memory
11958      * data object passed to the constructor), read the data object into
11959      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11960      * process that block using the passed callback.
11961      * @param {Object} params This parameter is not used by the MemoryProxy class.
11962      * @param {Roo.data.DataReader} reader The Reader object which converts the data
11963      * object into a block of Roo.data.Records.
11964      * @param {Function} callback The function into which to pass the block of Roo.data.records.
11965      * The function must be passed <ul>
11966      * <li>The Record block object</li>
11967      * <li>The "arg" argument from the load function</li>
11968      * <li>A boolean success indicator</li>
11969      * </ul>
11970      * @param {Object} scope The scope in which to call the callback
11971      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11972      */
11973     load : function(params, reader, callback, scope, arg){
11974         params = params || {};
11975         var result;
11976         try {
11977             result = reader.readRecords(this.data);
11978         }catch(e){
11979             this.fireEvent("loadexception", this, arg, null, e);
11980             callback.call(scope, null, arg, false);
11981             return;
11982         }
11983         callback.call(scope, result, arg, true);
11984     },
11985     
11986     // private
11987     update : function(params, records){
11988         
11989     }
11990 });/*
11991  * Based on:
11992  * Ext JS Library 1.1.1
11993  * Copyright(c) 2006-2007, Ext JS, LLC.
11994  *
11995  * Originally Released Under LGPL - original licence link has changed is not relivant.
11996  *
11997  * Fork - LGPL
11998  * <script type="text/javascript">
11999  */
12000 /**
12001  * @class Roo.data.HttpProxy
12002  * @extends Roo.data.DataProxy
12003  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12004  * configured to reference a certain URL.<br><br>
12005  * <p>
12006  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12007  * from which the running page was served.<br><br>
12008  * <p>
12009  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12010  * <p>
12011  * Be aware that to enable the browser to parse an XML document, the server must set
12012  * the Content-Type header in the HTTP response to "text/xml".
12013  * @constructor
12014  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12015  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
12016  * will be used to make the request.
12017  */
12018 Roo.data.HttpProxy = function(conn){
12019     Roo.data.HttpProxy.superclass.constructor.call(this);
12020     // is conn a conn config or a real conn?
12021     this.conn = conn;
12022     this.useAjax = !conn || !conn.events;
12023   
12024 };
12025
12026 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12027     // thse are take from connection...
12028     
12029     /**
12030      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12031      */
12032     /**
12033      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12034      * extra parameters to each request made by this object. (defaults to undefined)
12035      */
12036     /**
12037      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12038      *  to each request made by this object. (defaults to undefined)
12039      */
12040     /**
12041      * @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)
12042      */
12043     /**
12044      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12045      */
12046      /**
12047      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12048      * @type Boolean
12049      */
12050   
12051
12052     /**
12053      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12054      * @type Boolean
12055      */
12056     /**
12057      * Return the {@link Roo.data.Connection} object being used by this Proxy.
12058      * @return {Connection} The Connection object. This object may be used to subscribe to events on
12059      * a finer-grained basis than the DataProxy events.
12060      */
12061     getConnection : function(){
12062         return this.useAjax ? Roo.Ajax : this.conn;
12063     },
12064
12065     /**
12066      * Load data from the configured {@link Roo.data.Connection}, read the data object into
12067      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12068      * process that block using the passed callback.
12069      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12070      * for the request to the remote server.
12071      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12072      * object into a block of Roo.data.Records.
12073      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12074      * The function must be passed <ul>
12075      * <li>The Record block object</li>
12076      * <li>The "arg" argument from the load function</li>
12077      * <li>A boolean success indicator</li>
12078      * </ul>
12079      * @param {Object} scope The scope in which to call the callback
12080      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12081      */
12082     load : function(params, reader, callback, scope, arg){
12083         if(this.fireEvent("beforeload", this, params) !== false){
12084             var  o = {
12085                 params : params || {},
12086                 request: {
12087                     callback : callback,
12088                     scope : scope,
12089                     arg : arg
12090                 },
12091                 reader: reader,
12092                 callback : this.loadResponse,
12093                 scope: this
12094             };
12095             if(this.useAjax){
12096                 Roo.applyIf(o, this.conn);
12097                 if(this.activeRequest){
12098                     Roo.Ajax.abort(this.activeRequest);
12099                 }
12100                 this.activeRequest = Roo.Ajax.request(o);
12101             }else{
12102                 this.conn.request(o);
12103             }
12104         }else{
12105             callback.call(scope||this, null, arg, false);
12106         }
12107     },
12108
12109     // private
12110     loadResponse : function(o, success, response){
12111         delete this.activeRequest;
12112         if(!success){
12113             this.fireEvent("loadexception", this, o, response);
12114             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12115             return;
12116         }
12117         var result;
12118         try {
12119             result = o.reader.read(response);
12120         }catch(e){
12121             this.fireEvent("loadexception", this, o, response, e);
12122             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12123             return;
12124         }
12125         
12126         this.fireEvent("load", this, o, o.request.arg);
12127         o.request.callback.call(o.request.scope, result, o.request.arg, true);
12128     },
12129
12130     // private
12131     update : function(dataSet){
12132
12133     },
12134
12135     // private
12136     updateResponse : function(dataSet){
12137
12138     }
12139 });/*
12140  * Based on:
12141  * Ext JS Library 1.1.1
12142  * Copyright(c) 2006-2007, Ext JS, LLC.
12143  *
12144  * Originally Released Under LGPL - original licence link has changed is not relivant.
12145  *
12146  * Fork - LGPL
12147  * <script type="text/javascript">
12148  */
12149
12150 /**
12151  * @class Roo.data.ScriptTagProxy
12152  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12153  * other than the originating domain of the running page.<br><br>
12154  * <p>
12155  * <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
12156  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12157  * <p>
12158  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12159  * source code that is used as the source inside a &lt;script> tag.<br><br>
12160  * <p>
12161  * In order for the browser to process the returned data, the server must wrap the data object
12162  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12163  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12164  * depending on whether the callback name was passed:
12165  * <p>
12166  * <pre><code>
12167 boolean scriptTag = false;
12168 String cb = request.getParameter("callback");
12169 if (cb != null) {
12170     scriptTag = true;
12171     response.setContentType("text/javascript");
12172 } else {
12173     response.setContentType("application/x-json");
12174 }
12175 Writer out = response.getWriter();
12176 if (scriptTag) {
12177     out.write(cb + "(");
12178 }
12179 out.print(dataBlock.toJsonString());
12180 if (scriptTag) {
12181     out.write(");");
12182 }
12183 </pre></code>
12184  *
12185  * @constructor
12186  * @param {Object} config A configuration object.
12187  */
12188 Roo.data.ScriptTagProxy = function(config){
12189     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12190     Roo.apply(this, config);
12191     this.head = document.getElementsByTagName("head")[0];
12192 };
12193
12194 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12195
12196 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12197     /**
12198      * @cfg {String} url The URL from which to request the data object.
12199      */
12200     /**
12201      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12202      */
12203     timeout : 30000,
12204     /**
12205      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12206      * the server the name of the callback function set up by the load call to process the returned data object.
12207      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12208      * javascript output which calls this named function passing the data object as its only parameter.
12209      */
12210     callbackParam : "callback",
12211     /**
12212      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12213      * name to the request.
12214      */
12215     nocache : true,
12216
12217     /**
12218      * Load data from the configured URL, read the data object into
12219      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12220      * process that block using the passed callback.
12221      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12222      * for the request to the remote server.
12223      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12224      * object into a block of Roo.data.Records.
12225      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12226      * The function must be passed <ul>
12227      * <li>The Record block object</li>
12228      * <li>The "arg" argument from the load function</li>
12229      * <li>A boolean success indicator</li>
12230      * </ul>
12231      * @param {Object} scope The scope in which to call the callback
12232      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12233      */
12234     load : function(params, reader, callback, scope, arg){
12235         if(this.fireEvent("beforeload", this, params) !== false){
12236
12237             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12238
12239             var url = this.url;
12240             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12241             if(this.nocache){
12242                 url += "&_dc=" + (new Date().getTime());
12243             }
12244             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12245             var trans = {
12246                 id : transId,
12247                 cb : "stcCallback"+transId,
12248                 scriptId : "stcScript"+transId,
12249                 params : params,
12250                 arg : arg,
12251                 url : url,
12252                 callback : callback,
12253                 scope : scope,
12254                 reader : reader
12255             };
12256             var conn = this;
12257
12258             window[trans.cb] = function(o){
12259                 conn.handleResponse(o, trans);
12260             };
12261
12262             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12263
12264             if(this.autoAbort !== false){
12265                 this.abort();
12266             }
12267
12268             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12269
12270             var script = document.createElement("script");
12271             script.setAttribute("src", url);
12272             script.setAttribute("type", "text/javascript");
12273             script.setAttribute("id", trans.scriptId);
12274             this.head.appendChild(script);
12275
12276             this.trans = trans;
12277         }else{
12278             callback.call(scope||this, null, arg, false);
12279         }
12280     },
12281
12282     // private
12283     isLoading : function(){
12284         return this.trans ? true : false;
12285     },
12286
12287     /**
12288      * Abort the current server request.
12289      */
12290     abort : function(){
12291         if(this.isLoading()){
12292             this.destroyTrans(this.trans);
12293         }
12294     },
12295
12296     // private
12297     destroyTrans : function(trans, isLoaded){
12298         this.head.removeChild(document.getElementById(trans.scriptId));
12299         clearTimeout(trans.timeoutId);
12300         if(isLoaded){
12301             window[trans.cb] = undefined;
12302             try{
12303                 delete window[trans.cb];
12304             }catch(e){}
12305         }else{
12306             // if hasn't been loaded, wait for load to remove it to prevent script error
12307             window[trans.cb] = function(){
12308                 window[trans.cb] = undefined;
12309                 try{
12310                     delete window[trans.cb];
12311                 }catch(e){}
12312             };
12313         }
12314     },
12315
12316     // private
12317     handleResponse : function(o, trans){
12318         this.trans = false;
12319         this.destroyTrans(trans, true);
12320         var result;
12321         try {
12322             result = trans.reader.readRecords(o);
12323         }catch(e){
12324             this.fireEvent("loadexception", this, o, trans.arg, e);
12325             trans.callback.call(trans.scope||window, null, trans.arg, false);
12326             return;
12327         }
12328         this.fireEvent("load", this, o, trans.arg);
12329         trans.callback.call(trans.scope||window, result, trans.arg, true);
12330     },
12331
12332     // private
12333     handleFailure : function(trans){
12334         this.trans = false;
12335         this.destroyTrans(trans, false);
12336         this.fireEvent("loadexception", this, null, trans.arg);
12337         trans.callback.call(trans.scope||window, null, trans.arg, false);
12338     }
12339 });/*
12340  * Based on:
12341  * Ext JS Library 1.1.1
12342  * Copyright(c) 2006-2007, Ext JS, LLC.
12343  *
12344  * Originally Released Under LGPL - original licence link has changed is not relivant.
12345  *
12346  * Fork - LGPL
12347  * <script type="text/javascript">
12348  */
12349
12350 /**
12351  * @class Roo.data.JsonReader
12352  * @extends Roo.data.DataReader
12353  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12354  * based on mappings in a provided Roo.data.Record constructor.
12355  * 
12356  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12357  * in the reply previously. 
12358  * 
12359  * <p>
12360  * Example code:
12361  * <pre><code>
12362 var RecordDef = Roo.data.Record.create([
12363     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
12364     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
12365 ]);
12366 var myReader = new Roo.data.JsonReader({
12367     totalProperty: "results",    // The property which contains the total dataset size (optional)
12368     root: "rows",                // The property which contains an Array of row objects
12369     id: "id"                     // The property within each row object that provides an ID for the record (optional)
12370 }, RecordDef);
12371 </code></pre>
12372  * <p>
12373  * This would consume a JSON file like this:
12374  * <pre><code>
12375 { 'results': 2, 'rows': [
12376     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12377     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12378 }
12379 </code></pre>
12380  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12381  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12382  * paged from the remote server.
12383  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12384  * @cfg {String} root name of the property which contains the Array of row objects.
12385  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12386  * @cfg {Array} fields Array of field definition objects
12387  * @constructor
12388  * Create a new JsonReader
12389  * @param {Object} meta Metadata configuration options
12390  * @param {Object} recordType Either an Array of field definition objects,
12391  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12392  */
12393 Roo.data.JsonReader = function(meta, recordType){
12394     
12395     meta = meta || {};
12396     // set some defaults:
12397     Roo.applyIf(meta, {
12398         totalProperty: 'total',
12399         successProperty : 'success',
12400         root : 'data',
12401         id : 'id'
12402     });
12403     
12404     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12405 };
12406 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12407     
12408     /**
12409      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
12410      * Used by Store query builder to append _requestMeta to params.
12411      * 
12412      */
12413     metaFromRemote : false,
12414     /**
12415      * This method is only used by a DataProxy which has retrieved data from a remote server.
12416      * @param {Object} response The XHR object which contains the JSON data in its responseText.
12417      * @return {Object} data A data block which is used by an Roo.data.Store object as
12418      * a cache of Roo.data.Records.
12419      */
12420     read : function(response){
12421         var json = response.responseText;
12422        
12423         var o = /* eval:var:o */ eval("("+json+")");
12424         if(!o) {
12425             throw {message: "JsonReader.read: Json object not found"};
12426         }
12427         
12428         if(o.metaData){
12429             
12430             delete this.ef;
12431             this.metaFromRemote = true;
12432             this.meta = o.metaData;
12433             this.recordType = Roo.data.Record.create(o.metaData.fields);
12434             this.onMetaChange(this.meta, this.recordType, o);
12435         }
12436         return this.readRecords(o);
12437     },
12438
12439     // private function a store will implement
12440     onMetaChange : function(meta, recordType, o){
12441
12442     },
12443
12444     /**
12445          * @ignore
12446          */
12447     simpleAccess: function(obj, subsc) {
12448         return obj[subsc];
12449     },
12450
12451         /**
12452          * @ignore
12453          */
12454     getJsonAccessor: function(){
12455         var re = /[\[\.]/;
12456         return function(expr) {
12457             try {
12458                 return(re.test(expr))
12459                     ? new Function("obj", "return obj." + expr)
12460                     : function(obj){
12461                         return obj[expr];
12462                     };
12463             } catch(e){}
12464             return Roo.emptyFn;
12465         };
12466     }(),
12467
12468     /**
12469      * Create a data block containing Roo.data.Records from an XML document.
12470      * @param {Object} o An object which contains an Array of row objects in the property specified
12471      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12472      * which contains the total size of the dataset.
12473      * @return {Object} data A data block which is used by an Roo.data.Store object as
12474      * a cache of Roo.data.Records.
12475      */
12476     readRecords : function(o){
12477         /**
12478          * After any data loads, the raw JSON data is available for further custom processing.
12479          * @type Object
12480          */
12481         this.o = o;
12482         var s = this.meta, Record = this.recordType,
12483             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12484
12485 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
12486         if (!this.ef) {
12487             if(s.totalProperty) {
12488                     this.getTotal = this.getJsonAccessor(s.totalProperty);
12489                 }
12490                 if(s.successProperty) {
12491                     this.getSuccess = this.getJsonAccessor(s.successProperty);
12492                 }
12493                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12494                 if (s.id) {
12495                         var g = this.getJsonAccessor(s.id);
12496                         this.getId = function(rec) {
12497                                 var r = g(rec);  
12498                                 return (r === undefined || r === "") ? null : r;
12499                         };
12500                 } else {
12501                         this.getId = function(){return null;};
12502                 }
12503             this.ef = [];
12504             for(var jj = 0; jj < fl; jj++){
12505                 f = fi[jj];
12506                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12507                 this.ef[jj] = this.getJsonAccessor(map);
12508             }
12509         }
12510
12511         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12512         if(s.totalProperty){
12513             var vt = parseInt(this.getTotal(o), 10);
12514             if(!isNaN(vt)){
12515                 totalRecords = vt;
12516             }
12517         }
12518         if(s.successProperty){
12519             var vs = this.getSuccess(o);
12520             if(vs === false || vs === 'false'){
12521                 success = false;
12522             }
12523         }
12524         var records = [];
12525         for(var i = 0; i < c; i++){
12526                 var n = root[i];
12527             var values = {};
12528             var id = this.getId(n);
12529             for(var j = 0; j < fl; j++){
12530                 f = fi[j];
12531             var v = this.ef[j](n);
12532             if (!f.convert) {
12533                 Roo.log('missing convert for ' + f.name);
12534                 Roo.log(f);
12535                 continue;
12536             }
12537             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12538             }
12539             var record = new Record(values, id);
12540             record.json = n;
12541             records[i] = record;
12542         }
12543         return {
12544             raw : o,
12545             success : success,
12546             records : records,
12547             totalRecords : totalRecords
12548         };
12549     }
12550 });/*
12551  * Based on:
12552  * Ext JS Library 1.1.1
12553  * Copyright(c) 2006-2007, Ext JS, LLC.
12554  *
12555  * Originally Released Under LGPL - original licence link has changed is not relivant.
12556  *
12557  * Fork - LGPL
12558  * <script type="text/javascript">
12559  */
12560
12561 /**
12562  * @class Roo.data.ArrayReader
12563  * @extends Roo.data.DataReader
12564  * Data reader class to create an Array of Roo.data.Record objects from an Array.
12565  * Each element of that Array represents a row of data fields. The
12566  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12567  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12568  * <p>
12569  * Example code:.
12570  * <pre><code>
12571 var RecordDef = Roo.data.Record.create([
12572     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
12573     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
12574 ]);
12575 var myReader = new Roo.data.ArrayReader({
12576     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
12577 }, RecordDef);
12578 </code></pre>
12579  * <p>
12580  * This would consume an Array like this:
12581  * <pre><code>
12582 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12583   </code></pre>
12584  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12585  * @constructor
12586  * Create a new JsonReader
12587  * @param {Object} meta Metadata configuration options.
12588  * @param {Object} recordType Either an Array of field definition objects
12589  * as specified to {@link Roo.data.Record#create},
12590  * or an {@link Roo.data.Record} object
12591  * created using {@link Roo.data.Record#create}.
12592  */
12593 Roo.data.ArrayReader = function(meta, recordType){
12594     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12595 };
12596
12597 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12598     /**
12599      * Create a data block containing Roo.data.Records from an XML document.
12600      * @param {Object} o An Array of row objects which represents the dataset.
12601      * @return {Object} data A data block which is used by an Roo.data.Store object as
12602      * a cache of Roo.data.Records.
12603      */
12604     readRecords : function(o){
12605         var sid = this.meta ? this.meta.id : null;
12606         var recordType = this.recordType, fields = recordType.prototype.fields;
12607         var records = [];
12608         var root = o;
12609             for(var i = 0; i < root.length; i++){
12610                     var n = root[i];
12611                 var values = {};
12612                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12613                 for(var j = 0, jlen = fields.length; j < jlen; j++){
12614                 var f = fields.items[j];
12615                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12616                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12617                 v = f.convert(v);
12618                 values[f.name] = v;
12619             }
12620                 var record = new recordType(values, id);
12621                 record.json = n;
12622                 records[records.length] = record;
12623             }
12624             return {
12625                 records : records,
12626                 totalRecords : records.length
12627             };
12628     }
12629 });/*
12630  * - LGPL
12631  * * 
12632  */
12633
12634 /**
12635  * @class Roo.bootstrap.ComboBox
12636  * @extends Roo.bootstrap.TriggerField
12637  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12638  * @cfg {Boolean} append (true|false) default false
12639  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12640  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12641  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12642  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12643  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12644  * @cfg {Boolean} animate default true
12645  * @cfg {Boolean} emptyResultText only for touch device
12646  * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12647  * @cfg {String} emptyTitle default ''
12648  * @constructor
12649  * Create a new ComboBox.
12650  * @param {Object} config Configuration options
12651  */
12652 Roo.bootstrap.ComboBox = function(config){
12653     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12654     this.addEvents({
12655         /**
12656          * @event expand
12657          * Fires when the dropdown list is expanded
12658         * @param {Roo.bootstrap.ComboBox} combo This combo box
12659         */
12660         'expand' : true,
12661         /**
12662          * @event collapse
12663          * Fires when the dropdown list is collapsed
12664         * @param {Roo.bootstrap.ComboBox} combo This combo box
12665         */
12666         'collapse' : true,
12667         /**
12668          * @event beforeselect
12669          * Fires before a list item is selected. Return false to cancel the selection.
12670         * @param {Roo.bootstrap.ComboBox} combo This combo box
12671         * @param {Roo.data.Record} record The data record returned from the underlying store
12672         * @param {Number} index The index of the selected item in the dropdown list
12673         */
12674         'beforeselect' : true,
12675         /**
12676          * @event select
12677          * Fires when a list item is selected
12678         * @param {Roo.bootstrap.ComboBox} combo This combo box
12679         * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12680         * @param {Number} index The index of the selected item in the dropdown list
12681         */
12682         'select' : true,
12683         /**
12684          * @event beforequery
12685          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12686          * The event object passed has these properties:
12687         * @param {Roo.bootstrap.ComboBox} combo This combo box
12688         * @param {String} query The query
12689         * @param {Boolean} forceAll true to force "all" query
12690         * @param {Boolean} cancel true to cancel the query
12691         * @param {Object} e The query event object
12692         */
12693         'beforequery': true,
12694          /**
12695          * @event add
12696          * Fires when the 'add' icon is pressed (add a listener to enable add button)
12697         * @param {Roo.bootstrap.ComboBox} combo This combo box
12698         */
12699         'add' : true,
12700         /**
12701          * @event edit
12702          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12703         * @param {Roo.bootstrap.ComboBox} combo This combo box
12704         * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12705         */
12706         'edit' : true,
12707         /**
12708          * @event remove
12709          * Fires when the remove value from the combobox array
12710         * @param {Roo.bootstrap.ComboBox} combo This combo box
12711         */
12712         'remove' : true,
12713         /**
12714          * @event afterremove
12715          * Fires when the remove value from the combobox array
12716         * @param {Roo.bootstrap.ComboBox} combo This combo box
12717         */
12718         'afterremove' : true,
12719         /**
12720          * @event specialfilter
12721          * Fires when specialfilter
12722             * @param {Roo.bootstrap.ComboBox} combo This combo box
12723             */
12724         'specialfilter' : true,
12725         /**
12726          * @event tick
12727          * Fires when tick the element
12728             * @param {Roo.bootstrap.ComboBox} combo This combo box
12729             */
12730         'tick' : true,
12731         /**
12732          * @event touchviewdisplay
12733          * Fires when touch view require special display (default is using displayField)
12734             * @param {Roo.bootstrap.ComboBox} combo This combo box
12735             * @param {Object} cfg set html .
12736             */
12737         'touchviewdisplay' : true
12738         
12739     });
12740     
12741     this.item = [];
12742     this.tickItems = [];
12743     
12744     this.selectedIndex = -1;
12745     if(this.mode == 'local'){
12746         if(config.queryDelay === undefined){
12747             this.queryDelay = 10;
12748         }
12749         if(config.minChars === undefined){
12750             this.minChars = 0;
12751         }
12752     }
12753 };
12754
12755 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12756      
12757     /**
12758      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12759      * rendering into an Roo.Editor, defaults to false)
12760      */
12761     /**
12762      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12763      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12764      */
12765     /**
12766      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12767      */
12768     /**
12769      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12770      * the dropdown list (defaults to undefined, with no header element)
12771      */
12772
12773      /**
12774      * @cfg {String/Roo.Template} tpl The template to use to render the output
12775      */
12776      
12777      /**
12778      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12779      */
12780     listWidth: undefined,
12781     /**
12782      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12783      * mode = 'remote' or 'text' if mode = 'local')
12784      */
12785     displayField: undefined,
12786     
12787     /**
12788      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12789      * mode = 'remote' or 'value' if mode = 'local'). 
12790      * Note: use of a valueField requires the user make a selection
12791      * in order for a value to be mapped.
12792      */
12793     valueField: undefined,
12794     /**
12795      * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12796      */
12797     modalTitle : '',
12798     
12799     /**
12800      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12801      * field's data value (defaults to the underlying DOM element's name)
12802      */
12803     hiddenName: undefined,
12804     /**
12805      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12806      */
12807     listClass: '',
12808     /**
12809      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12810      */
12811     selectedClass: 'active',
12812     
12813     /**
12814      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12815      */
12816     shadow:'sides',
12817     /**
12818      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12819      * anchor positions (defaults to 'tl-bl')
12820      */
12821     listAlign: 'tl-bl?',
12822     /**
12823      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12824      */
12825     maxHeight: 300,
12826     /**
12827      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
12828      * query specified by the allQuery config option (defaults to 'query')
12829      */
12830     triggerAction: 'query',
12831     /**
12832      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12833      * (defaults to 4, does not apply if editable = false)
12834      */
12835     minChars : 4,
12836     /**
12837      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12838      * delay (typeAheadDelay) if it matches a known value (defaults to false)
12839      */
12840     typeAhead: false,
12841     /**
12842      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12843      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12844      */
12845     queryDelay: 500,
12846     /**
12847      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12848      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
12849      */
12850     pageSize: 0,
12851     /**
12852      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
12853      * when editable = true (defaults to false)
12854      */
12855     selectOnFocus:false,
12856     /**
12857      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12858      */
12859     queryParam: 'query',
12860     /**
12861      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
12862      * when mode = 'remote' (defaults to 'Loading...')
12863      */
12864     loadingText: 'Loading...',
12865     /**
12866      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12867      */
12868     resizable: false,
12869     /**
12870      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12871      */
12872     handleHeight : 8,
12873     /**
12874      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12875      * traditional select (defaults to true)
12876      */
12877     editable: true,
12878     /**
12879      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12880      */
12881     allQuery: '',
12882     /**
12883      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12884      */
12885     mode: 'remote',
12886     /**
12887      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12888      * listWidth has a higher value)
12889      */
12890     minListWidth : 70,
12891     /**
12892      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12893      * allow the user to set arbitrary text into the field (defaults to false)
12894      */
12895     forceSelection:false,
12896     /**
12897      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12898      * if typeAhead = true (defaults to 250)
12899      */
12900     typeAheadDelay : 250,
12901     /**
12902      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12903      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12904      */
12905     valueNotFoundText : undefined,
12906     /**
12907      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12908      */
12909     blockFocus : false,
12910     
12911     /**
12912      * @cfg {Boolean} disableClear Disable showing of clear button.
12913      */
12914     disableClear : false,
12915     /**
12916      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
12917      */
12918     alwaysQuery : false,
12919     
12920     /**
12921      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
12922      */
12923     multiple : false,
12924     
12925     /**
12926      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12927      */
12928     invalidClass : "has-warning",
12929     
12930     /**
12931      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12932      */
12933     validClass : "has-success",
12934     
12935     /**
12936      * @cfg {Boolean} specialFilter (true|false) special filter default false
12937      */
12938     specialFilter : false,
12939     
12940     /**
12941      * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12942      */
12943     mobileTouchView : true,
12944     
12945     /**
12946      * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12947      */
12948     useNativeIOS : false,
12949     
12950     ios_options : false,
12951     
12952     //private
12953     addicon : false,
12954     editicon: false,
12955     
12956     page: 0,
12957     hasQuery: false,
12958     append: false,
12959     loadNext: false,
12960     autoFocus : true,
12961     tickable : false,
12962     btnPosition : 'right',
12963     triggerList : true,
12964     showToggleBtn : true,
12965     animate : true,
12966     emptyResultText: 'Empty',
12967     triggerText : 'Select',
12968     emptyTitle : '',
12969     
12970     // element that contains real text value.. (when hidden is used..)
12971     
12972     getAutoCreate : function()
12973     {   
12974         var cfg = false;
12975         //render
12976         /*
12977          * Render classic select for iso
12978          */
12979         
12980         if(Roo.isIOS && this.useNativeIOS){
12981             cfg = this.getAutoCreateNativeIOS();
12982             return cfg;
12983         }
12984         
12985         /*
12986          * Touch Devices
12987          */
12988         
12989         if(Roo.isTouch && this.mobileTouchView){
12990             cfg = this.getAutoCreateTouchView();
12991             return cfg;;
12992         }
12993         
12994         /*
12995          *  Normal ComboBox
12996          */
12997         if(!this.tickable){
12998             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12999             return cfg;
13000         }
13001         
13002         /*
13003          *  ComboBox with tickable selections
13004          */
13005              
13006         var align = this.labelAlign || this.parentLabelAlign();
13007         
13008         cfg = {
13009             cls : 'form-group roo-combobox-tickable' //input-group
13010         };
13011         
13012         var btn_text_select = '';
13013         var btn_text_done = '';
13014         var btn_text_cancel = '';
13015         
13016         if (this.btn_text_show) {
13017             btn_text_select = 'Select';
13018             btn_text_done = 'Done';
13019             btn_text_cancel = 'Cancel'; 
13020         }
13021         
13022         var buttons = {
13023             tag : 'div',
13024             cls : 'tickable-buttons',
13025             cn : [
13026                 {
13027                     tag : 'button',
13028                     type : 'button',
13029                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13030                     //html : this.triggerText
13031                     html: btn_text_select
13032                 },
13033                 {
13034                     tag : 'button',
13035                     type : 'button',
13036                     name : 'ok',
13037                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13038                     //html : 'Done'
13039                     html: btn_text_done
13040                 },
13041                 {
13042                     tag : 'button',
13043                     type : 'button',
13044                     name : 'cancel',
13045                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13046                     //html : 'Cancel'
13047                     html: btn_text_cancel
13048                 }
13049             ]
13050         };
13051         
13052         if(this.editable){
13053             buttons.cn.unshift({
13054                 tag: 'input',
13055                 cls: 'roo-select2-search-field-input'
13056             });
13057         }
13058         
13059         var _this = this;
13060         
13061         Roo.each(buttons.cn, function(c){
13062             if (_this.size) {
13063                 c.cls += ' btn-' + _this.size;
13064             }
13065
13066             if (_this.disabled) {
13067                 c.disabled = true;
13068             }
13069         });
13070         
13071         var box = {
13072             tag: 'div',
13073             cn: [
13074                 {
13075                     tag: 'input',
13076                     type : 'hidden',
13077                     cls: 'form-hidden-field'
13078                 },
13079                 {
13080                     tag: 'ul',
13081                     cls: 'roo-select2-choices',
13082                     cn:[
13083                         {
13084                             tag: 'li',
13085                             cls: 'roo-select2-search-field',
13086                             cn: [
13087                                 buttons
13088                             ]
13089                         }
13090                     ]
13091                 }
13092             ]
13093         };
13094         
13095         var combobox = {
13096             cls: 'roo-select2-container input-group roo-select2-container-multi',
13097             cn: [
13098                 box
13099 //                {
13100 //                    tag: 'ul',
13101 //                    cls: 'typeahead typeahead-long dropdown-menu',
13102 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
13103 //                }
13104             ]
13105         };
13106         
13107         if(this.hasFeedback && !this.allowBlank){
13108             
13109             var feedback = {
13110                 tag: 'span',
13111                 cls: 'glyphicon form-control-feedback'
13112             };
13113
13114             combobox.cn.push(feedback);
13115         }
13116         
13117         
13118         if (align ==='left' && this.fieldLabel.length) {
13119             
13120             cfg.cls += ' roo-form-group-label-left';
13121             
13122             cfg.cn = [
13123                 {
13124                     tag : 'i',
13125                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13126                     tooltip : 'This field is required'
13127                 },
13128                 {
13129                     tag: 'label',
13130                     'for' :  id,
13131                     cls : 'control-label',
13132                     html : this.fieldLabel
13133
13134                 },
13135                 {
13136                     cls : "", 
13137                     cn: [
13138                         combobox
13139                     ]
13140                 }
13141
13142             ];
13143             
13144             var labelCfg = cfg.cn[1];
13145             var contentCfg = cfg.cn[2];
13146             
13147
13148             if(this.indicatorpos == 'right'){
13149                 
13150                 cfg.cn = [
13151                     {
13152                         tag: 'label',
13153                         'for' :  id,
13154                         cls : 'control-label',
13155                         cn : [
13156                             {
13157                                 tag : 'span',
13158                                 html : this.fieldLabel
13159                             },
13160                             {
13161                                 tag : 'i',
13162                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13163                                 tooltip : 'This field is required'
13164                             }
13165                         ]
13166                     },
13167                     {
13168                         cls : "",
13169                         cn: [
13170                             combobox
13171                         ]
13172                     }
13173
13174                 ];
13175                 
13176                 
13177                 
13178                 labelCfg = cfg.cn[0];
13179                 contentCfg = cfg.cn[1];
13180             
13181             }
13182             
13183             if(this.labelWidth > 12){
13184                 labelCfg.style = "width: " + this.labelWidth + 'px';
13185             }
13186             
13187             if(this.labelWidth < 13 && this.labelmd == 0){
13188                 this.labelmd = this.labelWidth;
13189             }
13190             
13191             if(this.labellg > 0){
13192                 labelCfg.cls += ' col-lg-' + this.labellg;
13193                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13194             }
13195             
13196             if(this.labelmd > 0){
13197                 labelCfg.cls += ' col-md-' + this.labelmd;
13198                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13199             }
13200             
13201             if(this.labelsm > 0){
13202                 labelCfg.cls += ' col-sm-' + this.labelsm;
13203                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13204             }
13205             
13206             if(this.labelxs > 0){
13207                 labelCfg.cls += ' col-xs-' + this.labelxs;
13208                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13209             }
13210                 
13211                 
13212         } else if ( this.fieldLabel.length) {
13213 //                Roo.log(" label");
13214                  cfg.cn = [
13215                     {
13216                         tag : 'i',
13217                         cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13218                         tooltip : 'This field is required'
13219                     },
13220                     {
13221                         tag: 'label',
13222                         //cls : 'input-group-addon',
13223                         html : this.fieldLabel
13224                     },
13225                     combobox
13226                 ];
13227                 
13228                 if(this.indicatorpos == 'right'){
13229                     cfg.cn = [
13230                         {
13231                             tag: 'label',
13232                             //cls : 'input-group-addon',
13233                             html : this.fieldLabel
13234                         },
13235                         {
13236                             tag : 'i',
13237                             cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13238                             tooltip : 'This field is required'
13239                         },
13240                         combobox
13241                     ];
13242                     
13243                 }
13244
13245         } else {
13246             
13247 //                Roo.log(" no label && no align");
13248                 cfg = combobox
13249                      
13250                 
13251         }
13252          
13253         var settings=this;
13254         ['xs','sm','md','lg'].map(function(size){
13255             if (settings[size]) {
13256                 cfg.cls += ' col-' + size + '-' + settings[size];
13257             }
13258         });
13259         
13260         return cfg;
13261         
13262     },
13263     
13264     _initEventsCalled : false,
13265     
13266     // private
13267     initEvents: function()
13268     {   
13269         if (this._initEventsCalled) { // as we call render... prevent looping...
13270             return;
13271         }
13272         this._initEventsCalled = true;
13273         
13274         if (!this.store) {
13275             throw "can not find store for combo";
13276         }
13277         
13278         this.indicator = this.indicatorEl();
13279         
13280         this.store = Roo.factory(this.store, Roo.data);
13281         this.store.parent = this;
13282         
13283         // if we are building from html. then this element is so complex, that we can not really
13284         // use the rendered HTML.
13285         // so we have to trash and replace the previous code.
13286         if (Roo.XComponent.build_from_html) {
13287             // remove this element....
13288             var e = this.el.dom, k=0;
13289             while (e ) { e = e.previousSibling;  ++k;}
13290
13291             this.el.remove();
13292             
13293             this.el=false;
13294             this.rendered = false;
13295             
13296             this.render(this.parent().getChildContainer(true), k);
13297         }
13298         
13299         if(Roo.isIOS && this.useNativeIOS){
13300             this.initIOSView();
13301             return;
13302         }
13303         
13304         /*
13305          * Touch Devices
13306          */
13307         
13308         if(Roo.isTouch && this.mobileTouchView){
13309             this.initTouchView();
13310             return;
13311         }
13312         
13313         if(this.tickable){
13314             this.initTickableEvents();
13315             return;
13316         }
13317         
13318         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13319         
13320         if(this.hiddenName){
13321             
13322             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13323             
13324             this.hiddenField.dom.value =
13325                 this.hiddenValue !== undefined ? this.hiddenValue :
13326                 this.value !== undefined ? this.value : '';
13327
13328             // prevent input submission
13329             this.el.dom.removeAttribute('name');
13330             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13331              
13332              
13333         }
13334         //if(Roo.isGecko){
13335         //    this.el.dom.setAttribute('autocomplete', 'off');
13336         //}
13337         
13338         var cls = 'x-combo-list';
13339         
13340         //this.list = new Roo.Layer({
13341         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13342         //});
13343         
13344         var _this = this;
13345         
13346         (function(){
13347             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13348             _this.list.setWidth(lw);
13349         }).defer(100);
13350         
13351         this.list.on('mouseover', this.onViewOver, this);
13352         this.list.on('mousemove', this.onViewMove, this);
13353         this.list.on('scroll', this.onViewScroll, this);
13354         
13355         /*
13356         this.list.swallowEvent('mousewheel');
13357         this.assetHeight = 0;
13358
13359         if(this.title){
13360             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13361             this.assetHeight += this.header.getHeight();
13362         }
13363
13364         this.innerList = this.list.createChild({cls:cls+'-inner'});
13365         this.innerList.on('mouseover', this.onViewOver, this);
13366         this.innerList.on('mousemove', this.onViewMove, this);
13367         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13368         
13369         if(this.allowBlank && !this.pageSize && !this.disableClear){
13370             this.footer = this.list.createChild({cls:cls+'-ft'});
13371             this.pageTb = new Roo.Toolbar(this.footer);
13372            
13373         }
13374         if(this.pageSize){
13375             this.footer = this.list.createChild({cls:cls+'-ft'});
13376             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13377                     {pageSize: this.pageSize});
13378             
13379         }
13380         
13381         if (this.pageTb && this.allowBlank && !this.disableClear) {
13382             var _this = this;
13383             this.pageTb.add(new Roo.Toolbar.Fill(), {
13384                 cls: 'x-btn-icon x-btn-clear',
13385                 text: '&#160;',
13386                 handler: function()
13387                 {
13388                     _this.collapse();
13389                     _this.clearValue();
13390                     _this.onSelect(false, -1);
13391                 }
13392             });
13393         }
13394         if (this.footer) {
13395             this.assetHeight += this.footer.getHeight();
13396         }
13397         */
13398             
13399         if(!this.tpl){
13400             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13401         }
13402
13403         this.view = new Roo.View(this.list, this.tpl, {
13404             singleSelect:true, store: this.store, selectedClass: this.selectedClass
13405         });
13406         //this.view.wrapEl.setDisplayed(false);
13407         this.view.on('click', this.onViewClick, this);
13408         
13409         
13410         this.store.on('beforeload', this.onBeforeLoad, this);
13411         this.store.on('load', this.onLoad, this);
13412         this.store.on('loadexception', this.onLoadException, this);
13413         /*
13414         if(this.resizable){
13415             this.resizer = new Roo.Resizable(this.list,  {
13416                pinned:true, handles:'se'
13417             });
13418             this.resizer.on('resize', function(r, w, h){
13419                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13420                 this.listWidth = w;
13421                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13422                 this.restrictHeight();
13423             }, this);
13424             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13425         }
13426         */
13427         if(!this.editable){
13428             this.editable = true;
13429             this.setEditable(false);
13430         }
13431         
13432         /*
13433         
13434         if (typeof(this.events.add.listeners) != 'undefined') {
13435             
13436             this.addicon = this.wrap.createChild(
13437                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
13438        
13439             this.addicon.on('click', function(e) {
13440                 this.fireEvent('add', this);
13441             }, this);
13442         }
13443         if (typeof(this.events.edit.listeners) != 'undefined') {
13444             
13445             this.editicon = this.wrap.createChild(
13446                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
13447             if (this.addicon) {
13448                 this.editicon.setStyle('margin-left', '40px');
13449             }
13450             this.editicon.on('click', function(e) {
13451                 
13452                 // we fire even  if inothing is selected..
13453                 this.fireEvent('edit', this, this.lastData );
13454                 
13455             }, this);
13456         }
13457         */
13458         
13459         this.keyNav = new Roo.KeyNav(this.inputEl(), {
13460             "up" : function(e){
13461                 this.inKeyMode = true;
13462                 this.selectPrev();
13463             },
13464
13465             "down" : function(e){
13466                 if(!this.isExpanded()){
13467                     this.onTriggerClick();
13468                 }else{
13469                     this.inKeyMode = true;
13470                     this.selectNext();
13471                 }
13472             },
13473
13474             "enter" : function(e){
13475 //                this.onViewClick();
13476                 //return true;
13477                 this.collapse();
13478                 
13479                 if(this.fireEvent("specialkey", this, e)){
13480                     this.onViewClick(false);
13481                 }
13482                 
13483                 return true;
13484             },
13485
13486             "esc" : function(e){
13487                 this.collapse();
13488             },
13489
13490             "tab" : function(e){
13491                 this.collapse();
13492                 
13493                 if(this.fireEvent("specialkey", this, e)){
13494                     this.onViewClick(false);
13495                 }
13496                 
13497                 return true;
13498             },
13499
13500             scope : this,
13501
13502             doRelay : function(foo, bar, hname){
13503                 if(hname == 'down' || this.scope.isExpanded()){
13504                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13505                 }
13506                 return true;
13507             },
13508
13509             forceKeyDown: true
13510         });
13511         
13512         
13513         this.queryDelay = Math.max(this.queryDelay || 10,
13514                 this.mode == 'local' ? 10 : 250);
13515         
13516         
13517         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13518         
13519         if(this.typeAhead){
13520             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13521         }
13522         if(this.editable !== false){
13523             this.inputEl().on("keyup", this.onKeyUp, this);
13524         }
13525         if(this.forceSelection){
13526             this.inputEl().on('blur', this.doForce, this);
13527         }
13528         
13529         if(this.multiple){
13530             this.choices = this.el.select('ul.roo-select2-choices', true).first();
13531             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13532         }
13533     },
13534     
13535     initTickableEvents: function()
13536     {   
13537         this.createList();
13538         
13539         if(this.hiddenName){
13540             
13541             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13542             
13543             this.hiddenField.dom.value =
13544                 this.hiddenValue !== undefined ? this.hiddenValue :
13545                 this.value !== undefined ? this.value : '';
13546
13547             // prevent input submission
13548             this.el.dom.removeAttribute('name');
13549             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13550              
13551              
13552         }
13553         
13554 //        this.list = this.el.select('ul.dropdown-menu',true).first();
13555         
13556         this.choices = this.el.select('ul.roo-select2-choices', true).first();
13557         this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13558         if(this.triggerList){
13559             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13560         }
13561          
13562         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13563         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13564         
13565         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13566         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13567         
13568         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13569         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13570         
13571         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13572         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13573         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13574         
13575         this.okBtn.hide();
13576         this.cancelBtn.hide();
13577         
13578         var _this = this;
13579         
13580         (function(){
13581             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13582             _this.list.setWidth(lw);
13583         }).defer(100);
13584         
13585         this.list.on('mouseover', this.onViewOver, this);
13586         this.list.on('mousemove', this.onViewMove, this);
13587         
13588         this.list.on('scroll', this.onViewScroll, this);
13589         
13590         if(!this.tpl){
13591             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>';
13592         }
13593
13594         this.view = new Roo.View(this.list, this.tpl, {
13595             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13596         });
13597         
13598         //this.view.wrapEl.setDisplayed(false);
13599         this.view.on('click', this.onViewClick, this);
13600         
13601         
13602         
13603         this.store.on('beforeload', this.onBeforeLoad, this);
13604         this.store.on('load', this.onLoad, this);
13605         this.store.on('loadexception', this.onLoadException, this);
13606         
13607         if(this.editable){
13608             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13609                 "up" : function(e){
13610                     this.inKeyMode = true;
13611                     this.selectPrev();
13612                 },
13613
13614                 "down" : function(e){
13615                     this.inKeyMode = true;
13616                     this.selectNext();
13617                 },
13618
13619                 "enter" : function(e){
13620                     if(this.fireEvent("specialkey", this, e)){
13621                         this.onViewClick(false);
13622                     }
13623                     
13624                     return true;
13625                 },
13626
13627                 "esc" : function(e){
13628                     this.onTickableFooterButtonClick(e, false, false);
13629                 },
13630
13631                 "tab" : function(e){
13632                     this.fireEvent("specialkey", this, e);
13633                     
13634                     this.onTickableFooterButtonClick(e, false, false);
13635                     
13636                     return true;
13637                 },
13638
13639                 scope : this,
13640
13641                 doRelay : function(e, fn, key){
13642                     if(this.scope.isExpanded()){
13643                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13644                     }
13645                     return true;
13646                 },
13647
13648                 forceKeyDown: true
13649             });
13650         }
13651         
13652         this.queryDelay = Math.max(this.queryDelay || 10,
13653                 this.mode == 'local' ? 10 : 250);
13654         
13655         
13656         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13657         
13658         if(this.typeAhead){
13659             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13660         }
13661         
13662         if(this.editable !== false){
13663             this.tickableInputEl().on("keyup", this.onKeyUp, this);
13664         }
13665         
13666         this.indicator = this.indicatorEl();
13667         
13668         if(this.indicator){
13669             this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13670             this.indicator.hide();
13671         }
13672         
13673     },
13674
13675     onDestroy : function(){
13676         if(this.view){
13677             this.view.setStore(null);
13678             this.view.el.removeAllListeners();
13679             this.view.el.remove();
13680             this.view.purgeListeners();
13681         }
13682         if(this.list){
13683             this.list.dom.innerHTML  = '';
13684         }
13685         
13686         if(this.store){
13687             this.store.un('beforeload', this.onBeforeLoad, this);
13688             this.store.un('load', this.onLoad, this);
13689             this.store.un('loadexception', this.onLoadException, this);
13690         }
13691         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13692     },
13693
13694     // private
13695     fireKey : function(e){
13696         if(e.isNavKeyPress() && !this.list.isVisible()){
13697             this.fireEvent("specialkey", this, e);
13698         }
13699     },
13700
13701     // private
13702     onResize: function(w, h){
13703 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13704 //        
13705 //        if(typeof w != 'number'){
13706 //            // we do not handle it!?!?
13707 //            return;
13708 //        }
13709 //        var tw = this.trigger.getWidth();
13710 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
13711 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
13712 //        var x = w - tw;
13713 //        this.inputEl().setWidth( this.adjustWidth('input', x));
13714 //            
13715 //        //this.trigger.setStyle('left', x+'px');
13716 //        
13717 //        if(this.list && this.listWidth === undefined){
13718 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13719 //            this.list.setWidth(lw);
13720 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13721 //        }
13722         
13723     
13724         
13725     },
13726
13727     /**
13728      * Allow or prevent the user from directly editing the field text.  If false is passed,
13729      * the user will only be able to select from the items defined in the dropdown list.  This method
13730      * is the runtime equivalent of setting the 'editable' config option at config time.
13731      * @param {Boolean} value True to allow the user to directly edit the field text
13732      */
13733     setEditable : function(value){
13734         if(value == this.editable){
13735             return;
13736         }
13737         this.editable = value;
13738         if(!value){
13739             this.inputEl().dom.setAttribute('readOnly', true);
13740             this.inputEl().on('mousedown', this.onTriggerClick,  this);
13741             this.inputEl().addClass('x-combo-noedit');
13742         }else{
13743             this.inputEl().dom.setAttribute('readOnly', false);
13744             this.inputEl().un('mousedown', this.onTriggerClick,  this);
13745             this.inputEl().removeClass('x-combo-noedit');
13746         }
13747     },
13748
13749     // private
13750     
13751     onBeforeLoad : function(combo,opts){
13752         if(!this.hasFocus){
13753             return;
13754         }
13755          if (!opts.add) {
13756             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13757          }
13758         this.restrictHeight();
13759         this.selectedIndex = -1;
13760     },
13761
13762     // private
13763     onLoad : function(){
13764         
13765         this.hasQuery = false;
13766         
13767         if(!this.hasFocus){
13768             return;
13769         }
13770         
13771         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13772             this.loading.hide();
13773         }
13774         
13775         if(this.store.getCount() > 0){
13776             
13777             this.expand();
13778             this.restrictHeight();
13779             if(this.lastQuery == this.allQuery){
13780                 if(this.editable && !this.tickable){
13781                     this.inputEl().dom.select();
13782                 }
13783                 
13784                 if(
13785                     !this.selectByValue(this.value, true) &&
13786                     this.autoFocus && 
13787                     (
13788                         !this.store.lastOptions ||
13789                         typeof(this.store.lastOptions.add) == 'undefined' || 
13790                         this.store.lastOptions.add != true
13791                     )
13792                 ){
13793                     this.select(0, true);
13794                 }
13795             }else{
13796                 if(this.autoFocus){
13797                     this.selectNext();
13798                 }
13799                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13800                     this.taTask.delay(this.typeAheadDelay);
13801                 }
13802             }
13803         }else{
13804             this.onEmptyResults();
13805         }
13806         
13807         //this.el.focus();
13808     },
13809     // private
13810     onLoadException : function()
13811     {
13812         this.hasQuery = false;
13813         
13814         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13815             this.loading.hide();
13816         }
13817         
13818         if(this.tickable && this.editable){
13819             return;
13820         }
13821         
13822         this.collapse();
13823         // only causes errors at present
13824         //Roo.log(this.store.reader.jsonData);
13825         //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13826             // fixme
13827             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13828         //}
13829         
13830         
13831     },
13832     // private
13833     onTypeAhead : function(){
13834         if(this.store.getCount() > 0){
13835             var r = this.store.getAt(0);
13836             var newValue = r.data[this.displayField];
13837             var len = newValue.length;
13838             var selStart = this.getRawValue().length;
13839             
13840             if(selStart != len){
13841                 this.setRawValue(newValue);
13842                 this.selectText(selStart, newValue.length);
13843             }
13844         }
13845     },
13846
13847     // private
13848     onSelect : function(record, index){
13849         
13850         if(this.fireEvent('beforeselect', this, record, index) !== false){
13851         
13852             this.setFromData(index > -1 ? record.data : false);
13853             
13854             this.collapse();
13855             this.fireEvent('select', this, record, index);
13856         }
13857     },
13858
13859     /**
13860      * Returns the currently selected field value or empty string if no value is set.
13861      * @return {String} value The selected value
13862      */
13863     getValue : function()
13864     {
13865         if(Roo.isIOS && this.useNativeIOS){
13866             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13867         }
13868         
13869         if(this.multiple){
13870             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13871         }
13872         
13873         if(this.valueField){
13874             return typeof this.value != 'undefined' ? this.value : '';
13875         }else{
13876             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13877         }
13878     },
13879     
13880     getRawValue : function()
13881     {
13882         if(Roo.isIOS && this.useNativeIOS){
13883             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13884         }
13885         
13886         var v = this.inputEl().getValue();
13887         
13888         return v;
13889     },
13890
13891     /**
13892      * Clears any text/value currently set in the field
13893      */
13894     clearValue : function(){
13895         
13896         if(this.hiddenField){
13897             this.hiddenField.dom.value = '';
13898         }
13899         this.value = '';
13900         this.setRawValue('');
13901         this.lastSelectionText = '';
13902         this.lastData = false;
13903         
13904         var close = this.closeTriggerEl();
13905         
13906         if(close){
13907             close.hide();
13908         }
13909         
13910         this.validate();
13911         
13912     },
13913
13914     /**
13915      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
13916      * will be displayed in the field.  If the value does not match the data value of an existing item,
13917      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13918      * Otherwise the field will be blank (although the value will still be set).
13919      * @param {String} value The value to match
13920      */
13921     setValue : function(v)
13922     {
13923         if(Roo.isIOS && this.useNativeIOS){
13924             this.setIOSValue(v);
13925             return;
13926         }
13927         
13928         if(this.multiple){
13929             this.syncValue();
13930             return;
13931         }
13932         
13933         var text = v;
13934         if(this.valueField){
13935             var r = this.findRecord(this.valueField, v);
13936             if(r){
13937                 text = r.data[this.displayField];
13938             }else if(this.valueNotFoundText !== undefined){
13939                 text = this.valueNotFoundText;
13940             }
13941         }
13942         this.lastSelectionText = text;
13943         if(this.hiddenField){
13944             this.hiddenField.dom.value = v;
13945         }
13946         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13947         this.value = v;
13948         
13949         var close = this.closeTriggerEl();
13950         
13951         if(close){
13952             (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13953         }
13954         
13955         this.validate();
13956     },
13957     /**
13958      * @property {Object} the last set data for the element
13959      */
13960     
13961     lastData : false,
13962     /**
13963      * Sets the value of the field based on a object which is related to the record format for the store.
13964      * @param {Object} value the value to set as. or false on reset?
13965      */
13966     setFromData : function(o){
13967         
13968         if(this.multiple){
13969             this.addItem(o);
13970             return;
13971         }
13972             
13973         var dv = ''; // display value
13974         var vv = ''; // value value..
13975         this.lastData = o;
13976         if (this.displayField) {
13977             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13978         } else {
13979             // this is an error condition!!!
13980             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
13981         }
13982         
13983         if(this.valueField){
13984             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13985         }
13986         
13987         var close = this.closeTriggerEl();
13988         
13989         if(close){
13990             if(dv.length || vv * 1 > 0){
13991                 close.show() ;
13992                 this.blockFocus=true;
13993             } else {
13994                 close.hide();
13995             }             
13996         }
13997         
13998         if(this.hiddenField){
13999             this.hiddenField.dom.value = vv;
14000             
14001             this.lastSelectionText = dv;
14002             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14003             this.value = vv;
14004             return;
14005         }
14006         // no hidden field.. - we store the value in 'value', but still display
14007         // display field!!!!
14008         this.lastSelectionText = dv;
14009         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14010         this.value = vv;
14011         
14012         
14013         
14014     },
14015     // private
14016     reset : function(){
14017         // overridden so that last data is reset..
14018         
14019         if(this.multiple){
14020             this.clearItem();
14021             return;
14022         }
14023         
14024         this.setValue(this.originalValue);
14025         //this.clearInvalid();
14026         this.lastData = false;
14027         if (this.view) {
14028             this.view.clearSelections();
14029         }
14030         
14031         this.validate();
14032     },
14033     // private
14034     findRecord : function(prop, value){
14035         var record;
14036         if(this.store.getCount() > 0){
14037             this.store.each(function(r){
14038                 if(r.data[prop] == value){
14039                     record = r;
14040                     return false;
14041                 }
14042                 return true;
14043             });
14044         }
14045         return record;
14046     },
14047     
14048     getName: function()
14049     {
14050         // returns hidden if it's set..
14051         if (!this.rendered) {return ''};
14052         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
14053         
14054     },
14055     // private
14056     onViewMove : function(e, t){
14057         this.inKeyMode = false;
14058     },
14059
14060     // private
14061     onViewOver : function(e, t){
14062         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14063             return;
14064         }
14065         var item = this.view.findItemFromChild(t);
14066         
14067         if(item){
14068             var index = this.view.indexOf(item);
14069             this.select(index, false);
14070         }
14071     },
14072
14073     // private
14074     onViewClick : function(view, doFocus, el, e)
14075     {
14076         var index = this.view.getSelectedIndexes()[0];
14077         
14078         var r = this.store.getAt(index);
14079         
14080         if(this.tickable){
14081             
14082             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14083                 return;
14084             }
14085             
14086             var rm = false;
14087             var _this = this;
14088             
14089             Roo.each(this.tickItems, function(v,k){
14090                 
14091                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14092                     Roo.log(v);
14093                     _this.tickItems.splice(k, 1);
14094                     
14095                     if(typeof(e) == 'undefined' && view == false){
14096                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14097                     }
14098                     
14099                     rm = true;
14100                     return;
14101                 }
14102             });
14103             
14104             if(rm){
14105                 return;
14106             }
14107             
14108             if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14109                 this.tickItems.push(r.data);
14110             }
14111             
14112             if(typeof(e) == 'undefined' && view == false){
14113                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14114             }
14115                     
14116             return;
14117         }
14118         
14119         if(r){
14120             this.onSelect(r, index);
14121         }
14122         if(doFocus !== false && !this.blockFocus){
14123             this.inputEl().focus();
14124         }
14125     },
14126
14127     // private
14128     restrictHeight : function(){
14129         //this.innerList.dom.style.height = '';
14130         //var inner = this.innerList.dom;
14131         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14132         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14133         //this.list.beginUpdate();
14134         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14135         this.list.alignTo(this.inputEl(), this.listAlign);
14136         this.list.alignTo(this.inputEl(), this.listAlign);
14137         //this.list.endUpdate();
14138     },
14139
14140     // private
14141     onEmptyResults : function(){
14142         
14143         if(this.tickable && this.editable){
14144             this.hasFocus = false;
14145             this.restrictHeight();
14146             return;
14147         }
14148         
14149         this.collapse();
14150     },
14151
14152     /**
14153      * Returns true if the dropdown list is expanded, else false.
14154      */
14155     isExpanded : function(){
14156         return this.list.isVisible();
14157     },
14158
14159     /**
14160      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14161      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14162      * @param {String} value The data value of the item to select
14163      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14164      * selected item if it is not currently in view (defaults to true)
14165      * @return {Boolean} True if the value matched an item in the list, else false
14166      */
14167     selectByValue : function(v, scrollIntoView){
14168         if(v !== undefined && v !== null){
14169             var r = this.findRecord(this.valueField || this.displayField, v);
14170             if(r){
14171                 this.select(this.store.indexOf(r), scrollIntoView);
14172                 return true;
14173             }
14174         }
14175         return false;
14176     },
14177
14178     /**
14179      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14180      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14181      * @param {Number} index The zero-based index of the list item to select
14182      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14183      * selected item if it is not currently in view (defaults to true)
14184      */
14185     select : function(index, scrollIntoView){
14186         this.selectedIndex = index;
14187         this.view.select(index);
14188         if(scrollIntoView !== false){
14189             var el = this.view.getNode(index);
14190             /*
14191              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14192              */
14193             if(el){
14194                 this.list.scrollChildIntoView(el, false);
14195             }
14196         }
14197     },
14198
14199     // private
14200     selectNext : function(){
14201         var ct = this.store.getCount();
14202         if(ct > 0){
14203             if(this.selectedIndex == -1){
14204                 this.select(0);
14205             }else if(this.selectedIndex < ct-1){
14206                 this.select(this.selectedIndex+1);
14207             }
14208         }
14209     },
14210
14211     // private
14212     selectPrev : function(){
14213         var ct = this.store.getCount();
14214         if(ct > 0){
14215             if(this.selectedIndex == -1){
14216                 this.select(0);
14217             }else if(this.selectedIndex != 0){
14218                 this.select(this.selectedIndex-1);
14219             }
14220         }
14221     },
14222
14223     // private
14224     onKeyUp : function(e){
14225         if(this.editable !== false && !e.isSpecialKey()){
14226             this.lastKey = e.getKey();
14227             this.dqTask.delay(this.queryDelay);
14228         }
14229     },
14230
14231     // private
14232     validateBlur : function(){
14233         return !this.list || !this.list.isVisible();   
14234     },
14235
14236     // private
14237     initQuery : function(){
14238         
14239         var v = this.getRawValue();
14240         
14241         if(this.tickable && this.editable){
14242             v = this.tickableInputEl().getValue();
14243         }
14244         
14245         this.doQuery(v);
14246     },
14247
14248     // private
14249     doForce : function(){
14250         if(this.inputEl().dom.value.length > 0){
14251             this.inputEl().dom.value =
14252                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14253              
14254         }
14255     },
14256
14257     /**
14258      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
14259      * query allowing the query action to be canceled if needed.
14260      * @param {String} query The SQL query to execute
14261      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14262      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
14263      * saved in the current store (defaults to false)
14264      */
14265     doQuery : function(q, forceAll){
14266         
14267         if(q === undefined || q === null){
14268             q = '';
14269         }
14270         var qe = {
14271             query: q,
14272             forceAll: forceAll,
14273             combo: this,
14274             cancel:false
14275         };
14276         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14277             return false;
14278         }
14279         q = qe.query;
14280         
14281         forceAll = qe.forceAll;
14282         if(forceAll === true || (q.length >= this.minChars)){
14283             
14284             this.hasQuery = true;
14285             
14286             if(this.lastQuery != q || this.alwaysQuery){
14287                 this.lastQuery = q;
14288                 if(this.mode == 'local'){
14289                     this.selectedIndex = -1;
14290                     if(forceAll){
14291                         this.store.clearFilter();
14292                     }else{
14293                         
14294                         if(this.specialFilter){
14295                             this.fireEvent('specialfilter', this);
14296                             this.onLoad();
14297                             return;
14298                         }
14299                         
14300                         this.store.filter(this.displayField, q);
14301                     }
14302                     
14303                     this.store.fireEvent("datachanged", this.store);
14304                     
14305                     this.onLoad();
14306                     
14307                     
14308                 }else{
14309                     
14310                     this.store.baseParams[this.queryParam] = q;
14311                     
14312                     var options = {params : this.getParams(q)};
14313                     
14314                     if(this.loadNext){
14315                         options.add = true;
14316                         options.params.start = this.page * this.pageSize;
14317                     }
14318                     
14319                     this.store.load(options);
14320                     
14321                     /*
14322                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
14323                      *  we should expand the list on onLoad
14324                      *  so command out it
14325                      */
14326 //                    this.expand();
14327                 }
14328             }else{
14329                 this.selectedIndex = -1;
14330                 this.onLoad();   
14331             }
14332         }
14333         
14334         this.loadNext = false;
14335     },
14336     
14337     // private
14338     getParams : function(q){
14339         var p = {};
14340         //p[this.queryParam] = q;
14341         
14342         if(this.pageSize){
14343             p.start = 0;
14344             p.limit = this.pageSize;
14345         }
14346         return p;
14347     },
14348
14349     /**
14350      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14351      */
14352     collapse : function(){
14353         if(!this.isExpanded()){
14354             return;
14355         }
14356         
14357         this.list.hide();
14358         
14359         this.hasFocus = false;
14360         
14361         if(this.tickable){
14362             this.okBtn.hide();
14363             this.cancelBtn.hide();
14364             this.trigger.show();
14365             
14366             if(this.editable){
14367                 this.tickableInputEl().dom.value = '';
14368                 this.tickableInputEl().blur();
14369             }
14370             
14371         }
14372         
14373         Roo.get(document).un('mousedown', this.collapseIf, this);
14374         Roo.get(document).un('mousewheel', this.collapseIf, this);
14375         if (!this.editable) {
14376             Roo.get(document).un('keydown', this.listKeyPress, this);
14377         }
14378         this.fireEvent('collapse', this);
14379         
14380         this.validate();
14381     },
14382
14383     // private
14384     collapseIf : function(e){
14385         var in_combo  = e.within(this.el);
14386         var in_list =  e.within(this.list);
14387         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14388         
14389         if (in_combo || in_list || is_list) {
14390             //e.stopPropagation();
14391             return;
14392         }
14393         
14394         if(this.tickable){
14395             this.onTickableFooterButtonClick(e, false, false);
14396         }
14397
14398         this.collapse();
14399         
14400     },
14401
14402     /**
14403      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14404      */
14405     expand : function(){
14406        
14407         if(this.isExpanded() || !this.hasFocus){
14408             return;
14409         }
14410         
14411         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14412         this.list.setWidth(lw);
14413         
14414         Roo.log('expand');
14415         
14416         this.list.show();
14417         
14418         this.restrictHeight();
14419         
14420         if(this.tickable){
14421             
14422             this.tickItems = Roo.apply([], this.item);
14423             
14424             this.okBtn.show();
14425             this.cancelBtn.show();
14426             this.trigger.hide();
14427             
14428             if(this.editable){
14429                 this.tickableInputEl().focus();
14430             }
14431             
14432         }
14433         
14434         Roo.get(document).on('mousedown', this.collapseIf, this);
14435         Roo.get(document).on('mousewheel', this.collapseIf, this);
14436         if (!this.editable) {
14437             Roo.get(document).on('keydown', this.listKeyPress, this);
14438         }
14439         
14440         this.fireEvent('expand', this);
14441     },
14442
14443     // private
14444     // Implements the default empty TriggerField.onTriggerClick function
14445     onTriggerClick : function(e)
14446     {
14447         Roo.log('trigger click');
14448         
14449         if(this.disabled || !this.triggerList){
14450             return;
14451         }
14452         
14453         this.page = 0;
14454         this.loadNext = false;
14455         
14456         if(this.isExpanded()){
14457             this.collapse();
14458             if (!this.blockFocus) {
14459                 this.inputEl().focus();
14460             }
14461             
14462         }else {
14463             this.hasFocus = true;
14464             if(this.triggerAction == 'all') {
14465                 this.doQuery(this.allQuery, true);
14466             } else {
14467                 this.doQuery(this.getRawValue());
14468             }
14469             if (!this.blockFocus) {
14470                 this.inputEl().focus();
14471             }
14472         }
14473     },
14474     
14475     onTickableTriggerClick : function(e)
14476     {
14477         if(this.disabled){
14478             return;
14479         }
14480         
14481         this.page = 0;
14482         this.loadNext = false;
14483         this.hasFocus = true;
14484         
14485         if(this.triggerAction == 'all') {
14486             this.doQuery(this.allQuery, true);
14487         } else {
14488             this.doQuery(this.getRawValue());
14489         }
14490     },
14491     
14492     onSearchFieldClick : function(e)
14493     {
14494         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14495             this.onTickableFooterButtonClick(e, false, false);
14496             return;
14497         }
14498         
14499         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14500             return;
14501         }
14502         
14503         this.page = 0;
14504         this.loadNext = false;
14505         this.hasFocus = true;
14506         
14507         if(this.triggerAction == 'all') {
14508             this.doQuery(this.allQuery, true);
14509         } else {
14510             this.doQuery(this.getRawValue());
14511         }
14512     },
14513     
14514     listKeyPress : function(e)
14515     {
14516         //Roo.log('listkeypress');
14517         // scroll to first matching element based on key pres..
14518         if (e.isSpecialKey()) {
14519             return false;
14520         }
14521         var k = String.fromCharCode(e.getKey()).toUpperCase();
14522         //Roo.log(k);
14523         var match  = false;
14524         var csel = this.view.getSelectedNodes();
14525         var cselitem = false;
14526         if (csel.length) {
14527             var ix = this.view.indexOf(csel[0]);
14528             cselitem  = this.store.getAt(ix);
14529             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14530                 cselitem = false;
14531             }
14532             
14533         }
14534         
14535         this.store.each(function(v) { 
14536             if (cselitem) {
14537                 // start at existing selection.
14538                 if (cselitem.id == v.id) {
14539                     cselitem = false;
14540                 }
14541                 return true;
14542             }
14543                 
14544             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14545                 match = this.store.indexOf(v);
14546                 return false;
14547             }
14548             return true;
14549         }, this);
14550         
14551         if (match === false) {
14552             return true; // no more action?
14553         }
14554         // scroll to?
14555         this.view.select(match);
14556         var sn = Roo.get(this.view.getSelectedNodes()[0]);
14557         sn.scrollIntoView(sn.dom.parentNode, false);
14558     },
14559     
14560     onViewScroll : function(e, t){
14561         
14562         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){
14563             return;
14564         }
14565         
14566         this.hasQuery = true;
14567         
14568         this.loading = this.list.select('.loading', true).first();
14569         
14570         if(this.loading === null){
14571             this.list.createChild({
14572                 tag: 'div',
14573                 cls: 'loading roo-select2-more-results roo-select2-active',
14574                 html: 'Loading more results...'
14575             });
14576             
14577             this.loading = this.list.select('.loading', true).first();
14578             
14579             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14580             
14581             this.loading.hide();
14582         }
14583         
14584         this.loading.show();
14585         
14586         var _combo = this;
14587         
14588         this.page++;
14589         this.loadNext = true;
14590         
14591         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14592         
14593         return;
14594     },
14595     
14596     addItem : function(o)
14597     {   
14598         var dv = ''; // display value
14599         
14600         if (this.displayField) {
14601             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14602         } else {
14603             // this is an error condition!!!
14604             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14605         }
14606         
14607         if(!dv.length){
14608             return;
14609         }
14610         
14611         var choice = this.choices.createChild({
14612             tag: 'li',
14613             cls: 'roo-select2-search-choice',
14614             cn: [
14615                 {
14616                     tag: 'div',
14617                     html: dv
14618                 },
14619                 {
14620                     tag: 'a',
14621                     href: '#',
14622                     cls: 'roo-select2-search-choice-close fa fa-times',
14623                     tabindex: '-1'
14624                 }
14625             ]
14626             
14627         }, this.searchField);
14628         
14629         var close = choice.select('a.roo-select2-search-choice-close', true).first();
14630         
14631         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14632         
14633         this.item.push(o);
14634         
14635         this.lastData = o;
14636         
14637         this.syncValue();
14638         
14639         this.inputEl().dom.value = '';
14640         
14641         this.validate();
14642     },
14643     
14644     onRemoveItem : function(e, _self, o)
14645     {
14646         e.preventDefault();
14647         
14648         this.lastItem = Roo.apply([], this.item);
14649         
14650         var index = this.item.indexOf(o.data) * 1;
14651         
14652         if( index < 0){
14653             Roo.log('not this item?!');
14654             return;
14655         }
14656         
14657         this.item.splice(index, 1);
14658         o.item.remove();
14659         
14660         this.syncValue();
14661         
14662         this.fireEvent('remove', this, e);
14663         
14664         this.validate();
14665         
14666     },
14667     
14668     syncValue : function()
14669     {
14670         if(!this.item.length){
14671             this.clearValue();
14672             return;
14673         }
14674             
14675         var value = [];
14676         var _this = this;
14677         Roo.each(this.item, function(i){
14678             if(_this.valueField){
14679                 value.push(i[_this.valueField]);
14680                 return;
14681             }
14682
14683             value.push(i);
14684         });
14685
14686         this.value = value.join(',');
14687
14688         if(this.hiddenField){
14689             this.hiddenField.dom.value = this.value;
14690         }
14691         
14692         this.store.fireEvent("datachanged", this.store);
14693         
14694         this.validate();
14695     },
14696     
14697     clearItem : function()
14698     {
14699         if(!this.multiple){
14700             return;
14701         }
14702         
14703         this.item = [];
14704         
14705         Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14706            c.remove();
14707         });
14708         
14709         this.syncValue();
14710         
14711         this.validate();
14712         
14713         if(this.tickable && !Roo.isTouch){
14714             this.view.refresh();
14715         }
14716     },
14717     
14718     inputEl: function ()
14719     {
14720         if(Roo.isIOS && this.useNativeIOS){
14721             return this.el.select('select.roo-ios-select', true).first();
14722         }
14723         
14724         if(Roo.isTouch && this.mobileTouchView){
14725             return this.el.select('input.form-control',true).first();
14726         }
14727         
14728         if(this.tickable){
14729             return this.searchField;
14730         }
14731         
14732         return this.el.select('input.form-control',true).first();
14733     },
14734     
14735     onTickableFooterButtonClick : function(e, btn, el)
14736     {
14737         e.preventDefault();
14738         
14739         this.lastItem = Roo.apply([], this.item);
14740         
14741         if(btn && btn.name == 'cancel'){
14742             this.tickItems = Roo.apply([], this.item);
14743             this.collapse();
14744             return;
14745         }
14746         
14747         this.clearItem();
14748         
14749         var _this = this;
14750         
14751         Roo.each(this.tickItems, function(o){
14752             _this.addItem(o);
14753         });
14754         
14755         this.collapse();
14756         
14757     },
14758     
14759     validate : function()
14760     {
14761         if(this.getVisibilityEl().hasClass('hidden')){
14762             return true;
14763         }
14764         
14765         var v = this.getRawValue();
14766         
14767         if(this.multiple){
14768             v = this.getValue();
14769         }
14770         
14771         if(this.disabled || this.allowBlank || v.length){
14772             this.markValid();
14773             return true;
14774         }
14775         
14776         this.markInvalid();
14777         return false;
14778     },
14779     
14780     tickableInputEl : function()
14781     {
14782         if(!this.tickable || !this.editable){
14783             return this.inputEl();
14784         }
14785         
14786         return this.inputEl().select('.roo-select2-search-field-input', true).first();
14787     },
14788     
14789     
14790     getAutoCreateTouchView : function()
14791     {
14792         var id = Roo.id();
14793         
14794         var cfg = {
14795             cls: 'form-group' //input-group
14796         };
14797         
14798         var input =  {
14799             tag: 'input',
14800             id : id,
14801             type : this.inputType,
14802             cls : 'form-control x-combo-noedit',
14803             autocomplete: 'new-password',
14804             placeholder : this.placeholder || '',
14805             readonly : true
14806         };
14807         
14808         if (this.name) {
14809             input.name = this.name;
14810         }
14811         
14812         if (this.size) {
14813             input.cls += ' input-' + this.size;
14814         }
14815         
14816         if (this.disabled) {
14817             input.disabled = true;
14818         }
14819         
14820         var inputblock = {
14821             cls : '',
14822             cn : [
14823                 input
14824             ]
14825         };
14826         
14827         if(this.before){
14828             inputblock.cls += ' input-group';
14829             
14830             inputblock.cn.unshift({
14831                 tag :'span',
14832                 cls : 'input-group-addon',
14833                 html : this.before
14834             });
14835         }
14836         
14837         if(this.removable && !this.multiple){
14838             inputblock.cls += ' roo-removable';
14839             
14840             inputblock.cn.push({
14841                 tag: 'button',
14842                 html : 'x',
14843                 cls : 'roo-combo-removable-btn close'
14844             });
14845         }
14846
14847         if(this.hasFeedback && !this.allowBlank){
14848             
14849             inputblock.cls += ' has-feedback';
14850             
14851             inputblock.cn.push({
14852                 tag: 'span',
14853                 cls: 'glyphicon form-control-feedback'
14854             });
14855             
14856         }
14857         
14858         if (this.after) {
14859             
14860             inputblock.cls += (this.before) ? '' : ' input-group';
14861             
14862             inputblock.cn.push({
14863                 tag :'span',
14864                 cls : 'input-group-addon',
14865                 html : this.after
14866             });
14867         }
14868
14869         var box = {
14870             tag: 'div',
14871             cn: [
14872                 {
14873                     tag: 'input',
14874                     type : 'hidden',
14875                     cls: 'form-hidden-field'
14876                 },
14877                 inputblock
14878             ]
14879             
14880         };
14881         
14882         if(this.multiple){
14883             box = {
14884                 tag: 'div',
14885                 cn: [
14886                     {
14887                         tag: 'input',
14888                         type : 'hidden',
14889                         cls: 'form-hidden-field'
14890                     },
14891                     {
14892                         tag: 'ul',
14893                         cls: 'roo-select2-choices',
14894                         cn:[
14895                             {
14896                                 tag: 'li',
14897                                 cls: 'roo-select2-search-field',
14898                                 cn: [
14899
14900                                     inputblock
14901                                 ]
14902                             }
14903                         ]
14904                     }
14905                 ]
14906             }
14907         };
14908         
14909         var combobox = {
14910             cls: 'roo-select2-container input-group roo-touchview-combobox ',
14911             cn: [
14912                 box
14913             ]
14914         };
14915         
14916         if(!this.multiple && this.showToggleBtn){
14917             
14918             var caret = {
14919                         tag: 'span',
14920                         cls: 'caret'
14921             };
14922             
14923             if (this.caret != false) {
14924                 caret = {
14925                      tag: 'i',
14926                      cls: 'fa fa-' + this.caret
14927                 };
14928                 
14929             }
14930             
14931             combobox.cn.push({
14932                 tag :'span',
14933                 cls : 'input-group-addon btn dropdown-toggle',
14934                 cn : [
14935                     caret,
14936                     {
14937                         tag: 'span',
14938                         cls: 'combobox-clear',
14939                         cn  : [
14940                             {
14941                                 tag : 'i',
14942                                 cls: 'icon-remove'
14943                             }
14944                         ]
14945                     }
14946                 ]
14947
14948             })
14949         }
14950         
14951         if(this.multiple){
14952             combobox.cls += ' roo-select2-container-multi';
14953         }
14954         
14955         var align = this.labelAlign || this.parentLabelAlign();
14956         
14957         if (align ==='left' && this.fieldLabel.length) {
14958
14959             cfg.cn = [
14960                 {
14961                    tag : 'i',
14962                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14963                    tooltip : 'This field is required'
14964                 },
14965                 {
14966                     tag: 'label',
14967                     cls : 'control-label',
14968                     html : this.fieldLabel
14969
14970                 },
14971                 {
14972                     cls : '', 
14973                     cn: [
14974                         combobox
14975                     ]
14976                 }
14977             ];
14978             
14979             var labelCfg = cfg.cn[1];
14980             var contentCfg = cfg.cn[2];
14981             
14982
14983             if(this.indicatorpos == 'right'){
14984                 cfg.cn = [
14985                     {
14986                         tag: 'label',
14987                         'for' :  id,
14988                         cls : 'control-label',
14989                         cn : [
14990                             {
14991                                 tag : 'span',
14992                                 html : this.fieldLabel
14993                             },
14994                             {
14995                                 tag : 'i',
14996                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14997                                 tooltip : 'This field is required'
14998                             }
14999                         ]
15000                     },
15001                     {
15002                         cls : "",
15003                         cn: [
15004                             combobox
15005                         ]
15006                     }
15007
15008                 ];
15009                 
15010                 labelCfg = cfg.cn[0];
15011                 contentCfg = cfg.cn[1];
15012             }
15013             
15014            
15015             
15016             if(this.labelWidth > 12){
15017                 labelCfg.style = "width: " + this.labelWidth + 'px';
15018             }
15019             
15020             if(this.labelWidth < 13 && this.labelmd == 0){
15021                 this.labelmd = this.labelWidth;
15022             }
15023             
15024             if(this.labellg > 0){
15025                 labelCfg.cls += ' col-lg-' + this.labellg;
15026                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15027             }
15028             
15029             if(this.labelmd > 0){
15030                 labelCfg.cls += ' col-md-' + this.labelmd;
15031                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15032             }
15033             
15034             if(this.labelsm > 0){
15035                 labelCfg.cls += ' col-sm-' + this.labelsm;
15036                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15037             }
15038             
15039             if(this.labelxs > 0){
15040                 labelCfg.cls += ' col-xs-' + this.labelxs;
15041                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15042             }
15043                 
15044                 
15045         } else if ( this.fieldLabel.length) {
15046             cfg.cn = [
15047                 {
15048                    tag : 'i',
15049                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15050                    tooltip : 'This field is required'
15051                 },
15052                 {
15053                     tag: 'label',
15054                     cls : 'control-label',
15055                     html : this.fieldLabel
15056
15057                 },
15058                 {
15059                     cls : '', 
15060                     cn: [
15061                         combobox
15062                     ]
15063                 }
15064             ];
15065             
15066             if(this.indicatorpos == 'right'){
15067                 cfg.cn = [
15068                     {
15069                         tag: 'label',
15070                         cls : 'control-label',
15071                         html : this.fieldLabel,
15072                         cn : [
15073                             {
15074                                tag : 'i',
15075                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15076                                tooltip : 'This field is required'
15077                             }
15078                         ]
15079                     },
15080                     {
15081                         cls : '', 
15082                         cn: [
15083                             combobox
15084                         ]
15085                     }
15086                 ];
15087             }
15088         } else {
15089             cfg.cn = combobox;    
15090         }
15091         
15092         
15093         var settings = this;
15094         
15095         ['xs','sm','md','lg'].map(function(size){
15096             if (settings[size]) {
15097                 cfg.cls += ' col-' + size + '-' + settings[size];
15098             }
15099         });
15100         
15101         return cfg;
15102     },
15103     
15104     initTouchView : function()
15105     {
15106         this.renderTouchView();
15107         
15108         this.touchViewEl.on('scroll', function(){
15109             this.el.dom.scrollTop = 0;
15110         }, this);
15111         
15112         this.originalValue = this.getValue();
15113         
15114         this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15115         
15116         this.inputEl().on("click", this.showTouchView, this);
15117         if (this.triggerEl) {
15118             this.triggerEl.on("click", this.showTouchView, this);
15119         }
15120         
15121         
15122         this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15123         this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15124         
15125         this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15126         
15127         this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15128         this.store.on('load', this.onTouchViewLoad, this);
15129         this.store.on('loadexception', this.onTouchViewLoadException, this);
15130         
15131         if(this.hiddenName){
15132             
15133             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15134             
15135             this.hiddenField.dom.value =
15136                 this.hiddenValue !== undefined ? this.hiddenValue :
15137                 this.value !== undefined ? this.value : '';
15138         
15139             this.el.dom.removeAttribute('name');
15140             this.hiddenField.dom.setAttribute('name', this.hiddenName);
15141         }
15142         
15143         if(this.multiple){
15144             this.choices = this.el.select('ul.roo-select2-choices', true).first();
15145             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15146         }
15147         
15148         if(this.removable && !this.multiple){
15149             var close = this.closeTriggerEl();
15150             if(close){
15151                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15152                 close.on('click', this.removeBtnClick, this, close);
15153             }
15154         }
15155         /*
15156          * fix the bug in Safari iOS8
15157          */
15158         this.inputEl().on("focus", function(e){
15159             document.activeElement.blur();
15160         }, this);
15161         
15162         return;
15163         
15164         
15165     },
15166     
15167     renderTouchView : function()
15168     {
15169         this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15170         this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15171         
15172         this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15173         this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15174         
15175         this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15176         this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15177         this.touchViewBodyEl.setStyle('overflow', 'auto');
15178         
15179         this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15180         this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15181         
15182         this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15183         this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15184         
15185     },
15186     
15187     showTouchView : function()
15188     {
15189         if(this.disabled){
15190             return;
15191         }
15192         
15193         this.touchViewHeaderEl.hide();
15194
15195         if(this.modalTitle.length){
15196             this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15197             this.touchViewHeaderEl.show();
15198         }
15199
15200         this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15201         this.touchViewEl.show();
15202
15203         this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15204         
15205         //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15206         //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15207
15208         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15209
15210         if(this.modalTitle.length){
15211             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15212         }
15213         
15214         this.touchViewBodyEl.setHeight(bodyHeight);
15215
15216         if(this.animate){
15217             var _this = this;
15218             (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15219         }else{
15220             this.touchViewEl.addClass('in');
15221         }
15222
15223         this.doTouchViewQuery();
15224         
15225     },
15226     
15227     hideTouchView : function()
15228     {
15229         this.touchViewEl.removeClass('in');
15230
15231         if(this.animate){
15232             var _this = this;
15233             (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15234         }else{
15235             this.touchViewEl.setStyle('display', 'none');
15236         }
15237         
15238     },
15239     
15240     setTouchViewValue : function()
15241     {
15242         if(this.multiple){
15243             this.clearItem();
15244         
15245             var _this = this;
15246
15247             Roo.each(this.tickItems, function(o){
15248                 this.addItem(o);
15249             }, this);
15250         }
15251         
15252         this.hideTouchView();
15253     },
15254     
15255     doTouchViewQuery : function()
15256     {
15257         var qe = {
15258             query: '',
15259             forceAll: true,
15260             combo: this,
15261             cancel:false
15262         };
15263         
15264         if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15265             return false;
15266         }
15267         
15268         if(!this.alwaysQuery || this.mode == 'local'){
15269             this.onTouchViewLoad();
15270             return;
15271         }
15272         
15273         this.store.load();
15274     },
15275     
15276     onTouchViewBeforeLoad : function(combo,opts)
15277     {
15278         return;
15279     },
15280
15281     // private
15282     onTouchViewLoad : function()
15283     {
15284         if(this.store.getCount() < 1){
15285             this.onTouchViewEmptyResults();
15286             return;
15287         }
15288         
15289         this.clearTouchView();
15290         
15291         var rawValue = this.getRawValue();
15292         
15293         var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15294         
15295         this.tickItems = [];
15296         
15297         this.store.data.each(function(d, rowIndex){
15298             var row = this.touchViewListGroup.createChild(template);
15299             
15300             if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15301                 row.addClass(d.data.cls);
15302             }
15303             
15304             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15305                 var cfg = {
15306                     data : d.data,
15307                     html : d.data[this.displayField]
15308                 };
15309                 
15310                 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15311                     row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15312                 }
15313             }
15314             row.removeClass('selected');
15315             if(!this.multiple && this.valueField &&
15316                     typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15317             {
15318                 // radio buttons..
15319                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15320                 row.addClass('selected');
15321             }
15322             
15323             if(this.multiple && this.valueField &&
15324                     typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15325             {
15326                 
15327                 // checkboxes...
15328                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15329                 this.tickItems.push(d.data);
15330             }
15331             
15332             row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15333             
15334         }, this);
15335         
15336         var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15337         
15338         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15339
15340         if(this.modalTitle.length){
15341             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15342         }
15343
15344         var listHeight = this.touchViewListGroup.getHeight();
15345         
15346         var _this = this;
15347         
15348         if(firstChecked && listHeight > bodyHeight){
15349             (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15350         }
15351         
15352     },
15353     
15354     onTouchViewLoadException : function()
15355     {
15356         this.hideTouchView();
15357     },
15358     
15359     onTouchViewEmptyResults : function()
15360     {
15361         this.clearTouchView();
15362         
15363         this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15364         
15365         this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15366         
15367     },
15368     
15369     clearTouchView : function()
15370     {
15371         this.touchViewListGroup.dom.innerHTML = '';
15372     },
15373     
15374     onTouchViewClick : function(e, el, o)
15375     {
15376         e.preventDefault();
15377         
15378         var row = o.row;
15379         var rowIndex = o.rowIndex;
15380         
15381         var r = this.store.getAt(rowIndex);
15382         
15383         if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15384             
15385             if(!this.multiple){
15386                 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15387                     c.dom.removeAttribute('checked');
15388                 }, this);
15389
15390                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15391
15392                 this.setFromData(r.data);
15393
15394                 var close = this.closeTriggerEl();
15395
15396                 if(close){
15397                     close.show();
15398                 }
15399
15400                 this.hideTouchView();
15401
15402                 this.fireEvent('select', this, r, rowIndex);
15403
15404                 return;
15405             }
15406
15407             if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15408                 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15409                 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15410                 return;
15411             }
15412
15413             row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15414             this.addItem(r.data);
15415             this.tickItems.push(r.data);
15416         }
15417     },
15418     
15419     getAutoCreateNativeIOS : function()
15420     {
15421         var cfg = {
15422             cls: 'form-group' //input-group,
15423         };
15424         
15425         var combobox =  {
15426             tag: 'select',
15427             cls : 'roo-ios-select'
15428         };
15429         
15430         if (this.name) {
15431             combobox.name = this.name;
15432         }
15433         
15434         if (this.disabled) {
15435             combobox.disabled = true;
15436         }
15437         
15438         var settings = this;
15439         
15440         ['xs','sm','md','lg'].map(function(size){
15441             if (settings[size]) {
15442                 cfg.cls += ' col-' + size + '-' + settings[size];
15443             }
15444         });
15445         
15446         cfg.cn = combobox;
15447         
15448         return cfg;
15449         
15450     },
15451     
15452     initIOSView : function()
15453     {
15454         this.store.on('load', this.onIOSViewLoad, this);
15455         
15456         return;
15457     },
15458     
15459     onIOSViewLoad : function()
15460     {
15461         if(this.store.getCount() < 1){
15462             return;
15463         }
15464         
15465         this.clearIOSView();
15466         
15467         if(this.allowBlank) {
15468             
15469             var default_text = '-- SELECT --';
15470             
15471             if(this.placeholder.length){
15472                 default_text = this.placeholder;
15473             }
15474             
15475             if(this.emptyTitle.length){
15476                 default_text += ' - ' + this.emptyTitle + ' -';
15477             }
15478             
15479             var opt = this.inputEl().createChild({
15480                 tag: 'option',
15481                 value : 0,
15482                 html : default_text
15483             });
15484             
15485             var o = {};
15486             o[this.valueField] = 0;
15487             o[this.displayField] = default_text;
15488             
15489             this.ios_options.push({
15490                 data : o,
15491                 el : opt
15492             });
15493             
15494         }
15495         
15496         this.store.data.each(function(d, rowIndex){
15497             
15498             var html = '';
15499             
15500             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15501                 html = d.data[this.displayField];
15502             }
15503             
15504             var value = '';
15505             
15506             if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15507                 value = d.data[this.valueField];
15508             }
15509             
15510             var option = {
15511                 tag: 'option',
15512                 value : value,
15513                 html : html
15514             };
15515             
15516             if(this.value == d.data[this.valueField]){
15517                 option['selected'] = true;
15518             }
15519             
15520             var opt = this.inputEl().createChild(option);
15521             
15522             this.ios_options.push({
15523                 data : d.data,
15524                 el : opt
15525             });
15526             
15527         }, this);
15528         
15529         this.inputEl().on('change', function(){
15530            this.fireEvent('select', this);
15531         }, this);
15532         
15533     },
15534     
15535     clearIOSView: function()
15536     {
15537         this.inputEl().dom.innerHTML = '';
15538         
15539         this.ios_options = [];
15540     },
15541     
15542     setIOSValue: function(v)
15543     {
15544         this.value = v;
15545         
15546         if(!this.ios_options){
15547             return;
15548         }
15549         
15550         Roo.each(this.ios_options, function(opts){
15551            
15552            opts.el.dom.removeAttribute('selected');
15553            
15554            if(opts.data[this.valueField] != v){
15555                return;
15556            }
15557            
15558            opts.el.dom.setAttribute('selected', true);
15559            
15560         }, this);
15561     }
15562
15563     /** 
15564     * @cfg {Boolean} grow 
15565     * @hide 
15566     */
15567     /** 
15568     * @cfg {Number} growMin 
15569     * @hide 
15570     */
15571     /** 
15572     * @cfg {Number} growMax 
15573     * @hide 
15574     */
15575     /**
15576      * @hide
15577      * @method autoSize
15578      */
15579 });
15580
15581 Roo.apply(Roo.bootstrap.ComboBox,  {
15582     
15583     header : {
15584         tag: 'div',
15585         cls: 'modal-header',
15586         cn: [
15587             {
15588                 tag: 'h4',
15589                 cls: 'modal-title'
15590             }
15591         ]
15592     },
15593     
15594     body : {
15595         tag: 'div',
15596         cls: 'modal-body',
15597         cn: [
15598             {
15599                 tag: 'ul',
15600                 cls: 'list-group'
15601             }
15602         ]
15603     },
15604     
15605     listItemRadio : {
15606         tag: 'li',
15607         cls: 'list-group-item',
15608         cn: [
15609             {
15610                 tag: 'span',
15611                 cls: 'roo-combobox-list-group-item-value'
15612             },
15613             {
15614                 tag: 'div',
15615                 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15616                 cn: [
15617                     {
15618                         tag: 'input',
15619                         type: 'radio'
15620                     },
15621                     {
15622                         tag: 'label'
15623                     }
15624                 ]
15625             }
15626         ]
15627     },
15628     
15629     listItemCheckbox : {
15630         tag: 'li',
15631         cls: 'list-group-item',
15632         cn: [
15633             {
15634                 tag: 'span',
15635                 cls: 'roo-combobox-list-group-item-value'
15636             },
15637             {
15638                 tag: 'div',
15639                 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15640                 cn: [
15641                     {
15642                         tag: 'input',
15643                         type: 'checkbox'
15644                     },
15645                     {
15646                         tag: 'label'
15647                     }
15648                 ]
15649             }
15650         ]
15651     },
15652     
15653     emptyResult : {
15654         tag: 'div',
15655         cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15656     },
15657     
15658     footer : {
15659         tag: 'div',
15660         cls: 'modal-footer',
15661         cn: [
15662             {
15663                 tag: 'div',
15664                 cls: 'row',
15665                 cn: [
15666                     {
15667                         tag: 'div',
15668                         cls: 'col-xs-6 text-left',
15669                         cn: {
15670                             tag: 'button',
15671                             cls: 'btn btn-danger roo-touch-view-cancel',
15672                             html: 'Cancel'
15673                         }
15674                     },
15675                     {
15676                         tag: 'div',
15677                         cls: 'col-xs-6 text-right',
15678                         cn: {
15679                             tag: 'button',
15680                             cls: 'btn btn-success roo-touch-view-ok',
15681                             html: 'OK'
15682                         }
15683                     }
15684                 ]
15685             }
15686         ]
15687         
15688     }
15689 });
15690
15691 Roo.apply(Roo.bootstrap.ComboBox,  {
15692     
15693     touchViewTemplate : {
15694         tag: 'div',
15695         cls: 'modal fade roo-combobox-touch-view',
15696         cn: [
15697             {
15698                 tag: 'div',
15699                 cls: 'modal-dialog',
15700                 style : 'position:fixed', // we have to fix position....
15701                 cn: [
15702                     {
15703                         tag: 'div',
15704                         cls: 'modal-content',
15705                         cn: [
15706                             Roo.bootstrap.ComboBox.header,
15707                             Roo.bootstrap.ComboBox.body,
15708                             Roo.bootstrap.ComboBox.footer
15709                         ]
15710                     }
15711                 ]
15712             }
15713         ]
15714     }
15715 });/*
15716  * Based on:
15717  * Ext JS Library 1.1.1
15718  * Copyright(c) 2006-2007, Ext JS, LLC.
15719  *
15720  * Originally Released Under LGPL - original licence link has changed is not relivant.
15721  *
15722  * Fork - LGPL
15723  * <script type="text/javascript">
15724  */
15725
15726 /**
15727  * @class Roo.View
15728  * @extends Roo.util.Observable
15729  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
15730  * This class also supports single and multi selection modes. <br>
15731  * Create a data model bound view:
15732  <pre><code>
15733  var store = new Roo.data.Store(...);
15734
15735  var view = new Roo.View({
15736     el : "my-element",
15737     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
15738  
15739     singleSelect: true,
15740     selectedClass: "ydataview-selected",
15741     store: store
15742  });
15743
15744  // listen for node click?
15745  view.on("click", function(vw, index, node, e){
15746  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15747  });
15748
15749  // load XML data
15750  dataModel.load("foobar.xml");
15751  </code></pre>
15752  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15753  * <br><br>
15754  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15755  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15756  * 
15757  * Note: old style constructor is still suported (container, template, config)
15758  * 
15759  * @constructor
15760  * Create a new View
15761  * @param {Object} config The config object
15762  * 
15763  */
15764 Roo.View = function(config, depreciated_tpl, depreciated_config){
15765     
15766     this.parent = false;
15767     
15768     if (typeof(depreciated_tpl) == 'undefined') {
15769         // new way.. - universal constructor.
15770         Roo.apply(this, config);
15771         this.el  = Roo.get(this.el);
15772     } else {
15773         // old format..
15774         this.el  = Roo.get(config);
15775         this.tpl = depreciated_tpl;
15776         Roo.apply(this, depreciated_config);
15777     }
15778     this.wrapEl  = this.el.wrap().wrap();
15779     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15780     
15781     
15782     if(typeof(this.tpl) == "string"){
15783         this.tpl = new Roo.Template(this.tpl);
15784     } else {
15785         // support xtype ctors..
15786         this.tpl = new Roo.factory(this.tpl, Roo);
15787     }
15788     
15789     
15790     this.tpl.compile();
15791     
15792     /** @private */
15793     this.addEvents({
15794         /**
15795          * @event beforeclick
15796          * Fires before a click is processed. Returns false to cancel the default action.
15797          * @param {Roo.View} this
15798          * @param {Number} index The index of the target node
15799          * @param {HTMLElement} node The target node
15800          * @param {Roo.EventObject} e The raw event object
15801          */
15802             "beforeclick" : true,
15803         /**
15804          * @event click
15805          * Fires when a template node is clicked.
15806          * @param {Roo.View} this
15807          * @param {Number} index The index of the target node
15808          * @param {HTMLElement} node The target node
15809          * @param {Roo.EventObject} e The raw event object
15810          */
15811             "click" : true,
15812         /**
15813          * @event dblclick
15814          * Fires when a template node is double clicked.
15815          * @param {Roo.View} this
15816          * @param {Number} index The index of the target node
15817          * @param {HTMLElement} node The target node
15818          * @param {Roo.EventObject} e The raw event object
15819          */
15820             "dblclick" : true,
15821         /**
15822          * @event contextmenu
15823          * Fires when a template node is right clicked.
15824          * @param {Roo.View} this
15825          * @param {Number} index The index of the target node
15826          * @param {HTMLElement} node The target node
15827          * @param {Roo.EventObject} e The raw event object
15828          */
15829             "contextmenu" : true,
15830         /**
15831          * @event selectionchange
15832          * Fires when the selected nodes change.
15833          * @param {Roo.View} this
15834          * @param {Array} selections Array of the selected nodes
15835          */
15836             "selectionchange" : true,
15837     
15838         /**
15839          * @event beforeselect
15840          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15841          * @param {Roo.View} this
15842          * @param {HTMLElement} node The node to be selected
15843          * @param {Array} selections Array of currently selected nodes
15844          */
15845             "beforeselect" : true,
15846         /**
15847          * @event preparedata
15848          * Fires on every row to render, to allow you to change the data.
15849          * @param {Roo.View} this
15850          * @param {Object} data to be rendered (change this)
15851          */
15852           "preparedata" : true
15853           
15854           
15855         });
15856
15857
15858
15859     this.el.on({
15860         "click": this.onClick,
15861         "dblclick": this.onDblClick,
15862         "contextmenu": this.onContextMenu,
15863         scope:this
15864     });
15865
15866     this.selections = [];
15867     this.nodes = [];
15868     this.cmp = new Roo.CompositeElementLite([]);
15869     if(this.store){
15870         this.store = Roo.factory(this.store, Roo.data);
15871         this.setStore(this.store, true);
15872     }
15873     
15874     if ( this.footer && this.footer.xtype) {
15875            
15876          var fctr = this.wrapEl.appendChild(document.createElement("div"));
15877         
15878         this.footer.dataSource = this.store;
15879         this.footer.container = fctr;
15880         this.footer = Roo.factory(this.footer, Roo);
15881         fctr.insertFirst(this.el);
15882         
15883         // this is a bit insane - as the paging toolbar seems to detach the el..
15884 //        dom.parentNode.parentNode.parentNode
15885          // they get detached?
15886     }
15887     
15888     
15889     Roo.View.superclass.constructor.call(this);
15890     
15891     
15892 };
15893
15894 Roo.extend(Roo.View, Roo.util.Observable, {
15895     
15896      /**
15897      * @cfg {Roo.data.Store} store Data store to load data from.
15898      */
15899     store : false,
15900     
15901     /**
15902      * @cfg {String|Roo.Element} el The container element.
15903      */
15904     el : '',
15905     
15906     /**
15907      * @cfg {String|Roo.Template} tpl The template used by this View 
15908      */
15909     tpl : false,
15910     /**
15911      * @cfg {String} dataName the named area of the template to use as the data area
15912      *                          Works with domtemplates roo-name="name"
15913      */
15914     dataName: false,
15915     /**
15916      * @cfg {String} selectedClass The css class to add to selected nodes
15917      */
15918     selectedClass : "x-view-selected",
15919      /**
15920      * @cfg {String} emptyText The empty text to show when nothing is loaded.
15921      */
15922     emptyText : "",
15923     
15924     /**
15925      * @cfg {String} text to display on mask (default Loading)
15926      */
15927     mask : false,
15928     /**
15929      * @cfg {Boolean} multiSelect Allow multiple selection
15930      */
15931     multiSelect : false,
15932     /**
15933      * @cfg {Boolean} singleSelect Allow single selection
15934      */
15935     singleSelect:  false,
15936     
15937     /**
15938      * @cfg {Boolean} toggleSelect - selecting 
15939      */
15940     toggleSelect : false,
15941     
15942     /**
15943      * @cfg {Boolean} tickable - selecting 
15944      */
15945     tickable : false,
15946     
15947     /**
15948      * Returns the element this view is bound to.
15949      * @return {Roo.Element}
15950      */
15951     getEl : function(){
15952         return this.wrapEl;
15953     },
15954     
15955     
15956
15957     /**
15958      * Refreshes the view. - called by datachanged on the store. - do not call directly.
15959      */
15960     refresh : function(){
15961         //Roo.log('refresh');
15962         var t = this.tpl;
15963         
15964         // if we are using something like 'domtemplate', then
15965         // the what gets used is:
15966         // t.applySubtemplate(NAME, data, wrapping data..)
15967         // the outer template then get' applied with
15968         //     the store 'extra data'
15969         // and the body get's added to the
15970         //      roo-name="data" node?
15971         //      <span class='roo-tpl-{name}'></span> ?????
15972         
15973         
15974         
15975         this.clearSelections();
15976         this.el.update("");
15977         var html = [];
15978         var records = this.store.getRange();
15979         if(records.length < 1) {
15980             
15981             // is this valid??  = should it render a template??
15982             
15983             this.el.update(this.emptyText);
15984             return;
15985         }
15986         var el = this.el;
15987         if (this.dataName) {
15988             this.el.update(t.apply(this.store.meta)); //????
15989             el = this.el.child('.roo-tpl-' + this.dataName);
15990         }
15991         
15992         for(var i = 0, len = records.length; i < len; i++){
15993             var data = this.prepareData(records[i].data, i, records[i]);
15994             this.fireEvent("preparedata", this, data, i, records[i]);
15995             
15996             var d = Roo.apply({}, data);
15997             
15998             if(this.tickable){
15999                 Roo.apply(d, {'roo-id' : Roo.id()});
16000                 
16001                 var _this = this;
16002             
16003                 Roo.each(this.parent.item, function(item){
16004                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16005                         return;
16006                     }
16007                     Roo.apply(d, {'roo-data-checked' : 'checked'});
16008                 });
16009             }
16010             
16011             html[html.length] = Roo.util.Format.trim(
16012                 this.dataName ?
16013                     t.applySubtemplate(this.dataName, d, this.store.meta) :
16014                     t.apply(d)
16015             );
16016         }
16017         
16018         
16019         
16020         el.update(html.join(""));
16021         this.nodes = el.dom.childNodes;
16022         this.updateIndexes(0);
16023     },
16024     
16025
16026     /**
16027      * Function to override to reformat the data that is sent to
16028      * the template for each node.
16029      * DEPRICATED - use the preparedata event handler.
16030      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16031      * a JSON object for an UpdateManager bound view).
16032      */
16033     prepareData : function(data, index, record)
16034     {
16035         this.fireEvent("preparedata", this, data, index, record);
16036         return data;
16037     },
16038
16039     onUpdate : function(ds, record){
16040         // Roo.log('on update');   
16041         this.clearSelections();
16042         var index = this.store.indexOf(record);
16043         var n = this.nodes[index];
16044         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16045         n.parentNode.removeChild(n);
16046         this.updateIndexes(index, index);
16047     },
16048
16049     
16050     
16051 // --------- FIXME     
16052     onAdd : function(ds, records, index)
16053     {
16054         //Roo.log(['on Add', ds, records, index] );        
16055         this.clearSelections();
16056         if(this.nodes.length == 0){
16057             this.refresh();
16058             return;
16059         }
16060         var n = this.nodes[index];
16061         for(var i = 0, len = records.length; i < len; i++){
16062             var d = this.prepareData(records[i].data, i, records[i]);
16063             if(n){
16064                 this.tpl.insertBefore(n, d);
16065             }else{
16066                 
16067                 this.tpl.append(this.el, d);
16068             }
16069         }
16070         this.updateIndexes(index);
16071     },
16072
16073     onRemove : function(ds, record, index){
16074        // Roo.log('onRemove');
16075         this.clearSelections();
16076         var el = this.dataName  ?
16077             this.el.child('.roo-tpl-' + this.dataName) :
16078             this.el; 
16079         
16080         el.dom.removeChild(this.nodes[index]);
16081         this.updateIndexes(index);
16082     },
16083
16084     /**
16085      * Refresh an individual node.
16086      * @param {Number} index
16087      */
16088     refreshNode : function(index){
16089         this.onUpdate(this.store, this.store.getAt(index));
16090     },
16091
16092     updateIndexes : function(startIndex, endIndex){
16093         var ns = this.nodes;
16094         startIndex = startIndex || 0;
16095         endIndex = endIndex || ns.length - 1;
16096         for(var i = startIndex; i <= endIndex; i++){
16097             ns[i].nodeIndex = i;
16098         }
16099     },
16100
16101     /**
16102      * Changes the data store this view uses and refresh the view.
16103      * @param {Store} store
16104      */
16105     setStore : function(store, initial){
16106         if(!initial && this.store){
16107             this.store.un("datachanged", this.refresh);
16108             this.store.un("add", this.onAdd);
16109             this.store.un("remove", this.onRemove);
16110             this.store.un("update", this.onUpdate);
16111             this.store.un("clear", this.refresh);
16112             this.store.un("beforeload", this.onBeforeLoad);
16113             this.store.un("load", this.onLoad);
16114             this.store.un("loadexception", this.onLoad);
16115         }
16116         if(store){
16117           
16118             store.on("datachanged", this.refresh, this);
16119             store.on("add", this.onAdd, this);
16120             store.on("remove", this.onRemove, this);
16121             store.on("update", this.onUpdate, this);
16122             store.on("clear", this.refresh, this);
16123             store.on("beforeload", this.onBeforeLoad, this);
16124             store.on("load", this.onLoad, this);
16125             store.on("loadexception", this.onLoad, this);
16126         }
16127         
16128         if(store){
16129             this.refresh();
16130         }
16131     },
16132     /**
16133      * onbeforeLoad - masks the loading area.
16134      *
16135      */
16136     onBeforeLoad : function(store,opts)
16137     {
16138          //Roo.log('onBeforeLoad');   
16139         if (!opts.add) {
16140             this.el.update("");
16141         }
16142         this.el.mask(this.mask ? this.mask : "Loading" ); 
16143     },
16144     onLoad : function ()
16145     {
16146         this.el.unmask();
16147     },
16148     
16149
16150     /**
16151      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16152      * @param {HTMLElement} node
16153      * @return {HTMLElement} The template node
16154      */
16155     findItemFromChild : function(node){
16156         var el = this.dataName  ?
16157             this.el.child('.roo-tpl-' + this.dataName,true) :
16158             this.el.dom; 
16159         
16160         if(!node || node.parentNode == el){
16161                     return node;
16162             }
16163             var p = node.parentNode;
16164             while(p && p != el){
16165             if(p.parentNode == el){
16166                 return p;
16167             }
16168             p = p.parentNode;
16169         }
16170             return null;
16171     },
16172
16173     /** @ignore */
16174     onClick : function(e){
16175         var item = this.findItemFromChild(e.getTarget());
16176         if(item){
16177             var index = this.indexOf(item);
16178             if(this.onItemClick(item, index, e) !== false){
16179                 this.fireEvent("click", this, index, item, e);
16180             }
16181         }else{
16182             this.clearSelections();
16183         }
16184     },
16185
16186     /** @ignore */
16187     onContextMenu : function(e){
16188         var item = this.findItemFromChild(e.getTarget());
16189         if(item){
16190             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16191         }
16192     },
16193
16194     /** @ignore */
16195     onDblClick : function(e){
16196         var item = this.findItemFromChild(e.getTarget());
16197         if(item){
16198             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16199         }
16200     },
16201
16202     onItemClick : function(item, index, e)
16203     {
16204         if(this.fireEvent("beforeclick", this, index, item, e) === false){
16205             return false;
16206         }
16207         if (this.toggleSelect) {
16208             var m = this.isSelected(item) ? 'unselect' : 'select';
16209             //Roo.log(m);
16210             var _t = this;
16211             _t[m](item, true, false);
16212             return true;
16213         }
16214         if(this.multiSelect || this.singleSelect){
16215             if(this.multiSelect && e.shiftKey && this.lastSelection){
16216                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16217             }else{
16218                 this.select(item, this.multiSelect && e.ctrlKey);
16219                 this.lastSelection = item;
16220             }
16221             
16222             if(!this.tickable){
16223                 e.preventDefault();
16224             }
16225             
16226         }
16227         return true;
16228     },
16229
16230     /**
16231      * Get the number of selected nodes.
16232      * @return {Number}
16233      */
16234     getSelectionCount : function(){
16235         return this.selections.length;
16236     },
16237
16238     /**
16239      * Get the currently selected nodes.
16240      * @return {Array} An array of HTMLElements
16241      */
16242     getSelectedNodes : function(){
16243         return this.selections;
16244     },
16245
16246     /**
16247      * Get the indexes of the selected nodes.
16248      * @return {Array}
16249      */
16250     getSelectedIndexes : function(){
16251         var indexes = [], s = this.selections;
16252         for(var i = 0, len = s.length; i < len; i++){
16253             indexes.push(s[i].nodeIndex);
16254         }
16255         return indexes;
16256     },
16257
16258     /**
16259      * Clear all selections
16260      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16261      */
16262     clearSelections : function(suppressEvent){
16263         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16264             this.cmp.elements = this.selections;
16265             this.cmp.removeClass(this.selectedClass);
16266             this.selections = [];
16267             if(!suppressEvent){
16268                 this.fireEvent("selectionchange", this, this.selections);
16269             }
16270         }
16271     },
16272
16273     /**
16274      * Returns true if the passed node is selected
16275      * @param {HTMLElement/Number} node The node or node index
16276      * @return {Boolean}
16277      */
16278     isSelected : function(node){
16279         var s = this.selections;
16280         if(s.length < 1){
16281             return false;
16282         }
16283         node = this.getNode(node);
16284         return s.indexOf(node) !== -1;
16285     },
16286
16287     /**
16288      * Selects nodes.
16289      * @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
16290      * @param {Boolean} keepExisting (optional) true to keep existing selections
16291      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16292      */
16293     select : function(nodeInfo, keepExisting, suppressEvent){
16294         if(nodeInfo instanceof Array){
16295             if(!keepExisting){
16296                 this.clearSelections(true);
16297             }
16298             for(var i = 0, len = nodeInfo.length; i < len; i++){
16299                 this.select(nodeInfo[i], true, true);
16300             }
16301             return;
16302         } 
16303         var node = this.getNode(nodeInfo);
16304         if(!node || this.isSelected(node)){
16305             return; // already selected.
16306         }
16307         if(!keepExisting){
16308             this.clearSelections(true);
16309         }
16310         
16311         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16312             Roo.fly(node).addClass(this.selectedClass);
16313             this.selections.push(node);
16314             if(!suppressEvent){
16315                 this.fireEvent("selectionchange", this, this.selections);
16316             }
16317         }
16318         
16319         
16320     },
16321       /**
16322      * Unselects nodes.
16323      * @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
16324      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16325      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16326      */
16327     unselect : function(nodeInfo, keepExisting, suppressEvent)
16328     {
16329         if(nodeInfo instanceof Array){
16330             Roo.each(this.selections, function(s) {
16331                 this.unselect(s, nodeInfo);
16332             }, this);
16333             return;
16334         }
16335         var node = this.getNode(nodeInfo);
16336         if(!node || !this.isSelected(node)){
16337             //Roo.log("not selected");
16338             return; // not selected.
16339         }
16340         // fireevent???
16341         var ns = [];
16342         Roo.each(this.selections, function(s) {
16343             if (s == node ) {
16344                 Roo.fly(node).removeClass(this.selectedClass);
16345
16346                 return;
16347             }
16348             ns.push(s);
16349         },this);
16350         
16351         this.selections= ns;
16352         this.fireEvent("selectionchange", this, this.selections);
16353     },
16354
16355     /**
16356      * Gets a template node.
16357      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16358      * @return {HTMLElement} The node or null if it wasn't found
16359      */
16360     getNode : function(nodeInfo){
16361         if(typeof nodeInfo == "string"){
16362             return document.getElementById(nodeInfo);
16363         }else if(typeof nodeInfo == "number"){
16364             return this.nodes[nodeInfo];
16365         }
16366         return nodeInfo;
16367     },
16368
16369     /**
16370      * Gets a range template nodes.
16371      * @param {Number} startIndex
16372      * @param {Number} endIndex
16373      * @return {Array} An array of nodes
16374      */
16375     getNodes : function(start, end){
16376         var ns = this.nodes;
16377         start = start || 0;
16378         end = typeof end == "undefined" ? ns.length - 1 : end;
16379         var nodes = [];
16380         if(start <= end){
16381             for(var i = start; i <= end; i++){
16382                 nodes.push(ns[i]);
16383             }
16384         } else{
16385             for(var i = start; i >= end; i--){
16386                 nodes.push(ns[i]);
16387             }
16388         }
16389         return nodes;
16390     },
16391
16392     /**
16393      * Finds the index of the passed node
16394      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16395      * @return {Number} The index of the node or -1
16396      */
16397     indexOf : function(node){
16398         node = this.getNode(node);
16399         if(typeof node.nodeIndex == "number"){
16400             return node.nodeIndex;
16401         }
16402         var ns = this.nodes;
16403         for(var i = 0, len = ns.length; i < len; i++){
16404             if(ns[i] == node){
16405                 return i;
16406             }
16407         }
16408         return -1;
16409     }
16410 });
16411 /*
16412  * - LGPL
16413  *
16414  * based on jquery fullcalendar
16415  * 
16416  */
16417
16418 Roo.bootstrap = Roo.bootstrap || {};
16419 /**
16420  * @class Roo.bootstrap.Calendar
16421  * @extends Roo.bootstrap.Component
16422  * Bootstrap Calendar class
16423  * @cfg {Boolean} loadMask (true|false) default false
16424  * @cfg {Object} header generate the user specific header of the calendar, default false
16425
16426  * @constructor
16427  * Create a new Container
16428  * @param {Object} config The config object
16429  */
16430
16431
16432
16433 Roo.bootstrap.Calendar = function(config){
16434     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16435      this.addEvents({
16436         /**
16437              * @event select
16438              * Fires when a date is selected
16439              * @param {DatePicker} this
16440              * @param {Date} date The selected date
16441              */
16442         'select': true,
16443         /**
16444              * @event monthchange
16445              * Fires when the displayed month changes 
16446              * @param {DatePicker} this
16447              * @param {Date} date The selected month
16448              */
16449         'monthchange': true,
16450         /**
16451              * @event evententer
16452              * Fires when mouse over an event
16453              * @param {Calendar} this
16454              * @param {event} Event
16455              */
16456         'evententer': true,
16457         /**
16458              * @event eventleave
16459              * Fires when the mouse leaves an
16460              * @param {Calendar} this
16461              * @param {event}
16462              */
16463         'eventleave': true,
16464         /**
16465              * @event eventclick
16466              * Fires when the mouse click an
16467              * @param {Calendar} this
16468              * @param {event}
16469              */
16470         'eventclick': true
16471         
16472     });
16473
16474 };
16475
16476 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
16477     
16478      /**
16479      * @cfg {Number} startDay
16480      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16481      */
16482     startDay : 0,
16483     
16484     loadMask : false,
16485     
16486     header : false,
16487       
16488     getAutoCreate : function(){
16489         
16490         
16491         var fc_button = function(name, corner, style, content ) {
16492             return Roo.apply({},{
16493                 tag : 'span',
16494                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
16495                          (corner.length ?
16496                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16497                             ''
16498                         ),
16499                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16500                 unselectable: 'on'
16501             });
16502         };
16503         
16504         var header = {};
16505         
16506         if(!this.header){
16507             header = {
16508                 tag : 'table',
16509                 cls : 'fc-header',
16510                 style : 'width:100%',
16511                 cn : [
16512                     {
16513                         tag: 'tr',
16514                         cn : [
16515                             {
16516                                 tag : 'td',
16517                                 cls : 'fc-header-left',
16518                                 cn : [
16519                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
16520                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
16521                                     { tag: 'span', cls: 'fc-header-space' },
16522                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
16523
16524
16525                                 ]
16526                             },
16527
16528                             {
16529                                 tag : 'td',
16530                                 cls : 'fc-header-center',
16531                                 cn : [
16532                                     {
16533                                         tag: 'span',
16534                                         cls: 'fc-header-title',
16535                                         cn : {
16536                                             tag: 'H2',
16537                                             html : 'month / year'
16538                                         }
16539                                     }
16540
16541                                 ]
16542                             },
16543                             {
16544                                 tag : 'td',
16545                                 cls : 'fc-header-right',
16546                                 cn : [
16547                               /*      fc_button('month', 'left', '', 'month' ),
16548                                     fc_button('week', '', '', 'week' ),
16549                                     fc_button('day', 'right', '', 'day' )
16550                                 */    
16551
16552                                 ]
16553                             }
16554
16555                         ]
16556                     }
16557                 ]
16558             };
16559         }
16560         
16561         header = this.header;
16562         
16563        
16564         var cal_heads = function() {
16565             var ret = [];
16566             // fixme - handle this.
16567             
16568             for (var i =0; i < Date.dayNames.length; i++) {
16569                 var d = Date.dayNames[i];
16570                 ret.push({
16571                     tag: 'th',
16572                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16573                     html : d.substring(0,3)
16574                 });
16575                 
16576             }
16577             ret[0].cls += ' fc-first';
16578             ret[6].cls += ' fc-last';
16579             return ret;
16580         };
16581         var cal_cell = function(n) {
16582             return  {
16583                 tag: 'td',
16584                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16585                 cn : [
16586                     {
16587                         cn : [
16588                             {
16589                                 cls: 'fc-day-number',
16590                                 html: 'D'
16591                             },
16592                             {
16593                                 cls: 'fc-day-content',
16594                              
16595                                 cn : [
16596                                      {
16597                                         style: 'position: relative;' // height: 17px;
16598                                     }
16599                                 ]
16600                             }
16601                             
16602                             
16603                         ]
16604                     }
16605                 ]
16606                 
16607             }
16608         };
16609         var cal_rows = function() {
16610             
16611             var ret = [];
16612             for (var r = 0; r < 6; r++) {
16613                 var row= {
16614                     tag : 'tr',
16615                     cls : 'fc-week',
16616                     cn : []
16617                 };
16618                 
16619                 for (var i =0; i < Date.dayNames.length; i++) {
16620                     var d = Date.dayNames[i];
16621                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16622
16623                 }
16624                 row.cn[0].cls+=' fc-first';
16625                 row.cn[0].cn[0].style = 'min-height:90px';
16626                 row.cn[6].cls+=' fc-last';
16627                 ret.push(row);
16628                 
16629             }
16630             ret[0].cls += ' fc-first';
16631             ret[4].cls += ' fc-prev-last';
16632             ret[5].cls += ' fc-last';
16633             return ret;
16634             
16635         };
16636         
16637         var cal_table = {
16638             tag: 'table',
16639             cls: 'fc-border-separate',
16640             style : 'width:100%',
16641             cellspacing  : 0,
16642             cn : [
16643                 { 
16644                     tag: 'thead',
16645                     cn : [
16646                         { 
16647                             tag: 'tr',
16648                             cls : 'fc-first fc-last',
16649                             cn : cal_heads()
16650                         }
16651                     ]
16652                 },
16653                 { 
16654                     tag: 'tbody',
16655                     cn : cal_rows()
16656                 }
16657                   
16658             ]
16659         };
16660          
16661          var cfg = {
16662             cls : 'fc fc-ltr',
16663             cn : [
16664                 header,
16665                 {
16666                     cls : 'fc-content',
16667                     style : "position: relative;",
16668                     cn : [
16669                         {
16670                             cls : 'fc-view fc-view-month fc-grid',
16671                             style : 'position: relative',
16672                             unselectable : 'on',
16673                             cn : [
16674                                 {
16675                                     cls : 'fc-event-container',
16676                                     style : 'position:absolute;z-index:8;top:0;left:0;'
16677                                 },
16678                                 cal_table
16679                             ]
16680                         }
16681                     ]
16682     
16683                 }
16684            ] 
16685             
16686         };
16687         
16688          
16689         
16690         return cfg;
16691     },
16692     
16693     
16694     initEvents : function()
16695     {
16696         if(!this.store){
16697             throw "can not find store for calendar";
16698         }
16699         
16700         var mark = {
16701             tag: "div",
16702             cls:"x-dlg-mask",
16703             style: "text-align:center",
16704             cn: [
16705                 {
16706                     tag: "div",
16707                     style: "background-color:white;width:50%;margin:250 auto",
16708                     cn: [
16709                         {
16710                             tag: "img",
16711                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
16712                         },
16713                         {
16714                             tag: "span",
16715                             html: "Loading"
16716                         }
16717                         
16718                     ]
16719                 }
16720             ]
16721         };
16722         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16723         
16724         var size = this.el.select('.fc-content', true).first().getSize();
16725         this.maskEl.setSize(size.width, size.height);
16726         this.maskEl.enableDisplayMode("block");
16727         if(!this.loadMask){
16728             this.maskEl.hide();
16729         }
16730         
16731         this.store = Roo.factory(this.store, Roo.data);
16732         this.store.on('load', this.onLoad, this);
16733         this.store.on('beforeload', this.onBeforeLoad, this);
16734         
16735         this.resize();
16736         
16737         this.cells = this.el.select('.fc-day',true);
16738         //Roo.log(this.cells);
16739         this.textNodes = this.el.query('.fc-day-number');
16740         this.cells.addClassOnOver('fc-state-hover');
16741         
16742         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16743         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16744         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16745         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16746         
16747         this.on('monthchange', this.onMonthChange, this);
16748         
16749         this.update(new Date().clearTime());
16750     },
16751     
16752     resize : function() {
16753         var sz  = this.el.getSize();
16754         
16755         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16756         this.el.select('.fc-day-content div',true).setHeight(34);
16757     },
16758     
16759     
16760     // private
16761     showPrevMonth : function(e){
16762         this.update(this.activeDate.add("mo", -1));
16763     },
16764     showToday : function(e){
16765         this.update(new Date().clearTime());
16766     },
16767     // private
16768     showNextMonth : function(e){
16769         this.update(this.activeDate.add("mo", 1));
16770     },
16771
16772     // private
16773     showPrevYear : function(){
16774         this.update(this.activeDate.add("y", -1));
16775     },
16776
16777     // private
16778     showNextYear : function(){
16779         this.update(this.activeDate.add("y", 1));
16780     },
16781
16782     
16783    // private
16784     update : function(date)
16785     {
16786         var vd = this.activeDate;
16787         this.activeDate = date;
16788 //        if(vd && this.el){
16789 //            var t = date.getTime();
16790 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16791 //                Roo.log('using add remove');
16792 //                
16793 //                this.fireEvent('monthchange', this, date);
16794 //                
16795 //                this.cells.removeClass("fc-state-highlight");
16796 //                this.cells.each(function(c){
16797 //                   if(c.dateValue == t){
16798 //                       c.addClass("fc-state-highlight");
16799 //                       setTimeout(function(){
16800 //                            try{c.dom.firstChild.focus();}catch(e){}
16801 //                       }, 50);
16802 //                       return false;
16803 //                   }
16804 //                   return true;
16805 //                });
16806 //                return;
16807 //            }
16808 //        }
16809         
16810         var days = date.getDaysInMonth();
16811         
16812         var firstOfMonth = date.getFirstDateOfMonth();
16813         var startingPos = firstOfMonth.getDay()-this.startDay;
16814         
16815         if(startingPos < this.startDay){
16816             startingPos += 7;
16817         }
16818         
16819         var pm = date.add(Date.MONTH, -1);
16820         var prevStart = pm.getDaysInMonth()-startingPos;
16821 //        
16822         this.cells = this.el.select('.fc-day',true);
16823         this.textNodes = this.el.query('.fc-day-number');
16824         this.cells.addClassOnOver('fc-state-hover');
16825         
16826         var cells = this.cells.elements;
16827         var textEls = this.textNodes;
16828         
16829         Roo.each(cells, function(cell){
16830             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16831         });
16832         
16833         days += startingPos;
16834
16835         // convert everything to numbers so it's fast
16836         var day = 86400000;
16837         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16838         //Roo.log(d);
16839         //Roo.log(pm);
16840         //Roo.log(prevStart);
16841         
16842         var today = new Date().clearTime().getTime();
16843         var sel = date.clearTime().getTime();
16844         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16845         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16846         var ddMatch = this.disabledDatesRE;
16847         var ddText = this.disabledDatesText;
16848         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16849         var ddaysText = this.disabledDaysText;
16850         var format = this.format;
16851         
16852         var setCellClass = function(cal, cell){
16853             cell.row = 0;
16854             cell.events = [];
16855             cell.more = [];
16856             //Roo.log('set Cell Class');
16857             cell.title = "";
16858             var t = d.getTime();
16859             
16860             //Roo.log(d);
16861             
16862             cell.dateValue = t;
16863             if(t == today){
16864                 cell.className += " fc-today";
16865                 cell.className += " fc-state-highlight";
16866                 cell.title = cal.todayText;
16867             }
16868             if(t == sel){
16869                 // disable highlight in other month..
16870                 //cell.className += " fc-state-highlight";
16871                 
16872             }
16873             // disabling
16874             if(t < min) {
16875                 cell.className = " fc-state-disabled";
16876                 cell.title = cal.minText;
16877                 return;
16878             }
16879             if(t > max) {
16880                 cell.className = " fc-state-disabled";
16881                 cell.title = cal.maxText;
16882                 return;
16883             }
16884             if(ddays){
16885                 if(ddays.indexOf(d.getDay()) != -1){
16886                     cell.title = ddaysText;
16887                     cell.className = " fc-state-disabled";
16888                 }
16889             }
16890             if(ddMatch && format){
16891                 var fvalue = d.dateFormat(format);
16892                 if(ddMatch.test(fvalue)){
16893                     cell.title = ddText.replace("%0", fvalue);
16894                     cell.className = " fc-state-disabled";
16895                 }
16896             }
16897             
16898             if (!cell.initialClassName) {
16899                 cell.initialClassName = cell.dom.className;
16900             }
16901             
16902             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
16903         };
16904
16905         var i = 0;
16906         
16907         for(; i < startingPos; i++) {
16908             textEls[i].innerHTML = (++prevStart);
16909             d.setDate(d.getDate()+1);
16910             
16911             cells[i].className = "fc-past fc-other-month";
16912             setCellClass(this, cells[i]);
16913         }
16914         
16915         var intDay = 0;
16916         
16917         for(; i < days; i++){
16918             intDay = i - startingPos + 1;
16919             textEls[i].innerHTML = (intDay);
16920             d.setDate(d.getDate()+1);
16921             
16922             cells[i].className = ''; // "x-date-active";
16923             setCellClass(this, cells[i]);
16924         }
16925         var extraDays = 0;
16926         
16927         for(; i < 42; i++) {
16928             textEls[i].innerHTML = (++extraDays);
16929             d.setDate(d.getDate()+1);
16930             
16931             cells[i].className = "fc-future fc-other-month";
16932             setCellClass(this, cells[i]);
16933         }
16934         
16935         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16936         
16937         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16938         
16939         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16940         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16941         
16942         if(totalRows != 6){
16943             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16944             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16945         }
16946         
16947         this.fireEvent('monthchange', this, date);
16948         
16949         
16950         /*
16951         if(!this.internalRender){
16952             var main = this.el.dom.firstChild;
16953             var w = main.offsetWidth;
16954             this.el.setWidth(w + this.el.getBorderWidth("lr"));
16955             Roo.fly(main).setWidth(w);
16956             this.internalRender = true;
16957             // opera does not respect the auto grow header center column
16958             // then, after it gets a width opera refuses to recalculate
16959             // without a second pass
16960             if(Roo.isOpera && !this.secondPass){
16961                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16962                 this.secondPass = true;
16963                 this.update.defer(10, this, [date]);
16964             }
16965         }
16966         */
16967         
16968     },
16969     
16970     findCell : function(dt) {
16971         dt = dt.clearTime().getTime();
16972         var ret = false;
16973         this.cells.each(function(c){
16974             //Roo.log("check " +c.dateValue + '?=' + dt);
16975             if(c.dateValue == dt){
16976                 ret = c;
16977                 return false;
16978             }
16979             return true;
16980         });
16981         
16982         return ret;
16983     },
16984     
16985     findCells : function(ev) {
16986         var s = ev.start.clone().clearTime().getTime();
16987        // Roo.log(s);
16988         var e= ev.end.clone().clearTime().getTime();
16989        // Roo.log(e);
16990         var ret = [];
16991         this.cells.each(function(c){
16992              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16993             
16994             if(c.dateValue > e){
16995                 return ;
16996             }
16997             if(c.dateValue < s){
16998                 return ;
16999             }
17000             ret.push(c);
17001         });
17002         
17003         return ret;    
17004     },
17005     
17006 //    findBestRow: function(cells)
17007 //    {
17008 //        var ret = 0;
17009 //        
17010 //        for (var i =0 ; i < cells.length;i++) {
17011 //            ret  = Math.max(cells[i].rows || 0,ret);
17012 //        }
17013 //        return ret;
17014 //        
17015 //    },
17016     
17017     
17018     addItem : function(ev)
17019     {
17020         // look for vertical location slot in
17021         var cells = this.findCells(ev);
17022         
17023 //        ev.row = this.findBestRow(cells);
17024         
17025         // work out the location.
17026         
17027         var crow = false;
17028         var rows = [];
17029         for(var i =0; i < cells.length; i++) {
17030             
17031             cells[i].row = cells[0].row;
17032             
17033             if(i == 0){
17034                 cells[i].row = cells[i].row + 1;
17035             }
17036             
17037             if (!crow) {
17038                 crow = {
17039                     start : cells[i],
17040                     end :  cells[i]
17041                 };
17042                 continue;
17043             }
17044             if (crow.start.getY() == cells[i].getY()) {
17045                 // on same row.
17046                 crow.end = cells[i];
17047                 continue;
17048             }
17049             // different row.
17050             rows.push(crow);
17051             crow = {
17052                 start: cells[i],
17053                 end : cells[i]
17054             };
17055             
17056         }
17057         
17058         rows.push(crow);
17059         ev.els = [];
17060         ev.rows = rows;
17061         ev.cells = cells;
17062         
17063         cells[0].events.push(ev);
17064         
17065         this.calevents.push(ev);
17066     },
17067     
17068     clearEvents: function() {
17069         
17070         if(!this.calevents){
17071             return;
17072         }
17073         
17074         Roo.each(this.cells.elements, function(c){
17075             c.row = 0;
17076             c.events = [];
17077             c.more = [];
17078         });
17079         
17080         Roo.each(this.calevents, function(e) {
17081             Roo.each(e.els, function(el) {
17082                 el.un('mouseenter' ,this.onEventEnter, this);
17083                 el.un('mouseleave' ,this.onEventLeave, this);
17084                 el.remove();
17085             },this);
17086         },this);
17087         
17088         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17089             e.remove();
17090         });
17091         
17092     },
17093     
17094     renderEvents: function()
17095     {   
17096         var _this = this;
17097         
17098         this.cells.each(function(c) {
17099             
17100             if(c.row < 5){
17101                 return;
17102             }
17103             
17104             var ev = c.events;
17105             
17106             var r = 4;
17107             if(c.row != c.events.length){
17108                 r = 4 - (4 - (c.row - c.events.length));
17109             }
17110             
17111             c.events = ev.slice(0, r);
17112             c.more = ev.slice(r);
17113             
17114             if(c.more.length && c.more.length == 1){
17115                 c.events.push(c.more.pop());
17116             }
17117             
17118             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17119             
17120         });
17121             
17122         this.cells.each(function(c) {
17123             
17124             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17125             
17126             
17127             for (var e = 0; e < c.events.length; e++){
17128                 var ev = c.events[e];
17129                 var rows = ev.rows;
17130                 
17131                 for(var i = 0; i < rows.length; i++) {
17132                 
17133                     // how many rows should it span..
17134
17135                     var  cfg = {
17136                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17137                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17138
17139                         unselectable : "on",
17140                         cn : [
17141                             {
17142                                 cls: 'fc-event-inner',
17143                                 cn : [
17144     //                                {
17145     //                                  tag:'span',
17146     //                                  cls: 'fc-event-time',
17147     //                                  html : cells.length > 1 ? '' : ev.time
17148     //                                },
17149                                     {
17150                                       tag:'span',
17151                                       cls: 'fc-event-title',
17152                                       html : String.format('{0}', ev.title)
17153                                     }
17154
17155
17156                                 ]
17157                             },
17158                             {
17159                                 cls: 'ui-resizable-handle ui-resizable-e',
17160                                 html : '&nbsp;&nbsp;&nbsp'
17161                             }
17162
17163                         ]
17164                     };
17165
17166                     if (i == 0) {
17167                         cfg.cls += ' fc-event-start';
17168                     }
17169                     if ((i+1) == rows.length) {
17170                         cfg.cls += ' fc-event-end';
17171                     }
17172
17173                     var ctr = _this.el.select('.fc-event-container',true).first();
17174                     var cg = ctr.createChild(cfg);
17175
17176                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17177                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17178
17179                     var r = (c.more.length) ? 1 : 0;
17180                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
17181                     cg.setWidth(ebox.right - sbox.x -2);
17182
17183                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17184                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17185                     cg.on('click', _this.onEventClick, _this, ev);
17186
17187                     ev.els.push(cg);
17188                     
17189                 }
17190                 
17191             }
17192             
17193             
17194             if(c.more.length){
17195                 var  cfg = {
17196                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17197                     style : 'position: absolute',
17198                     unselectable : "on",
17199                     cn : [
17200                         {
17201                             cls: 'fc-event-inner',
17202                             cn : [
17203                                 {
17204                                   tag:'span',
17205                                   cls: 'fc-event-title',
17206                                   html : 'More'
17207                                 }
17208
17209
17210                             ]
17211                         },
17212                         {
17213                             cls: 'ui-resizable-handle ui-resizable-e',
17214                             html : '&nbsp;&nbsp;&nbsp'
17215                         }
17216
17217                     ]
17218                 };
17219
17220                 var ctr = _this.el.select('.fc-event-container',true).first();
17221                 var cg = ctr.createChild(cfg);
17222
17223                 var sbox = c.select('.fc-day-content',true).first().getBox();
17224                 var ebox = c.select('.fc-day-content',true).first().getBox();
17225                 //Roo.log(cg);
17226                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
17227                 cg.setWidth(ebox.right - sbox.x -2);
17228
17229                 cg.on('click', _this.onMoreEventClick, _this, c.more);
17230                 
17231             }
17232             
17233         });
17234         
17235         
17236         
17237     },
17238     
17239     onEventEnter: function (e, el,event,d) {
17240         this.fireEvent('evententer', this, el, event);
17241     },
17242     
17243     onEventLeave: function (e, el,event,d) {
17244         this.fireEvent('eventleave', this, el, event);
17245     },
17246     
17247     onEventClick: function (e, el,event,d) {
17248         this.fireEvent('eventclick', this, el, event);
17249     },
17250     
17251     onMonthChange: function () {
17252         this.store.load();
17253     },
17254     
17255     onMoreEventClick: function(e, el, more)
17256     {
17257         var _this = this;
17258         
17259         this.calpopover.placement = 'right';
17260         this.calpopover.setTitle('More');
17261         
17262         this.calpopover.setContent('');
17263         
17264         var ctr = this.calpopover.el.select('.popover-content', true).first();
17265         
17266         Roo.each(more, function(m){
17267             var cfg = {
17268                 cls : 'fc-event-hori fc-event-draggable',
17269                 html : m.title
17270             };
17271             var cg = ctr.createChild(cfg);
17272             
17273             cg.on('click', _this.onEventClick, _this, m);
17274         });
17275         
17276         this.calpopover.show(el);
17277         
17278         
17279     },
17280     
17281     onLoad: function () 
17282     {   
17283         this.calevents = [];
17284         var cal = this;
17285         
17286         if(this.store.getCount() > 0){
17287             this.store.data.each(function(d){
17288                cal.addItem({
17289                     id : d.data.id,
17290                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17291                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17292                     time : d.data.start_time,
17293                     title : d.data.title,
17294                     description : d.data.description,
17295                     venue : d.data.venue
17296                 });
17297             });
17298         }
17299         
17300         this.renderEvents();
17301         
17302         if(this.calevents.length && this.loadMask){
17303             this.maskEl.hide();
17304         }
17305     },
17306     
17307     onBeforeLoad: function()
17308     {
17309         this.clearEvents();
17310         if(this.loadMask){
17311             this.maskEl.show();
17312         }
17313     }
17314 });
17315
17316  
17317  /*
17318  * - LGPL
17319  *
17320  * element
17321  * 
17322  */
17323
17324 /**
17325  * @class Roo.bootstrap.Popover
17326  * @extends Roo.bootstrap.Component
17327  * Bootstrap Popover class
17328  * @cfg {String} html contents of the popover   (or false to use children..)
17329  * @cfg {String} title of popover (or false to hide)
17330  * @cfg {String} placement how it is placed
17331  * @cfg {String} trigger click || hover (or false to trigger manually)
17332  * @cfg {String} over what (parent or false to trigger manually.)
17333  * @cfg {Number} delay - delay before showing
17334  
17335  * @constructor
17336  * Create a new Popover
17337  * @param {Object} config The config object
17338  */
17339
17340 Roo.bootstrap.Popover = function(config){
17341     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17342     
17343     this.addEvents({
17344         // raw events
17345          /**
17346          * @event show
17347          * After the popover show
17348          * 
17349          * @param {Roo.bootstrap.Popover} this
17350          */
17351         "show" : true,
17352         /**
17353          * @event hide
17354          * After the popover hide
17355          * 
17356          * @param {Roo.bootstrap.Popover} this
17357          */
17358         "hide" : true
17359     });
17360 };
17361
17362 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
17363     
17364     title: 'Fill in a title',
17365     html: false,
17366     
17367     placement : 'right',
17368     trigger : 'hover', // hover
17369     
17370     delay : 0,
17371     
17372     over: 'parent',
17373     
17374     can_build_overlaid : false,
17375     
17376     getChildContainer : function()
17377     {
17378         return this.el.select('.popover-content',true).first();
17379     },
17380     
17381     getAutoCreate : function(){
17382          
17383         var cfg = {
17384            cls : 'popover roo-dynamic',
17385            style: 'display:block',
17386            cn : [
17387                 {
17388                     cls : 'arrow'
17389                 },
17390                 {
17391                     cls : 'popover-inner',
17392                     cn : [
17393                         {
17394                             tag: 'h3',
17395                             cls: 'popover-title',
17396                             html : this.title
17397                         },
17398                         {
17399                             cls : 'popover-content',
17400                             html : this.html
17401                         }
17402                     ]
17403                     
17404                 }
17405            ]
17406         };
17407         
17408         return cfg;
17409     },
17410     setTitle: function(str)
17411     {
17412         this.title = str;
17413         this.el.select('.popover-title',true).first().dom.innerHTML = str;
17414     },
17415     setContent: function(str)
17416     {
17417         this.html = str;
17418         this.el.select('.popover-content',true).first().dom.innerHTML = str;
17419     },
17420     // as it get's added to the bottom of the page.
17421     onRender : function(ct, position)
17422     {
17423         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17424         if(!this.el){
17425             var cfg = Roo.apply({},  this.getAutoCreate());
17426             cfg.id = Roo.id();
17427             
17428             if (this.cls) {
17429                 cfg.cls += ' ' + this.cls;
17430             }
17431             if (this.style) {
17432                 cfg.style = this.style;
17433             }
17434             //Roo.log("adding to ");
17435             this.el = Roo.get(document.body).createChild(cfg, position);
17436 //            Roo.log(this.el);
17437         }
17438         this.initEvents();
17439     },
17440     
17441     initEvents : function()
17442     {
17443         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17444         this.el.enableDisplayMode('block');
17445         this.el.hide();
17446         if (this.over === false) {
17447             return; 
17448         }
17449         if (this.triggers === false) {
17450             return;
17451         }
17452         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17453         var triggers = this.trigger ? this.trigger.split(' ') : [];
17454         Roo.each(triggers, function(trigger) {
17455         
17456             if (trigger == 'click') {
17457                 on_el.on('click', this.toggle, this);
17458             } else if (trigger != 'manual') {
17459                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
17460                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17461       
17462                 on_el.on(eventIn  ,this.enter, this);
17463                 on_el.on(eventOut, this.leave, this);
17464             }
17465         }, this);
17466         
17467     },
17468     
17469     
17470     // private
17471     timeout : null,
17472     hoverState : null,
17473     
17474     toggle : function () {
17475         this.hoverState == 'in' ? this.leave() : this.enter();
17476     },
17477     
17478     enter : function () {
17479         
17480         clearTimeout(this.timeout);
17481     
17482         this.hoverState = 'in';
17483     
17484         if (!this.delay || !this.delay.show) {
17485             this.show();
17486             return;
17487         }
17488         var _t = this;
17489         this.timeout = setTimeout(function () {
17490             if (_t.hoverState == 'in') {
17491                 _t.show();
17492             }
17493         }, this.delay.show)
17494     },
17495     
17496     leave : function() {
17497         clearTimeout(this.timeout);
17498     
17499         this.hoverState = 'out';
17500     
17501         if (!this.delay || !this.delay.hide) {
17502             this.hide();
17503             return;
17504         }
17505         var _t = this;
17506         this.timeout = setTimeout(function () {
17507             if (_t.hoverState == 'out') {
17508                 _t.hide();
17509             }
17510         }, this.delay.hide)
17511     },
17512     
17513     show : function (on_el)
17514     {
17515         if (!on_el) {
17516             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17517         }
17518         
17519         // set content.
17520         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17521         if (this.html !== false) {
17522             this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17523         }
17524         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17525         if (!this.title.length) {
17526             this.el.select('.popover-title',true).hide();
17527         }
17528         
17529         var placement = typeof this.placement == 'function' ?
17530             this.placement.call(this, this.el, on_el) :
17531             this.placement;
17532             
17533         var autoToken = /\s?auto?\s?/i;
17534         var autoPlace = autoToken.test(placement);
17535         if (autoPlace) {
17536             placement = placement.replace(autoToken, '') || 'top';
17537         }
17538         
17539         //this.el.detach()
17540         //this.el.setXY([0,0]);
17541         this.el.show();
17542         this.el.dom.style.display='block';
17543         this.el.addClass(placement);
17544         
17545         //this.el.appendTo(on_el);
17546         
17547         var p = this.getPosition();
17548         var box = this.el.getBox();
17549         
17550         if (autoPlace) {
17551             // fixme..
17552         }
17553         var align = Roo.bootstrap.Popover.alignment[placement];
17554         
17555 //        Roo.log(align);
17556         this.el.alignTo(on_el, align[0],align[1]);
17557         //var arrow = this.el.select('.arrow',true).first();
17558         //arrow.set(align[2], 
17559         
17560         this.el.addClass('in');
17561         
17562         
17563         if (this.el.hasClass('fade')) {
17564             // fade it?
17565         }
17566         
17567         this.hoverState = 'in';
17568         
17569         this.fireEvent('show', this);
17570         
17571     },
17572     hide : function()
17573     {
17574         this.el.setXY([0,0]);
17575         this.el.removeClass('in');
17576         this.el.hide();
17577         this.hoverState = null;
17578         
17579         this.fireEvent('hide', this);
17580     }
17581     
17582 });
17583
17584 Roo.bootstrap.Popover.alignment = {
17585     'left' : ['r-l', [-10,0], 'right'],
17586     'right' : ['l-r', [10,0], 'left'],
17587     'bottom' : ['t-b', [0,10], 'top'],
17588     'top' : [ 'b-t', [0,-10], 'bottom']
17589 };
17590
17591  /*
17592  * - LGPL
17593  *
17594  * Progress
17595  * 
17596  */
17597
17598 /**
17599  * @class Roo.bootstrap.Progress
17600  * @extends Roo.bootstrap.Component
17601  * Bootstrap Progress class
17602  * @cfg {Boolean} striped striped of the progress bar
17603  * @cfg {Boolean} active animated of the progress bar
17604  * 
17605  * 
17606  * @constructor
17607  * Create a new Progress
17608  * @param {Object} config The config object
17609  */
17610
17611 Roo.bootstrap.Progress = function(config){
17612     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17613 };
17614
17615 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
17616     
17617     striped : false,
17618     active: false,
17619     
17620     getAutoCreate : function(){
17621         var cfg = {
17622             tag: 'div',
17623             cls: 'progress'
17624         };
17625         
17626         
17627         if(this.striped){
17628             cfg.cls += ' progress-striped';
17629         }
17630       
17631         if(this.active){
17632             cfg.cls += ' active';
17633         }
17634         
17635         
17636         return cfg;
17637     }
17638    
17639 });
17640
17641  
17642
17643  /*
17644  * - LGPL
17645  *
17646  * ProgressBar
17647  * 
17648  */
17649
17650 /**
17651  * @class Roo.bootstrap.ProgressBar
17652  * @extends Roo.bootstrap.Component
17653  * Bootstrap ProgressBar class
17654  * @cfg {Number} aria_valuenow aria-value now
17655  * @cfg {Number} aria_valuemin aria-value min
17656  * @cfg {Number} aria_valuemax aria-value max
17657  * @cfg {String} label label for the progress bar
17658  * @cfg {String} panel (success | info | warning | danger )
17659  * @cfg {String} role role of the progress bar
17660  * @cfg {String} sr_only text
17661  * 
17662  * 
17663  * @constructor
17664  * Create a new ProgressBar
17665  * @param {Object} config The config object
17666  */
17667
17668 Roo.bootstrap.ProgressBar = function(config){
17669     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17670 };
17671
17672 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
17673     
17674     aria_valuenow : 0,
17675     aria_valuemin : 0,
17676     aria_valuemax : 100,
17677     label : false,
17678     panel : false,
17679     role : false,
17680     sr_only: false,
17681     
17682     getAutoCreate : function()
17683     {
17684         
17685         var cfg = {
17686             tag: 'div',
17687             cls: 'progress-bar',
17688             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17689         };
17690         
17691         if(this.sr_only){
17692             cfg.cn = {
17693                 tag: 'span',
17694                 cls: 'sr-only',
17695                 html: this.sr_only
17696             }
17697         }
17698         
17699         if(this.role){
17700             cfg.role = this.role;
17701         }
17702         
17703         if(this.aria_valuenow){
17704             cfg['aria-valuenow'] = this.aria_valuenow;
17705         }
17706         
17707         if(this.aria_valuemin){
17708             cfg['aria-valuemin'] = this.aria_valuemin;
17709         }
17710         
17711         if(this.aria_valuemax){
17712             cfg['aria-valuemax'] = this.aria_valuemax;
17713         }
17714         
17715         if(this.label && !this.sr_only){
17716             cfg.html = this.label;
17717         }
17718         
17719         if(this.panel){
17720             cfg.cls += ' progress-bar-' + this.panel;
17721         }
17722         
17723         return cfg;
17724     },
17725     
17726     update : function(aria_valuenow)
17727     {
17728         this.aria_valuenow = aria_valuenow;
17729         
17730         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17731     }
17732    
17733 });
17734
17735  
17736
17737  /*
17738  * - LGPL
17739  *
17740  * column
17741  * 
17742  */
17743
17744 /**
17745  * @class Roo.bootstrap.TabGroup
17746  * @extends Roo.bootstrap.Column
17747  * Bootstrap Column class
17748  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17749  * @cfg {Boolean} carousel true to make the group behave like a carousel
17750  * @cfg {Boolean} bullets show bullets for the panels
17751  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17752  * @cfg {Number} timer auto slide timer .. default 0 millisecond
17753  * @cfg {Boolean} showarrow (true|false) show arrow default true
17754  * 
17755  * @constructor
17756  * Create a new TabGroup
17757  * @param {Object} config The config object
17758  */
17759
17760 Roo.bootstrap.TabGroup = function(config){
17761     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17762     if (!this.navId) {
17763         this.navId = Roo.id();
17764     }
17765     this.tabs = [];
17766     Roo.bootstrap.TabGroup.register(this);
17767     
17768 };
17769
17770 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
17771     
17772     carousel : false,
17773     transition : false,
17774     bullets : 0,
17775     timer : 0,
17776     autoslide : false,
17777     slideFn : false,
17778     slideOnTouch : false,
17779     showarrow : true,
17780     
17781     getAutoCreate : function()
17782     {
17783         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17784         
17785         cfg.cls += ' tab-content';
17786         
17787         if (this.carousel) {
17788             cfg.cls += ' carousel slide';
17789             
17790             cfg.cn = [{
17791                cls : 'carousel-inner',
17792                cn : []
17793             }];
17794         
17795             if(this.bullets  && !Roo.isTouch){
17796                 
17797                 var bullets = {
17798                     cls : 'carousel-bullets',
17799                     cn : []
17800                 };
17801                
17802                 if(this.bullets_cls){
17803                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17804                 }
17805                 
17806                 bullets.cn.push({
17807                     cls : 'clear'
17808                 });
17809                 
17810                 cfg.cn[0].cn.push(bullets);
17811             }
17812             
17813             if(this.showarrow){
17814                 cfg.cn[0].cn.push({
17815                     tag : 'div',
17816                     class : 'carousel-arrow',
17817                     cn : [
17818                         {
17819                             tag : 'div',
17820                             class : 'carousel-prev',
17821                             cn : [
17822                                 {
17823                                     tag : 'i',
17824                                     class : 'fa fa-chevron-left'
17825                                 }
17826                             ]
17827                         },
17828                         {
17829                             tag : 'div',
17830                             class : 'carousel-next',
17831                             cn : [
17832                                 {
17833                                     tag : 'i',
17834                                     class : 'fa fa-chevron-right'
17835                                 }
17836                             ]
17837                         }
17838                     ]
17839                 });
17840             }
17841             
17842         }
17843         
17844         return cfg;
17845     },
17846     
17847     initEvents:  function()
17848     {
17849 //        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17850 //            this.el.on("touchstart", this.onTouchStart, this);
17851 //        }
17852         
17853         if(this.autoslide){
17854             var _this = this;
17855             
17856             this.slideFn = window.setInterval(function() {
17857                 _this.showPanelNext();
17858             }, this.timer);
17859         }
17860         
17861         if(this.showarrow){
17862             this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17863             this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17864         }
17865         
17866         
17867     },
17868     
17869 //    onTouchStart : function(e, el, o)
17870 //    {
17871 //        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17872 //            return;
17873 //        }
17874 //        
17875 //        this.showPanelNext();
17876 //    },
17877     
17878     
17879     getChildContainer : function()
17880     {
17881         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17882     },
17883     
17884     /**
17885     * register a Navigation item
17886     * @param {Roo.bootstrap.NavItem} the navitem to add
17887     */
17888     register : function(item)
17889     {
17890         this.tabs.push( item);
17891         item.navId = this.navId; // not really needed..
17892         this.addBullet();
17893     
17894     },
17895     
17896     getActivePanel : function()
17897     {
17898         var r = false;
17899         Roo.each(this.tabs, function(t) {
17900             if (t.active) {
17901                 r = t;
17902                 return false;
17903             }
17904             return null;
17905         });
17906         return r;
17907         
17908     },
17909     getPanelByName : function(n)
17910     {
17911         var r = false;
17912         Roo.each(this.tabs, function(t) {
17913             if (t.tabId == n) {
17914                 r = t;
17915                 return false;
17916             }
17917             return null;
17918         });
17919         return r;
17920     },
17921     indexOfPanel : function(p)
17922     {
17923         var r = false;
17924         Roo.each(this.tabs, function(t,i) {
17925             if (t.tabId == p.tabId) {
17926                 r = i;
17927                 return false;
17928             }
17929             return null;
17930         });
17931         return r;
17932     },
17933     /**
17934      * show a specific panel
17935      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17936      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17937      */
17938     showPanel : function (pan)
17939     {
17940         if(this.transition || typeof(pan) == 'undefined'){
17941             Roo.log("waiting for the transitionend");
17942             return;
17943         }
17944         
17945         if (typeof(pan) == 'number') {
17946             pan = this.tabs[pan];
17947         }
17948         
17949         if (typeof(pan) == 'string') {
17950             pan = this.getPanelByName(pan);
17951         }
17952         
17953         var cur = this.getActivePanel();
17954         
17955         if(!pan || !cur){
17956             Roo.log('pan or acitve pan is undefined');
17957             return false;
17958         }
17959         
17960         if (pan.tabId == this.getActivePanel().tabId) {
17961             return true;
17962         }
17963         
17964         if (false === cur.fireEvent('beforedeactivate')) {
17965             return false;
17966         }
17967         
17968         if(this.bullets > 0 && !Roo.isTouch){
17969             this.setActiveBullet(this.indexOfPanel(pan));
17970         }
17971         
17972         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17973             
17974             this.transition = true;
17975             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
17976             var lr = dir == 'next' ? 'left' : 'right';
17977             pan.el.addClass(dir); // or prev
17978             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17979             cur.el.addClass(lr); // or right
17980             pan.el.addClass(lr);
17981             
17982             var _this = this;
17983             cur.el.on('transitionend', function() {
17984                 Roo.log("trans end?");
17985                 
17986                 pan.el.removeClass([lr,dir]);
17987                 pan.setActive(true);
17988                 
17989                 cur.el.removeClass([lr]);
17990                 cur.setActive(false);
17991                 
17992                 _this.transition = false;
17993                 
17994             }, this, { single:  true } );
17995             
17996             return true;
17997         }
17998         
17999         cur.setActive(false);
18000         pan.setActive(true);
18001         
18002         return true;
18003         
18004     },
18005     showPanelNext : function()
18006     {
18007         var i = this.indexOfPanel(this.getActivePanel());
18008         
18009         if (i >= this.tabs.length - 1 && !this.autoslide) {
18010             return;
18011         }
18012         
18013         if (i >= this.tabs.length - 1 && this.autoslide) {
18014             i = -1;
18015         }
18016         
18017         this.showPanel(this.tabs[i+1]);
18018     },
18019     
18020     showPanelPrev : function()
18021     {
18022         var i = this.indexOfPanel(this.getActivePanel());
18023         
18024         if (i  < 1 && !this.autoslide) {
18025             return;
18026         }
18027         
18028         if (i < 1 && this.autoslide) {
18029             i = this.tabs.length;
18030         }
18031         
18032         this.showPanel(this.tabs[i-1]);
18033     },
18034     
18035     
18036     addBullet: function()
18037     {
18038         if(!this.bullets || Roo.isTouch){
18039             return;
18040         }
18041         var ctr = this.el.select('.carousel-bullets',true).first();
18042         var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18043         var bullet = ctr.createChild({
18044             cls : 'bullet bullet-' + i
18045         },ctr.dom.lastChild);
18046         
18047         
18048         var _this = this;
18049         
18050         bullet.on('click', (function(e, el, o, ii, t){
18051
18052             e.preventDefault();
18053
18054             this.showPanel(ii);
18055
18056             if(this.autoslide && this.slideFn){
18057                 clearInterval(this.slideFn);
18058                 this.slideFn = window.setInterval(function() {
18059                     _this.showPanelNext();
18060                 }, this.timer);
18061             }
18062
18063         }).createDelegate(this, [i, bullet], true));
18064                 
18065         
18066     },
18067      
18068     setActiveBullet : function(i)
18069     {
18070         if(Roo.isTouch){
18071             return;
18072         }
18073         
18074         Roo.each(this.el.select('.bullet', true).elements, function(el){
18075             el.removeClass('selected');
18076         });
18077
18078         var bullet = this.el.select('.bullet-' + i, true).first();
18079         
18080         if(!bullet){
18081             return;
18082         }
18083         
18084         bullet.addClass('selected');
18085     }
18086     
18087     
18088   
18089 });
18090
18091  
18092
18093  
18094  
18095 Roo.apply(Roo.bootstrap.TabGroup, {
18096     
18097     groups: {},
18098      /**
18099     * register a Navigation Group
18100     * @param {Roo.bootstrap.NavGroup} the navgroup to add
18101     */
18102     register : function(navgrp)
18103     {
18104         this.groups[navgrp.navId] = navgrp;
18105         
18106     },
18107     /**
18108     * fetch a Navigation Group based on the navigation ID
18109     * if one does not exist , it will get created.
18110     * @param {string} the navgroup to add
18111     * @returns {Roo.bootstrap.NavGroup} the navgroup 
18112     */
18113     get: function(navId) {
18114         if (typeof(this.groups[navId]) == 'undefined') {
18115             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18116         }
18117         return this.groups[navId] ;
18118     }
18119     
18120     
18121     
18122 });
18123
18124  /*
18125  * - LGPL
18126  *
18127  * TabPanel
18128  * 
18129  */
18130
18131 /**
18132  * @class Roo.bootstrap.TabPanel
18133  * @extends Roo.bootstrap.Component
18134  * Bootstrap TabPanel class
18135  * @cfg {Boolean} active panel active
18136  * @cfg {String} html panel content
18137  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18138  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18139  * @cfg {String} href click to link..
18140  * 
18141  * 
18142  * @constructor
18143  * Create a new TabPanel
18144  * @param {Object} config The config object
18145  */
18146
18147 Roo.bootstrap.TabPanel = function(config){
18148     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18149     this.addEvents({
18150         /**
18151              * @event changed
18152              * Fires when the active status changes
18153              * @param {Roo.bootstrap.TabPanel} this
18154              * @param {Boolean} state the new state
18155             
18156          */
18157         'changed': true,
18158         /**
18159              * @event beforedeactivate
18160              * Fires before a tab is de-activated - can be used to do validation on a form.
18161              * @param {Roo.bootstrap.TabPanel} this
18162              * @return {Boolean} false if there is an error
18163             
18164          */
18165         'beforedeactivate': true
18166      });
18167     
18168     this.tabId = this.tabId || Roo.id();
18169   
18170 };
18171
18172 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
18173     
18174     active: false,
18175     html: false,
18176     tabId: false,
18177     navId : false,
18178     href : '',
18179     
18180     getAutoCreate : function(){
18181         var cfg = {
18182             tag: 'div',
18183             // item is needed for carousel - not sure if it has any effect otherwise
18184             cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18185             html: this.html || ''
18186         };
18187         
18188         if(this.active){
18189             cfg.cls += ' active';
18190         }
18191         
18192         if(this.tabId){
18193             cfg.tabId = this.tabId;
18194         }
18195         
18196         
18197         return cfg;
18198     },
18199     
18200     initEvents:  function()
18201     {
18202         var p = this.parent();
18203         
18204         this.navId = this.navId || p.navId;
18205         
18206         if (typeof(this.navId) != 'undefined') {
18207             // not really needed.. but just in case.. parent should be a NavGroup.
18208             var tg = Roo.bootstrap.TabGroup.get(this.navId);
18209             
18210             tg.register(this);
18211             
18212             var i = tg.tabs.length - 1;
18213             
18214             if(this.active && tg.bullets > 0 && i < tg.bullets){
18215                 tg.setActiveBullet(i);
18216             }
18217         }
18218         
18219         this.el.on('click', this.onClick, this);
18220         
18221         if(Roo.isTouch){
18222             this.el.on("touchstart", this.onTouchStart, this);
18223             this.el.on("touchmove", this.onTouchMove, this);
18224             this.el.on("touchend", this.onTouchEnd, this);
18225         }
18226         
18227     },
18228     
18229     onRender : function(ct, position)
18230     {
18231         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18232     },
18233     
18234     setActive : function(state)
18235     {
18236         Roo.log("panel - set active " + this.tabId + "=" + state);
18237         
18238         this.active = state;
18239         if (!state) {
18240             this.el.removeClass('active');
18241             
18242         } else  if (!this.el.hasClass('active')) {
18243             this.el.addClass('active');
18244         }
18245         
18246         this.fireEvent('changed', this, state);
18247     },
18248     
18249     onClick : function(e)
18250     {
18251         e.preventDefault();
18252         
18253         if(!this.href.length){
18254             return;
18255         }
18256         
18257         window.location.href = this.href;
18258     },
18259     
18260     startX : 0,
18261     startY : 0,
18262     endX : 0,
18263     endY : 0,
18264     swiping : false,
18265     
18266     onTouchStart : function(e)
18267     {
18268         this.swiping = false;
18269         
18270         this.startX = e.browserEvent.touches[0].clientX;
18271         this.startY = e.browserEvent.touches[0].clientY;
18272     },
18273     
18274     onTouchMove : function(e)
18275     {
18276         this.swiping = true;
18277         
18278         this.endX = e.browserEvent.touches[0].clientX;
18279         this.endY = e.browserEvent.touches[0].clientY;
18280     },
18281     
18282     onTouchEnd : function(e)
18283     {
18284         if(!this.swiping){
18285             this.onClick(e);
18286             return;
18287         }
18288         
18289         var tabGroup = this.parent();
18290         
18291         if(this.endX > this.startX){ // swiping right
18292             tabGroup.showPanelPrev();
18293             return;
18294         }
18295         
18296         if(this.startX > this.endX){ // swiping left
18297             tabGroup.showPanelNext();
18298             return;
18299         }
18300     }
18301     
18302     
18303 });
18304  
18305
18306  
18307
18308  /*
18309  * - LGPL
18310  *
18311  * DateField
18312  * 
18313  */
18314
18315 /**
18316  * @class Roo.bootstrap.DateField
18317  * @extends Roo.bootstrap.Input
18318  * Bootstrap DateField class
18319  * @cfg {Number} weekStart default 0
18320  * @cfg {String} viewMode default empty, (months|years)
18321  * @cfg {String} minViewMode default empty, (months|years)
18322  * @cfg {Number} startDate default -Infinity
18323  * @cfg {Number} endDate default Infinity
18324  * @cfg {Boolean} todayHighlight default false
18325  * @cfg {Boolean} todayBtn default false
18326  * @cfg {Boolean} calendarWeeks default false
18327  * @cfg {Object} daysOfWeekDisabled default empty
18328  * @cfg {Boolean} singleMode default false (true | false)
18329  * 
18330  * @cfg {Boolean} keyboardNavigation default true
18331  * @cfg {String} language default en
18332  * 
18333  * @constructor
18334  * Create a new DateField
18335  * @param {Object} config The config object
18336  */
18337
18338 Roo.bootstrap.DateField = function(config){
18339     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18340      this.addEvents({
18341             /**
18342              * @event show
18343              * Fires when this field show.
18344              * @param {Roo.bootstrap.DateField} this
18345              * @param {Mixed} date The date value
18346              */
18347             show : true,
18348             /**
18349              * @event show
18350              * Fires when this field hide.
18351              * @param {Roo.bootstrap.DateField} this
18352              * @param {Mixed} date The date value
18353              */
18354             hide : true,
18355             /**
18356              * @event select
18357              * Fires when select a date.
18358              * @param {Roo.bootstrap.DateField} this
18359              * @param {Mixed} date The date value
18360              */
18361             select : true,
18362             /**
18363              * @event beforeselect
18364              * Fires when before select a date.
18365              * @param {Roo.bootstrap.DateField} this
18366              * @param {Mixed} date The date value
18367              */
18368             beforeselect : true
18369         });
18370 };
18371
18372 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
18373     
18374     /**
18375      * @cfg {String} format
18376      * The default date format string which can be overriden for localization support.  The format must be
18377      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18378      */
18379     format : "m/d/y",
18380     /**
18381      * @cfg {String} altFormats
18382      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18383      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18384      */
18385     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18386     
18387     weekStart : 0,
18388     
18389     viewMode : '',
18390     
18391     minViewMode : '',
18392     
18393     todayHighlight : false,
18394     
18395     todayBtn: false,
18396     
18397     language: 'en',
18398     
18399     keyboardNavigation: true,
18400     
18401     calendarWeeks: false,
18402     
18403     startDate: -Infinity,
18404     
18405     endDate: Infinity,
18406     
18407     daysOfWeekDisabled: [],
18408     
18409     _events: [],
18410     
18411     singleMode : false,
18412     
18413     UTCDate: function()
18414     {
18415         return new Date(Date.UTC.apply(Date, arguments));
18416     },
18417     
18418     UTCToday: function()
18419     {
18420         var today = new Date();
18421         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18422     },
18423     
18424     getDate: function() {
18425             var d = this.getUTCDate();
18426             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18427     },
18428     
18429     getUTCDate: function() {
18430             return this.date;
18431     },
18432     
18433     setDate: function(d) {
18434             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18435     },
18436     
18437     setUTCDate: function(d) {
18438             this.date = d;
18439             this.setValue(this.formatDate(this.date));
18440     },
18441         
18442     onRender: function(ct, position)
18443     {
18444         
18445         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18446         
18447         this.language = this.language || 'en';
18448         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18449         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18450         
18451         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18452         this.format = this.format || 'm/d/y';
18453         this.isInline = false;
18454         this.isInput = true;
18455         this.component = this.el.select('.add-on', true).first() || false;
18456         this.component = (this.component && this.component.length === 0) ? false : this.component;
18457         this.hasInput = this.component && this.inputEl().length;
18458         
18459         if (typeof(this.minViewMode === 'string')) {
18460             switch (this.minViewMode) {
18461                 case 'months':
18462                     this.minViewMode = 1;
18463                     break;
18464                 case 'years':
18465                     this.minViewMode = 2;
18466                     break;
18467                 default:
18468                     this.minViewMode = 0;
18469                     break;
18470             }
18471         }
18472         
18473         if (typeof(this.viewMode === 'string')) {
18474             switch (this.viewMode) {
18475                 case 'months':
18476                     this.viewMode = 1;
18477                     break;
18478                 case 'years':
18479                     this.viewMode = 2;
18480                     break;
18481                 default:
18482                     this.viewMode = 0;
18483                     break;
18484             }
18485         }
18486                 
18487         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18488         
18489 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18490         
18491         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18492         
18493         this.picker().on('mousedown', this.onMousedown, this);
18494         this.picker().on('click', this.onClick, this);
18495         
18496         this.picker().addClass('datepicker-dropdown');
18497         
18498         this.startViewMode = this.viewMode;
18499         
18500         if(this.singleMode){
18501             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18502                 v.setVisibilityMode(Roo.Element.DISPLAY);
18503                 v.hide();
18504             });
18505             
18506             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18507                 v.setStyle('width', '189px');
18508             });
18509         }
18510         
18511         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18512             if(!this.calendarWeeks){
18513                 v.remove();
18514                 return;
18515             }
18516             
18517             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18518             v.attr('colspan', function(i, val){
18519                 return parseInt(val) + 1;
18520             });
18521         });
18522                         
18523         
18524         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18525         
18526         this.setStartDate(this.startDate);
18527         this.setEndDate(this.endDate);
18528         
18529         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18530         
18531         this.fillDow();
18532         this.fillMonths();
18533         this.update();
18534         this.showMode();
18535         
18536         if(this.isInline) {
18537             this.show();
18538         }
18539     },
18540     
18541     picker : function()
18542     {
18543         return this.pickerEl;
18544 //        return this.el.select('.datepicker', true).first();
18545     },
18546     
18547     fillDow: function()
18548     {
18549         var dowCnt = this.weekStart;
18550         
18551         var dow = {
18552             tag: 'tr',
18553             cn: [
18554                 
18555             ]
18556         };
18557         
18558         if(this.calendarWeeks){
18559             dow.cn.push({
18560                 tag: 'th',
18561                 cls: 'cw',
18562                 html: '&nbsp;'
18563             })
18564         }
18565         
18566         while (dowCnt < this.weekStart + 7) {
18567             dow.cn.push({
18568                 tag: 'th',
18569                 cls: 'dow',
18570                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18571             });
18572         }
18573         
18574         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18575     },
18576     
18577     fillMonths: function()
18578     {    
18579         var i = 0;
18580         var months = this.picker().select('>.datepicker-months td', true).first();
18581         
18582         months.dom.innerHTML = '';
18583         
18584         while (i < 12) {
18585             var month = {
18586                 tag: 'span',
18587                 cls: 'month',
18588                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18589             };
18590             
18591             months.createChild(month);
18592         }
18593         
18594     },
18595     
18596     update: function()
18597     {
18598         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;
18599         
18600         if (this.date < this.startDate) {
18601             this.viewDate = new Date(this.startDate);
18602         } else if (this.date > this.endDate) {
18603             this.viewDate = new Date(this.endDate);
18604         } else {
18605             this.viewDate = new Date(this.date);
18606         }
18607         
18608         this.fill();
18609     },
18610     
18611     fill: function() 
18612     {
18613         var d = new Date(this.viewDate),
18614                 year = d.getUTCFullYear(),
18615                 month = d.getUTCMonth(),
18616                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18617                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18618                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18619                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18620                 currentDate = this.date && this.date.valueOf(),
18621                 today = this.UTCToday();
18622         
18623         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18624         
18625 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18626         
18627 //        this.picker.select('>tfoot th.today').
18628 //                                              .text(dates[this.language].today)
18629 //                                              .toggle(this.todayBtn !== false);
18630     
18631         this.updateNavArrows();
18632         this.fillMonths();
18633                                                 
18634         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18635         
18636         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18637          
18638         prevMonth.setUTCDate(day);
18639         
18640         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18641         
18642         var nextMonth = new Date(prevMonth);
18643         
18644         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18645         
18646         nextMonth = nextMonth.valueOf();
18647         
18648         var fillMonths = false;
18649         
18650         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18651         
18652         while(prevMonth.valueOf() < nextMonth) {
18653             var clsName = '';
18654             
18655             if (prevMonth.getUTCDay() === this.weekStart) {
18656                 if(fillMonths){
18657                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18658                 }
18659                     
18660                 fillMonths = {
18661                     tag: 'tr',
18662                     cn: []
18663                 };
18664                 
18665                 if(this.calendarWeeks){
18666                     // ISO 8601: First week contains first thursday.
18667                     // ISO also states week starts on Monday, but we can be more abstract here.
18668                     var
18669                     // Start of current week: based on weekstart/current date
18670                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18671                     // Thursday of this week
18672                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18673                     // First Thursday of year, year from thursday
18674                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18675                     // Calendar week: ms between thursdays, div ms per day, div 7 days
18676                     calWeek =  (th - yth) / 864e5 / 7 + 1;
18677                     
18678                     fillMonths.cn.push({
18679                         tag: 'td',
18680                         cls: 'cw',
18681                         html: calWeek
18682                     });
18683                 }
18684             }
18685             
18686             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18687                 clsName += ' old';
18688             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18689                 clsName += ' new';
18690             }
18691             if (this.todayHighlight &&
18692                 prevMonth.getUTCFullYear() == today.getFullYear() &&
18693                 prevMonth.getUTCMonth() == today.getMonth() &&
18694                 prevMonth.getUTCDate() == today.getDate()) {
18695                 clsName += ' today';
18696             }
18697             
18698             if (currentDate && prevMonth.valueOf() === currentDate) {
18699                 clsName += ' active';
18700             }
18701             
18702             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18703                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18704                     clsName += ' disabled';
18705             }
18706             
18707             fillMonths.cn.push({
18708                 tag: 'td',
18709                 cls: 'day ' + clsName,
18710                 html: prevMonth.getDate()
18711             });
18712             
18713             prevMonth.setDate(prevMonth.getDate()+1);
18714         }
18715           
18716         var currentYear = this.date && this.date.getUTCFullYear();
18717         var currentMonth = this.date && this.date.getUTCMonth();
18718         
18719         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18720         
18721         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18722             v.removeClass('active');
18723             
18724             if(currentYear === year && k === currentMonth){
18725                 v.addClass('active');
18726             }
18727             
18728             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18729                 v.addClass('disabled');
18730             }
18731             
18732         });
18733         
18734         
18735         year = parseInt(year/10, 10) * 10;
18736         
18737         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18738         
18739         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18740         
18741         year -= 1;
18742         for (var i = -1; i < 11; i++) {
18743             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18744                 tag: 'span',
18745                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18746                 html: year
18747             });
18748             
18749             year += 1;
18750         }
18751     },
18752     
18753     showMode: function(dir) 
18754     {
18755         if (dir) {
18756             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18757         }
18758         
18759         Roo.each(this.picker().select('>div',true).elements, function(v){
18760             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18761             v.hide();
18762         });
18763         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18764     },
18765     
18766     place: function()
18767     {
18768         if(this.isInline) {
18769             return;
18770         }
18771         
18772         this.picker().removeClass(['bottom', 'top']);
18773         
18774         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18775             /*
18776              * place to the top of element!
18777              *
18778              */
18779             
18780             this.picker().addClass('top');
18781             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18782             
18783             return;
18784         }
18785         
18786         this.picker().addClass('bottom');
18787         
18788         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18789     },
18790     
18791     parseDate : function(value)
18792     {
18793         if(!value || value instanceof Date){
18794             return value;
18795         }
18796         var v = Date.parseDate(value, this.format);
18797         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18798             v = Date.parseDate(value, 'Y-m-d');
18799         }
18800         if(!v && this.altFormats){
18801             if(!this.altFormatsArray){
18802                 this.altFormatsArray = this.altFormats.split("|");
18803             }
18804             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18805                 v = Date.parseDate(value, this.altFormatsArray[i]);
18806             }
18807         }
18808         return v;
18809     },
18810     
18811     formatDate : function(date, fmt)
18812     {   
18813         return (!date || !(date instanceof Date)) ?
18814         date : date.dateFormat(fmt || this.format);
18815     },
18816     
18817     onFocus : function()
18818     {
18819         Roo.bootstrap.DateField.superclass.onFocus.call(this);
18820         this.show();
18821     },
18822     
18823     onBlur : function()
18824     {
18825         Roo.bootstrap.DateField.superclass.onBlur.call(this);
18826         
18827         var d = this.inputEl().getValue();
18828         
18829         this.setValue(d);
18830                 
18831         this.hide();
18832     },
18833     
18834     show : function()
18835     {
18836         this.picker().show();
18837         this.update();
18838         this.place();
18839         
18840         this.fireEvent('show', this, this.date);
18841     },
18842     
18843     hide : function()
18844     {
18845         if(this.isInline) {
18846             return;
18847         }
18848         this.picker().hide();
18849         this.viewMode = this.startViewMode;
18850         this.showMode();
18851         
18852         this.fireEvent('hide', this, this.date);
18853         
18854     },
18855     
18856     onMousedown: function(e)
18857     {
18858         e.stopPropagation();
18859         e.preventDefault();
18860     },
18861     
18862     keyup: function(e)
18863     {
18864         Roo.bootstrap.DateField.superclass.keyup.call(this);
18865         this.update();
18866     },
18867
18868     setValue: function(v)
18869     {
18870         if(this.fireEvent('beforeselect', this, v) !== false){
18871             var d = new Date(this.parseDate(v) ).clearTime();
18872         
18873             if(isNaN(d.getTime())){
18874                 this.date = this.viewDate = '';
18875                 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18876                 return;
18877             }
18878
18879             v = this.formatDate(d);
18880
18881             Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18882
18883             this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18884
18885             this.update();
18886
18887             this.fireEvent('select', this, this.date);
18888         }
18889     },
18890     
18891     getValue: function()
18892     {
18893         return this.formatDate(this.date);
18894     },
18895     
18896     fireKey: function(e)
18897     {
18898         if (!this.picker().isVisible()){
18899             if (e.keyCode == 27) { // allow escape to hide and re-show picker
18900                 this.show();
18901             }
18902             return;
18903         }
18904         
18905         var dateChanged = false,
18906         dir, day, month,
18907         newDate, newViewDate;
18908         
18909         switch(e.keyCode){
18910             case 27: // escape
18911                 this.hide();
18912                 e.preventDefault();
18913                 break;
18914             case 37: // left
18915             case 39: // right
18916                 if (!this.keyboardNavigation) {
18917                     break;
18918                 }
18919                 dir = e.keyCode == 37 ? -1 : 1;
18920                 
18921                 if (e.ctrlKey){
18922                     newDate = this.moveYear(this.date, dir);
18923                     newViewDate = this.moveYear(this.viewDate, dir);
18924                 } else if (e.shiftKey){
18925                     newDate = this.moveMonth(this.date, dir);
18926                     newViewDate = this.moveMonth(this.viewDate, dir);
18927                 } else {
18928                     newDate = new Date(this.date);
18929                     newDate.setUTCDate(this.date.getUTCDate() + dir);
18930                     newViewDate = new Date(this.viewDate);
18931                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18932                 }
18933                 if (this.dateWithinRange(newDate)){
18934                     this.date = newDate;
18935                     this.viewDate = newViewDate;
18936                     this.setValue(this.formatDate(this.date));
18937 //                    this.update();
18938                     e.preventDefault();
18939                     dateChanged = true;
18940                 }
18941                 break;
18942             case 38: // up
18943             case 40: // down
18944                 if (!this.keyboardNavigation) {
18945                     break;
18946                 }
18947                 dir = e.keyCode == 38 ? -1 : 1;
18948                 if (e.ctrlKey){
18949                     newDate = this.moveYear(this.date, dir);
18950                     newViewDate = this.moveYear(this.viewDate, dir);
18951                 } else if (e.shiftKey){
18952                     newDate = this.moveMonth(this.date, dir);
18953                     newViewDate = this.moveMonth(this.viewDate, dir);
18954                 } else {
18955                     newDate = new Date(this.date);
18956                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18957                     newViewDate = new Date(this.viewDate);
18958                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18959                 }
18960                 if (this.dateWithinRange(newDate)){
18961                     this.date = newDate;
18962                     this.viewDate = newViewDate;
18963                     this.setValue(this.formatDate(this.date));
18964 //                    this.update();
18965                     e.preventDefault();
18966                     dateChanged = true;
18967                 }
18968                 break;
18969             case 13: // enter
18970                 this.setValue(this.formatDate(this.date));
18971                 this.hide();
18972                 e.preventDefault();
18973                 break;
18974             case 9: // tab
18975                 this.setValue(this.formatDate(this.date));
18976                 this.hide();
18977                 break;
18978             case 16: // shift
18979             case 17: // ctrl
18980             case 18: // alt
18981                 break;
18982             default :
18983                 this.hide();
18984                 
18985         }
18986     },
18987     
18988     
18989     onClick: function(e) 
18990     {
18991         e.stopPropagation();
18992         e.preventDefault();
18993         
18994         var target = e.getTarget();
18995         
18996         if(target.nodeName.toLowerCase() === 'i'){
18997             target = Roo.get(target).dom.parentNode;
18998         }
18999         
19000         var nodeName = target.nodeName;
19001         var className = target.className;
19002         var html = target.innerHTML;
19003         //Roo.log(nodeName);
19004         
19005         switch(nodeName.toLowerCase()) {
19006             case 'th':
19007                 switch(className) {
19008                     case 'switch':
19009                         this.showMode(1);
19010                         break;
19011                     case 'prev':
19012                     case 'next':
19013                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19014                         switch(this.viewMode){
19015                                 case 0:
19016                                         this.viewDate = this.moveMonth(this.viewDate, dir);
19017                                         break;
19018                                 case 1:
19019                                 case 2:
19020                                         this.viewDate = this.moveYear(this.viewDate, dir);
19021                                         break;
19022                         }
19023                         this.fill();
19024                         break;
19025                     case 'today':
19026                         var date = new Date();
19027                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19028 //                        this.fill()
19029                         this.setValue(this.formatDate(this.date));
19030                         
19031                         this.hide();
19032                         break;
19033                 }
19034                 break;
19035             case 'span':
19036                 if (className.indexOf('disabled') < 0) {
19037                     this.viewDate.setUTCDate(1);
19038                     if (className.indexOf('month') > -1) {
19039                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19040                     } else {
19041                         var year = parseInt(html, 10) || 0;
19042                         this.viewDate.setUTCFullYear(year);
19043                         
19044                     }
19045                     
19046                     if(this.singleMode){
19047                         this.setValue(this.formatDate(this.viewDate));
19048                         this.hide();
19049                         return;
19050                     }
19051                     
19052                     this.showMode(-1);
19053                     this.fill();
19054                 }
19055                 break;
19056                 
19057             case 'td':
19058                 //Roo.log(className);
19059                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19060                     var day = parseInt(html, 10) || 1;
19061                     var year = this.viewDate.getUTCFullYear(),
19062                         month = this.viewDate.getUTCMonth();
19063
19064                     if (className.indexOf('old') > -1) {
19065                         if(month === 0 ){
19066                             month = 11;
19067                             year -= 1;
19068                         }else{
19069                             month -= 1;
19070                         }
19071                     } else if (className.indexOf('new') > -1) {
19072                         if (month == 11) {
19073                             month = 0;
19074                             year += 1;
19075                         } else {
19076                             month += 1;
19077                         }
19078                     }
19079                     //Roo.log([year,month,day]);
19080                     this.date = this.UTCDate(year, month, day,0,0,0,0);
19081                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19082 //                    this.fill();
19083                     //Roo.log(this.formatDate(this.date));
19084                     this.setValue(this.formatDate(this.date));
19085                     this.hide();
19086                 }
19087                 break;
19088         }
19089     },
19090     
19091     setStartDate: function(startDate)
19092     {
19093         this.startDate = startDate || -Infinity;
19094         if (this.startDate !== -Infinity) {
19095             this.startDate = this.parseDate(this.startDate);
19096         }
19097         this.update();
19098         this.updateNavArrows();
19099     },
19100
19101     setEndDate: function(endDate)
19102     {
19103         this.endDate = endDate || Infinity;
19104         if (this.endDate !== Infinity) {
19105             this.endDate = this.parseDate(this.endDate);
19106         }
19107         this.update();
19108         this.updateNavArrows();
19109     },
19110     
19111     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19112     {
19113         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19114         if (typeof(this.daysOfWeekDisabled) !== 'object') {
19115             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19116         }
19117         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19118             return parseInt(d, 10);
19119         });
19120         this.update();
19121         this.updateNavArrows();
19122     },
19123     
19124     updateNavArrows: function() 
19125     {
19126         if(this.singleMode){
19127             return;
19128         }
19129         
19130         var d = new Date(this.viewDate),
19131         year = d.getUTCFullYear(),
19132         month = d.getUTCMonth();
19133         
19134         Roo.each(this.picker().select('.prev', true).elements, function(v){
19135             v.show();
19136             switch (this.viewMode) {
19137                 case 0:
19138
19139                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19140                         v.hide();
19141                     }
19142                     break;
19143                 case 1:
19144                 case 2:
19145                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19146                         v.hide();
19147                     }
19148                     break;
19149             }
19150         });
19151         
19152         Roo.each(this.picker().select('.next', true).elements, function(v){
19153             v.show();
19154             switch (this.viewMode) {
19155                 case 0:
19156
19157                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19158                         v.hide();
19159                     }
19160                     break;
19161                 case 1:
19162                 case 2:
19163                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19164                         v.hide();
19165                     }
19166                     break;
19167             }
19168         })
19169     },
19170     
19171     moveMonth: function(date, dir)
19172     {
19173         if (!dir) {
19174             return date;
19175         }
19176         var new_date = new Date(date.valueOf()),
19177         day = new_date.getUTCDate(),
19178         month = new_date.getUTCMonth(),
19179         mag = Math.abs(dir),
19180         new_month, test;
19181         dir = dir > 0 ? 1 : -1;
19182         if (mag == 1){
19183             test = dir == -1
19184             // If going back one month, make sure month is not current month
19185             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19186             ? function(){
19187                 return new_date.getUTCMonth() == month;
19188             }
19189             // If going forward one month, make sure month is as expected
19190             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19191             : function(){
19192                 return new_date.getUTCMonth() != new_month;
19193             };
19194             new_month = month + dir;
19195             new_date.setUTCMonth(new_month);
19196             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19197             if (new_month < 0 || new_month > 11) {
19198                 new_month = (new_month + 12) % 12;
19199             }
19200         } else {
19201             // For magnitudes >1, move one month at a time...
19202             for (var i=0; i<mag; i++) {
19203                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19204                 new_date = this.moveMonth(new_date, dir);
19205             }
19206             // ...then reset the day, keeping it in the new month
19207             new_month = new_date.getUTCMonth();
19208             new_date.setUTCDate(day);
19209             test = function(){
19210                 return new_month != new_date.getUTCMonth();
19211             };
19212         }
19213         // Common date-resetting loop -- if date is beyond end of month, make it
19214         // end of month
19215         while (test()){
19216             new_date.setUTCDate(--day);
19217             new_date.setUTCMonth(new_month);
19218         }
19219         return new_date;
19220     },
19221
19222     moveYear: function(date, dir)
19223     {
19224         return this.moveMonth(date, dir*12);
19225     },
19226
19227     dateWithinRange: function(date)
19228     {
19229         return date >= this.startDate && date <= this.endDate;
19230     },
19231
19232     
19233     remove: function() 
19234     {
19235         this.picker().remove();
19236     },
19237     
19238     validateValue : function(value)
19239     {
19240         if(this.getVisibilityEl().hasClass('hidden')){
19241             return true;
19242         }
19243         
19244         if(value.length < 1)  {
19245             if(this.allowBlank){
19246                 return true;
19247             }
19248             return false;
19249         }
19250         
19251         if(value.length < this.minLength){
19252             return false;
19253         }
19254         if(value.length > this.maxLength){
19255             return false;
19256         }
19257         if(this.vtype){
19258             var vt = Roo.form.VTypes;
19259             if(!vt[this.vtype](value, this)){
19260                 return false;
19261             }
19262         }
19263         if(typeof this.validator == "function"){
19264             var msg = this.validator(value);
19265             if(msg !== true){
19266                 return false;
19267             }
19268         }
19269         
19270         if(this.regex && !this.regex.test(value)){
19271             return false;
19272         }
19273         
19274         if(typeof(this.parseDate(value)) == 'undefined'){
19275             return false;
19276         }
19277         
19278         if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19279             return false;
19280         }      
19281         
19282         if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19283             return false;
19284         } 
19285         
19286         
19287         return true;
19288     },
19289     
19290     setVisible : function(visible)
19291     {
19292         if(!this.getEl()){
19293             return;
19294         }
19295         
19296         this.getEl().removeClass('hidden');
19297         
19298         if(visible){
19299             return;
19300         }
19301         
19302         this.getEl().addClass('hidden');
19303     }
19304    
19305 });
19306
19307 Roo.apply(Roo.bootstrap.DateField,  {
19308     
19309     head : {
19310         tag: 'thead',
19311         cn: [
19312         {
19313             tag: 'tr',
19314             cn: [
19315             {
19316                 tag: 'th',
19317                 cls: 'prev',
19318                 html: '<i class="fa fa-arrow-left"/>'
19319             },
19320             {
19321                 tag: 'th',
19322                 cls: 'switch',
19323                 colspan: '5'
19324             },
19325             {
19326                 tag: 'th',
19327                 cls: 'next',
19328                 html: '<i class="fa fa-arrow-right"/>'
19329             }
19330
19331             ]
19332         }
19333         ]
19334     },
19335     
19336     content : {
19337         tag: 'tbody',
19338         cn: [
19339         {
19340             tag: 'tr',
19341             cn: [
19342             {
19343                 tag: 'td',
19344                 colspan: '7'
19345             }
19346             ]
19347         }
19348         ]
19349     },
19350     
19351     footer : {
19352         tag: 'tfoot',
19353         cn: [
19354         {
19355             tag: 'tr',
19356             cn: [
19357             {
19358                 tag: 'th',
19359                 colspan: '7',
19360                 cls: 'today'
19361             }
19362                     
19363             ]
19364         }
19365         ]
19366     },
19367     
19368     dates:{
19369         en: {
19370             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19371             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19372             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19373             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19374             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19375             today: "Today"
19376         }
19377     },
19378     
19379     modes: [
19380     {
19381         clsName: 'days',
19382         navFnc: 'Month',
19383         navStep: 1
19384     },
19385     {
19386         clsName: 'months',
19387         navFnc: 'FullYear',
19388         navStep: 1
19389     },
19390     {
19391         clsName: 'years',
19392         navFnc: 'FullYear',
19393         navStep: 10
19394     }]
19395 });
19396
19397 Roo.apply(Roo.bootstrap.DateField,  {
19398   
19399     template : {
19400         tag: 'div',
19401         cls: 'datepicker dropdown-menu roo-dynamic',
19402         cn: [
19403         {
19404             tag: 'div',
19405             cls: 'datepicker-days',
19406             cn: [
19407             {
19408                 tag: 'table',
19409                 cls: 'table-condensed',
19410                 cn:[
19411                 Roo.bootstrap.DateField.head,
19412                 {
19413                     tag: 'tbody'
19414                 },
19415                 Roo.bootstrap.DateField.footer
19416                 ]
19417             }
19418             ]
19419         },
19420         {
19421             tag: 'div',
19422             cls: 'datepicker-months',
19423             cn: [
19424             {
19425                 tag: 'table',
19426                 cls: 'table-condensed',
19427                 cn:[
19428                 Roo.bootstrap.DateField.head,
19429                 Roo.bootstrap.DateField.content,
19430                 Roo.bootstrap.DateField.footer
19431                 ]
19432             }
19433             ]
19434         },
19435         {
19436             tag: 'div',
19437             cls: 'datepicker-years',
19438             cn: [
19439             {
19440                 tag: 'table',
19441                 cls: 'table-condensed',
19442                 cn:[
19443                 Roo.bootstrap.DateField.head,
19444                 Roo.bootstrap.DateField.content,
19445                 Roo.bootstrap.DateField.footer
19446                 ]
19447             }
19448             ]
19449         }
19450         ]
19451     }
19452 });
19453
19454  
19455
19456  /*
19457  * - LGPL
19458  *
19459  * TimeField
19460  * 
19461  */
19462
19463 /**
19464  * @class Roo.bootstrap.TimeField
19465  * @extends Roo.bootstrap.Input
19466  * Bootstrap DateField class
19467  * 
19468  * 
19469  * @constructor
19470  * Create a new TimeField
19471  * @param {Object} config The config object
19472  */
19473
19474 Roo.bootstrap.TimeField = function(config){
19475     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19476     this.addEvents({
19477             /**
19478              * @event show
19479              * Fires when this field show.
19480              * @param {Roo.bootstrap.DateField} thisthis
19481              * @param {Mixed} date The date value
19482              */
19483             show : true,
19484             /**
19485              * @event show
19486              * Fires when this field hide.
19487              * @param {Roo.bootstrap.DateField} this
19488              * @param {Mixed} date The date value
19489              */
19490             hide : true,
19491             /**
19492              * @event select
19493              * Fires when select a date.
19494              * @param {Roo.bootstrap.DateField} this
19495              * @param {Mixed} date The date value
19496              */
19497             select : true
19498         });
19499 };
19500
19501 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
19502     
19503     /**
19504      * @cfg {String} format
19505      * The default time format string which can be overriden for localization support.  The format must be
19506      * valid according to {@link Date#parseDate} (defaults to 'H:i').
19507      */
19508     format : "H:i",
19509        
19510     onRender: function(ct, position)
19511     {
19512         
19513         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19514                 
19515         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19516         
19517         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19518         
19519         this.pop = this.picker().select('>.datepicker-time',true).first();
19520         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19521         
19522         this.picker().on('mousedown', this.onMousedown, this);
19523         this.picker().on('click', this.onClick, this);
19524         
19525         this.picker().addClass('datepicker-dropdown');
19526     
19527         this.fillTime();
19528         this.update();
19529             
19530         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19531         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19532         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19533         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19534         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19535         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19536
19537     },
19538     
19539     fireKey: function(e){
19540         if (!this.picker().isVisible()){
19541             if (e.keyCode == 27) { // allow escape to hide and re-show picker
19542                 this.show();
19543             }
19544             return;
19545         }
19546
19547         e.preventDefault();
19548         
19549         switch(e.keyCode){
19550             case 27: // escape
19551                 this.hide();
19552                 break;
19553             case 37: // left
19554             case 39: // right
19555                 this.onTogglePeriod();
19556                 break;
19557             case 38: // up
19558                 this.onIncrementMinutes();
19559                 break;
19560             case 40: // down
19561                 this.onDecrementMinutes();
19562                 break;
19563             case 13: // enter
19564             case 9: // tab
19565                 this.setTime();
19566                 break;
19567         }
19568     },
19569     
19570     onClick: function(e) {
19571         e.stopPropagation();
19572         e.preventDefault();
19573     },
19574     
19575     picker : function()
19576     {
19577         return this.el.select('.datepicker', true).first();
19578     },
19579     
19580     fillTime: function()
19581     {    
19582         var time = this.pop.select('tbody', true).first();
19583         
19584         time.dom.innerHTML = '';
19585         
19586         time.createChild({
19587             tag: 'tr',
19588             cn: [
19589                 {
19590                     tag: 'td',
19591                     cn: [
19592                         {
19593                             tag: 'a',
19594                             href: '#',
19595                             cls: 'btn',
19596                             cn: [
19597                                 {
19598                                     tag: 'span',
19599                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
19600                                 }
19601                             ]
19602                         } 
19603                     ]
19604                 },
19605                 {
19606                     tag: 'td',
19607                     cls: 'separator'
19608                 },
19609                 {
19610                     tag: 'td',
19611                     cn: [
19612                         {
19613                             tag: 'a',
19614                             href: '#',
19615                             cls: 'btn',
19616                             cn: [
19617                                 {
19618                                     tag: 'span',
19619                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
19620                                 }
19621                             ]
19622                         }
19623                     ]
19624                 },
19625                 {
19626                     tag: 'td',
19627                     cls: 'separator'
19628                 }
19629             ]
19630         });
19631         
19632         time.createChild({
19633             tag: 'tr',
19634             cn: [
19635                 {
19636                     tag: 'td',
19637                     cn: [
19638                         {
19639                             tag: 'span',
19640                             cls: 'timepicker-hour',
19641                             html: '00'
19642                         }  
19643                     ]
19644                 },
19645                 {
19646                     tag: 'td',
19647                     cls: 'separator',
19648                     html: ':'
19649                 },
19650                 {
19651                     tag: 'td',
19652                     cn: [
19653                         {
19654                             tag: 'span',
19655                             cls: 'timepicker-minute',
19656                             html: '00'
19657                         }  
19658                     ]
19659                 },
19660                 {
19661                     tag: 'td',
19662                     cls: 'separator'
19663                 },
19664                 {
19665                     tag: 'td',
19666                     cn: [
19667                         {
19668                             tag: 'button',
19669                             type: 'button',
19670                             cls: 'btn btn-primary period',
19671                             html: 'AM'
19672                             
19673                         }
19674                     ]
19675                 }
19676             ]
19677         });
19678         
19679         time.createChild({
19680             tag: 'tr',
19681             cn: [
19682                 {
19683                     tag: 'td',
19684                     cn: [
19685                         {
19686                             tag: 'a',
19687                             href: '#',
19688                             cls: 'btn',
19689                             cn: [
19690                                 {
19691                                     tag: 'span',
19692                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
19693                                 }
19694                             ]
19695                         }
19696                     ]
19697                 },
19698                 {
19699                     tag: 'td',
19700                     cls: 'separator'
19701                 },
19702                 {
19703                     tag: 'td',
19704                     cn: [
19705                         {
19706                             tag: 'a',
19707                             href: '#',
19708                             cls: 'btn',
19709                             cn: [
19710                                 {
19711                                     tag: 'span',
19712                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
19713                                 }
19714                             ]
19715                         }
19716                     ]
19717                 },
19718                 {
19719                     tag: 'td',
19720                     cls: 'separator'
19721                 }
19722             ]
19723         });
19724         
19725     },
19726     
19727     update: function()
19728     {
19729         
19730         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19731         
19732         this.fill();
19733     },
19734     
19735     fill: function() 
19736     {
19737         var hours = this.time.getHours();
19738         var minutes = this.time.getMinutes();
19739         var period = 'AM';
19740         
19741         if(hours > 11){
19742             period = 'PM';
19743         }
19744         
19745         if(hours == 0){
19746             hours = 12;
19747         }
19748         
19749         
19750         if(hours > 12){
19751             hours = hours - 12;
19752         }
19753         
19754         if(hours < 10){
19755             hours = '0' + hours;
19756         }
19757         
19758         if(minutes < 10){
19759             minutes = '0' + minutes;
19760         }
19761         
19762         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19763         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19764         this.pop.select('button', true).first().dom.innerHTML = period;
19765         
19766     },
19767     
19768     place: function()
19769     {   
19770         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19771         
19772         var cls = ['bottom'];
19773         
19774         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19775             cls.pop();
19776             cls.push('top');
19777         }
19778         
19779         cls.push('right');
19780         
19781         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19782             cls.pop();
19783             cls.push('left');
19784         }
19785         
19786         this.picker().addClass(cls.join('-'));
19787         
19788         var _this = this;
19789         
19790         Roo.each(cls, function(c){
19791             if(c == 'bottom'){
19792                 _this.picker().setTop(_this.inputEl().getHeight());
19793                 return;
19794             }
19795             if(c == 'top'){
19796                 _this.picker().setTop(0 - _this.picker().getHeight());
19797                 return;
19798             }
19799             
19800             if(c == 'left'){
19801                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19802                 return;
19803             }
19804             if(c == 'right'){
19805                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19806                 return;
19807             }
19808         });
19809         
19810     },
19811   
19812     onFocus : function()
19813     {
19814         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19815         this.show();
19816     },
19817     
19818     onBlur : function()
19819     {
19820         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19821         this.hide();
19822     },
19823     
19824     show : function()
19825     {
19826         this.picker().show();
19827         this.pop.show();
19828         this.update();
19829         this.place();
19830         
19831         this.fireEvent('show', this, this.date);
19832     },
19833     
19834     hide : function()
19835     {
19836         this.picker().hide();
19837         this.pop.hide();
19838         
19839         this.fireEvent('hide', this, this.date);
19840     },
19841     
19842     setTime : function()
19843     {
19844         this.hide();
19845         this.setValue(this.time.format(this.format));
19846         
19847         this.fireEvent('select', this, this.date);
19848         
19849         
19850     },
19851     
19852     onMousedown: function(e){
19853         e.stopPropagation();
19854         e.preventDefault();
19855     },
19856     
19857     onIncrementHours: function()
19858     {
19859         Roo.log('onIncrementHours');
19860         this.time = this.time.add(Date.HOUR, 1);
19861         this.update();
19862         
19863     },
19864     
19865     onDecrementHours: function()
19866     {
19867         Roo.log('onDecrementHours');
19868         this.time = this.time.add(Date.HOUR, -1);
19869         this.update();
19870     },
19871     
19872     onIncrementMinutes: function()
19873     {
19874         Roo.log('onIncrementMinutes');
19875         this.time = this.time.add(Date.MINUTE, 1);
19876         this.update();
19877     },
19878     
19879     onDecrementMinutes: function()
19880     {
19881         Roo.log('onDecrementMinutes');
19882         this.time = this.time.add(Date.MINUTE, -1);
19883         this.update();
19884     },
19885     
19886     onTogglePeriod: function()
19887     {
19888         Roo.log('onTogglePeriod');
19889         this.time = this.time.add(Date.HOUR, 12);
19890         this.update();
19891     }
19892     
19893    
19894 });
19895
19896 Roo.apply(Roo.bootstrap.TimeField,  {
19897     
19898     content : {
19899         tag: 'tbody',
19900         cn: [
19901             {
19902                 tag: 'tr',
19903                 cn: [
19904                 {
19905                     tag: 'td',
19906                     colspan: '7'
19907                 }
19908                 ]
19909             }
19910         ]
19911     },
19912     
19913     footer : {
19914         tag: 'tfoot',
19915         cn: [
19916             {
19917                 tag: 'tr',
19918                 cn: [
19919                 {
19920                     tag: 'th',
19921                     colspan: '7',
19922                     cls: '',
19923                     cn: [
19924                         {
19925                             tag: 'button',
19926                             cls: 'btn btn-info ok',
19927                             html: 'OK'
19928                         }
19929                     ]
19930                 }
19931
19932                 ]
19933             }
19934         ]
19935     }
19936 });
19937
19938 Roo.apply(Roo.bootstrap.TimeField,  {
19939   
19940     template : {
19941         tag: 'div',
19942         cls: 'datepicker dropdown-menu',
19943         cn: [
19944             {
19945                 tag: 'div',
19946                 cls: 'datepicker-time',
19947                 cn: [
19948                 {
19949                     tag: 'table',
19950                     cls: 'table-condensed',
19951                     cn:[
19952                     Roo.bootstrap.TimeField.content,
19953                     Roo.bootstrap.TimeField.footer
19954                     ]
19955                 }
19956                 ]
19957             }
19958         ]
19959     }
19960 });
19961
19962  
19963
19964  /*
19965  * - LGPL
19966  *
19967  * MonthField
19968  * 
19969  */
19970
19971 /**
19972  * @class Roo.bootstrap.MonthField
19973  * @extends Roo.bootstrap.Input
19974  * Bootstrap MonthField class
19975  * 
19976  * @cfg {String} language default en
19977  * 
19978  * @constructor
19979  * Create a new MonthField
19980  * @param {Object} config The config object
19981  */
19982
19983 Roo.bootstrap.MonthField = function(config){
19984     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19985     
19986     this.addEvents({
19987         /**
19988          * @event show
19989          * Fires when this field show.
19990          * @param {Roo.bootstrap.MonthField} this
19991          * @param {Mixed} date The date value
19992          */
19993         show : true,
19994         /**
19995          * @event show
19996          * Fires when this field hide.
19997          * @param {Roo.bootstrap.MonthField} this
19998          * @param {Mixed} date The date value
19999          */
20000         hide : true,
20001         /**
20002          * @event select
20003          * Fires when select a date.
20004          * @param {Roo.bootstrap.MonthField} this
20005          * @param {String} oldvalue The old value
20006          * @param {String} newvalue The new value
20007          */
20008         select : true
20009     });
20010 };
20011
20012 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
20013     
20014     onRender: function(ct, position)
20015     {
20016         
20017         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20018         
20019         this.language = this.language || 'en';
20020         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20021         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20022         
20023         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20024         this.isInline = false;
20025         this.isInput = true;
20026         this.component = this.el.select('.add-on', true).first() || false;
20027         this.component = (this.component && this.component.length === 0) ? false : this.component;
20028         this.hasInput = this.component && this.inputEL().length;
20029         
20030         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20031         
20032         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20033         
20034         this.picker().on('mousedown', this.onMousedown, this);
20035         this.picker().on('click', this.onClick, this);
20036         
20037         this.picker().addClass('datepicker-dropdown');
20038         
20039         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20040             v.setStyle('width', '189px');
20041         });
20042         
20043         this.fillMonths();
20044         
20045         this.update();
20046         
20047         if(this.isInline) {
20048             this.show();
20049         }
20050         
20051     },
20052     
20053     setValue: function(v, suppressEvent)
20054     {   
20055         var o = this.getValue();
20056         
20057         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20058         
20059         this.update();
20060
20061         if(suppressEvent !== true){
20062             this.fireEvent('select', this, o, v);
20063         }
20064         
20065     },
20066     
20067     getValue: function()
20068     {
20069         return this.value;
20070     },
20071     
20072     onClick: function(e) 
20073     {
20074         e.stopPropagation();
20075         e.preventDefault();
20076         
20077         var target = e.getTarget();
20078         
20079         if(target.nodeName.toLowerCase() === 'i'){
20080             target = Roo.get(target).dom.parentNode;
20081         }
20082         
20083         var nodeName = target.nodeName;
20084         var className = target.className;
20085         var html = target.innerHTML;
20086         
20087         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20088             return;
20089         }
20090         
20091         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20092         
20093         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20094         
20095         this.hide();
20096                         
20097     },
20098     
20099     picker : function()
20100     {
20101         return this.pickerEl;
20102     },
20103     
20104     fillMonths: function()
20105     {    
20106         var i = 0;
20107         var months = this.picker().select('>.datepicker-months td', true).first();
20108         
20109         months.dom.innerHTML = '';
20110         
20111         while (i < 12) {
20112             var month = {
20113                 tag: 'span',
20114                 cls: 'month',
20115                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20116             };
20117             
20118             months.createChild(month);
20119         }
20120         
20121     },
20122     
20123     update: function()
20124     {
20125         var _this = this;
20126         
20127         if(typeof(this.vIndex) == 'undefined' && this.value.length){
20128             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20129         }
20130         
20131         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20132             e.removeClass('active');
20133             
20134             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20135                 e.addClass('active');
20136             }
20137         })
20138     },
20139     
20140     place: function()
20141     {
20142         if(this.isInline) {
20143             return;
20144         }
20145         
20146         this.picker().removeClass(['bottom', 'top']);
20147         
20148         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20149             /*
20150              * place to the top of element!
20151              *
20152              */
20153             
20154             this.picker().addClass('top');
20155             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20156             
20157             return;
20158         }
20159         
20160         this.picker().addClass('bottom');
20161         
20162         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20163     },
20164     
20165     onFocus : function()
20166     {
20167         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20168         this.show();
20169     },
20170     
20171     onBlur : function()
20172     {
20173         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20174         
20175         var d = this.inputEl().getValue();
20176         
20177         this.setValue(d);
20178                 
20179         this.hide();
20180     },
20181     
20182     show : function()
20183     {
20184         this.picker().show();
20185         this.picker().select('>.datepicker-months', true).first().show();
20186         this.update();
20187         this.place();
20188         
20189         this.fireEvent('show', this, this.date);
20190     },
20191     
20192     hide : function()
20193     {
20194         if(this.isInline) {
20195             return;
20196         }
20197         this.picker().hide();
20198         this.fireEvent('hide', this, this.date);
20199         
20200     },
20201     
20202     onMousedown: function(e)
20203     {
20204         e.stopPropagation();
20205         e.preventDefault();
20206     },
20207     
20208     keyup: function(e)
20209     {
20210         Roo.bootstrap.MonthField.superclass.keyup.call(this);
20211         this.update();
20212     },
20213
20214     fireKey: function(e)
20215     {
20216         if (!this.picker().isVisible()){
20217             if (e.keyCode == 27)   {// allow escape to hide and re-show picker
20218                 this.show();
20219             }
20220             return;
20221         }
20222         
20223         var dir;
20224         
20225         switch(e.keyCode){
20226             case 27: // escape
20227                 this.hide();
20228                 e.preventDefault();
20229                 break;
20230             case 37: // left
20231             case 39: // right
20232                 dir = e.keyCode == 37 ? -1 : 1;
20233                 
20234                 this.vIndex = this.vIndex + dir;
20235                 
20236                 if(this.vIndex < 0){
20237                     this.vIndex = 0;
20238                 }
20239                 
20240                 if(this.vIndex > 11){
20241                     this.vIndex = 11;
20242                 }
20243                 
20244                 if(isNaN(this.vIndex)){
20245                     this.vIndex = 0;
20246                 }
20247                 
20248                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20249                 
20250                 break;
20251             case 38: // up
20252             case 40: // down
20253                 
20254                 dir = e.keyCode == 38 ? -1 : 1;
20255                 
20256                 this.vIndex = this.vIndex + dir * 4;
20257                 
20258                 if(this.vIndex < 0){
20259                     this.vIndex = 0;
20260                 }
20261                 
20262                 if(this.vIndex > 11){
20263                     this.vIndex = 11;
20264                 }
20265                 
20266                 if(isNaN(this.vIndex)){
20267                     this.vIndex = 0;
20268                 }
20269                 
20270                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20271                 break;
20272                 
20273             case 13: // enter
20274                 
20275                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20276                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20277                 }
20278                 
20279                 this.hide();
20280                 e.preventDefault();
20281                 break;
20282             case 9: // tab
20283                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20284                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20285                 }
20286                 this.hide();
20287                 break;
20288             case 16: // shift
20289             case 17: // ctrl
20290             case 18: // alt
20291                 break;
20292             default :
20293                 this.hide();
20294                 
20295         }
20296     },
20297     
20298     remove: function() 
20299     {
20300         this.picker().remove();
20301     }
20302    
20303 });
20304
20305 Roo.apply(Roo.bootstrap.MonthField,  {
20306     
20307     content : {
20308         tag: 'tbody',
20309         cn: [
20310         {
20311             tag: 'tr',
20312             cn: [
20313             {
20314                 tag: 'td',
20315                 colspan: '7'
20316             }
20317             ]
20318         }
20319         ]
20320     },
20321     
20322     dates:{
20323         en: {
20324             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20325             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20326         }
20327     }
20328 });
20329
20330 Roo.apply(Roo.bootstrap.MonthField,  {
20331   
20332     template : {
20333         tag: 'div',
20334         cls: 'datepicker dropdown-menu roo-dynamic',
20335         cn: [
20336             {
20337                 tag: 'div',
20338                 cls: 'datepicker-months',
20339                 cn: [
20340                 {
20341                     tag: 'table',
20342                     cls: 'table-condensed',
20343                     cn:[
20344                         Roo.bootstrap.DateField.content
20345                     ]
20346                 }
20347                 ]
20348             }
20349         ]
20350     }
20351 });
20352
20353  
20354
20355  
20356  /*
20357  * - LGPL
20358  *
20359  * CheckBox
20360  * 
20361  */
20362
20363 /**
20364  * @class Roo.bootstrap.CheckBox
20365  * @extends Roo.bootstrap.Input
20366  * Bootstrap CheckBox class
20367  * 
20368  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20369  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20370  * @cfg {String} boxLabel The text that appears beside the checkbox
20371  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20372  * @cfg {Boolean} checked initnal the element
20373  * @cfg {Boolean} inline inline the element (default false)
20374  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20375  * @cfg {String} tooltip label tooltip
20376  * 
20377  * @constructor
20378  * Create a new CheckBox
20379  * @param {Object} config The config object
20380  */
20381
20382 Roo.bootstrap.CheckBox = function(config){
20383     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20384    
20385     this.addEvents({
20386         /**
20387         * @event check
20388         * Fires when the element is checked or unchecked.
20389         * @param {Roo.bootstrap.CheckBox} this This input
20390         * @param {Boolean} checked The new checked value
20391         */
20392        check : true,
20393        /**
20394         * @event click
20395         * Fires when the element is click.
20396         * @param {Roo.bootstrap.CheckBox} this This input
20397         */
20398        click : true
20399     });
20400     
20401 };
20402
20403 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
20404   
20405     inputType: 'checkbox',
20406     inputValue: 1,
20407     valueOff: 0,
20408     boxLabel: false,
20409     checked: false,
20410     weight : false,
20411     inline: false,
20412     tooltip : '',
20413     
20414     getAutoCreate : function()
20415     {
20416         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20417         
20418         var id = Roo.id();
20419         
20420         var cfg = {};
20421         
20422         cfg.cls = 'form-group ' + this.inputType; //input-group
20423         
20424         if(this.inline){
20425             cfg.cls += ' ' + this.inputType + '-inline';
20426         }
20427         
20428         var input =  {
20429             tag: 'input',
20430             id : id,
20431             type : this.inputType,
20432             value : this.inputValue,
20433             cls : 'roo-' + this.inputType, //'form-box',
20434             placeholder : this.placeholder || ''
20435             
20436         };
20437         
20438         if(this.inputType != 'radio'){
20439             var hidden =  {
20440                 tag: 'input',
20441                 type : 'hidden',
20442                 cls : 'roo-hidden-value',
20443                 value : this.checked ? this.inputValue : this.valueOff
20444             };
20445         }
20446         
20447             
20448         if (this.weight) { // Validity check?
20449             cfg.cls += " " + this.inputType + "-" + this.weight;
20450         }
20451         
20452         if (this.disabled) {
20453             input.disabled=true;
20454         }
20455         
20456         if(this.checked){
20457             input.checked = this.checked;
20458         }
20459         
20460         if (this.name) {
20461             
20462             input.name = this.name;
20463             
20464             if(this.inputType != 'radio'){
20465                 hidden.name = this.name;
20466                 input.name = '_hidden_' + this.name;
20467             }
20468         }
20469         
20470         if (this.size) {
20471             input.cls += ' input-' + this.size;
20472         }
20473         
20474         var settings=this;
20475         
20476         ['xs','sm','md','lg'].map(function(size){
20477             if (settings[size]) {
20478                 cfg.cls += ' col-' + size + '-' + settings[size];
20479             }
20480         });
20481         
20482         var inputblock = input;
20483          
20484         if (this.before || this.after) {
20485             
20486             inputblock = {
20487                 cls : 'input-group',
20488                 cn :  [] 
20489             };
20490             
20491             if (this.before) {
20492                 inputblock.cn.push({
20493                     tag :'span',
20494                     cls : 'input-group-addon',
20495                     html : this.before
20496                 });
20497             }
20498             
20499             inputblock.cn.push(input);
20500             
20501             if(this.inputType != 'radio'){
20502                 inputblock.cn.push(hidden);
20503             }
20504             
20505             if (this.after) {
20506                 inputblock.cn.push({
20507                     tag :'span',
20508                     cls : 'input-group-addon',
20509                     html : this.after
20510                 });
20511             }
20512             
20513         }
20514         
20515         if (align ==='left' && this.fieldLabel.length) {
20516 //                Roo.log("left and has label");
20517             cfg.cn = [
20518                 {
20519                     tag: 'label',
20520                     'for' :  id,
20521                     cls : 'control-label',
20522                     html : this.fieldLabel
20523                 },
20524                 {
20525                     cls : "", 
20526                     cn: [
20527                         inputblock
20528                     ]
20529                 }
20530             ];
20531             
20532             if(this.labelWidth > 12){
20533                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20534             }
20535             
20536             if(this.labelWidth < 13 && this.labelmd == 0){
20537                 this.labelmd = this.labelWidth;
20538             }
20539             
20540             if(this.labellg > 0){
20541                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20542                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20543             }
20544             
20545             if(this.labelmd > 0){
20546                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20547                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20548             }
20549             
20550             if(this.labelsm > 0){
20551                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20552                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20553             }
20554             
20555             if(this.labelxs > 0){
20556                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20557                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20558             }
20559             
20560         } else if ( this.fieldLabel.length) {
20561 //                Roo.log(" label");
20562                 cfg.cn = [
20563                    
20564                     {
20565                         tag: this.boxLabel ? 'span' : 'label',
20566                         'for': id,
20567                         cls: 'control-label box-input-label',
20568                         //cls : 'input-group-addon',
20569                         html : this.fieldLabel
20570                     },
20571                     
20572                     inputblock
20573                     
20574                 ];
20575
20576         } else {
20577             
20578 //                Roo.log(" no label && no align");
20579                 cfg.cn = [  inputblock ] ;
20580                 
20581                 
20582         }
20583         
20584         if(this.boxLabel){
20585              var boxLabelCfg = {
20586                 tag: 'label',
20587                 //'for': id, // box label is handled by onclick - so no for...
20588                 cls: 'box-label',
20589                 html: this.boxLabel
20590             };
20591             
20592             if(this.tooltip){
20593                 boxLabelCfg.tooltip = this.tooltip;
20594             }
20595              
20596             cfg.cn.push(boxLabelCfg);
20597         }
20598         
20599         if(this.inputType != 'radio'){
20600             cfg.cn.push(hidden);
20601         }
20602         
20603         return cfg;
20604         
20605     },
20606     
20607     /**
20608      * return the real input element.
20609      */
20610     inputEl: function ()
20611     {
20612         return this.el.select('input.roo-' + this.inputType,true).first();
20613     },
20614     hiddenEl: function ()
20615     {
20616         return this.el.select('input.roo-hidden-value',true).first();
20617     },
20618     
20619     labelEl: function()
20620     {
20621         return this.el.select('label.control-label',true).first();
20622     },
20623     /* depricated... */
20624     
20625     label: function()
20626     {
20627         return this.labelEl();
20628     },
20629     
20630     boxLabelEl: function()
20631     {
20632         return this.el.select('label.box-label',true).first();
20633     },
20634     
20635     initEvents : function()
20636     {
20637 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20638         
20639         this.inputEl().on('click', this.onClick,  this);
20640         
20641         if (this.boxLabel) { 
20642             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
20643         }
20644         
20645         this.startValue = this.getValue();
20646         
20647         if(this.groupId){
20648             Roo.bootstrap.CheckBox.register(this);
20649         }
20650     },
20651     
20652     onClick : function(e)
20653     {   
20654         if(this.fireEvent('click', this, e) !== false){
20655             this.setChecked(!this.checked);
20656         }
20657         
20658     },
20659     
20660     setChecked : function(state,suppressEvent)
20661     {
20662         this.startValue = this.getValue();
20663
20664         if(this.inputType == 'radio'){
20665             
20666             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20667                 e.dom.checked = false;
20668             });
20669             
20670             this.inputEl().dom.checked = true;
20671             
20672             this.inputEl().dom.value = this.inputValue;
20673             
20674             if(suppressEvent !== true){
20675                 this.fireEvent('check', this, true);
20676             }
20677             
20678             this.validate();
20679             
20680             return;
20681         }
20682         
20683         this.checked = state;
20684         
20685         this.inputEl().dom.checked = state;
20686         
20687         
20688         this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20689         
20690         if(suppressEvent !== true){
20691             this.fireEvent('check', this, state);
20692         }
20693         
20694         this.validate();
20695     },
20696     
20697     getValue : function()
20698     {
20699         if(this.inputType == 'radio'){
20700             return this.getGroupValue();
20701         }
20702         
20703         return this.hiddenEl().dom.value;
20704         
20705     },
20706     
20707     getGroupValue : function()
20708     {
20709         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20710             return '';
20711         }
20712         
20713         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20714     },
20715     
20716     setValue : function(v,suppressEvent)
20717     {
20718         if(this.inputType == 'radio'){
20719             this.setGroupValue(v, suppressEvent);
20720             return;
20721         }
20722         
20723         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20724         
20725         this.validate();
20726     },
20727     
20728     setGroupValue : function(v, suppressEvent)
20729     {
20730         this.startValue = this.getValue();
20731         
20732         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20733             e.dom.checked = false;
20734             
20735             if(e.dom.value == v){
20736                 e.dom.checked = true;
20737             }
20738         });
20739         
20740         if(suppressEvent !== true){
20741             this.fireEvent('check', this, true);
20742         }
20743
20744         this.validate();
20745         
20746         return;
20747     },
20748     
20749     validate : function()
20750     {
20751         if(this.getVisibilityEl().hasClass('hidden')){
20752             return true;
20753         }
20754         
20755         if(
20756                 this.disabled || 
20757                 (this.inputType == 'radio' && this.validateRadio()) ||
20758                 (this.inputType == 'checkbox' && this.validateCheckbox())
20759         ){
20760             this.markValid();
20761             return true;
20762         }
20763         
20764         this.markInvalid();
20765         return false;
20766     },
20767     
20768     validateRadio : function()
20769     {
20770         if(this.getVisibilityEl().hasClass('hidden')){
20771             return true;
20772         }
20773         
20774         if(this.allowBlank){
20775             return true;
20776         }
20777         
20778         var valid = false;
20779         
20780         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20781             if(!e.dom.checked){
20782                 return;
20783             }
20784             
20785             valid = true;
20786             
20787             return false;
20788         });
20789         
20790         return valid;
20791     },
20792     
20793     validateCheckbox : function()
20794     {
20795         if(!this.groupId){
20796             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20797             //return (this.getValue() == this.inputValue) ? true : false;
20798         }
20799         
20800         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20801         
20802         if(!group){
20803             return false;
20804         }
20805         
20806         var r = false;
20807         
20808         for(var i in group){
20809             if(group[i].el.isVisible(true)){
20810                 r = false;
20811                 break;
20812             }
20813             
20814             r = true;
20815         }
20816         
20817         for(var i in group){
20818             if(r){
20819                 break;
20820             }
20821             
20822             r = (group[i].getValue() == group[i].inputValue) ? true : false;
20823         }
20824         
20825         return r;
20826     },
20827     
20828     /**
20829      * Mark this field as valid
20830      */
20831     markValid : function()
20832     {
20833         var _this = this;
20834         
20835         this.fireEvent('valid', this);
20836         
20837         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20838         
20839         if(this.groupId){
20840             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20841         }
20842         
20843         if(label){
20844             label.markValid();
20845         }
20846
20847         if(this.inputType == 'radio'){
20848             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20849                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20850                 e.findParent('.form-group', false, true).addClass(_this.validClass);
20851             });
20852             
20853             return;
20854         }
20855
20856         if(!this.groupId){
20857             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20858             this.el.findParent('.form-group', false, true).addClass(this.validClass);
20859             return;
20860         }
20861         
20862         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20863         
20864         if(!group){
20865             return;
20866         }
20867         
20868         for(var i in group){
20869             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20870             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20871         }
20872     },
20873     
20874      /**
20875      * Mark this field as invalid
20876      * @param {String} msg The validation message
20877      */
20878     markInvalid : function(msg)
20879     {
20880         if(this.allowBlank){
20881             return;
20882         }
20883         
20884         var _this = this;
20885         
20886         this.fireEvent('invalid', this, msg);
20887         
20888         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20889         
20890         if(this.groupId){
20891             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20892         }
20893         
20894         if(label){
20895             label.markInvalid();
20896         }
20897             
20898         if(this.inputType == 'radio'){
20899             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20900                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20901                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20902             });
20903             
20904             return;
20905         }
20906         
20907         if(!this.groupId){
20908             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20909             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20910             return;
20911         }
20912         
20913         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20914         
20915         if(!group){
20916             return;
20917         }
20918         
20919         for(var i in group){
20920             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20921             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20922         }
20923         
20924     },
20925     
20926     clearInvalid : function()
20927     {
20928         Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20929         
20930         // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20931         
20932         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20933         
20934         if (label && label.iconEl) {
20935             label.iconEl.removeClass(label.validClass);
20936             label.iconEl.removeClass(label.invalidClass);
20937         }
20938     },
20939     
20940     disable : function()
20941     {
20942         if(this.inputType != 'radio'){
20943             Roo.bootstrap.CheckBox.superclass.disable.call(this);
20944             return;
20945         }
20946         
20947         var _this = this;
20948         
20949         if(this.rendered){
20950             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20951                 _this.getActionEl().addClass(this.disabledClass);
20952                 e.dom.disabled = true;
20953             });
20954         }
20955         
20956         this.disabled = true;
20957         this.fireEvent("disable", this);
20958         return this;
20959     },
20960
20961     enable : function()
20962     {
20963         if(this.inputType != 'radio'){
20964             Roo.bootstrap.CheckBox.superclass.enable.call(this);
20965             return;
20966         }
20967         
20968         var _this = this;
20969         
20970         if(this.rendered){
20971             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20972                 _this.getActionEl().removeClass(this.disabledClass);
20973                 e.dom.disabled = false;
20974             });
20975         }
20976         
20977         this.disabled = false;
20978         this.fireEvent("enable", this);
20979         return this;
20980     },
20981     
20982     setBoxLabel : function(v)
20983     {
20984         this.boxLabel = v;
20985         
20986         if(this.rendered){
20987             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20988         }
20989     }
20990
20991 });
20992
20993 Roo.apply(Roo.bootstrap.CheckBox, {
20994     
20995     groups: {},
20996     
20997      /**
20998     * register a CheckBox Group
20999     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21000     */
21001     register : function(checkbox)
21002     {
21003         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21004             this.groups[checkbox.groupId] = {};
21005         }
21006         
21007         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21008             return;
21009         }
21010         
21011         this.groups[checkbox.groupId][checkbox.name] = checkbox;
21012         
21013     },
21014     /**
21015     * fetch a CheckBox Group based on the group ID
21016     * @param {string} the group ID
21017     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21018     */
21019     get: function(groupId) {
21020         if (typeof(this.groups[groupId]) == 'undefined') {
21021             return false;
21022         }
21023         
21024         return this.groups[groupId] ;
21025     }
21026     
21027     
21028 });
21029 /*
21030  * - LGPL
21031  *
21032  * RadioItem
21033  * 
21034  */
21035
21036 /**
21037  * @class Roo.bootstrap.Radio
21038  * @extends Roo.bootstrap.Component
21039  * Bootstrap Radio class
21040  * @cfg {String} boxLabel - the label associated
21041  * @cfg {String} value - the value of radio
21042  * 
21043  * @constructor
21044  * Create a new Radio
21045  * @param {Object} config The config object
21046  */
21047 Roo.bootstrap.Radio = function(config){
21048     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21049     
21050 };
21051
21052 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21053     
21054     boxLabel : '',
21055     
21056     value : '',
21057     
21058     getAutoCreate : function()
21059     {
21060         var cfg = {
21061             tag : 'div',
21062             cls : 'form-group radio',
21063             cn : [
21064                 {
21065                     tag : 'label',
21066                     cls : 'box-label',
21067                     html : this.boxLabel
21068                 }
21069             ]
21070         };
21071         
21072         return cfg;
21073     },
21074     
21075     initEvents : function() 
21076     {
21077         this.parent().register(this);
21078         
21079         this.el.on('click', this.onClick, this);
21080         
21081     },
21082     
21083     onClick : function(e)
21084     {
21085         if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21086             this.setChecked(true);
21087         }
21088     },
21089     
21090     setChecked : function(state, suppressEvent)
21091     {
21092         this.parent().setValue(this.value, suppressEvent);
21093         
21094     },
21095     
21096     setBoxLabel : function(v)
21097     {
21098         this.boxLabel = v;
21099         
21100         if(this.rendered){
21101             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21102         }
21103     }
21104     
21105 });
21106  
21107
21108  /*
21109  * - LGPL
21110  *
21111  * Input
21112  * 
21113  */
21114
21115 /**
21116  * @class Roo.bootstrap.SecurePass
21117  * @extends Roo.bootstrap.Input
21118  * Bootstrap SecurePass class
21119  *
21120  * 
21121  * @constructor
21122  * Create a new SecurePass
21123  * @param {Object} config The config object
21124  */
21125  
21126 Roo.bootstrap.SecurePass = function (config) {
21127     // these go here, so the translation tool can replace them..
21128     this.errors = {
21129         PwdEmpty: "Please type a password, and then retype it to confirm.",
21130         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21131         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21132         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21133         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21134         FNInPwd: "Your password can't contain your first name. Please type a different password.",
21135         LNInPwd: "Your password can't contain your last name. Please type a different password.",
21136         TooWeak: "Your password is Too Weak."
21137     },
21138     this.meterLabel = "Password strength:";
21139     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21140     this.meterClass = [
21141         "roo-password-meter-tooweak", 
21142         "roo-password-meter-weak", 
21143         "roo-password-meter-medium", 
21144         "roo-password-meter-strong", 
21145         "roo-password-meter-grey"
21146     ];
21147     
21148     this.errors = {};
21149     
21150     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21151 }
21152
21153 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21154     /**
21155      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21156      * {
21157      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
21158      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21159      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21160      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21161      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21162      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
21163      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
21164      * })
21165      */
21166     // private
21167     
21168     meterWidth: 300,
21169     errorMsg :'',    
21170     errors: false,
21171     imageRoot: '/',
21172     /**
21173      * @cfg {String/Object} Label for the strength meter (defaults to
21174      * 'Password strength:')
21175      */
21176     // private
21177     meterLabel: '',
21178     /**
21179      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21180      * ['Weak', 'Medium', 'Strong'])
21181      */
21182     // private    
21183     pwdStrengths: false,    
21184     // private
21185     strength: 0,
21186     // private
21187     _lastPwd: null,
21188     // private
21189     kCapitalLetter: 0,
21190     kSmallLetter: 1,
21191     kDigit: 2,
21192     kPunctuation: 3,
21193     
21194     insecure: false,
21195     // private
21196     initEvents: function ()
21197     {
21198         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21199
21200         if (this.el.is('input[type=password]') && Roo.isSafari) {
21201             this.el.on('keydown', this.SafariOnKeyDown, this);
21202         }
21203
21204         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21205     },
21206     // private
21207     onRender: function (ct, position)
21208     {
21209         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21210         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21211         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21212
21213         this.trigger.createChild({
21214                    cn: [
21215                     {
21216                     //id: 'PwdMeter',
21217                     tag: 'div',
21218                     cls: 'roo-password-meter-grey col-xs-12',
21219                     style: {
21220                         //width: 0,
21221                         //width: this.meterWidth + 'px'                                                
21222                         }
21223                     },
21224                     {                            
21225                          cls: 'roo-password-meter-text'                          
21226                     }
21227                 ]            
21228         });
21229
21230          
21231         if (this.hideTrigger) {
21232             this.trigger.setDisplayed(false);
21233         }
21234         this.setSize(this.width || '', this.height || '');
21235     },
21236     // private
21237     onDestroy: function ()
21238     {
21239         if (this.trigger) {
21240             this.trigger.removeAllListeners();
21241             this.trigger.remove();
21242         }
21243         if (this.wrap) {
21244             this.wrap.remove();
21245         }
21246         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21247     },
21248     // private
21249     checkStrength: function ()
21250     {
21251         var pwd = this.inputEl().getValue();
21252         if (pwd == this._lastPwd) {
21253             return;
21254         }
21255
21256         var strength;
21257         if (this.ClientSideStrongPassword(pwd)) {
21258             strength = 3;
21259         } else if (this.ClientSideMediumPassword(pwd)) {
21260             strength = 2;
21261         } else if (this.ClientSideWeakPassword(pwd)) {
21262             strength = 1;
21263         } else {
21264             strength = 0;
21265         }
21266         
21267         Roo.log('strength1: ' + strength);
21268         
21269         //var pm = this.trigger.child('div/div/div').dom;
21270         var pm = this.trigger.child('div/div');
21271         pm.removeClass(this.meterClass);
21272         pm.addClass(this.meterClass[strength]);
21273                 
21274         
21275         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21276                 
21277         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21278         
21279         this._lastPwd = pwd;
21280     },
21281     reset: function ()
21282     {
21283         Roo.bootstrap.SecurePass.superclass.reset.call(this);
21284         
21285         this._lastPwd = '';
21286         
21287         var pm = this.trigger.child('div/div');
21288         pm.removeClass(this.meterClass);
21289         pm.addClass('roo-password-meter-grey');        
21290         
21291         
21292         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21293         
21294         pt.innerHTML = '';
21295         this.inputEl().dom.type='password';
21296     },
21297     // private
21298     validateValue: function (value)
21299     {
21300         
21301         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21302             return false;
21303         }
21304         if (value.length == 0) {
21305             if (this.allowBlank) {
21306                 this.clearInvalid();
21307                 return true;
21308             }
21309
21310             this.markInvalid(this.errors.PwdEmpty);
21311             this.errorMsg = this.errors.PwdEmpty;
21312             return false;
21313         }
21314         
21315         if(this.insecure){
21316             return true;
21317         }
21318         
21319         if ('[\x21-\x7e]*'.match(value)) {
21320             this.markInvalid(this.errors.PwdBadChar);
21321             this.errorMsg = this.errors.PwdBadChar;
21322             return false;
21323         }
21324         if (value.length < 6) {
21325             this.markInvalid(this.errors.PwdShort);
21326             this.errorMsg = this.errors.PwdShort;
21327             return false;
21328         }
21329         if (value.length > 16) {
21330             this.markInvalid(this.errors.PwdLong);
21331             this.errorMsg = this.errors.PwdLong;
21332             return false;
21333         }
21334         var strength;
21335         if (this.ClientSideStrongPassword(value)) {
21336             strength = 3;
21337         } else if (this.ClientSideMediumPassword(value)) {
21338             strength = 2;
21339         } else if (this.ClientSideWeakPassword(value)) {
21340             strength = 1;
21341         } else {
21342             strength = 0;
21343         }
21344
21345         
21346         if (strength < 2) {
21347             //this.markInvalid(this.errors.TooWeak);
21348             this.errorMsg = this.errors.TooWeak;
21349             //return false;
21350         }
21351         
21352         
21353         console.log('strength2: ' + strength);
21354         
21355         //var pm = this.trigger.child('div/div/div').dom;
21356         
21357         var pm = this.trigger.child('div/div');
21358         pm.removeClass(this.meterClass);
21359         pm.addClass(this.meterClass[strength]);
21360                 
21361         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21362                 
21363         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21364         
21365         this.errorMsg = ''; 
21366         return true;
21367     },
21368     // private
21369     CharacterSetChecks: function (type)
21370     {
21371         this.type = type;
21372         this.fResult = false;
21373     },
21374     // private
21375     isctype: function (character, type)
21376     {
21377         switch (type) {  
21378             case this.kCapitalLetter:
21379                 if (character >= 'A' && character <= 'Z') {
21380                     return true;
21381                 }
21382                 break;
21383             
21384             case this.kSmallLetter:
21385                 if (character >= 'a' && character <= 'z') {
21386                     return true;
21387                 }
21388                 break;
21389             
21390             case this.kDigit:
21391                 if (character >= '0' && character <= '9') {
21392                     return true;
21393                 }
21394                 break;
21395             
21396             case this.kPunctuation:
21397                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21398                     return true;
21399                 }
21400                 break;
21401             
21402             default:
21403                 return false;
21404         }
21405
21406     },
21407     // private
21408     IsLongEnough: function (pwd, size)
21409     {
21410         return !(pwd == null || isNaN(size) || pwd.length < size);
21411     },
21412     // private
21413     SpansEnoughCharacterSets: function (word, nb)
21414     {
21415         if (!this.IsLongEnough(word, nb))
21416         {
21417             return false;
21418         }
21419
21420         var characterSetChecks = new Array(
21421             new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21422             new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21423         );
21424         
21425         for (var index = 0; index < word.length; ++index) {
21426             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21427                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21428                     characterSetChecks[nCharSet].fResult = true;
21429                     break;
21430                 }
21431             }
21432         }
21433
21434         var nCharSets = 0;
21435         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21436             if (characterSetChecks[nCharSet].fResult) {
21437                 ++nCharSets;
21438             }
21439         }
21440
21441         if (nCharSets < nb) {
21442             return false;
21443         }
21444         return true;
21445     },
21446     // private
21447     ClientSideStrongPassword: function (pwd)
21448     {
21449         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21450     },
21451     // private
21452     ClientSideMediumPassword: function (pwd)
21453     {
21454         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21455     },
21456     // private
21457     ClientSideWeakPassword: function (pwd)
21458     {
21459         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21460     }
21461           
21462 })//<script type="text/javascript">
21463
21464 /*
21465  * Based  Ext JS Library 1.1.1
21466  * Copyright(c) 2006-2007, Ext JS, LLC.
21467  * LGPL
21468  *
21469  */
21470  
21471 /**
21472  * @class Roo.HtmlEditorCore
21473  * @extends Roo.Component
21474  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21475  *
21476  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21477  */
21478
21479 Roo.HtmlEditorCore = function(config){
21480     
21481     
21482     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21483     
21484     
21485     this.addEvents({
21486         /**
21487          * @event initialize
21488          * Fires when the editor is fully initialized (including the iframe)
21489          * @param {Roo.HtmlEditorCore} this
21490          */
21491         initialize: true,
21492         /**
21493          * @event activate
21494          * Fires when the editor is first receives the focus. Any insertion must wait
21495          * until after this event.
21496          * @param {Roo.HtmlEditorCore} this
21497          */
21498         activate: true,
21499          /**
21500          * @event beforesync
21501          * Fires before the textarea is updated with content from the editor iframe. Return false
21502          * to cancel the sync.
21503          * @param {Roo.HtmlEditorCore} this
21504          * @param {String} html
21505          */
21506         beforesync: true,
21507          /**
21508          * @event beforepush
21509          * Fires before the iframe editor is updated with content from the textarea. Return false
21510          * to cancel the push.
21511          * @param {Roo.HtmlEditorCore} this
21512          * @param {String} html
21513          */
21514         beforepush: true,
21515          /**
21516          * @event sync
21517          * Fires when the textarea is updated with content from the editor iframe.
21518          * @param {Roo.HtmlEditorCore} this
21519          * @param {String} html
21520          */
21521         sync: true,
21522          /**
21523          * @event push
21524          * Fires when the iframe editor is updated with content from the textarea.
21525          * @param {Roo.HtmlEditorCore} this
21526          * @param {String} html
21527          */
21528         push: true,
21529         
21530         /**
21531          * @event editorevent
21532          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21533          * @param {Roo.HtmlEditorCore} this
21534          */
21535         editorevent: true
21536         
21537     });
21538     
21539     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21540     
21541     // defaults : white / black...
21542     this.applyBlacklists();
21543     
21544     
21545     
21546 };
21547
21548
21549 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
21550
21551
21552      /**
21553      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
21554      */
21555     
21556     owner : false,
21557     
21558      /**
21559      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
21560      *                        Roo.resizable.
21561      */
21562     resizable : false,
21563      /**
21564      * @cfg {Number} height (in pixels)
21565      */   
21566     height: 300,
21567    /**
21568      * @cfg {Number} width (in pixels)
21569      */   
21570     width: 500,
21571     
21572     /**
21573      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21574      * 
21575      */
21576     stylesheets: false,
21577     
21578     // id of frame..
21579     frameId: false,
21580     
21581     // private properties
21582     validationEvent : false,
21583     deferHeight: true,
21584     initialized : false,
21585     activated : false,
21586     sourceEditMode : false,
21587     onFocus : Roo.emptyFn,
21588     iframePad:3,
21589     hideMode:'offsets',
21590     
21591     clearUp: true,
21592     
21593     // blacklist + whitelisted elements..
21594     black: false,
21595     white: false,
21596      
21597     bodyCls : '',
21598
21599     /**
21600      * Protected method that will not generally be called directly. It
21601      * is called when the editor initializes the iframe with HTML contents. Override this method if you
21602      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21603      */
21604     getDocMarkup : function(){
21605         // body styles..
21606         var st = '';
21607         
21608         // inherit styels from page...?? 
21609         if (this.stylesheets === false) {
21610             
21611             Roo.get(document.head).select('style').each(function(node) {
21612                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21613             });
21614             
21615             Roo.get(document.head).select('link').each(function(node) { 
21616                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21617             });
21618             
21619         } else if (!this.stylesheets.length) {
21620                 // simple..
21621                 st = '<style type="text/css">' +
21622                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21623                    '</style>';
21624         } else { 
21625             st = '<style type="text/css">' +
21626                     this.stylesheets +
21627                 '</style>';
21628         }
21629         
21630         st +=  '<style type="text/css">' +
21631             'IMG { cursor: pointer } ' +
21632         '</style>';
21633
21634         var cls = 'roo-htmleditor-body';
21635         
21636         if(this.bodyCls.length){
21637             cls += ' ' + this.bodyCls;
21638         }
21639         
21640         return '<html><head>' + st  +
21641             //<style type="text/css">' +
21642             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21643             //'</style>' +
21644             ' </head><body class="' +  cls + '"></body></html>';
21645     },
21646
21647     // private
21648     onRender : function(ct, position)
21649     {
21650         var _t = this;
21651         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21652         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21653         
21654         
21655         this.el.dom.style.border = '0 none';
21656         this.el.dom.setAttribute('tabIndex', -1);
21657         this.el.addClass('x-hidden hide');
21658         
21659         
21660         
21661         if(Roo.isIE){ // fix IE 1px bogus margin
21662             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21663         }
21664        
21665         
21666         this.frameId = Roo.id();
21667         
21668          
21669         
21670         var iframe = this.owner.wrap.createChild({
21671             tag: 'iframe',
21672             cls: 'form-control', // bootstrap..
21673             id: this.frameId,
21674             name: this.frameId,
21675             frameBorder : 'no',
21676             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
21677         }, this.el
21678         );
21679         
21680         
21681         this.iframe = iframe.dom;
21682
21683          this.assignDocWin();
21684         
21685         this.doc.designMode = 'on';
21686        
21687         this.doc.open();
21688         this.doc.write(this.getDocMarkup());
21689         this.doc.close();
21690
21691         
21692         var task = { // must defer to wait for browser to be ready
21693             run : function(){
21694                 //console.log("run task?" + this.doc.readyState);
21695                 this.assignDocWin();
21696                 if(this.doc.body || this.doc.readyState == 'complete'){
21697                     try {
21698                         this.doc.designMode="on";
21699                     } catch (e) {
21700                         return;
21701                     }
21702                     Roo.TaskMgr.stop(task);
21703                     this.initEditor.defer(10, this);
21704                 }
21705             },
21706             interval : 10,
21707             duration: 10000,
21708             scope: this
21709         };
21710         Roo.TaskMgr.start(task);
21711
21712     },
21713
21714     // private
21715     onResize : function(w, h)
21716     {
21717          Roo.log('resize: ' +w + ',' + h );
21718         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21719         if(!this.iframe){
21720             return;
21721         }
21722         if(typeof w == 'number'){
21723             
21724             this.iframe.style.width = w + 'px';
21725         }
21726         if(typeof h == 'number'){
21727             
21728             this.iframe.style.height = h + 'px';
21729             if(this.doc){
21730                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21731             }
21732         }
21733         
21734     },
21735
21736     /**
21737      * Toggles the editor between standard and source edit mode.
21738      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21739      */
21740     toggleSourceEdit : function(sourceEditMode){
21741         
21742         this.sourceEditMode = sourceEditMode === true;
21743         
21744         if(this.sourceEditMode){
21745  
21746             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
21747             
21748         }else{
21749             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21750             //this.iframe.className = '';
21751             this.deferFocus();
21752         }
21753         //this.setSize(this.owner.wrap.getSize());
21754         //this.fireEvent('editmodechange', this, this.sourceEditMode);
21755     },
21756
21757     
21758   
21759
21760     /**
21761      * Protected method that will not generally be called directly. If you need/want
21762      * custom HTML cleanup, this is the method you should override.
21763      * @param {String} html The HTML to be cleaned
21764      * return {String} The cleaned HTML
21765      */
21766     cleanHtml : function(html){
21767         html = String(html);
21768         if(html.length > 5){
21769             if(Roo.isSafari){ // strip safari nonsense
21770                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21771             }
21772         }
21773         if(html == '&nbsp;'){
21774             html = '';
21775         }
21776         return html;
21777     },
21778
21779     /**
21780      * HTML Editor -> Textarea
21781      * Protected method that will not generally be called directly. Syncs the contents
21782      * of the editor iframe with the textarea.
21783      */
21784     syncValue : function(){
21785         if(this.initialized){
21786             var bd = (this.doc.body || this.doc.documentElement);
21787             //this.cleanUpPaste(); -- this is done else where and causes havoc..
21788             var html = bd.innerHTML;
21789             if(Roo.isSafari){
21790                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21791                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21792                 if(m && m[1]){
21793                     html = '<div style="'+m[0]+'">' + html + '</div>';
21794                 }
21795             }
21796             html = this.cleanHtml(html);
21797             // fix up the special chars.. normaly like back quotes in word...
21798             // however we do not want to do this with chinese..
21799             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21800                 var cc = b.charCodeAt();
21801                 if (
21802                     (cc >= 0x4E00 && cc < 0xA000 ) ||
21803                     (cc >= 0x3400 && cc < 0x4E00 ) ||
21804                     (cc >= 0xf900 && cc < 0xfb00 )
21805                 ) {
21806                         return b;
21807                 }
21808                 return "&#"+cc+";" 
21809             });
21810             if(this.owner.fireEvent('beforesync', this, html) !== false){
21811                 this.el.dom.value = html;
21812                 this.owner.fireEvent('sync', this, html);
21813             }
21814         }
21815     },
21816
21817     /**
21818      * Protected method that will not generally be called directly. Pushes the value of the textarea
21819      * into the iframe editor.
21820      */
21821     pushValue : function(){
21822         if(this.initialized){
21823             var v = this.el.dom.value.trim();
21824             
21825 //            if(v.length < 1){
21826 //                v = '&#160;';
21827 //            }
21828             
21829             if(this.owner.fireEvent('beforepush', this, v) !== false){
21830                 var d = (this.doc.body || this.doc.documentElement);
21831                 d.innerHTML = v;
21832                 this.cleanUpPaste();
21833                 this.el.dom.value = d.innerHTML;
21834                 this.owner.fireEvent('push', this, v);
21835             }
21836         }
21837     },
21838
21839     // private
21840     deferFocus : function(){
21841         this.focus.defer(10, this);
21842     },
21843
21844     // doc'ed in Field
21845     focus : function(){
21846         if(this.win && !this.sourceEditMode){
21847             this.win.focus();
21848         }else{
21849             this.el.focus();
21850         }
21851     },
21852     
21853     assignDocWin: function()
21854     {
21855         var iframe = this.iframe;
21856         
21857          if(Roo.isIE){
21858             this.doc = iframe.contentWindow.document;
21859             this.win = iframe.contentWindow;
21860         } else {
21861 //            if (!Roo.get(this.frameId)) {
21862 //                return;
21863 //            }
21864 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21865 //            this.win = Roo.get(this.frameId).dom.contentWindow;
21866             
21867             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21868                 return;
21869             }
21870             
21871             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21872             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21873         }
21874     },
21875     
21876     // private
21877     initEditor : function(){
21878         //console.log("INIT EDITOR");
21879         this.assignDocWin();
21880         
21881         
21882         
21883         this.doc.designMode="on";
21884         this.doc.open();
21885         this.doc.write(this.getDocMarkup());
21886         this.doc.close();
21887         
21888         var dbody = (this.doc.body || this.doc.documentElement);
21889         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21890         // this copies styles from the containing element into thsi one..
21891         // not sure why we need all of this..
21892         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21893         
21894         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21895         //ss['background-attachment'] = 'fixed'; // w3c
21896         dbody.bgProperties = 'fixed'; // ie
21897         //Roo.DomHelper.applyStyles(dbody, ss);
21898         Roo.EventManager.on(this.doc, {
21899             //'mousedown': this.onEditorEvent,
21900             'mouseup': this.onEditorEvent,
21901             'dblclick': this.onEditorEvent,
21902             'click': this.onEditorEvent,
21903             'keyup': this.onEditorEvent,
21904             buffer:100,
21905             scope: this
21906         });
21907         if(Roo.isGecko){
21908             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21909         }
21910         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21911             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21912         }
21913         this.initialized = true;
21914
21915         this.owner.fireEvent('initialize', this);
21916         this.pushValue();
21917     },
21918
21919     // private
21920     onDestroy : function(){
21921         
21922         
21923         
21924         if(this.rendered){
21925             
21926             //for (var i =0; i < this.toolbars.length;i++) {
21927             //    // fixme - ask toolbars for heights?
21928             //    this.toolbars[i].onDestroy();
21929            // }
21930             
21931             //this.wrap.dom.innerHTML = '';
21932             //this.wrap.remove();
21933         }
21934     },
21935
21936     // private
21937     onFirstFocus : function(){
21938         
21939         this.assignDocWin();
21940         
21941         
21942         this.activated = true;
21943          
21944     
21945         if(Roo.isGecko){ // prevent silly gecko errors
21946             this.win.focus();
21947             var s = this.win.getSelection();
21948             if(!s.focusNode || s.focusNode.nodeType != 3){
21949                 var r = s.getRangeAt(0);
21950                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21951                 r.collapse(true);
21952                 this.deferFocus();
21953             }
21954             try{
21955                 this.execCmd('useCSS', true);
21956                 this.execCmd('styleWithCSS', false);
21957             }catch(e){}
21958         }
21959         this.owner.fireEvent('activate', this);
21960     },
21961
21962     // private
21963     adjustFont: function(btn){
21964         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21965         //if(Roo.isSafari){ // safari
21966         //    adjust *= 2;
21967        // }
21968         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21969         if(Roo.isSafari){ // safari
21970             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21971             v =  (v < 10) ? 10 : v;
21972             v =  (v > 48) ? 48 : v;
21973             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21974             
21975         }
21976         
21977         
21978         v = Math.max(1, v+adjust);
21979         
21980         this.execCmd('FontSize', v  );
21981     },
21982
21983     onEditorEvent : function(e)
21984     {
21985         this.owner.fireEvent('editorevent', this, e);
21986       //  this.updateToolbar();
21987         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21988     },
21989
21990     insertTag : function(tg)
21991     {
21992         // could be a bit smarter... -> wrap the current selected tRoo..
21993         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21994             
21995             range = this.createRange(this.getSelection());
21996             var wrappingNode = this.doc.createElement(tg.toLowerCase());
21997             wrappingNode.appendChild(range.extractContents());
21998             range.insertNode(wrappingNode);
21999
22000             return;
22001             
22002             
22003             
22004         }
22005         this.execCmd("formatblock",   tg);
22006         
22007     },
22008     
22009     insertText : function(txt)
22010     {
22011         
22012         
22013         var range = this.createRange();
22014         range.deleteContents();
22015                //alert(Sender.getAttribute('label'));
22016                
22017         range.insertNode(this.doc.createTextNode(txt));
22018     } ,
22019     
22020      
22021
22022     /**
22023      * Executes a Midas editor command on the editor document and performs necessary focus and
22024      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22025      * @param {String} cmd The Midas command
22026      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22027      */
22028     relayCmd : function(cmd, value){
22029         this.win.focus();
22030         this.execCmd(cmd, value);
22031         this.owner.fireEvent('editorevent', this);
22032         //this.updateToolbar();
22033         this.owner.deferFocus();
22034     },
22035
22036     /**
22037      * Executes a Midas editor command directly on the editor document.
22038      * For visual commands, you should use {@link #relayCmd} instead.
22039      * <b>This should only be called after the editor is initialized.</b>
22040      * @param {String} cmd The Midas command
22041      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22042      */
22043     execCmd : function(cmd, value){
22044         this.doc.execCommand(cmd, false, value === undefined ? null : value);
22045         this.syncValue();
22046     },
22047  
22048  
22049    
22050     /**
22051      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22052      * to insert tRoo.
22053      * @param {String} text | dom node.. 
22054      */
22055     insertAtCursor : function(text)
22056     {
22057         
22058         if(!this.activated){
22059             return;
22060         }
22061         /*
22062         if(Roo.isIE){
22063             this.win.focus();
22064             var r = this.doc.selection.createRange();
22065             if(r){
22066                 r.collapse(true);
22067                 r.pasteHTML(text);
22068                 this.syncValue();
22069                 this.deferFocus();
22070             
22071             }
22072             return;
22073         }
22074         */
22075         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22076             this.win.focus();
22077             
22078             
22079             // from jquery ui (MIT licenced)
22080             var range, node;
22081             var win = this.win;
22082             
22083             if (win.getSelection && win.getSelection().getRangeAt) {
22084                 range = win.getSelection().getRangeAt(0);
22085                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22086                 range.insertNode(node);
22087             } else if (win.document.selection && win.document.selection.createRange) {
22088                 // no firefox support
22089                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22090                 win.document.selection.createRange().pasteHTML(txt);
22091             } else {
22092                 // no firefox support
22093                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22094                 this.execCmd('InsertHTML', txt);
22095             } 
22096             
22097             this.syncValue();
22098             
22099             this.deferFocus();
22100         }
22101     },
22102  // private
22103     mozKeyPress : function(e){
22104         if(e.ctrlKey){
22105             var c = e.getCharCode(), cmd;
22106           
22107             if(c > 0){
22108                 c = String.fromCharCode(c).toLowerCase();
22109                 switch(c){
22110                     case 'b':
22111                         cmd = 'bold';
22112                         break;
22113                     case 'i':
22114                         cmd = 'italic';
22115                         break;
22116                     
22117                     case 'u':
22118                         cmd = 'underline';
22119                         break;
22120                     
22121                     case 'v':
22122                         this.cleanUpPaste.defer(100, this);
22123                         return;
22124                         
22125                 }
22126                 if(cmd){
22127                     this.win.focus();
22128                     this.execCmd(cmd);
22129                     this.deferFocus();
22130                     e.preventDefault();
22131                 }
22132                 
22133             }
22134         }
22135     },
22136
22137     // private
22138     fixKeys : function(){ // load time branching for fastest keydown performance
22139         if(Roo.isIE){
22140             return function(e){
22141                 var k = e.getKey(), r;
22142                 if(k == e.TAB){
22143                     e.stopEvent();
22144                     r = this.doc.selection.createRange();
22145                     if(r){
22146                         r.collapse(true);
22147                         r.pasteHTML('&#160;&#160;&#160;&#160;');
22148                         this.deferFocus();
22149                     }
22150                     return;
22151                 }
22152                 
22153                 if(k == e.ENTER){
22154                     r = this.doc.selection.createRange();
22155                     if(r){
22156                         var target = r.parentElement();
22157                         if(!target || target.tagName.toLowerCase() != 'li'){
22158                             e.stopEvent();
22159                             r.pasteHTML('<br />');
22160                             r.collapse(false);
22161                             r.select();
22162                         }
22163                     }
22164                 }
22165                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22166                     this.cleanUpPaste.defer(100, this);
22167                     return;
22168                 }
22169                 
22170                 
22171             };
22172         }else if(Roo.isOpera){
22173             return function(e){
22174                 var k = e.getKey();
22175                 if(k == e.TAB){
22176                     e.stopEvent();
22177                     this.win.focus();
22178                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
22179                     this.deferFocus();
22180                 }
22181                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22182                     this.cleanUpPaste.defer(100, this);
22183                     return;
22184                 }
22185                 
22186             };
22187         }else if(Roo.isSafari){
22188             return function(e){
22189                 var k = e.getKey();
22190                 
22191                 if(k == e.TAB){
22192                     e.stopEvent();
22193                     this.execCmd('InsertText','\t');
22194                     this.deferFocus();
22195                     return;
22196                 }
22197                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22198                     this.cleanUpPaste.defer(100, this);
22199                     return;
22200                 }
22201                 
22202              };
22203         }
22204     }(),
22205     
22206     getAllAncestors: function()
22207     {
22208         var p = this.getSelectedNode();
22209         var a = [];
22210         if (!p) {
22211             a.push(p); // push blank onto stack..
22212             p = this.getParentElement();
22213         }
22214         
22215         
22216         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22217             a.push(p);
22218             p = p.parentNode;
22219         }
22220         a.push(this.doc.body);
22221         return a;
22222     },
22223     lastSel : false,
22224     lastSelNode : false,
22225     
22226     
22227     getSelection : function() 
22228     {
22229         this.assignDocWin();
22230         return Roo.isIE ? this.doc.selection : this.win.getSelection();
22231     },
22232     
22233     getSelectedNode: function() 
22234     {
22235         // this may only work on Gecko!!!
22236         
22237         // should we cache this!!!!
22238         
22239         
22240         
22241          
22242         var range = this.createRange(this.getSelection()).cloneRange();
22243         
22244         if (Roo.isIE) {
22245             var parent = range.parentElement();
22246             while (true) {
22247                 var testRange = range.duplicate();
22248                 testRange.moveToElementText(parent);
22249                 if (testRange.inRange(range)) {
22250                     break;
22251                 }
22252                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22253                     break;
22254                 }
22255                 parent = parent.parentElement;
22256             }
22257             return parent;
22258         }
22259         
22260         // is ancestor a text element.
22261         var ac =  range.commonAncestorContainer;
22262         if (ac.nodeType == 3) {
22263             ac = ac.parentNode;
22264         }
22265         
22266         var ar = ac.childNodes;
22267          
22268         var nodes = [];
22269         var other_nodes = [];
22270         var has_other_nodes = false;
22271         for (var i=0;i<ar.length;i++) {
22272             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
22273                 continue;
22274             }
22275             // fullly contained node.
22276             
22277             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22278                 nodes.push(ar[i]);
22279                 continue;
22280             }
22281             
22282             // probably selected..
22283             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22284                 other_nodes.push(ar[i]);
22285                 continue;
22286             }
22287             // outer..
22288             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
22289                 continue;
22290             }
22291             
22292             
22293             has_other_nodes = true;
22294         }
22295         if (!nodes.length && other_nodes.length) {
22296             nodes= other_nodes;
22297         }
22298         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22299             return false;
22300         }
22301         
22302         return nodes[0];
22303     },
22304     createRange: function(sel)
22305     {
22306         // this has strange effects when using with 
22307         // top toolbar - not sure if it's a great idea.
22308         //this.editor.contentWindow.focus();
22309         if (typeof sel != "undefined") {
22310             try {
22311                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22312             } catch(e) {
22313                 return this.doc.createRange();
22314             }
22315         } else {
22316             return this.doc.createRange();
22317         }
22318     },
22319     getParentElement: function()
22320     {
22321         
22322         this.assignDocWin();
22323         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22324         
22325         var range = this.createRange(sel);
22326          
22327         try {
22328             var p = range.commonAncestorContainer;
22329             while (p.nodeType == 3) { // text node
22330                 p = p.parentNode;
22331             }
22332             return p;
22333         } catch (e) {
22334             return null;
22335         }
22336     
22337     },
22338     /***
22339      *
22340      * Range intersection.. the hard stuff...
22341      *  '-1' = before
22342      *  '0' = hits..
22343      *  '1' = after.
22344      *         [ -- selected range --- ]
22345      *   [fail]                        [fail]
22346      *
22347      *    basically..
22348      *      if end is before start or  hits it. fail.
22349      *      if start is after end or hits it fail.
22350      *
22351      *   if either hits (but other is outside. - then it's not 
22352      *   
22353      *    
22354      **/
22355     
22356     
22357     // @see http://www.thismuchiknow.co.uk/?p=64.
22358     rangeIntersectsNode : function(range, node)
22359     {
22360         var nodeRange = node.ownerDocument.createRange();
22361         try {
22362             nodeRange.selectNode(node);
22363         } catch (e) {
22364             nodeRange.selectNodeContents(node);
22365         }
22366     
22367         var rangeStartRange = range.cloneRange();
22368         rangeStartRange.collapse(true);
22369     
22370         var rangeEndRange = range.cloneRange();
22371         rangeEndRange.collapse(false);
22372     
22373         var nodeStartRange = nodeRange.cloneRange();
22374         nodeStartRange.collapse(true);
22375     
22376         var nodeEndRange = nodeRange.cloneRange();
22377         nodeEndRange.collapse(false);
22378     
22379         return rangeStartRange.compareBoundaryPoints(
22380                  Range.START_TO_START, nodeEndRange) == -1 &&
22381                rangeEndRange.compareBoundaryPoints(
22382                  Range.START_TO_START, nodeStartRange) == 1;
22383         
22384          
22385     },
22386     rangeCompareNode : function(range, node)
22387     {
22388         var nodeRange = node.ownerDocument.createRange();
22389         try {
22390             nodeRange.selectNode(node);
22391         } catch (e) {
22392             nodeRange.selectNodeContents(node);
22393         }
22394         
22395         
22396         range.collapse(true);
22397     
22398         nodeRange.collapse(true);
22399      
22400         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22401         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
22402          
22403         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22404         
22405         var nodeIsBefore   =  ss == 1;
22406         var nodeIsAfter    = ee == -1;
22407         
22408         if (nodeIsBefore && nodeIsAfter) {
22409             return 0; // outer
22410         }
22411         if (!nodeIsBefore && nodeIsAfter) {
22412             return 1; //right trailed.
22413         }
22414         
22415         if (nodeIsBefore && !nodeIsAfter) {
22416             return 2;  // left trailed.
22417         }
22418         // fully contined.
22419         return 3;
22420     },
22421
22422     // private? - in a new class?
22423     cleanUpPaste :  function()
22424     {
22425         // cleans up the whole document..
22426         Roo.log('cleanuppaste');
22427         
22428         this.cleanUpChildren(this.doc.body);
22429         var clean = this.cleanWordChars(this.doc.body.innerHTML);
22430         if (clean != this.doc.body.innerHTML) {
22431             this.doc.body.innerHTML = clean;
22432         }
22433         
22434     },
22435     
22436     cleanWordChars : function(input) {// change the chars to hex code
22437         var he = Roo.HtmlEditorCore;
22438         
22439         var output = input;
22440         Roo.each(he.swapCodes, function(sw) { 
22441             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22442             
22443             output = output.replace(swapper, sw[1]);
22444         });
22445         
22446         return output;
22447     },
22448     
22449     
22450     cleanUpChildren : function (n)
22451     {
22452         if (!n.childNodes.length) {
22453             return;
22454         }
22455         for (var i = n.childNodes.length-1; i > -1 ; i--) {
22456            this.cleanUpChild(n.childNodes[i]);
22457         }
22458     },
22459     
22460     
22461         
22462     
22463     cleanUpChild : function (node)
22464     {
22465         var ed = this;
22466         //console.log(node);
22467         if (node.nodeName == "#text") {
22468             // clean up silly Windows -- stuff?
22469             return; 
22470         }
22471         if (node.nodeName == "#comment") {
22472             node.parentNode.removeChild(node);
22473             // clean up silly Windows -- stuff?
22474             return; 
22475         }
22476         var lcname = node.tagName.toLowerCase();
22477         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22478         // whitelist of tags..
22479         
22480         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22481             // remove node.
22482             node.parentNode.removeChild(node);
22483             return;
22484             
22485         }
22486         
22487         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22488         
22489         // remove <a name=....> as rendering on yahoo mailer is borked with this.
22490         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22491         
22492         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22493         //    remove_keep_children = true;
22494         //}
22495         
22496         if (remove_keep_children) {
22497             this.cleanUpChildren(node);
22498             // inserts everything just before this node...
22499             while (node.childNodes.length) {
22500                 var cn = node.childNodes[0];
22501                 node.removeChild(cn);
22502                 node.parentNode.insertBefore(cn, node);
22503             }
22504             node.parentNode.removeChild(node);
22505             return;
22506         }
22507         
22508         if (!node.attributes || !node.attributes.length) {
22509             this.cleanUpChildren(node);
22510             return;
22511         }
22512         
22513         function cleanAttr(n,v)
22514         {
22515             
22516             if (v.match(/^\./) || v.match(/^\//)) {
22517                 return;
22518             }
22519             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22520                 return;
22521             }
22522             if (v.match(/^#/)) {
22523                 return;
22524             }
22525 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22526             node.removeAttribute(n);
22527             
22528         }
22529         
22530         var cwhite = this.cwhite;
22531         var cblack = this.cblack;
22532             
22533         function cleanStyle(n,v)
22534         {
22535             if (v.match(/expression/)) { //XSS?? should we even bother..
22536                 node.removeAttribute(n);
22537                 return;
22538             }
22539             
22540             var parts = v.split(/;/);
22541             var clean = [];
22542             
22543             Roo.each(parts, function(p) {
22544                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22545                 if (!p.length) {
22546                     return true;
22547                 }
22548                 var l = p.split(':').shift().replace(/\s+/g,'');
22549                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22550                 
22551                 if ( cwhite.length && cblack.indexOf(l) > -1) {
22552 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22553                     //node.removeAttribute(n);
22554                     return true;
22555                 }
22556                 //Roo.log()
22557                 // only allow 'c whitelisted system attributes'
22558                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
22559 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22560                     //node.removeAttribute(n);
22561                     return true;
22562                 }
22563                 
22564                 
22565                  
22566                 
22567                 clean.push(p);
22568                 return true;
22569             });
22570             if (clean.length) { 
22571                 node.setAttribute(n, clean.join(';'));
22572             } else {
22573                 node.removeAttribute(n);
22574             }
22575             
22576         }
22577         
22578         
22579         for (var i = node.attributes.length-1; i > -1 ; i--) {
22580             var a = node.attributes[i];
22581             //console.log(a);
22582             
22583             if (a.name.toLowerCase().substr(0,2)=='on')  {
22584                 node.removeAttribute(a.name);
22585                 continue;
22586             }
22587             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22588                 node.removeAttribute(a.name);
22589                 continue;
22590             }
22591             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22592                 cleanAttr(a.name,a.value); // fixme..
22593                 continue;
22594             }
22595             if (a.name == 'style') {
22596                 cleanStyle(a.name,a.value);
22597                 continue;
22598             }
22599             /// clean up MS crap..
22600             // tecnically this should be a list of valid class'es..
22601             
22602             
22603             if (a.name == 'class') {
22604                 if (a.value.match(/^Mso/)) {
22605                     node.className = '';
22606                 }
22607                 
22608                 if (a.value.match(/^body$/)) {
22609                     node.className = '';
22610                 }
22611                 continue;
22612             }
22613             
22614             // style cleanup!?
22615             // class cleanup?
22616             
22617         }
22618         
22619         
22620         this.cleanUpChildren(node);
22621         
22622         
22623     },
22624     
22625     /**
22626      * Clean up MS wordisms...
22627      */
22628     cleanWord : function(node)
22629     {
22630         
22631         
22632         if (!node) {
22633             this.cleanWord(this.doc.body);
22634             return;
22635         }
22636         if (node.nodeName == "#text") {
22637             // clean up silly Windows -- stuff?
22638             return; 
22639         }
22640         if (node.nodeName == "#comment") {
22641             node.parentNode.removeChild(node);
22642             // clean up silly Windows -- stuff?
22643             return; 
22644         }
22645         
22646         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22647             node.parentNode.removeChild(node);
22648             return;
22649         }
22650         
22651         // remove - but keep children..
22652         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22653             while (node.childNodes.length) {
22654                 var cn = node.childNodes[0];
22655                 node.removeChild(cn);
22656                 node.parentNode.insertBefore(cn, node);
22657             }
22658             node.parentNode.removeChild(node);
22659             this.iterateChildren(node, this.cleanWord);
22660             return;
22661         }
22662         // clean styles
22663         if (node.className.length) {
22664             
22665             var cn = node.className.split(/\W+/);
22666             var cna = [];
22667             Roo.each(cn, function(cls) {
22668                 if (cls.match(/Mso[a-zA-Z]+/)) {
22669                     return;
22670                 }
22671                 cna.push(cls);
22672             });
22673             node.className = cna.length ? cna.join(' ') : '';
22674             if (!cna.length) {
22675                 node.removeAttribute("class");
22676             }
22677         }
22678         
22679         if (node.hasAttribute("lang")) {
22680             node.removeAttribute("lang");
22681         }
22682         
22683         if (node.hasAttribute("style")) {
22684             
22685             var styles = node.getAttribute("style").split(";");
22686             var nstyle = [];
22687             Roo.each(styles, function(s) {
22688                 if (!s.match(/:/)) {
22689                     return;
22690                 }
22691                 var kv = s.split(":");
22692                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22693                     return;
22694                 }
22695                 // what ever is left... we allow.
22696                 nstyle.push(s);
22697             });
22698             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22699             if (!nstyle.length) {
22700                 node.removeAttribute('style');
22701             }
22702         }
22703         this.iterateChildren(node, this.cleanWord);
22704         
22705         
22706         
22707     },
22708     /**
22709      * iterateChildren of a Node, calling fn each time, using this as the scole..
22710      * @param {DomNode} node node to iterate children of.
22711      * @param {Function} fn method of this class to call on each item.
22712      */
22713     iterateChildren : function(node, fn)
22714     {
22715         if (!node.childNodes.length) {
22716                 return;
22717         }
22718         for (var i = node.childNodes.length-1; i > -1 ; i--) {
22719            fn.call(this, node.childNodes[i])
22720         }
22721     },
22722     
22723     
22724     /**
22725      * cleanTableWidths.
22726      *
22727      * Quite often pasting from word etc.. results in tables with column and widths.
22728      * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22729      *
22730      */
22731     cleanTableWidths : function(node)
22732     {
22733          
22734          
22735         if (!node) {
22736             this.cleanTableWidths(this.doc.body);
22737             return;
22738         }
22739         
22740         // ignore list...
22741         if (node.nodeName == "#text" || node.nodeName == "#comment") {
22742             return; 
22743         }
22744         Roo.log(node.tagName);
22745         if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22746             this.iterateChildren(node, this.cleanTableWidths);
22747             return;
22748         }
22749         if (node.hasAttribute('width')) {
22750             node.removeAttribute('width');
22751         }
22752         
22753          
22754         if (node.hasAttribute("style")) {
22755             // pretty basic...
22756             
22757             var styles = node.getAttribute("style").split(";");
22758             var nstyle = [];
22759             Roo.each(styles, function(s) {
22760                 if (!s.match(/:/)) {
22761                     return;
22762                 }
22763                 var kv = s.split(":");
22764                 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22765                     return;
22766                 }
22767                 // what ever is left... we allow.
22768                 nstyle.push(s);
22769             });
22770             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22771             if (!nstyle.length) {
22772                 node.removeAttribute('style');
22773             }
22774         }
22775         
22776         this.iterateChildren(node, this.cleanTableWidths);
22777         
22778         
22779     },
22780     
22781     
22782     
22783     
22784     domToHTML : function(currentElement, depth, nopadtext) {
22785         
22786         depth = depth || 0;
22787         nopadtext = nopadtext || false;
22788     
22789         if (!currentElement) {
22790             return this.domToHTML(this.doc.body);
22791         }
22792         
22793         //Roo.log(currentElement);
22794         var j;
22795         var allText = false;
22796         var nodeName = currentElement.nodeName;
22797         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22798         
22799         if  (nodeName == '#text') {
22800             
22801             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22802         }
22803         
22804         
22805         var ret = '';
22806         if (nodeName != 'BODY') {
22807              
22808             var i = 0;
22809             // Prints the node tagName, such as <A>, <IMG>, etc
22810             if (tagName) {
22811                 var attr = [];
22812                 for(i = 0; i < currentElement.attributes.length;i++) {
22813                     // quoting?
22814                     var aname = currentElement.attributes.item(i).name;
22815                     if (!currentElement.attributes.item(i).value.length) {
22816                         continue;
22817                     }
22818                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22819                 }
22820                 
22821                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22822             } 
22823             else {
22824                 
22825                 // eack
22826             }
22827         } else {
22828             tagName = false;
22829         }
22830         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22831             return ret;
22832         }
22833         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22834             nopadtext = true;
22835         }
22836         
22837         
22838         // Traverse the tree
22839         i = 0;
22840         var currentElementChild = currentElement.childNodes.item(i);
22841         var allText = true;
22842         var innerHTML  = '';
22843         lastnode = '';
22844         while (currentElementChild) {
22845             // Formatting code (indent the tree so it looks nice on the screen)
22846             var nopad = nopadtext;
22847             if (lastnode == 'SPAN') {
22848                 nopad  = true;
22849             }
22850             // text
22851             if  (currentElementChild.nodeName == '#text') {
22852                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22853                 toadd = nopadtext ? toadd : toadd.trim();
22854                 if (!nopad && toadd.length > 80) {
22855                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
22856                 }
22857                 innerHTML  += toadd;
22858                 
22859                 i++;
22860                 currentElementChild = currentElement.childNodes.item(i);
22861                 lastNode = '';
22862                 continue;
22863             }
22864             allText = false;
22865             
22866             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
22867                 
22868             // Recursively traverse the tree structure of the child node
22869             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
22870             lastnode = currentElementChild.nodeName;
22871             i++;
22872             currentElementChild=currentElement.childNodes.item(i);
22873         }
22874         
22875         ret += innerHTML;
22876         
22877         if (!allText) {
22878                 // The remaining code is mostly for formatting the tree
22879             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
22880         }
22881         
22882         
22883         if (tagName) {
22884             ret+= "</"+tagName+">";
22885         }
22886         return ret;
22887         
22888     },
22889         
22890     applyBlacklists : function()
22891     {
22892         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
22893         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
22894         
22895         this.white = [];
22896         this.black = [];
22897         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22898             if (b.indexOf(tag) > -1) {
22899                 return;
22900             }
22901             this.white.push(tag);
22902             
22903         }, this);
22904         
22905         Roo.each(w, function(tag) {
22906             if (b.indexOf(tag) > -1) {
22907                 return;
22908             }
22909             if (this.white.indexOf(tag) > -1) {
22910                 return;
22911             }
22912             this.white.push(tag);
22913             
22914         }, this);
22915         
22916         
22917         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22918             if (w.indexOf(tag) > -1) {
22919                 return;
22920             }
22921             this.black.push(tag);
22922             
22923         }, this);
22924         
22925         Roo.each(b, function(tag) {
22926             if (w.indexOf(tag) > -1) {
22927                 return;
22928             }
22929             if (this.black.indexOf(tag) > -1) {
22930                 return;
22931             }
22932             this.black.push(tag);
22933             
22934         }, this);
22935         
22936         
22937         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
22938         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
22939         
22940         this.cwhite = [];
22941         this.cblack = [];
22942         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22943             if (b.indexOf(tag) > -1) {
22944                 return;
22945             }
22946             this.cwhite.push(tag);
22947             
22948         }, this);
22949         
22950         Roo.each(w, function(tag) {
22951             if (b.indexOf(tag) > -1) {
22952                 return;
22953             }
22954             if (this.cwhite.indexOf(tag) > -1) {
22955                 return;
22956             }
22957             this.cwhite.push(tag);
22958             
22959         }, this);
22960         
22961         
22962         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22963             if (w.indexOf(tag) > -1) {
22964                 return;
22965             }
22966             this.cblack.push(tag);
22967             
22968         }, this);
22969         
22970         Roo.each(b, function(tag) {
22971             if (w.indexOf(tag) > -1) {
22972                 return;
22973             }
22974             if (this.cblack.indexOf(tag) > -1) {
22975                 return;
22976             }
22977             this.cblack.push(tag);
22978             
22979         }, this);
22980     },
22981     
22982     setStylesheets : function(stylesheets)
22983     {
22984         if(typeof(stylesheets) == 'string'){
22985             Roo.get(this.iframe.contentDocument.head).createChild({
22986                 tag : 'link',
22987                 rel : 'stylesheet',
22988                 type : 'text/css',
22989                 href : stylesheets
22990             });
22991             
22992             return;
22993         }
22994         var _this = this;
22995      
22996         Roo.each(stylesheets, function(s) {
22997             if(!s.length){
22998                 return;
22999             }
23000             
23001             Roo.get(_this.iframe.contentDocument.head).createChild({
23002                 tag : 'link',
23003                 rel : 'stylesheet',
23004                 type : 'text/css',
23005                 href : s
23006             });
23007         });
23008
23009         
23010     },
23011     
23012     removeStylesheets : function()
23013     {
23014         var _this = this;
23015         
23016         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23017             s.remove();
23018         });
23019     },
23020     
23021     setStyle : function(style)
23022     {
23023         Roo.get(this.iframe.contentDocument.head).createChild({
23024             tag : 'style',
23025             type : 'text/css',
23026             html : style
23027         });
23028
23029         return;
23030     }
23031     
23032     // hide stuff that is not compatible
23033     /**
23034      * @event blur
23035      * @hide
23036      */
23037     /**
23038      * @event change
23039      * @hide
23040      */
23041     /**
23042      * @event focus
23043      * @hide
23044      */
23045     /**
23046      * @event specialkey
23047      * @hide
23048      */
23049     /**
23050      * @cfg {String} fieldClass @hide
23051      */
23052     /**
23053      * @cfg {String} focusClass @hide
23054      */
23055     /**
23056      * @cfg {String} autoCreate @hide
23057      */
23058     /**
23059      * @cfg {String} inputType @hide
23060      */
23061     /**
23062      * @cfg {String} invalidClass @hide
23063      */
23064     /**
23065      * @cfg {String} invalidText @hide
23066      */
23067     /**
23068      * @cfg {String} msgFx @hide
23069      */
23070     /**
23071      * @cfg {String} validateOnBlur @hide
23072      */
23073 });
23074
23075 Roo.HtmlEditorCore.white = [
23076         'area', 'br', 'img', 'input', 'hr', 'wbr',
23077         
23078        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
23079        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
23080        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
23081        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
23082        'table',   'ul',         'xmp', 
23083        
23084        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
23085       'thead',   'tr', 
23086      
23087       'dir', 'menu', 'ol', 'ul', 'dl',
23088        
23089       'embed',  'object'
23090 ];
23091
23092
23093 Roo.HtmlEditorCore.black = [
23094     //    'embed',  'object', // enable - backend responsiblity to clean thiese
23095         'applet', // 
23096         'base',   'basefont', 'bgsound', 'blink',  'body', 
23097         'frame',  'frameset', 'head',    'html',   'ilayer', 
23098         'iframe', 'layer',  'link',     'meta',    'object',   
23099         'script', 'style' ,'title',  'xml' // clean later..
23100 ];
23101 Roo.HtmlEditorCore.clean = [
23102     'script', 'style', 'title', 'xml'
23103 ];
23104 Roo.HtmlEditorCore.remove = [
23105     'font'
23106 ];
23107 // attributes..
23108
23109 Roo.HtmlEditorCore.ablack = [
23110     'on'
23111 ];
23112     
23113 Roo.HtmlEditorCore.aclean = [ 
23114     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
23115 ];
23116
23117 // protocols..
23118 Roo.HtmlEditorCore.pwhite= [
23119         'http',  'https',  'mailto'
23120 ];
23121
23122 // white listed style attributes.
23123 Roo.HtmlEditorCore.cwhite= [
23124       //  'text-align', /// default is to allow most things..
23125       
23126          
23127 //        'font-size'//??
23128 ];
23129
23130 // black listed style attributes.
23131 Roo.HtmlEditorCore.cblack= [
23132       //  'font-size' -- this can be set by the project 
23133 ];
23134
23135
23136 Roo.HtmlEditorCore.swapCodes   =[ 
23137     [    8211, "--" ], 
23138     [    8212, "--" ], 
23139     [    8216,  "'" ],  
23140     [    8217, "'" ],  
23141     [    8220, '"' ],  
23142     [    8221, '"' ],  
23143     [    8226, "*" ],  
23144     [    8230, "..." ]
23145 ]; 
23146
23147     /*
23148  * - LGPL
23149  *
23150  * HtmlEditor
23151  * 
23152  */
23153
23154 /**
23155  * @class Roo.bootstrap.HtmlEditor
23156  * @extends Roo.bootstrap.TextArea
23157  * Bootstrap HtmlEditor class
23158
23159  * @constructor
23160  * Create a new HtmlEditor
23161  * @param {Object} config The config object
23162  */
23163
23164 Roo.bootstrap.HtmlEditor = function(config){
23165     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23166     if (!this.toolbars) {
23167         this.toolbars = [];
23168     }
23169     
23170     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23171     this.addEvents({
23172             /**
23173              * @event initialize
23174              * Fires when the editor is fully initialized (including the iframe)
23175              * @param {HtmlEditor} this
23176              */
23177             initialize: true,
23178             /**
23179              * @event activate
23180              * Fires when the editor is first receives the focus. Any insertion must wait
23181              * until after this event.
23182              * @param {HtmlEditor} this
23183              */
23184             activate: true,
23185              /**
23186              * @event beforesync
23187              * Fires before the textarea is updated with content from the editor iframe. Return false
23188              * to cancel the sync.
23189              * @param {HtmlEditor} this
23190              * @param {String} html
23191              */
23192             beforesync: true,
23193              /**
23194              * @event beforepush
23195              * Fires before the iframe editor is updated with content from the textarea. Return false
23196              * to cancel the push.
23197              * @param {HtmlEditor} this
23198              * @param {String} html
23199              */
23200             beforepush: true,
23201              /**
23202              * @event sync
23203              * Fires when the textarea is updated with content from the editor iframe.
23204              * @param {HtmlEditor} this
23205              * @param {String} html
23206              */
23207             sync: true,
23208              /**
23209              * @event push
23210              * Fires when the iframe editor is updated with content from the textarea.
23211              * @param {HtmlEditor} this
23212              * @param {String} html
23213              */
23214             push: true,
23215              /**
23216              * @event editmodechange
23217              * Fires when the editor switches edit modes
23218              * @param {HtmlEditor} this
23219              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23220              */
23221             editmodechange: true,
23222             /**
23223              * @event editorevent
23224              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23225              * @param {HtmlEditor} this
23226              */
23227             editorevent: true,
23228             /**
23229              * @event firstfocus
23230              * Fires when on first focus - needed by toolbars..
23231              * @param {HtmlEditor} this
23232              */
23233             firstfocus: true,
23234             /**
23235              * @event autosave
23236              * Auto save the htmlEditor value as a file into Events
23237              * @param {HtmlEditor} this
23238              */
23239             autosave: true,
23240             /**
23241              * @event savedpreview
23242              * preview the saved version of htmlEditor
23243              * @param {HtmlEditor} this
23244              */
23245             savedpreview: true
23246         });
23247 };
23248
23249
23250 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
23251     
23252     
23253       /**
23254      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23255      */
23256     toolbars : false,
23257     
23258      /**
23259     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23260     */
23261     btns : [],
23262    
23263      /**
23264      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
23265      *                        Roo.resizable.
23266      */
23267     resizable : false,
23268      /**
23269      * @cfg {Number} height (in pixels)
23270      */   
23271     height: 300,
23272    /**
23273      * @cfg {Number} width (in pixels)
23274      */   
23275     width: false,
23276     
23277     /**
23278      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23279      * 
23280      */
23281     stylesheets: false,
23282     
23283     // id of frame..
23284     frameId: false,
23285     
23286     // private properties
23287     validationEvent : false,
23288     deferHeight: true,
23289     initialized : false,
23290     activated : false,
23291     
23292     onFocus : Roo.emptyFn,
23293     iframePad:3,
23294     hideMode:'offsets',
23295     
23296     tbContainer : false,
23297     
23298     bodyCls : '',
23299     
23300     toolbarContainer :function() {
23301         return this.wrap.select('.x-html-editor-tb',true).first();
23302     },
23303
23304     /**
23305      * Protected method that will not generally be called directly. It
23306      * is called when the editor creates its toolbar. Override this method if you need to
23307      * add custom toolbar buttons.
23308      * @param {HtmlEditor} editor
23309      */
23310     createToolbar : function(){
23311         Roo.log('renewing');
23312         Roo.log("create toolbars");
23313         
23314         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23315         this.toolbars[0].render(this.toolbarContainer());
23316         
23317         return;
23318         
23319 //        if (!editor.toolbars || !editor.toolbars.length) {
23320 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23321 //        }
23322 //        
23323 //        for (var i =0 ; i < editor.toolbars.length;i++) {
23324 //            editor.toolbars[i] = Roo.factory(
23325 //                    typeof(editor.toolbars[i]) == 'string' ?
23326 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
23327 //                Roo.bootstrap.HtmlEditor);
23328 //            editor.toolbars[i].init(editor);
23329 //        }
23330     },
23331
23332      
23333     // private
23334     onRender : function(ct, position)
23335     {
23336        // Roo.log("Call onRender: " + this.xtype);
23337         var _t = this;
23338         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23339       
23340         this.wrap = this.inputEl().wrap({
23341             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23342         });
23343         
23344         this.editorcore.onRender(ct, position);
23345          
23346         if (this.resizable) {
23347             this.resizeEl = new Roo.Resizable(this.wrap, {
23348                 pinned : true,
23349                 wrap: true,
23350                 dynamic : true,
23351                 minHeight : this.height,
23352                 height: this.height,
23353                 handles : this.resizable,
23354                 width: this.width,
23355                 listeners : {
23356                     resize : function(r, w, h) {
23357                         _t.onResize(w,h); // -something
23358                     }
23359                 }
23360             });
23361             
23362         }
23363         this.createToolbar(this);
23364        
23365         
23366         if(!this.width && this.resizable){
23367             this.setSize(this.wrap.getSize());
23368         }
23369         if (this.resizeEl) {
23370             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23371             // should trigger onReize..
23372         }
23373         
23374     },
23375
23376     // private
23377     onResize : function(w, h)
23378     {
23379         Roo.log('resize: ' +w + ',' + h );
23380         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23381         var ew = false;
23382         var eh = false;
23383         
23384         if(this.inputEl() ){
23385             if(typeof w == 'number'){
23386                 var aw = w - this.wrap.getFrameWidth('lr');
23387                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23388                 ew = aw;
23389             }
23390             if(typeof h == 'number'){
23391                  var tbh = -11;  // fixme it needs to tool bar size!
23392                 for (var i =0; i < this.toolbars.length;i++) {
23393                     // fixme - ask toolbars for heights?
23394                     tbh += this.toolbars[i].el.getHeight();
23395                     //if (this.toolbars[i].footer) {
23396                     //    tbh += this.toolbars[i].footer.el.getHeight();
23397                     //}
23398                 }
23399               
23400                 
23401                 
23402                 
23403                 
23404                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23405                 ah -= 5; // knock a few pixes off for look..
23406                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23407                 var eh = ah;
23408             }
23409         }
23410         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23411         this.editorcore.onResize(ew,eh);
23412         
23413     },
23414
23415     /**
23416      * Toggles the editor between standard and source edit mode.
23417      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23418      */
23419     toggleSourceEdit : function(sourceEditMode)
23420     {
23421         this.editorcore.toggleSourceEdit(sourceEditMode);
23422         
23423         if(this.editorcore.sourceEditMode){
23424             Roo.log('editor - showing textarea');
23425             
23426 //            Roo.log('in');
23427 //            Roo.log(this.syncValue());
23428             this.syncValue();
23429             this.inputEl().removeClass(['hide', 'x-hidden']);
23430             this.inputEl().dom.removeAttribute('tabIndex');
23431             this.inputEl().focus();
23432         }else{
23433             Roo.log('editor - hiding textarea');
23434 //            Roo.log('out')
23435 //            Roo.log(this.pushValue()); 
23436             this.pushValue();
23437             
23438             this.inputEl().addClass(['hide', 'x-hidden']);
23439             this.inputEl().dom.setAttribute('tabIndex', -1);
23440             //this.deferFocus();
23441         }
23442          
23443         if(this.resizable){
23444             this.setSize(this.wrap.getSize());
23445         }
23446         
23447         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23448     },
23449  
23450     // private (for BoxComponent)
23451     adjustSize : Roo.BoxComponent.prototype.adjustSize,
23452
23453     // private (for BoxComponent)
23454     getResizeEl : function(){
23455         return this.wrap;
23456     },
23457
23458     // private (for BoxComponent)
23459     getPositionEl : function(){
23460         return this.wrap;
23461     },
23462
23463     // private
23464     initEvents : function(){
23465         this.originalValue = this.getValue();
23466     },
23467
23468 //    /**
23469 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23470 //     * @method
23471 //     */
23472 //    markInvalid : Roo.emptyFn,
23473 //    /**
23474 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23475 //     * @method
23476 //     */
23477 //    clearInvalid : Roo.emptyFn,
23478
23479     setValue : function(v){
23480         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23481         this.editorcore.pushValue();
23482     },
23483
23484      
23485     // private
23486     deferFocus : function(){
23487         this.focus.defer(10, this);
23488     },
23489
23490     // doc'ed in Field
23491     focus : function(){
23492         this.editorcore.focus();
23493         
23494     },
23495       
23496
23497     // private
23498     onDestroy : function(){
23499         
23500         
23501         
23502         if(this.rendered){
23503             
23504             for (var i =0; i < this.toolbars.length;i++) {
23505                 // fixme - ask toolbars for heights?
23506                 this.toolbars[i].onDestroy();
23507             }
23508             
23509             this.wrap.dom.innerHTML = '';
23510             this.wrap.remove();
23511         }
23512     },
23513
23514     // private
23515     onFirstFocus : function(){
23516         //Roo.log("onFirstFocus");
23517         this.editorcore.onFirstFocus();
23518          for (var i =0; i < this.toolbars.length;i++) {
23519             this.toolbars[i].onFirstFocus();
23520         }
23521         
23522     },
23523     
23524     // private
23525     syncValue : function()
23526     {   
23527         this.editorcore.syncValue();
23528     },
23529     
23530     pushValue : function()
23531     {   
23532         this.editorcore.pushValue();
23533     }
23534      
23535     
23536     // hide stuff that is not compatible
23537     /**
23538      * @event blur
23539      * @hide
23540      */
23541     /**
23542      * @event change
23543      * @hide
23544      */
23545     /**
23546      * @event focus
23547      * @hide
23548      */
23549     /**
23550      * @event specialkey
23551      * @hide
23552      */
23553     /**
23554      * @cfg {String} fieldClass @hide
23555      */
23556     /**
23557      * @cfg {String} focusClass @hide
23558      */
23559     /**
23560      * @cfg {String} autoCreate @hide
23561      */
23562     /**
23563      * @cfg {String} inputType @hide
23564      */
23565     /**
23566      * @cfg {String} invalidClass @hide
23567      */
23568     /**
23569      * @cfg {String} invalidText @hide
23570      */
23571     /**
23572      * @cfg {String} msgFx @hide
23573      */
23574     /**
23575      * @cfg {String} validateOnBlur @hide
23576      */
23577 });
23578  
23579     
23580    
23581    
23582    
23583       
23584 Roo.namespace('Roo.bootstrap.htmleditor');
23585 /**
23586  * @class Roo.bootstrap.HtmlEditorToolbar1
23587  * Basic Toolbar
23588  * 
23589  * Usage:
23590  *
23591  new Roo.bootstrap.HtmlEditor({
23592     ....
23593     toolbars : [
23594         new Roo.bootstrap.HtmlEditorToolbar1({
23595             disable : { fonts: 1 , format: 1, ..., ... , ...],
23596             btns : [ .... ]
23597         })
23598     }
23599      
23600  * 
23601  * @cfg {Object} disable List of elements to disable..
23602  * @cfg {Array} btns List of additional buttons.
23603  * 
23604  * 
23605  * NEEDS Extra CSS? 
23606  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23607  */
23608  
23609 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23610 {
23611     
23612     Roo.apply(this, config);
23613     
23614     // default disabled, based on 'good practice'..
23615     this.disable = this.disable || {};
23616     Roo.applyIf(this.disable, {
23617         fontSize : true,
23618         colors : true,
23619         specialElements : true
23620     });
23621     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23622     
23623     this.editor = config.editor;
23624     this.editorcore = config.editor.editorcore;
23625     
23626     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23627     
23628     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23629     // dont call parent... till later.
23630 }
23631 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
23632      
23633     bar : true,
23634     
23635     editor : false,
23636     editorcore : false,
23637     
23638     
23639     formats : [
23640         "p" ,  
23641         "h1","h2","h3","h4","h5","h6", 
23642         "pre", "code", 
23643         "abbr", "acronym", "address", "cite", "samp", "var",
23644         'div','span'
23645     ],
23646     
23647     onRender : function(ct, position)
23648     {
23649        // Roo.log("Call onRender: " + this.xtype);
23650         
23651        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23652        Roo.log(this.el);
23653        this.el.dom.style.marginBottom = '0';
23654        var _this = this;
23655        var editorcore = this.editorcore;
23656        var editor= this.editor;
23657        
23658        var children = [];
23659        var btn = function(id,cmd , toggle, handler, html){
23660        
23661             var  event = toggle ? 'toggle' : 'click';
23662        
23663             var a = {
23664                 size : 'sm',
23665                 xtype: 'Button',
23666                 xns: Roo.bootstrap,
23667                 glyphicon : id,
23668                 cmd : id || cmd,
23669                 enableToggle:toggle !== false,
23670                 html : html || '',
23671                 pressed : toggle ? false : null,
23672                 listeners : {}
23673             };
23674             a.listeners[toggle ? 'toggle' : 'click'] = function() {
23675                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
23676             };
23677             children.push(a);
23678             return a;
23679        }
23680        
23681     //    var cb_box = function...
23682         
23683         var style = {
23684                 xtype: 'Button',
23685                 size : 'sm',
23686                 xns: Roo.bootstrap,
23687                 glyphicon : 'font',
23688                 //html : 'submit'
23689                 menu : {
23690                     xtype: 'Menu',
23691                     xns: Roo.bootstrap,
23692                     items:  []
23693                 }
23694         };
23695         Roo.each(this.formats, function(f) {
23696             style.menu.items.push({
23697                 xtype :'MenuItem',
23698                 xns: Roo.bootstrap,
23699                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23700                 tagname : f,
23701                 listeners : {
23702                     click : function()
23703                     {
23704                         editorcore.insertTag(this.tagname);
23705                         editor.focus();
23706                     }
23707                 }
23708                 
23709             });
23710         });
23711         children.push(style);   
23712         
23713         btn('bold',false,true);
23714         btn('italic',false,true);
23715         btn('align-left', 'justifyleft',true);
23716         btn('align-center', 'justifycenter',true);
23717         btn('align-right' , 'justifyright',true);
23718         btn('link', false, false, function(btn) {
23719             //Roo.log("create link?");
23720             var url = prompt(this.createLinkText, this.defaultLinkValue);
23721             if(url && url != 'http:/'+'/'){
23722                 this.editorcore.relayCmd('createlink', url);
23723             }
23724         }),
23725         btn('list','insertunorderedlist',true);
23726         btn('pencil', false,true, function(btn){
23727                 Roo.log(this);
23728                 this.toggleSourceEdit(btn.pressed);
23729         });
23730         
23731         if (this.editor.btns.length > 0) {
23732             for (var i = 0; i<this.editor.btns.length; i++) {
23733                 children.push(this.editor.btns[i]);
23734             }
23735         }
23736         
23737         /*
23738         var cog = {
23739                 xtype: 'Button',
23740                 size : 'sm',
23741                 xns: Roo.bootstrap,
23742                 glyphicon : 'cog',
23743                 //html : 'submit'
23744                 menu : {
23745                     xtype: 'Menu',
23746                     xns: Roo.bootstrap,
23747                     items:  []
23748                 }
23749         };
23750         
23751         cog.menu.items.push({
23752             xtype :'MenuItem',
23753             xns: Roo.bootstrap,
23754             html : Clean styles,
23755             tagname : f,
23756             listeners : {
23757                 click : function()
23758                 {
23759                     editorcore.insertTag(this.tagname);
23760                     editor.focus();
23761                 }
23762             }
23763             
23764         });
23765        */
23766         
23767          
23768        this.xtype = 'NavSimplebar';
23769         
23770         for(var i=0;i< children.length;i++) {
23771             
23772             this.buttons.add(this.addxtypeChild(children[i]));
23773             
23774         }
23775         
23776         editor.on('editorevent', this.updateToolbar, this);
23777     },
23778     onBtnClick : function(id)
23779     {
23780        this.editorcore.relayCmd(id);
23781        this.editorcore.focus();
23782     },
23783     
23784     /**
23785      * Protected method that will not generally be called directly. It triggers
23786      * a toolbar update by reading the markup state of the current selection in the editor.
23787      */
23788     updateToolbar: function(){
23789
23790         if(!this.editorcore.activated){
23791             this.editor.onFirstFocus(); // is this neeed?
23792             return;
23793         }
23794
23795         var btns = this.buttons; 
23796         var doc = this.editorcore.doc;
23797         btns.get('bold').setActive(doc.queryCommandState('bold'));
23798         btns.get('italic').setActive(doc.queryCommandState('italic'));
23799         //btns.get('underline').setActive(doc.queryCommandState('underline'));
23800         
23801         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23802         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23803         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23804         
23805         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23806         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23807          /*
23808         
23809         var ans = this.editorcore.getAllAncestors();
23810         if (this.formatCombo) {
23811             
23812             
23813             var store = this.formatCombo.store;
23814             this.formatCombo.setValue("");
23815             for (var i =0; i < ans.length;i++) {
23816                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23817                     // select it..
23818                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23819                     break;
23820                 }
23821             }
23822         }
23823         
23824         
23825         
23826         // hides menus... - so this cant be on a menu...
23827         Roo.bootstrap.MenuMgr.hideAll();
23828         */
23829         Roo.bootstrap.MenuMgr.hideAll();
23830         //this.editorsyncValue();
23831     },
23832     onFirstFocus: function() {
23833         this.buttons.each(function(item){
23834            item.enable();
23835         });
23836     },
23837     toggleSourceEdit : function(sourceEditMode){
23838         
23839           
23840         if(sourceEditMode){
23841             Roo.log("disabling buttons");
23842            this.buttons.each( function(item){
23843                 if(item.cmd != 'pencil'){
23844                     item.disable();
23845                 }
23846             });
23847           
23848         }else{
23849             Roo.log("enabling buttons");
23850             if(this.editorcore.initialized){
23851                 this.buttons.each( function(item){
23852                     item.enable();
23853                 });
23854             }
23855             
23856         }
23857         Roo.log("calling toggole on editor");
23858         // tell the editor that it's been pressed..
23859         this.editor.toggleSourceEdit(sourceEditMode);
23860        
23861     }
23862 });
23863
23864
23865
23866
23867
23868 /**
23869  * @class Roo.bootstrap.Table.AbstractSelectionModel
23870  * @extends Roo.util.Observable
23871  * Abstract base class for grid SelectionModels.  It provides the interface that should be
23872  * implemented by descendant classes.  This class should not be directly instantiated.
23873  * @constructor
23874  */
23875 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23876     this.locked = false;
23877     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23878 };
23879
23880
23881 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
23882     /** @ignore Called by the grid automatically. Do not call directly. */
23883     init : function(grid){
23884         this.grid = grid;
23885         this.initEvents();
23886     },
23887
23888     /**
23889      * Locks the selections.
23890      */
23891     lock : function(){
23892         this.locked = true;
23893     },
23894
23895     /**
23896      * Unlocks the selections.
23897      */
23898     unlock : function(){
23899         this.locked = false;
23900     },
23901
23902     /**
23903      * Returns true if the selections are locked.
23904      * @return {Boolean}
23905      */
23906     isLocked : function(){
23907         return this.locked;
23908     }
23909 });
23910 /**
23911  * @extends Roo.bootstrap.Table.AbstractSelectionModel
23912  * @class Roo.bootstrap.Table.RowSelectionModel
23913  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23914  * It supports multiple selections and keyboard selection/navigation. 
23915  * @constructor
23916  * @param {Object} config
23917  */
23918
23919 Roo.bootstrap.Table.RowSelectionModel = function(config){
23920     Roo.apply(this, config);
23921     this.selections = new Roo.util.MixedCollection(false, function(o){
23922         return o.id;
23923     });
23924
23925     this.last = false;
23926     this.lastActive = false;
23927
23928     this.addEvents({
23929         /**
23930              * @event selectionchange
23931              * Fires when the selection changes
23932              * @param {SelectionModel} this
23933              */
23934             "selectionchange" : true,
23935         /**
23936              * @event afterselectionchange
23937              * Fires after the selection changes (eg. by key press or clicking)
23938              * @param {SelectionModel} this
23939              */
23940             "afterselectionchange" : true,
23941         /**
23942              * @event beforerowselect
23943              * Fires when a row is selected being selected, return false to cancel.
23944              * @param {SelectionModel} this
23945              * @param {Number} rowIndex The selected index
23946              * @param {Boolean} keepExisting False if other selections will be cleared
23947              */
23948             "beforerowselect" : true,
23949         /**
23950              * @event rowselect
23951              * Fires when a row is selected.
23952              * @param {SelectionModel} this
23953              * @param {Number} rowIndex The selected index
23954              * @param {Roo.data.Record} r The record
23955              */
23956             "rowselect" : true,
23957         /**
23958              * @event rowdeselect
23959              * Fires when a row is deselected.
23960              * @param {SelectionModel} this
23961              * @param {Number} rowIndex The selected index
23962              */
23963         "rowdeselect" : true
23964     });
23965     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23966     this.locked = false;
23967  };
23968
23969 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
23970     /**
23971      * @cfg {Boolean} singleSelect
23972      * True to allow selection of only one row at a time (defaults to false)
23973      */
23974     singleSelect : false,
23975
23976     // private
23977     initEvents : function()
23978     {
23979
23980         //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23981         //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
23982         //}else{ // allow click to work like normal
23983          //   this.grid.on("rowclick", this.handleDragableRowClick, this);
23984         //}
23985         //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23986         this.grid.on("rowclick", this.handleMouseDown, this);
23987         
23988         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23989             "up" : function(e){
23990                 if(!e.shiftKey){
23991                     this.selectPrevious(e.shiftKey);
23992                 }else if(this.last !== false && this.lastActive !== false){
23993                     var last = this.last;
23994                     this.selectRange(this.last,  this.lastActive-1);
23995                     this.grid.getView().focusRow(this.lastActive);
23996                     if(last !== false){
23997                         this.last = last;
23998                     }
23999                 }else{
24000                     this.selectFirstRow();
24001                 }
24002                 this.fireEvent("afterselectionchange", this);
24003             },
24004             "down" : function(e){
24005                 if(!e.shiftKey){
24006                     this.selectNext(e.shiftKey);
24007                 }else if(this.last !== false && this.lastActive !== false){
24008                     var last = this.last;
24009                     this.selectRange(this.last,  this.lastActive+1);
24010                     this.grid.getView().focusRow(this.lastActive);
24011                     if(last !== false){
24012                         this.last = last;
24013                     }
24014                 }else{
24015                     this.selectFirstRow();
24016                 }
24017                 this.fireEvent("afterselectionchange", this);
24018             },
24019             scope: this
24020         });
24021         this.grid.store.on('load', function(){
24022             this.selections.clear();
24023         },this);
24024         /*
24025         var view = this.grid.view;
24026         view.on("refresh", this.onRefresh, this);
24027         view.on("rowupdated", this.onRowUpdated, this);
24028         view.on("rowremoved", this.onRemove, this);
24029         */
24030     },
24031
24032     // private
24033     onRefresh : function()
24034     {
24035         var ds = this.grid.store, i, v = this.grid.view;
24036         var s = this.selections;
24037         s.each(function(r){
24038             if((i = ds.indexOfId(r.id)) != -1){
24039                 v.onRowSelect(i);
24040             }else{
24041                 s.remove(r);
24042             }
24043         });
24044     },
24045
24046     // private
24047     onRemove : function(v, index, r){
24048         this.selections.remove(r);
24049     },
24050
24051     // private
24052     onRowUpdated : function(v, index, r){
24053         if(this.isSelected(r)){
24054             v.onRowSelect(index);
24055         }
24056     },
24057
24058     /**
24059      * Select records.
24060      * @param {Array} records The records to select
24061      * @param {Boolean} keepExisting (optional) True to keep existing selections
24062      */
24063     selectRecords : function(records, keepExisting)
24064     {
24065         if(!keepExisting){
24066             this.clearSelections();
24067         }
24068             var ds = this.grid.store;
24069         for(var i = 0, len = records.length; i < len; i++){
24070             this.selectRow(ds.indexOf(records[i]), true);
24071         }
24072     },
24073
24074     /**
24075      * Gets the number of selected rows.
24076      * @return {Number}
24077      */
24078     getCount : function(){
24079         return this.selections.length;
24080     },
24081
24082     /**
24083      * Selects the first row in the grid.
24084      */
24085     selectFirstRow : function(){
24086         this.selectRow(0);
24087     },
24088
24089     /**
24090      * Select the last row.
24091      * @param {Boolean} keepExisting (optional) True to keep existing selections
24092      */
24093     selectLastRow : function(keepExisting){
24094         //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24095         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24096     },
24097
24098     /**
24099      * Selects the row immediately following the last selected row.
24100      * @param {Boolean} keepExisting (optional) True to keep existing selections
24101      */
24102     selectNext : function(keepExisting)
24103     {
24104             if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24105             this.selectRow(this.last+1, keepExisting);
24106             this.grid.getView().focusRow(this.last);
24107         }
24108     },
24109
24110     /**
24111      * Selects the row that precedes the last selected row.
24112      * @param {Boolean} keepExisting (optional) True to keep existing selections
24113      */
24114     selectPrevious : function(keepExisting){
24115         if(this.last){
24116             this.selectRow(this.last-1, keepExisting);
24117             this.grid.getView().focusRow(this.last);
24118         }
24119     },
24120
24121     /**
24122      * Returns the selected records
24123      * @return {Array} Array of selected records
24124      */
24125     getSelections : function(){
24126         return [].concat(this.selections.items);
24127     },
24128
24129     /**
24130      * Returns the first selected record.
24131      * @return {Record}
24132      */
24133     getSelected : function(){
24134         return this.selections.itemAt(0);
24135     },
24136
24137
24138     /**
24139      * Clears all selections.
24140      */
24141     clearSelections : function(fast)
24142     {
24143         if(this.locked) {
24144             return;
24145         }
24146         if(fast !== true){
24147                 var ds = this.grid.store;
24148             var s = this.selections;
24149             s.each(function(r){
24150                 this.deselectRow(ds.indexOfId(r.id));
24151             }, this);
24152             s.clear();
24153         }else{
24154             this.selections.clear();
24155         }
24156         this.last = false;
24157     },
24158
24159
24160     /**
24161      * Selects all rows.
24162      */
24163     selectAll : function(){
24164         if(this.locked) {
24165             return;
24166         }
24167         this.selections.clear();
24168         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24169             this.selectRow(i, true);
24170         }
24171     },
24172
24173     /**
24174      * Returns True if there is a selection.
24175      * @return {Boolean}
24176      */
24177     hasSelection : function(){
24178         return this.selections.length > 0;
24179     },
24180
24181     /**
24182      * Returns True if the specified row is selected.
24183      * @param {Number/Record} record The record or index of the record to check
24184      * @return {Boolean}
24185      */
24186     isSelected : function(index){
24187             var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24188         return (r && this.selections.key(r.id) ? true : false);
24189     },
24190
24191     /**
24192      * Returns True if the specified record id is selected.
24193      * @param {String} id The id of record to check
24194      * @return {Boolean}
24195      */
24196     isIdSelected : function(id){
24197         return (this.selections.key(id) ? true : false);
24198     },
24199
24200
24201     // private
24202     handleMouseDBClick : function(e, t){
24203         
24204     },
24205     // private
24206     handleMouseDown : function(e, t)
24207     {
24208             var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24209         if(this.isLocked() || rowIndex < 0 ){
24210             return;
24211         };
24212         if(e.shiftKey && this.last !== false){
24213             var last = this.last;
24214             this.selectRange(last, rowIndex, e.ctrlKey);
24215             this.last = last; // reset the last
24216             t.focus();
24217     
24218         }else{
24219             var isSelected = this.isSelected(rowIndex);
24220             //Roo.log("select row:" + rowIndex);
24221             if(isSelected){
24222                 this.deselectRow(rowIndex);
24223             } else {
24224                         this.selectRow(rowIndex, true);
24225             }
24226     
24227             /*
24228                 if(e.button !== 0 && isSelected){
24229                 alert('rowIndex 2: ' + rowIndex);
24230                     view.focusRow(rowIndex);
24231                 }else if(e.ctrlKey && isSelected){
24232                     this.deselectRow(rowIndex);
24233                 }else if(!isSelected){
24234                     this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24235                     view.focusRow(rowIndex);
24236                 }
24237             */
24238         }
24239         this.fireEvent("afterselectionchange", this);
24240     },
24241     // private
24242     handleDragableRowClick :  function(grid, rowIndex, e) 
24243     {
24244         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24245             this.selectRow(rowIndex, false);
24246             grid.view.focusRow(rowIndex);
24247              this.fireEvent("afterselectionchange", this);
24248         }
24249     },
24250     
24251     /**
24252      * Selects multiple rows.
24253      * @param {Array} rows Array of the indexes of the row to select
24254      * @param {Boolean} keepExisting (optional) True to keep existing selections
24255      */
24256     selectRows : function(rows, keepExisting){
24257         if(!keepExisting){
24258             this.clearSelections();
24259         }
24260         for(var i = 0, len = rows.length; i < len; i++){
24261             this.selectRow(rows[i], true);
24262         }
24263     },
24264
24265     /**
24266      * Selects a range of rows. All rows in between startRow and endRow are also selected.
24267      * @param {Number} startRow The index of the first row in the range
24268      * @param {Number} endRow The index of the last row in the range
24269      * @param {Boolean} keepExisting (optional) True to retain existing selections
24270      */
24271     selectRange : function(startRow, endRow, keepExisting){
24272         if(this.locked) {
24273             return;
24274         }
24275         if(!keepExisting){
24276             this.clearSelections();
24277         }
24278         if(startRow <= endRow){
24279             for(var i = startRow; i <= endRow; i++){
24280                 this.selectRow(i, true);
24281             }
24282         }else{
24283             for(var i = startRow; i >= endRow; i--){
24284                 this.selectRow(i, true);
24285             }
24286         }
24287     },
24288
24289     /**
24290      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24291      * @param {Number} startRow The index of the first row in the range
24292      * @param {Number} endRow The index of the last row in the range
24293      */
24294     deselectRange : function(startRow, endRow, preventViewNotify){
24295         if(this.locked) {
24296             return;
24297         }
24298         for(var i = startRow; i <= endRow; i++){
24299             this.deselectRow(i, preventViewNotify);
24300         }
24301     },
24302
24303     /**
24304      * Selects a row.
24305      * @param {Number} row The index of the row to select
24306      * @param {Boolean} keepExisting (optional) True to keep existing selections
24307      */
24308     selectRow : function(index, keepExisting, preventViewNotify)
24309     {
24310             if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24311             return;
24312         }
24313         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24314             if(!keepExisting || this.singleSelect){
24315                 this.clearSelections();
24316             }
24317             
24318             var r = this.grid.store.getAt(index);
24319             //console.log('selectRow - record id :' + r.id);
24320             
24321             this.selections.add(r);
24322             this.last = this.lastActive = index;
24323             if(!preventViewNotify){
24324                 var proxy = new Roo.Element(
24325                                 this.grid.getRowDom(index)
24326                 );
24327                 proxy.addClass('bg-info info');
24328             }
24329             this.fireEvent("rowselect", this, index, r);
24330             this.fireEvent("selectionchange", this);
24331         }
24332     },
24333
24334     /**
24335      * Deselects a row.
24336      * @param {Number} row The index of the row to deselect
24337      */
24338     deselectRow : function(index, preventViewNotify)
24339     {
24340         if(this.locked) {
24341             return;
24342         }
24343         if(this.last == index){
24344             this.last = false;
24345         }
24346         if(this.lastActive == index){
24347             this.lastActive = false;
24348         }
24349         
24350         var r = this.grid.store.getAt(index);
24351         if (!r) {
24352             return;
24353         }
24354         
24355         this.selections.remove(r);
24356         //.console.log('deselectRow - record id :' + r.id);
24357         if(!preventViewNotify){
24358         
24359             var proxy = new Roo.Element(
24360                 this.grid.getRowDom(index)
24361             );
24362             proxy.removeClass('bg-info info');
24363         }
24364         this.fireEvent("rowdeselect", this, index);
24365         this.fireEvent("selectionchange", this);
24366     },
24367
24368     // private
24369     restoreLast : function(){
24370         if(this._last){
24371             this.last = this._last;
24372         }
24373     },
24374
24375     // private
24376     acceptsNav : function(row, col, cm){
24377         return !cm.isHidden(col) && cm.isCellEditable(col, row);
24378     },
24379
24380     // private
24381     onEditorKey : function(field, e){
24382         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24383         if(k == e.TAB){
24384             e.stopEvent();
24385             ed.completeEdit();
24386             if(e.shiftKey){
24387                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24388             }else{
24389                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24390             }
24391         }else if(k == e.ENTER && !e.ctrlKey){
24392             e.stopEvent();
24393             ed.completeEdit();
24394             if(e.shiftKey){
24395                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24396             }else{
24397                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24398             }
24399         }else if(k == e.ESC){
24400             ed.cancelEdit();
24401         }
24402         if(newCell){
24403             g.startEditing(newCell[0], newCell[1]);
24404         }
24405     }
24406 });
24407 /*
24408  * Based on:
24409  * Ext JS Library 1.1.1
24410  * Copyright(c) 2006-2007, Ext JS, LLC.
24411  *
24412  * Originally Released Under LGPL - original licence link has changed is not relivant.
24413  *
24414  * Fork - LGPL
24415  * <script type="text/javascript">
24416  */
24417  
24418 /**
24419  * @class Roo.bootstrap.PagingToolbar
24420  * @extends Roo.bootstrap.NavSimplebar
24421  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24422  * @constructor
24423  * Create a new PagingToolbar
24424  * @param {Object} config The config object
24425  * @param {Roo.data.Store} store
24426  */
24427 Roo.bootstrap.PagingToolbar = function(config)
24428 {
24429     // old args format still supported... - xtype is prefered..
24430         // created from xtype...
24431     
24432     this.ds = config.dataSource;
24433     
24434     if (config.store && !this.ds) {
24435         this.store= Roo.factory(config.store, Roo.data);
24436         this.ds = this.store;
24437         this.ds.xmodule = this.xmodule || false;
24438     }
24439     
24440     this.toolbarItems = [];
24441     if (config.items) {
24442         this.toolbarItems = config.items;
24443     }
24444     
24445     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24446     
24447     this.cursor = 0;
24448     
24449     if (this.ds) { 
24450         this.bind(this.ds);
24451     }
24452     
24453     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24454     
24455 };
24456
24457 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24458     /**
24459      * @cfg {Roo.data.Store} dataSource
24460      * The underlying data store providing the paged data
24461      */
24462     /**
24463      * @cfg {String/HTMLElement/Element} container
24464      * container The id or element that will contain the toolbar
24465      */
24466     /**
24467      * @cfg {Boolean} displayInfo
24468      * True to display the displayMsg (defaults to false)
24469      */
24470     /**
24471      * @cfg {Number} pageSize
24472      * The number of records to display per page (defaults to 20)
24473      */
24474     pageSize: 20,
24475     /**
24476      * @cfg {String} displayMsg
24477      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24478      */
24479     displayMsg : 'Displaying {0} - {1} of {2}',
24480     /**
24481      * @cfg {String} emptyMsg
24482      * The message to display when no records are found (defaults to "No data to display")
24483      */
24484     emptyMsg : 'No data to display',
24485     /**
24486      * Customizable piece of the default paging text (defaults to "Page")
24487      * @type String
24488      */
24489     beforePageText : "Page",
24490     /**
24491      * Customizable piece of the default paging text (defaults to "of %0")
24492      * @type String
24493      */
24494     afterPageText : "of {0}",
24495     /**
24496      * Customizable piece of the default paging text (defaults to "First Page")
24497      * @type String
24498      */
24499     firstText : "First Page",
24500     /**
24501      * Customizable piece of the default paging text (defaults to "Previous Page")
24502      * @type String
24503      */
24504     prevText : "Previous Page",
24505     /**
24506      * Customizable piece of the default paging text (defaults to "Next Page")
24507      * @type String
24508      */
24509     nextText : "Next Page",
24510     /**
24511      * Customizable piece of the default paging text (defaults to "Last Page")
24512      * @type String
24513      */
24514     lastText : "Last Page",
24515     /**
24516      * Customizable piece of the default paging text (defaults to "Refresh")
24517      * @type String
24518      */
24519     refreshText : "Refresh",
24520
24521     buttons : false,
24522     // private
24523     onRender : function(ct, position) 
24524     {
24525         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24526         this.navgroup.parentId = this.id;
24527         this.navgroup.onRender(this.el, null);
24528         // add the buttons to the navgroup
24529         
24530         if(this.displayInfo){
24531             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24532             this.displayEl = this.el.select('.x-paging-info', true).first();
24533 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24534 //            this.displayEl = navel.el.select('span',true).first();
24535         }
24536         
24537         var _this = this;
24538         
24539         if(this.buttons){
24540             Roo.each(_this.buttons, function(e){ // this might need to use render????
24541                Roo.factory(e).render(_this.el);
24542             });
24543         }
24544             
24545         Roo.each(_this.toolbarItems, function(e) {
24546             _this.navgroup.addItem(e);
24547         });
24548         
24549         
24550         this.first = this.navgroup.addItem({
24551             tooltip: this.firstText,
24552             cls: "prev",
24553             icon : 'fa fa-backward',
24554             disabled: true,
24555             preventDefault: true,
24556             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24557         });
24558         
24559         this.prev =  this.navgroup.addItem({
24560             tooltip: this.prevText,
24561             cls: "prev",
24562             icon : 'fa fa-step-backward',
24563             disabled: true,
24564             preventDefault: true,
24565             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
24566         });
24567     //this.addSeparator();
24568         
24569         
24570         var field = this.navgroup.addItem( {
24571             tagtype : 'span',
24572             cls : 'x-paging-position',
24573             
24574             html : this.beforePageText  +
24575                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24576                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
24577          } ); //?? escaped?
24578         
24579         this.field = field.el.select('input', true).first();
24580         this.field.on("keydown", this.onPagingKeydown, this);
24581         this.field.on("focus", function(){this.dom.select();});
24582     
24583     
24584         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
24585         //this.field.setHeight(18);
24586         //this.addSeparator();
24587         this.next = this.navgroup.addItem({
24588             tooltip: this.nextText,
24589             cls: "next",
24590             html : ' <i class="fa fa-step-forward">',
24591             disabled: true,
24592             preventDefault: true,
24593             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
24594         });
24595         this.last = this.navgroup.addItem({
24596             tooltip: this.lastText,
24597             icon : 'fa fa-forward',
24598             cls: "next",
24599             disabled: true,
24600             preventDefault: true,
24601             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
24602         });
24603     //this.addSeparator();
24604         this.loading = this.navgroup.addItem({
24605             tooltip: this.refreshText,
24606             icon: 'fa fa-refresh',
24607             preventDefault: true,
24608             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24609         });
24610         
24611     },
24612
24613     // private
24614     updateInfo : function(){
24615         if(this.displayEl){
24616             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24617             var msg = count == 0 ?
24618                 this.emptyMsg :
24619                 String.format(
24620                     this.displayMsg,
24621                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
24622                 );
24623             this.displayEl.update(msg);
24624         }
24625     },
24626
24627     // private
24628     onLoad : function(ds, r, o)
24629     {
24630         this.cursor = o.params.start ? o.params.start : 0;
24631         
24632         var d = this.getPageData(),
24633             ap = d.activePage,
24634             ps = d.pages;
24635         
24636         
24637         this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24638         this.field.dom.value = ap;
24639         this.first.setDisabled(ap == 1);
24640         this.prev.setDisabled(ap == 1);
24641         this.next.setDisabled(ap == ps);
24642         this.last.setDisabled(ap == ps);
24643         this.loading.enable();
24644         this.updateInfo();
24645     },
24646
24647     // private
24648     getPageData : function(){
24649         var total = this.ds.getTotalCount();
24650         return {
24651             total : total,
24652             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24653             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24654         };
24655     },
24656
24657     // private
24658     onLoadError : function(){
24659         this.loading.enable();
24660     },
24661
24662     // private
24663     onPagingKeydown : function(e){
24664         var k = e.getKey();
24665         var d = this.getPageData();
24666         if(k == e.RETURN){
24667             var v = this.field.dom.value, pageNum;
24668             if(!v || isNaN(pageNum = parseInt(v, 10))){
24669                 this.field.dom.value = d.activePage;
24670                 return;
24671             }
24672             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24673             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24674             e.stopEvent();
24675         }
24676         else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
24677         {
24678           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24679           this.field.dom.value = pageNum;
24680           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24681           e.stopEvent();
24682         }
24683         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24684         {
24685           var v = this.field.dom.value, pageNum; 
24686           var increment = (e.shiftKey) ? 10 : 1;
24687           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24688                 increment *= -1;
24689           }
24690           if(!v || isNaN(pageNum = parseInt(v, 10))) {
24691             this.field.dom.value = d.activePage;
24692             return;
24693           }
24694           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24695           {
24696             this.field.dom.value = parseInt(v, 10) + increment;
24697             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24698             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24699           }
24700           e.stopEvent();
24701         }
24702     },
24703
24704     // private
24705     beforeLoad : function(){
24706         if(this.loading){
24707             this.loading.disable();
24708         }
24709     },
24710
24711     // private
24712     onClick : function(which){
24713         
24714         var ds = this.ds;
24715         if (!ds) {
24716             return;
24717         }
24718         
24719         switch(which){
24720             case "first":
24721                 ds.load({params:{start: 0, limit: this.pageSize}});
24722             break;
24723             case "prev":
24724                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24725             break;
24726             case "next":
24727                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24728             break;
24729             case "last":
24730                 var total = ds.getTotalCount();
24731                 var extra = total % this.pageSize;
24732                 var lastStart = extra ? (total - extra) : total-this.pageSize;
24733                 ds.load({params:{start: lastStart, limit: this.pageSize}});
24734             break;
24735             case "refresh":
24736                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24737             break;
24738         }
24739     },
24740
24741     /**
24742      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24743      * @param {Roo.data.Store} store The data store to unbind
24744      */
24745     unbind : function(ds){
24746         ds.un("beforeload", this.beforeLoad, this);
24747         ds.un("load", this.onLoad, this);
24748         ds.un("loadexception", this.onLoadError, this);
24749         ds.un("remove", this.updateInfo, this);
24750         ds.un("add", this.updateInfo, this);
24751         this.ds = undefined;
24752     },
24753
24754     /**
24755      * Binds the paging toolbar to the specified {@link Roo.data.Store}
24756      * @param {Roo.data.Store} store The data store to bind
24757      */
24758     bind : function(ds){
24759         ds.on("beforeload", this.beforeLoad, this);
24760         ds.on("load", this.onLoad, this);
24761         ds.on("loadexception", this.onLoadError, this);
24762         ds.on("remove", this.updateInfo, this);
24763         ds.on("add", this.updateInfo, this);
24764         this.ds = ds;
24765     }
24766 });/*
24767  * - LGPL
24768  *
24769  * element
24770  * 
24771  */
24772
24773 /**
24774  * @class Roo.bootstrap.MessageBar
24775  * @extends Roo.bootstrap.Component
24776  * Bootstrap MessageBar class
24777  * @cfg {String} html contents of the MessageBar
24778  * @cfg {String} weight (info | success | warning | danger) default info
24779  * @cfg {String} beforeClass insert the bar before the given class
24780  * @cfg {Boolean} closable (true | false) default false
24781  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24782  * 
24783  * @constructor
24784  * Create a new Element
24785  * @param {Object} config The config object
24786  */
24787
24788 Roo.bootstrap.MessageBar = function(config){
24789     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24790 };
24791
24792 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
24793     
24794     html: '',
24795     weight: 'info',
24796     closable: false,
24797     fixed: false,
24798     beforeClass: 'bootstrap-sticky-wrap',
24799     
24800     getAutoCreate : function(){
24801         
24802         var cfg = {
24803             tag: 'div',
24804             cls: 'alert alert-dismissable alert-' + this.weight,
24805             cn: [
24806                 {
24807                     tag: 'span',
24808                     cls: 'message',
24809                     html: this.html || ''
24810                 }
24811             ]
24812         };
24813         
24814         if(this.fixed){
24815             cfg.cls += ' alert-messages-fixed';
24816         }
24817         
24818         if(this.closable){
24819             cfg.cn.push({
24820                 tag: 'button',
24821                 cls: 'close',
24822                 html: 'x'
24823             });
24824         }
24825         
24826         return cfg;
24827     },
24828     
24829     onRender : function(ct, position)
24830     {
24831         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24832         
24833         if(!this.el){
24834             var cfg = Roo.apply({},  this.getAutoCreate());
24835             cfg.id = Roo.id();
24836             
24837             if (this.cls) {
24838                 cfg.cls += ' ' + this.cls;
24839             }
24840             if (this.style) {
24841                 cfg.style = this.style;
24842             }
24843             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24844             
24845             this.el.setVisibilityMode(Roo.Element.DISPLAY);
24846         }
24847         
24848         this.el.select('>button.close').on('click', this.hide, this);
24849         
24850     },
24851     
24852     show : function()
24853     {
24854         if (!this.rendered) {
24855             this.render();
24856         }
24857         
24858         this.el.show();
24859         
24860         this.fireEvent('show', this);
24861         
24862     },
24863     
24864     hide : function()
24865     {
24866         if (!this.rendered) {
24867             this.render();
24868         }
24869         
24870         this.el.hide();
24871         
24872         this.fireEvent('hide', this);
24873     },
24874     
24875     update : function()
24876     {
24877 //        var e = this.el.dom.firstChild;
24878 //        
24879 //        if(this.closable){
24880 //            e = e.nextSibling;
24881 //        }
24882 //        
24883 //        e.data = this.html || '';
24884
24885         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24886     }
24887    
24888 });
24889
24890  
24891
24892      /*
24893  * - LGPL
24894  *
24895  * Graph
24896  * 
24897  */
24898
24899
24900 /**
24901  * @class Roo.bootstrap.Graph
24902  * @extends Roo.bootstrap.Component
24903  * Bootstrap Graph class
24904 > Prameters
24905  -sm {number} sm 4
24906  -md {number} md 5
24907  @cfg {String} graphtype  bar | vbar | pie
24908  @cfg {number} g_x coodinator | centre x (pie)
24909  @cfg {number} g_y coodinator | centre y (pie)
24910  @cfg {number} g_r radius (pie)
24911  @cfg {number} g_height height of the chart (respected by all elements in the set)
24912  @cfg {number} g_width width of the chart (respected by all elements in the set)
24913  @cfg {Object} title The title of the chart
24914     
24915  -{Array}  values
24916  -opts (object) options for the chart 
24917      o {
24918      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24919      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24920      o vgutter (number)
24921      o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
24922      o stacked (boolean) whether or not to tread values as in a stacked bar chart
24923      o to
24924      o stretch (boolean)
24925      o }
24926  -opts (object) options for the pie
24927      o{
24928      o cut
24929      o startAngle (number)
24930      o endAngle (number)
24931      } 
24932  *
24933  * @constructor
24934  * Create a new Input
24935  * @param {Object} config The config object
24936  */
24937
24938 Roo.bootstrap.Graph = function(config){
24939     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24940     
24941     this.addEvents({
24942         // img events
24943         /**
24944          * @event click
24945          * The img click event for the img.
24946          * @param {Roo.EventObject} e
24947          */
24948         "click" : true
24949     });
24950 };
24951
24952 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
24953     
24954     sm: 4,
24955     md: 5,
24956     graphtype: 'bar',
24957     g_height: 250,
24958     g_width: 400,
24959     g_x: 50,
24960     g_y: 50,
24961     g_r: 30,
24962     opts:{
24963         //g_colors: this.colors,
24964         g_type: 'soft',
24965         g_gutter: '20%'
24966
24967     },
24968     title : false,
24969
24970     getAutoCreate : function(){
24971         
24972         var cfg = {
24973             tag: 'div',
24974             html : null
24975         };
24976         
24977         
24978         return  cfg;
24979     },
24980
24981     onRender : function(ct,position){
24982         
24983         
24984         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24985         
24986         if (typeof(Raphael) == 'undefined') {
24987             Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24988             return;
24989         }
24990         
24991         this.raphael = Raphael(this.el.dom);
24992         
24993                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24994                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24995                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24996                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24997                 /*
24998                 r.text(160, 10, "Single Series Chart").attr(txtattr);
24999                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25000                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25001                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25002                 
25003                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25004                 r.barchart(330, 10, 300, 220, data1);
25005                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25006                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25007                 */
25008                 
25009                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25010                 // r.barchart(30, 30, 560, 250,  xdata, {
25011                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25012                 //     axis : "0 0 1 1",
25013                 //     axisxlabels :  xdata
25014                 //     //yvalues : cols,
25015                    
25016                 // });
25017 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25018 //        
25019 //        this.load(null,xdata,{
25020 //                axis : "0 0 1 1",
25021 //                axisxlabels :  xdata
25022 //                });
25023
25024     },
25025
25026     load : function(graphtype,xdata,opts)
25027     {
25028         this.raphael.clear();
25029         if(!graphtype) {
25030             graphtype = this.graphtype;
25031         }
25032         if(!opts){
25033             opts = this.opts;
25034         }
25035         var r = this.raphael,
25036             fin = function () {
25037                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25038             },
25039             fout = function () {
25040                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25041             },
25042             pfin = function() {
25043                 this.sector.stop();
25044                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25045
25046                 if (this.label) {
25047                     this.label[0].stop();
25048                     this.label[0].attr({ r: 7.5 });
25049                     this.label[1].attr({ "font-weight": 800 });
25050                 }
25051             },
25052             pfout = function() {
25053                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25054
25055                 if (this.label) {
25056                     this.label[0].animate({ r: 5 }, 500, "bounce");
25057                     this.label[1].attr({ "font-weight": 400 });
25058                 }
25059             };
25060
25061         switch(graphtype){
25062             case 'bar':
25063                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25064                 break;
25065             case 'hbar':
25066                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25067                 break;
25068             case 'pie':
25069 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
25070 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25071 //            
25072                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25073                 
25074                 break;
25075
25076         }
25077         
25078         if(this.title){
25079             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25080         }
25081         
25082     },
25083     
25084     setTitle: function(o)
25085     {
25086         this.title = o;
25087     },
25088     
25089     initEvents: function() {
25090         
25091         if(!this.href){
25092             this.el.on('click', this.onClick, this);
25093         }
25094     },
25095     
25096     onClick : function(e)
25097     {
25098         Roo.log('img onclick');
25099         this.fireEvent('click', this, e);
25100     }
25101    
25102 });
25103
25104  
25105 /*
25106  * - LGPL
25107  *
25108  * numberBox
25109  * 
25110  */
25111 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25112
25113 /**
25114  * @class Roo.bootstrap.dash.NumberBox
25115  * @extends Roo.bootstrap.Component
25116  * Bootstrap NumberBox class
25117  * @cfg {String} headline Box headline
25118  * @cfg {String} content Box content
25119  * @cfg {String} icon Box icon
25120  * @cfg {String} footer Footer text
25121  * @cfg {String} fhref Footer href
25122  * 
25123  * @constructor
25124  * Create a new NumberBox
25125  * @param {Object} config The config object
25126  */
25127
25128
25129 Roo.bootstrap.dash.NumberBox = function(config){
25130     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25131     
25132 };
25133
25134 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
25135     
25136     headline : '',
25137     content : '',
25138     icon : '',
25139     footer : '',
25140     fhref : '',
25141     ficon : '',
25142     
25143     getAutoCreate : function(){
25144         
25145         var cfg = {
25146             tag : 'div',
25147             cls : 'small-box ',
25148             cn : [
25149                 {
25150                     tag : 'div',
25151                     cls : 'inner',
25152                     cn :[
25153                         {
25154                             tag : 'h3',
25155                             cls : 'roo-headline',
25156                             html : this.headline
25157                         },
25158                         {
25159                             tag : 'p',
25160                             cls : 'roo-content',
25161                             html : this.content
25162                         }
25163                     ]
25164                 }
25165             ]
25166         };
25167         
25168         if(this.icon){
25169             cfg.cn.push({
25170                 tag : 'div',
25171                 cls : 'icon',
25172                 cn :[
25173                     {
25174                         tag : 'i',
25175                         cls : 'ion ' + this.icon
25176                     }
25177                 ]
25178             });
25179         }
25180         
25181         if(this.footer){
25182             var footer = {
25183                 tag : 'a',
25184                 cls : 'small-box-footer',
25185                 href : this.fhref || '#',
25186                 html : this.footer
25187             };
25188             
25189             cfg.cn.push(footer);
25190             
25191         }
25192         
25193         return  cfg;
25194     },
25195
25196     onRender : function(ct,position){
25197         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25198
25199
25200        
25201                 
25202     },
25203
25204     setHeadline: function (value)
25205     {
25206         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25207     },
25208     
25209     setFooter: function (value, href)
25210     {
25211         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25212         
25213         if(href){
25214             this.el.select('a.small-box-footer',true).first().attr('href', href);
25215         }
25216         
25217     },
25218
25219     setContent: function (value)
25220     {
25221         this.el.select('.roo-content',true).first().dom.innerHTML = value;
25222     },
25223
25224     initEvents: function() 
25225     {   
25226         
25227     }
25228     
25229 });
25230
25231  
25232 /*
25233  * - LGPL
25234  *
25235  * TabBox
25236  * 
25237  */
25238 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25239
25240 /**
25241  * @class Roo.bootstrap.dash.TabBox
25242  * @extends Roo.bootstrap.Component
25243  * Bootstrap TabBox class
25244  * @cfg {String} title Title of the TabBox
25245  * @cfg {String} icon Icon of the TabBox
25246  * @cfg {Boolean} showtabs (true|false) show the tabs default true
25247  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25248  * 
25249  * @constructor
25250  * Create a new TabBox
25251  * @param {Object} config The config object
25252  */
25253
25254
25255 Roo.bootstrap.dash.TabBox = function(config){
25256     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25257     this.addEvents({
25258         // raw events
25259         /**
25260          * @event addpane
25261          * When a pane is added
25262          * @param {Roo.bootstrap.dash.TabPane} pane
25263          */
25264         "addpane" : true,
25265         /**
25266          * @event activatepane
25267          * When a pane is activated
25268          * @param {Roo.bootstrap.dash.TabPane} pane
25269          */
25270         "activatepane" : true
25271         
25272          
25273     });
25274     
25275     this.panes = [];
25276 };
25277
25278 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
25279
25280     title : '',
25281     icon : false,
25282     showtabs : true,
25283     tabScrollable : false,
25284     
25285     getChildContainer : function()
25286     {
25287         return this.el.select('.tab-content', true).first();
25288     },
25289     
25290     getAutoCreate : function(){
25291         
25292         var header = {
25293             tag: 'li',
25294             cls: 'pull-left header',
25295             html: this.title,
25296             cn : []
25297         };
25298         
25299         if(this.icon){
25300             header.cn.push({
25301                 tag: 'i',
25302                 cls: 'fa ' + this.icon
25303             });
25304         }
25305         
25306         var h = {
25307             tag: 'ul',
25308             cls: 'nav nav-tabs pull-right',
25309             cn: [
25310                 header
25311             ]
25312         };
25313         
25314         if(this.tabScrollable){
25315             h = {
25316                 tag: 'div',
25317                 cls: 'tab-header',
25318                 cn: [
25319                     {
25320                         tag: 'ul',
25321                         cls: 'nav nav-tabs pull-right',
25322                         cn: [
25323                             header
25324                         ]
25325                     }
25326                 ]
25327             };
25328         }
25329         
25330         var cfg = {
25331             tag: 'div',
25332             cls: 'nav-tabs-custom',
25333             cn: [
25334                 h,
25335                 {
25336                     tag: 'div',
25337                     cls: 'tab-content no-padding',
25338                     cn: []
25339                 }
25340             ]
25341         };
25342
25343         return  cfg;
25344     },
25345     initEvents : function()
25346     {
25347         //Roo.log('add add pane handler');
25348         this.on('addpane', this.onAddPane, this);
25349     },
25350      /**
25351      * Updates the box title
25352      * @param {String} html to set the title to.
25353      */
25354     setTitle : function(value)
25355     {
25356         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25357     },
25358     onAddPane : function(pane)
25359     {
25360         this.panes.push(pane);
25361         //Roo.log('addpane');
25362         //Roo.log(pane);
25363         // tabs are rendere left to right..
25364         if(!this.showtabs){
25365             return;
25366         }
25367         
25368         var ctr = this.el.select('.nav-tabs', true).first();
25369          
25370          
25371         var existing = ctr.select('.nav-tab',true);
25372         var qty = existing.getCount();;
25373         
25374         
25375         var tab = ctr.createChild({
25376             tag : 'li',
25377             cls : 'nav-tab' + (qty ? '' : ' active'),
25378             cn : [
25379                 {
25380                     tag : 'a',
25381                     href:'#',
25382                     html : pane.title
25383                 }
25384             ]
25385         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25386         pane.tab = tab;
25387         
25388         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25389         if (!qty) {
25390             pane.el.addClass('active');
25391         }
25392         
25393                 
25394     },
25395     onTabClick : function(ev,un,ob,pane)
25396     {
25397         //Roo.log('tab - prev default');
25398         ev.preventDefault();
25399         
25400         
25401         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25402         pane.tab.addClass('active');
25403         //Roo.log(pane.title);
25404         this.getChildContainer().select('.tab-pane',true).removeClass('active');
25405         // technically we should have a deactivate event.. but maybe add later.
25406         // and it should not de-activate the selected tab...
25407         this.fireEvent('activatepane', pane);
25408         pane.el.addClass('active');
25409         pane.fireEvent('activate');
25410         
25411         
25412     },
25413     
25414     getActivePane : function()
25415     {
25416         var r = false;
25417         Roo.each(this.panes, function(p) {
25418             if(p.el.hasClass('active')){
25419                 r = p;
25420                 return false;
25421             }
25422             
25423             return;
25424         });
25425         
25426         return r;
25427     }
25428     
25429     
25430 });
25431
25432  
25433 /*
25434  * - LGPL
25435  *
25436  * Tab pane
25437  * 
25438  */
25439 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25440 /**
25441  * @class Roo.bootstrap.TabPane
25442  * @extends Roo.bootstrap.Component
25443  * Bootstrap TabPane class
25444  * @cfg {Boolean} active (false | true) Default false
25445  * @cfg {String} title title of panel
25446
25447  * 
25448  * @constructor
25449  * Create a new TabPane
25450  * @param {Object} config The config object
25451  */
25452
25453 Roo.bootstrap.dash.TabPane = function(config){
25454     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25455     
25456     this.addEvents({
25457         // raw events
25458         /**
25459          * @event activate
25460          * When a pane is activated
25461          * @param {Roo.bootstrap.dash.TabPane} pane
25462          */
25463         "activate" : true
25464          
25465     });
25466 };
25467
25468 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
25469     
25470     active : false,
25471     title : '',
25472     
25473     // the tabBox that this is attached to.
25474     tab : false,
25475      
25476     getAutoCreate : function() 
25477     {
25478         var cfg = {
25479             tag: 'div',
25480             cls: 'tab-pane'
25481         };
25482         
25483         if(this.active){
25484             cfg.cls += ' active';
25485         }
25486         
25487         return cfg;
25488     },
25489     initEvents  : function()
25490     {
25491         //Roo.log('trigger add pane handler');
25492         this.parent().fireEvent('addpane', this)
25493     },
25494     
25495      /**
25496      * Updates the tab title 
25497      * @param {String} html to set the title to.
25498      */
25499     setTitle: function(str)
25500     {
25501         if (!this.tab) {
25502             return;
25503         }
25504         this.title = str;
25505         this.tab.select('a', true).first().dom.innerHTML = str;
25506         
25507     }
25508     
25509     
25510     
25511 });
25512
25513  
25514
25515
25516  /*
25517  * - LGPL
25518  *
25519  * menu
25520  * 
25521  */
25522 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25523
25524 /**
25525  * @class Roo.bootstrap.menu.Menu
25526  * @extends Roo.bootstrap.Component
25527  * Bootstrap Menu class - container for Menu
25528  * @cfg {String} html Text of the menu
25529  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25530  * @cfg {String} icon Font awesome icon
25531  * @cfg {String} pos Menu align to (top | bottom) default bottom
25532  * 
25533  * 
25534  * @constructor
25535  * Create a new Menu
25536  * @param {Object} config The config object
25537  */
25538
25539
25540 Roo.bootstrap.menu.Menu = function(config){
25541     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25542     
25543     this.addEvents({
25544         /**
25545          * @event beforeshow
25546          * Fires before this menu is displayed
25547          * @param {Roo.bootstrap.menu.Menu} this
25548          */
25549         beforeshow : true,
25550         /**
25551          * @event beforehide
25552          * Fires before this menu is hidden
25553          * @param {Roo.bootstrap.menu.Menu} this
25554          */
25555         beforehide : true,
25556         /**
25557          * @event show
25558          * Fires after this menu is displayed
25559          * @param {Roo.bootstrap.menu.Menu} this
25560          */
25561         show : true,
25562         /**
25563          * @event hide
25564          * Fires after this menu is hidden
25565          * @param {Roo.bootstrap.menu.Menu} this
25566          */
25567         hide : true,
25568         /**
25569          * @event click
25570          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25571          * @param {Roo.bootstrap.menu.Menu} this
25572          * @param {Roo.EventObject} e
25573          */
25574         click : true
25575     });
25576     
25577 };
25578
25579 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
25580     
25581     submenu : false,
25582     html : '',
25583     weight : 'default',
25584     icon : false,
25585     pos : 'bottom',
25586     
25587     
25588     getChildContainer : function() {
25589         if(this.isSubMenu){
25590             return this.el;
25591         }
25592         
25593         return this.el.select('ul.dropdown-menu', true).first();  
25594     },
25595     
25596     getAutoCreate : function()
25597     {
25598         var text = [
25599             {
25600                 tag : 'span',
25601                 cls : 'roo-menu-text',
25602                 html : this.html
25603             }
25604         ];
25605         
25606         if(this.icon){
25607             text.unshift({
25608                 tag : 'i',
25609                 cls : 'fa ' + this.icon
25610             })
25611         }
25612         
25613         
25614         var cfg = {
25615             tag : 'div',
25616             cls : 'btn-group',
25617             cn : [
25618                 {
25619                     tag : 'button',
25620                     cls : 'dropdown-button btn btn-' + this.weight,
25621                     cn : text
25622                 },
25623                 {
25624                     tag : 'button',
25625                     cls : 'dropdown-toggle btn btn-' + this.weight,
25626                     cn : [
25627                         {
25628                             tag : 'span',
25629                             cls : 'caret'
25630                         }
25631                     ]
25632                 },
25633                 {
25634                     tag : 'ul',
25635                     cls : 'dropdown-menu'
25636                 }
25637             ]
25638             
25639         };
25640         
25641         if(this.pos == 'top'){
25642             cfg.cls += ' dropup';
25643         }
25644         
25645         if(this.isSubMenu){
25646             cfg = {
25647                 tag : 'ul',
25648                 cls : 'dropdown-menu'
25649             }
25650         }
25651         
25652         return cfg;
25653     },
25654     
25655     onRender : function(ct, position)
25656     {
25657         this.isSubMenu = ct.hasClass('dropdown-submenu');
25658         
25659         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25660     },
25661     
25662     initEvents : function() 
25663     {
25664         if(this.isSubMenu){
25665             return;
25666         }
25667         
25668         this.hidden = true;
25669         
25670         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25671         this.triggerEl.on('click', this.onTriggerPress, this);
25672         
25673         this.buttonEl = this.el.select('button.dropdown-button', true).first();
25674         this.buttonEl.on('click', this.onClick, this);
25675         
25676     },
25677     
25678     list : function()
25679     {
25680         if(this.isSubMenu){
25681             return this.el;
25682         }
25683         
25684         return this.el.select('ul.dropdown-menu', true).first();
25685     },
25686     
25687     onClick : function(e)
25688     {
25689         this.fireEvent("click", this, e);
25690     },
25691     
25692     onTriggerPress  : function(e)
25693     {   
25694         if (this.isVisible()) {
25695             this.hide();
25696         } else {
25697             this.show();
25698         }
25699     },
25700     
25701     isVisible : function(){
25702         return !this.hidden;
25703     },
25704     
25705     show : function()
25706     {
25707         this.fireEvent("beforeshow", this);
25708         
25709         this.hidden = false;
25710         this.el.addClass('open');
25711         
25712         Roo.get(document).on("mouseup", this.onMouseUp, this);
25713         
25714         this.fireEvent("show", this);
25715         
25716         
25717     },
25718     
25719     hide : function()
25720     {
25721         this.fireEvent("beforehide", this);
25722         
25723         this.hidden = true;
25724         this.el.removeClass('open');
25725         
25726         Roo.get(document).un("mouseup", this.onMouseUp);
25727         
25728         this.fireEvent("hide", this);
25729     },
25730     
25731     onMouseUp : function()
25732     {
25733         this.hide();
25734     }
25735     
25736 });
25737
25738  
25739  /*
25740  * - LGPL
25741  *
25742  * menu item
25743  * 
25744  */
25745 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25746
25747 /**
25748  * @class Roo.bootstrap.menu.Item
25749  * @extends Roo.bootstrap.Component
25750  * Bootstrap MenuItem class
25751  * @cfg {Boolean} submenu (true | false) default false
25752  * @cfg {String} html text of the item
25753  * @cfg {String} href the link
25754  * @cfg {Boolean} disable (true | false) default false
25755  * @cfg {Boolean} preventDefault (true | false) default true
25756  * @cfg {String} icon Font awesome icon
25757  * @cfg {String} pos Submenu align to (left | right) default right 
25758  * 
25759  * 
25760  * @constructor
25761  * Create a new Item
25762  * @param {Object} config The config object
25763  */
25764
25765
25766 Roo.bootstrap.menu.Item = function(config){
25767     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25768     this.addEvents({
25769         /**
25770          * @event mouseover
25771          * Fires when the mouse is hovering over this menu
25772          * @param {Roo.bootstrap.menu.Item} this
25773          * @param {Roo.EventObject} e
25774          */
25775         mouseover : true,
25776         /**
25777          * @event mouseout
25778          * Fires when the mouse exits this menu
25779          * @param {Roo.bootstrap.menu.Item} this
25780          * @param {Roo.EventObject} e
25781          */
25782         mouseout : true,
25783         // raw events
25784         /**
25785          * @event click
25786          * The raw click event for the entire grid.
25787          * @param {Roo.EventObject} e
25788          */
25789         click : true
25790     });
25791 };
25792
25793 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
25794     
25795     submenu : false,
25796     href : '',
25797     html : '',
25798     preventDefault: true,
25799     disable : false,
25800     icon : false,
25801     pos : 'right',
25802     
25803     getAutoCreate : function()
25804     {
25805         var text = [
25806             {
25807                 tag : 'span',
25808                 cls : 'roo-menu-item-text',
25809                 html : this.html
25810             }
25811         ];
25812         
25813         if(this.icon){
25814             text.unshift({
25815                 tag : 'i',
25816                 cls : 'fa ' + this.icon
25817             })
25818         }
25819         
25820         var cfg = {
25821             tag : 'li',
25822             cn : [
25823                 {
25824                     tag : 'a',
25825                     href : this.href || '#',
25826                     cn : text
25827                 }
25828             ]
25829         };
25830         
25831         if(this.disable){
25832             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25833         }
25834         
25835         if(this.submenu){
25836             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25837             
25838             if(this.pos == 'left'){
25839                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25840             }
25841         }
25842         
25843         return cfg;
25844     },
25845     
25846     initEvents : function() 
25847     {
25848         this.el.on('mouseover', this.onMouseOver, this);
25849         this.el.on('mouseout', this.onMouseOut, this);
25850         
25851         this.el.select('a', true).first().on('click', this.onClick, this);
25852         
25853     },
25854     
25855     onClick : function(e)
25856     {
25857         if(this.preventDefault){
25858             e.preventDefault();
25859         }
25860         
25861         this.fireEvent("click", this, e);
25862     },
25863     
25864     onMouseOver : function(e)
25865     {
25866         if(this.submenu && this.pos == 'left'){
25867             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25868         }
25869         
25870         this.fireEvent("mouseover", this, e);
25871     },
25872     
25873     onMouseOut : function(e)
25874     {
25875         this.fireEvent("mouseout", this, e);
25876     }
25877 });
25878
25879  
25880
25881  /*
25882  * - LGPL
25883  *
25884  * menu separator
25885  * 
25886  */
25887 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25888
25889 /**
25890  * @class Roo.bootstrap.menu.Separator
25891  * @extends Roo.bootstrap.Component
25892  * Bootstrap Separator class
25893  * 
25894  * @constructor
25895  * Create a new Separator
25896  * @param {Object} config The config object
25897  */
25898
25899
25900 Roo.bootstrap.menu.Separator = function(config){
25901     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25902 };
25903
25904 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
25905     
25906     getAutoCreate : function(){
25907         var cfg = {
25908             tag : 'li',
25909             cls: 'divider'
25910         };
25911         
25912         return cfg;
25913     }
25914    
25915 });
25916
25917  
25918
25919  /*
25920  * - LGPL
25921  *
25922  * Tooltip
25923  * 
25924  */
25925
25926 /**
25927  * @class Roo.bootstrap.Tooltip
25928  * Bootstrap Tooltip class
25929  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25930  * to determine which dom element triggers the tooltip.
25931  * 
25932  * It needs to add support for additional attributes like tooltip-position
25933  * 
25934  * @constructor
25935  * Create a new Toolti
25936  * @param {Object} config The config object
25937  */
25938
25939 Roo.bootstrap.Tooltip = function(config){
25940     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25941     
25942     this.alignment = Roo.bootstrap.Tooltip.alignment;
25943     
25944     if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25945         this.alignment = config.alignment;
25946     }
25947     
25948 };
25949
25950 Roo.apply(Roo.bootstrap.Tooltip, {
25951     /**
25952      * @function init initialize tooltip monitoring.
25953      * @static
25954      */
25955     currentEl : false,
25956     currentTip : false,
25957     currentRegion : false,
25958     
25959     //  init : delay?
25960     
25961     init : function()
25962     {
25963         Roo.get(document).on('mouseover', this.enter ,this);
25964         Roo.get(document).on('mouseout', this.leave, this);
25965          
25966         
25967         this.currentTip = new Roo.bootstrap.Tooltip();
25968     },
25969     
25970     enter : function(ev)
25971     {
25972         var dom = ev.getTarget();
25973         
25974         //Roo.log(['enter',dom]);
25975         var el = Roo.fly(dom);
25976         if (this.currentEl) {
25977             //Roo.log(dom);
25978             //Roo.log(this.currentEl);
25979             //Roo.log(this.currentEl.contains(dom));
25980             if (this.currentEl == el) {
25981                 return;
25982             }
25983             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25984                 return;
25985             }
25986
25987         }
25988         
25989         if (this.currentTip.el) {
25990             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25991         }    
25992         //Roo.log(ev);
25993         
25994         if(!el || el.dom == document){
25995             return;
25996         }
25997         
25998         var bindEl = el;
25999         
26000         // you can not look for children, as if el is the body.. then everythign is the child..
26001         if (!el.attr('tooltip')) { //
26002             if (!el.select("[tooltip]").elements.length) {
26003                 return;
26004             }
26005             // is the mouse over this child...?
26006             bindEl = el.select("[tooltip]").first();
26007             var xy = ev.getXY();
26008             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26009                 //Roo.log("not in region.");
26010                 return;
26011             }
26012             //Roo.log("child element over..");
26013             
26014         }
26015         this.currentEl = bindEl;
26016         this.currentTip.bind(bindEl);
26017         this.currentRegion = Roo.lib.Region.getRegion(dom);
26018         this.currentTip.enter();
26019         
26020     },
26021     leave : function(ev)
26022     {
26023         var dom = ev.getTarget();
26024         //Roo.log(['leave',dom]);
26025         if (!this.currentEl) {
26026             return;
26027         }
26028         
26029         
26030         if (dom != this.currentEl.dom) {
26031             return;
26032         }
26033         var xy = ev.getXY();
26034         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
26035             return;
26036         }
26037         // only activate leave if mouse cursor is outside... bounding box..
26038         
26039         
26040         
26041         
26042         if (this.currentTip) {
26043             this.currentTip.leave();
26044         }
26045         //Roo.log('clear currentEl');
26046         this.currentEl = false;
26047         
26048         
26049     },
26050     alignment : {
26051         'left' : ['r-l', [-2,0], 'right'],
26052         'right' : ['l-r', [2,0], 'left'],
26053         'bottom' : ['t-b', [0,2], 'top'],
26054         'top' : [ 'b-t', [0,-2], 'bottom']
26055     }
26056     
26057 });
26058
26059
26060 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
26061     
26062     
26063     bindEl : false,
26064     
26065     delay : null, // can be { show : 300 , hide: 500}
26066     
26067     timeout : null,
26068     
26069     hoverState : null, //???
26070     
26071     placement : 'bottom', 
26072     
26073     alignment : false,
26074     
26075     getAutoCreate : function(){
26076     
26077         var cfg = {
26078            cls : 'tooltip',
26079            role : 'tooltip',
26080            cn : [
26081                 {
26082                     cls : 'tooltip-arrow'
26083                 },
26084                 {
26085                     cls : 'tooltip-inner'
26086                 }
26087            ]
26088         };
26089         
26090         return cfg;
26091     },
26092     bind : function(el)
26093     {
26094         this.bindEl = el;
26095     },
26096       
26097     
26098     enter : function () {
26099        
26100         if (this.timeout != null) {
26101             clearTimeout(this.timeout);
26102         }
26103         
26104         this.hoverState = 'in';
26105          //Roo.log("enter - show");
26106         if (!this.delay || !this.delay.show) {
26107             this.show();
26108             return;
26109         }
26110         var _t = this;
26111         this.timeout = setTimeout(function () {
26112             if (_t.hoverState == 'in') {
26113                 _t.show();
26114             }
26115         }, this.delay.show);
26116     },
26117     leave : function()
26118     {
26119         clearTimeout(this.timeout);
26120     
26121         this.hoverState = 'out';
26122          if (!this.delay || !this.delay.hide) {
26123             this.hide();
26124             return;
26125         }
26126        
26127         var _t = this;
26128         this.timeout = setTimeout(function () {
26129             //Roo.log("leave - timeout");
26130             
26131             if (_t.hoverState == 'out') {
26132                 _t.hide();
26133                 Roo.bootstrap.Tooltip.currentEl = false;
26134             }
26135         }, delay);
26136     },
26137     
26138     show : function (msg)
26139     {
26140         if (!this.el) {
26141             this.render(document.body);
26142         }
26143         // set content.
26144         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26145         
26146         var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26147         
26148         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26149         
26150         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26151         
26152         var placement = typeof this.placement == 'function' ?
26153             this.placement.call(this, this.el, on_el) :
26154             this.placement;
26155             
26156         var autoToken = /\s?auto?\s?/i;
26157         var autoPlace = autoToken.test(placement);
26158         if (autoPlace) {
26159             placement = placement.replace(autoToken, '') || 'top';
26160         }
26161         
26162         //this.el.detach()
26163         //this.el.setXY([0,0]);
26164         this.el.show();
26165         //this.el.dom.style.display='block';
26166         
26167         //this.el.appendTo(on_el);
26168         
26169         var p = this.getPosition();
26170         var box = this.el.getBox();
26171         
26172         if (autoPlace) {
26173             // fixme..
26174         }
26175         
26176         var align = this.alignment[placement];
26177         
26178         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26179         
26180         if(placement == 'top' || placement == 'bottom'){
26181             if(xy[0] < 0){
26182                 placement = 'right';
26183             }
26184             
26185             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26186                 placement = 'left';
26187             }
26188             
26189             var scroll = Roo.select('body', true).first().getScroll();
26190             
26191             if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26192                 placement = 'top';
26193             }
26194             
26195         }
26196         
26197         this.el.alignTo(this.bindEl, align[0],align[1]);
26198         //var arrow = this.el.select('.arrow',true).first();
26199         //arrow.set(align[2], 
26200         
26201         this.el.addClass(placement);
26202         
26203         this.el.addClass('in fade');
26204         
26205         this.hoverState = null;
26206         
26207         if (this.el.hasClass('fade')) {
26208             // fade it?
26209         }
26210         
26211     },
26212     hide : function()
26213     {
26214          
26215         if (!this.el) {
26216             return;
26217         }
26218         //this.el.setXY([0,0]);
26219         this.el.removeClass('in');
26220         //this.el.hide();
26221         
26222     }
26223     
26224 });
26225  
26226
26227  /*
26228  * - LGPL
26229  *
26230  * Location Picker
26231  * 
26232  */
26233
26234 /**
26235  * @class Roo.bootstrap.LocationPicker
26236  * @extends Roo.bootstrap.Component
26237  * Bootstrap LocationPicker class
26238  * @cfg {Number} latitude Position when init default 0
26239  * @cfg {Number} longitude Position when init default 0
26240  * @cfg {Number} zoom default 15
26241  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26242  * @cfg {Boolean} mapTypeControl default false
26243  * @cfg {Boolean} disableDoubleClickZoom default false
26244  * @cfg {Boolean} scrollwheel default true
26245  * @cfg {Boolean} streetViewControl default false
26246  * @cfg {Number} radius default 0
26247  * @cfg {String} locationName
26248  * @cfg {Boolean} draggable default true
26249  * @cfg {Boolean} enableAutocomplete default false
26250  * @cfg {Boolean} enableReverseGeocode default true
26251  * @cfg {String} markerTitle
26252  * 
26253  * @constructor
26254  * Create a new LocationPicker
26255  * @param {Object} config The config object
26256  */
26257
26258
26259 Roo.bootstrap.LocationPicker = function(config){
26260     
26261     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26262     
26263     this.addEvents({
26264         /**
26265          * @event initial
26266          * Fires when the picker initialized.
26267          * @param {Roo.bootstrap.LocationPicker} this
26268          * @param {Google Location} location
26269          */
26270         initial : true,
26271         /**
26272          * @event positionchanged
26273          * Fires when the picker position changed.
26274          * @param {Roo.bootstrap.LocationPicker} this
26275          * @param {Google Location} location
26276          */
26277         positionchanged : true,
26278         /**
26279          * @event resize
26280          * Fires when the map resize.
26281          * @param {Roo.bootstrap.LocationPicker} this
26282          */
26283         resize : true,
26284         /**
26285          * @event show
26286          * Fires when the map show.
26287          * @param {Roo.bootstrap.LocationPicker} this
26288          */
26289         show : true,
26290         /**
26291          * @event hide
26292          * Fires when the map hide.
26293          * @param {Roo.bootstrap.LocationPicker} this
26294          */
26295         hide : true,
26296         /**
26297          * @event mapClick
26298          * Fires when click the map.
26299          * @param {Roo.bootstrap.LocationPicker} this
26300          * @param {Map event} e
26301          */
26302         mapClick : true,
26303         /**
26304          * @event mapRightClick
26305          * Fires when right click the map.
26306          * @param {Roo.bootstrap.LocationPicker} this
26307          * @param {Map event} e
26308          */
26309         mapRightClick : true,
26310         /**
26311          * @event markerClick
26312          * Fires when click the marker.
26313          * @param {Roo.bootstrap.LocationPicker} this
26314          * @param {Map event} e
26315          */
26316         markerClick : true,
26317         /**
26318          * @event markerRightClick
26319          * Fires when right click the marker.
26320          * @param {Roo.bootstrap.LocationPicker} this
26321          * @param {Map event} e
26322          */
26323         markerRightClick : true,
26324         /**
26325          * @event OverlayViewDraw
26326          * Fires when OverlayView Draw
26327          * @param {Roo.bootstrap.LocationPicker} this
26328          */
26329         OverlayViewDraw : true,
26330         /**
26331          * @event OverlayViewOnAdd
26332          * Fires when OverlayView Draw
26333          * @param {Roo.bootstrap.LocationPicker} this
26334          */
26335         OverlayViewOnAdd : true,
26336         /**
26337          * @event OverlayViewOnRemove
26338          * Fires when OverlayView Draw
26339          * @param {Roo.bootstrap.LocationPicker} this
26340          */
26341         OverlayViewOnRemove : true,
26342         /**
26343          * @event OverlayViewShow
26344          * Fires when OverlayView Draw
26345          * @param {Roo.bootstrap.LocationPicker} this
26346          * @param {Pixel} cpx
26347          */
26348         OverlayViewShow : true,
26349         /**
26350          * @event OverlayViewHide
26351          * Fires when OverlayView Draw
26352          * @param {Roo.bootstrap.LocationPicker} this
26353          */
26354         OverlayViewHide : true,
26355         /**
26356          * @event loadexception
26357          * Fires when load google lib failed.
26358          * @param {Roo.bootstrap.LocationPicker} this
26359          */
26360         loadexception : true
26361     });
26362         
26363 };
26364
26365 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
26366     
26367     gMapContext: false,
26368     
26369     latitude: 0,
26370     longitude: 0,
26371     zoom: 15,
26372     mapTypeId: false,
26373     mapTypeControl: false,
26374     disableDoubleClickZoom: false,
26375     scrollwheel: true,
26376     streetViewControl: false,
26377     radius: 0,
26378     locationName: '',
26379     draggable: true,
26380     enableAutocomplete: false,
26381     enableReverseGeocode: true,
26382     markerTitle: '',
26383     
26384     getAutoCreate: function()
26385     {
26386
26387         var cfg = {
26388             tag: 'div',
26389             cls: 'roo-location-picker'
26390         };
26391         
26392         return cfg
26393     },
26394     
26395     initEvents: function(ct, position)
26396     {       
26397         if(!this.el.getWidth() || this.isApplied()){
26398             return;
26399         }
26400         
26401         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26402         
26403         this.initial();
26404     },
26405     
26406     initial: function()
26407     {
26408         if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26409             this.fireEvent('loadexception', this);
26410             return;
26411         }
26412         
26413         if(!this.mapTypeId){
26414             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26415         }
26416         
26417         this.gMapContext = this.GMapContext();
26418         
26419         this.initOverlayView();
26420         
26421         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26422         
26423         var _this = this;
26424                 
26425         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26426             _this.setPosition(_this.gMapContext.marker.position);
26427         });
26428         
26429         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26430             _this.fireEvent('mapClick', this, event);
26431             
26432         });
26433
26434         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26435             _this.fireEvent('mapRightClick', this, event);
26436             
26437         });
26438         
26439         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26440             _this.fireEvent('markerClick', this, event);
26441             
26442         });
26443
26444         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26445             _this.fireEvent('markerRightClick', this, event);
26446             
26447         });
26448         
26449         this.setPosition(this.gMapContext.location);
26450         
26451         this.fireEvent('initial', this, this.gMapContext.location);
26452     },
26453     
26454     initOverlayView: function()
26455     {
26456         var _this = this;
26457         
26458         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26459             
26460             draw: function()
26461             {
26462                 _this.fireEvent('OverlayViewDraw', _this);
26463             },
26464             
26465             onAdd: function()
26466             {
26467                 _this.fireEvent('OverlayViewOnAdd', _this);
26468             },
26469             
26470             onRemove: function()
26471             {
26472                 _this.fireEvent('OverlayViewOnRemove', _this);
26473             },
26474             
26475             show: function(cpx)
26476             {
26477                 _this.fireEvent('OverlayViewShow', _this, cpx);
26478             },
26479             
26480             hide: function()
26481             {
26482                 _this.fireEvent('OverlayViewHide', _this);
26483             }
26484             
26485         });
26486     },
26487     
26488     fromLatLngToContainerPixel: function(event)
26489     {
26490         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26491     },
26492     
26493     isApplied: function() 
26494     {
26495         return this.getGmapContext() == false ? false : true;
26496     },
26497     
26498     getGmapContext: function() 
26499     {
26500         return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26501     },
26502     
26503     GMapContext: function() 
26504     {
26505         var position = new google.maps.LatLng(this.latitude, this.longitude);
26506         
26507         var _map = new google.maps.Map(this.el.dom, {
26508             center: position,
26509             zoom: this.zoom,
26510             mapTypeId: this.mapTypeId,
26511             mapTypeControl: this.mapTypeControl,
26512             disableDoubleClickZoom: this.disableDoubleClickZoom,
26513             scrollwheel: this.scrollwheel,
26514             streetViewControl: this.streetViewControl,
26515             locationName: this.locationName,
26516             draggable: this.draggable,
26517             enableAutocomplete: this.enableAutocomplete,
26518             enableReverseGeocode: this.enableReverseGeocode
26519         });
26520         
26521         var _marker = new google.maps.Marker({
26522             position: position,
26523             map: _map,
26524             title: this.markerTitle,
26525             draggable: this.draggable
26526         });
26527         
26528         return {
26529             map: _map,
26530             marker: _marker,
26531             circle: null,
26532             location: position,
26533             radius: this.radius,
26534             locationName: this.locationName,
26535             addressComponents: {
26536                 formatted_address: null,
26537                 addressLine1: null,
26538                 addressLine2: null,
26539                 streetName: null,
26540                 streetNumber: null,
26541                 city: null,
26542                 district: null,
26543                 state: null,
26544                 stateOrProvince: null
26545             },
26546             settings: this,
26547             domContainer: this.el.dom,
26548             geodecoder: new google.maps.Geocoder()
26549         };
26550     },
26551     
26552     drawCircle: function(center, radius, options) 
26553     {
26554         if (this.gMapContext.circle != null) {
26555             this.gMapContext.circle.setMap(null);
26556         }
26557         if (radius > 0) {
26558             radius *= 1;
26559             options = Roo.apply({}, options, {
26560                 strokeColor: "#0000FF",
26561                 strokeOpacity: .35,
26562                 strokeWeight: 2,
26563                 fillColor: "#0000FF",
26564                 fillOpacity: .2
26565             });
26566             
26567             options.map = this.gMapContext.map;
26568             options.radius = radius;
26569             options.center = center;
26570             this.gMapContext.circle = new google.maps.Circle(options);
26571             return this.gMapContext.circle;
26572         }
26573         
26574         return null;
26575     },
26576     
26577     setPosition: function(location) 
26578     {
26579         this.gMapContext.location = location;
26580         this.gMapContext.marker.setPosition(location);
26581         this.gMapContext.map.panTo(location);
26582         this.drawCircle(location, this.gMapContext.radius, {});
26583         
26584         var _this = this;
26585         
26586         if (this.gMapContext.settings.enableReverseGeocode) {
26587             this.gMapContext.geodecoder.geocode({
26588                 latLng: this.gMapContext.location
26589             }, function(results, status) {
26590                 
26591                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26592                     _this.gMapContext.locationName = results[0].formatted_address;
26593                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26594                     
26595                     _this.fireEvent('positionchanged', this, location);
26596                 }
26597             });
26598             
26599             return;
26600         }
26601         
26602         this.fireEvent('positionchanged', this, location);
26603     },
26604     
26605     resize: function()
26606     {
26607         google.maps.event.trigger(this.gMapContext.map, "resize");
26608         
26609         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26610         
26611         this.fireEvent('resize', this);
26612     },
26613     
26614     setPositionByLatLng: function(latitude, longitude)
26615     {
26616         this.setPosition(new google.maps.LatLng(latitude, longitude));
26617     },
26618     
26619     getCurrentPosition: function() 
26620     {
26621         return {
26622             latitude: this.gMapContext.location.lat(),
26623             longitude: this.gMapContext.location.lng()
26624         };
26625     },
26626     
26627     getAddressName: function() 
26628     {
26629         return this.gMapContext.locationName;
26630     },
26631     
26632     getAddressComponents: function() 
26633     {
26634         return this.gMapContext.addressComponents;
26635     },
26636     
26637     address_component_from_google_geocode: function(address_components) 
26638     {
26639         var result = {};
26640         
26641         for (var i = 0; i < address_components.length; i++) {
26642             var component = address_components[i];
26643             if (component.types.indexOf("postal_code") >= 0) {
26644                 result.postalCode = component.short_name;
26645             } else if (component.types.indexOf("street_number") >= 0) {
26646                 result.streetNumber = component.short_name;
26647             } else if (component.types.indexOf("route") >= 0) {
26648                 result.streetName = component.short_name;
26649             } else if (component.types.indexOf("neighborhood") >= 0) {
26650                 result.city = component.short_name;
26651             } else if (component.types.indexOf("locality") >= 0) {
26652                 result.city = component.short_name;
26653             } else if (component.types.indexOf("sublocality") >= 0) {
26654                 result.district = component.short_name;
26655             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26656                 result.stateOrProvince = component.short_name;
26657             } else if (component.types.indexOf("country") >= 0) {
26658                 result.country = component.short_name;
26659             }
26660         }
26661         
26662         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26663         result.addressLine2 = "";
26664         return result;
26665     },
26666     
26667     setZoomLevel: function(zoom)
26668     {
26669         this.gMapContext.map.setZoom(zoom);
26670     },
26671     
26672     show: function()
26673     {
26674         if(!this.el){
26675             return;
26676         }
26677         
26678         this.el.show();
26679         
26680         this.resize();
26681         
26682         this.fireEvent('show', this);
26683     },
26684     
26685     hide: function()
26686     {
26687         if(!this.el){
26688             return;
26689         }
26690         
26691         this.el.hide();
26692         
26693         this.fireEvent('hide', this);
26694     }
26695     
26696 });
26697
26698 Roo.apply(Roo.bootstrap.LocationPicker, {
26699     
26700     OverlayView : function(map, options)
26701     {
26702         options = options || {};
26703         
26704         this.setMap(map);
26705     }
26706     
26707     
26708 });/*
26709  * - LGPL
26710  *
26711  * Alert
26712  * 
26713  */
26714
26715 /**
26716  * @class Roo.bootstrap.Alert
26717  * @extends Roo.bootstrap.Component
26718  * Bootstrap Alert class
26719  * @cfg {String} title The title of alert
26720  * @cfg {String} html The content of alert
26721  * @cfg {String} weight (  success | info | warning | danger )
26722  * @cfg {String} faicon font-awesomeicon
26723  * 
26724  * @constructor
26725  * Create a new alert
26726  * @param {Object} config The config object
26727  */
26728
26729
26730 Roo.bootstrap.Alert = function(config){
26731     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26732     
26733 };
26734
26735 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
26736     
26737     title: '',
26738     html: '',
26739     weight: false,
26740     faicon: false,
26741     
26742     getAutoCreate : function()
26743     {
26744         
26745         var cfg = {
26746             tag : 'div',
26747             cls : 'alert',
26748             cn : [
26749                 {
26750                     tag : 'i',
26751                     cls : 'roo-alert-icon'
26752                     
26753                 },
26754                 {
26755                     tag : 'b',
26756                     cls : 'roo-alert-title',
26757                     html : this.title
26758                 },
26759                 {
26760                     tag : 'span',
26761                     cls : 'roo-alert-text',
26762                     html : this.html
26763                 }
26764             ]
26765         };
26766         
26767         if(this.faicon){
26768             cfg.cn[0].cls += ' fa ' + this.faicon;
26769         }
26770         
26771         if(this.weight){
26772             cfg.cls += ' alert-' + this.weight;
26773         }
26774         
26775         return cfg;
26776     },
26777     
26778     initEvents: function() 
26779     {
26780         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26781     },
26782     
26783     setTitle : function(str)
26784     {
26785         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26786     },
26787     
26788     setText : function(str)
26789     {
26790         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26791     },
26792     
26793     setWeight : function(weight)
26794     {
26795         if(this.weight){
26796             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26797         }
26798         
26799         this.weight = weight;
26800         
26801         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26802     },
26803     
26804     setIcon : function(icon)
26805     {
26806         if(this.faicon){
26807             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26808         }
26809         
26810         this.faicon = icon;
26811         
26812         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26813     },
26814     
26815     hide: function() 
26816     {
26817         this.el.hide();   
26818     },
26819     
26820     show: function() 
26821     {  
26822         this.el.show();   
26823     }
26824     
26825 });
26826
26827  
26828 /*
26829 * Licence: LGPL
26830 */
26831
26832 /**
26833  * @class Roo.bootstrap.UploadCropbox
26834  * @extends Roo.bootstrap.Component
26835  * Bootstrap UploadCropbox class
26836  * @cfg {String} emptyText show when image has been loaded
26837  * @cfg {String} rotateNotify show when image too small to rotate
26838  * @cfg {Number} errorTimeout default 3000
26839  * @cfg {Number} minWidth default 300
26840  * @cfg {Number} minHeight default 300
26841  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26842  * @cfg {Boolean} isDocument (true|false) default false
26843  * @cfg {String} url action url
26844  * @cfg {String} paramName default 'imageUpload'
26845  * @cfg {String} method default POST
26846  * @cfg {Boolean} loadMask (true|false) default true
26847  * @cfg {Boolean} loadingText default 'Loading...'
26848  * 
26849  * @constructor
26850  * Create a new UploadCropbox
26851  * @param {Object} config The config object
26852  */
26853
26854 Roo.bootstrap.UploadCropbox = function(config){
26855     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26856     
26857     this.addEvents({
26858         /**
26859          * @event beforeselectfile
26860          * Fire before select file
26861          * @param {Roo.bootstrap.UploadCropbox} this
26862          */
26863         "beforeselectfile" : true,
26864         /**
26865          * @event initial
26866          * Fire after initEvent
26867          * @param {Roo.bootstrap.UploadCropbox} this
26868          */
26869         "initial" : true,
26870         /**
26871          * @event crop
26872          * Fire after initEvent
26873          * @param {Roo.bootstrap.UploadCropbox} this
26874          * @param {String} data
26875          */
26876         "crop" : true,
26877         /**
26878          * @event prepare
26879          * Fire when preparing the file data
26880          * @param {Roo.bootstrap.UploadCropbox} this
26881          * @param {Object} file
26882          */
26883         "prepare" : true,
26884         /**
26885          * @event exception
26886          * Fire when get exception
26887          * @param {Roo.bootstrap.UploadCropbox} this
26888          * @param {XMLHttpRequest} xhr
26889          */
26890         "exception" : true,
26891         /**
26892          * @event beforeloadcanvas
26893          * Fire before load the canvas
26894          * @param {Roo.bootstrap.UploadCropbox} this
26895          * @param {String} src
26896          */
26897         "beforeloadcanvas" : true,
26898         /**
26899          * @event trash
26900          * Fire when trash image
26901          * @param {Roo.bootstrap.UploadCropbox} this
26902          */
26903         "trash" : true,
26904         /**
26905          * @event download
26906          * Fire when download the image
26907          * @param {Roo.bootstrap.UploadCropbox} this
26908          */
26909         "download" : true,
26910         /**
26911          * @event footerbuttonclick
26912          * Fire when footerbuttonclick
26913          * @param {Roo.bootstrap.UploadCropbox} this
26914          * @param {String} type
26915          */
26916         "footerbuttonclick" : true,
26917         /**
26918          * @event resize
26919          * Fire when resize
26920          * @param {Roo.bootstrap.UploadCropbox} this
26921          */
26922         "resize" : true,
26923         /**
26924          * @event rotate
26925          * Fire when rotate the image
26926          * @param {Roo.bootstrap.UploadCropbox} this
26927          * @param {String} pos
26928          */
26929         "rotate" : true,
26930         /**
26931          * @event inspect
26932          * Fire when inspect the file
26933          * @param {Roo.bootstrap.UploadCropbox} this
26934          * @param {Object} file
26935          */
26936         "inspect" : true,
26937         /**
26938          * @event upload
26939          * Fire when xhr upload the file
26940          * @param {Roo.bootstrap.UploadCropbox} this
26941          * @param {Object} data
26942          */
26943         "upload" : true,
26944         /**
26945          * @event arrange
26946          * Fire when arrange the file data
26947          * @param {Roo.bootstrap.UploadCropbox} this
26948          * @param {Object} formData
26949          */
26950         "arrange" : true
26951     });
26952     
26953     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26954 };
26955
26956 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
26957     
26958     emptyText : 'Click to upload image',
26959     rotateNotify : 'Image is too small to rotate',
26960     errorTimeout : 3000,
26961     scale : 0,
26962     baseScale : 1,
26963     rotate : 0,
26964     dragable : false,
26965     pinching : false,
26966     mouseX : 0,
26967     mouseY : 0,
26968     cropData : false,
26969     minWidth : 300,
26970     minHeight : 300,
26971     file : false,
26972     exif : {},
26973     baseRotate : 1,
26974     cropType : 'image/jpeg',
26975     buttons : false,
26976     canvasLoaded : false,
26977     isDocument : false,
26978     method : 'POST',
26979     paramName : 'imageUpload',
26980     loadMask : true,
26981     loadingText : 'Loading...',
26982     maskEl : false,
26983     
26984     getAutoCreate : function()
26985     {
26986         var cfg = {
26987             tag : 'div',
26988             cls : 'roo-upload-cropbox',
26989             cn : [
26990                 {
26991                     tag : 'input',
26992                     cls : 'roo-upload-cropbox-selector',
26993                     type : 'file'
26994                 },
26995                 {
26996                     tag : 'div',
26997                     cls : 'roo-upload-cropbox-body',
26998                     style : 'cursor:pointer',
26999                     cn : [
27000                         {
27001                             tag : 'div',
27002                             cls : 'roo-upload-cropbox-preview'
27003                         },
27004                         {
27005                             tag : 'div',
27006                             cls : 'roo-upload-cropbox-thumb'
27007                         },
27008                         {
27009                             tag : 'div',
27010                             cls : 'roo-upload-cropbox-empty-notify',
27011                             html : this.emptyText
27012                         },
27013                         {
27014                             tag : 'div',
27015                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27016                             html : this.rotateNotify
27017                         }
27018                     ]
27019                 },
27020                 {
27021                     tag : 'div',
27022                     cls : 'roo-upload-cropbox-footer',
27023                     cn : {
27024                         tag : 'div',
27025                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27026                         cn : []
27027                     }
27028                 }
27029             ]
27030         };
27031         
27032         return cfg;
27033     },
27034     
27035     onRender : function(ct, position)
27036     {
27037         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27038         
27039         if (this.buttons.length) {
27040             
27041             Roo.each(this.buttons, function(bb) {
27042                 
27043                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27044                 
27045                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27046                 
27047             }, this);
27048         }
27049         
27050         if(this.loadMask){
27051             this.maskEl = this.el;
27052         }
27053     },
27054     
27055     initEvents : function()
27056     {
27057         this.urlAPI = (window.createObjectURL && window) || 
27058                                 (window.URL && URL.revokeObjectURL && URL) || 
27059                                 (window.webkitURL && webkitURL);
27060                         
27061         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27062         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27063         
27064         this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27065         this.selectorEl.hide();
27066         
27067         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27068         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27069         
27070         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27071         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27072         this.thumbEl.hide();
27073         
27074         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27075         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27076         
27077         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27078         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27079         this.errorEl.hide();
27080         
27081         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27082         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27083         this.footerEl.hide();
27084         
27085         this.setThumbBoxSize();
27086         
27087         this.bind();
27088         
27089         this.resize();
27090         
27091         this.fireEvent('initial', this);
27092     },
27093
27094     bind : function()
27095     {
27096         var _this = this;
27097         
27098         window.addEventListener("resize", function() { _this.resize(); } );
27099         
27100         this.bodyEl.on('click', this.beforeSelectFile, this);
27101         
27102         if(Roo.isTouch){
27103             this.bodyEl.on('touchstart', this.onTouchStart, this);
27104             this.bodyEl.on('touchmove', this.onTouchMove, this);
27105             this.bodyEl.on('touchend', this.onTouchEnd, this);
27106         }
27107         
27108         if(!Roo.isTouch){
27109             this.bodyEl.on('mousedown', this.onMouseDown, this);
27110             this.bodyEl.on('mousemove', this.onMouseMove, this);
27111             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27112             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27113             Roo.get(document).on('mouseup', this.onMouseUp, this);
27114         }
27115         
27116         this.selectorEl.on('change', this.onFileSelected, this);
27117     },
27118     
27119     reset : function()
27120     {    
27121         this.scale = 0;
27122         this.baseScale = 1;
27123         this.rotate = 0;
27124         this.baseRotate = 1;
27125         this.dragable = false;
27126         this.pinching = false;
27127         this.mouseX = 0;
27128         this.mouseY = 0;
27129         this.cropData = false;
27130         this.notifyEl.dom.innerHTML = this.emptyText;
27131         
27132         this.selectorEl.dom.value = '';
27133         
27134     },
27135     
27136     resize : function()
27137     {
27138         if(this.fireEvent('resize', this) != false){
27139             this.setThumbBoxPosition();
27140             this.setCanvasPosition();
27141         }
27142     },
27143     
27144     onFooterButtonClick : function(e, el, o, type)
27145     {
27146         switch (type) {
27147             case 'rotate-left' :
27148                 this.onRotateLeft(e);
27149                 break;
27150             case 'rotate-right' :
27151                 this.onRotateRight(e);
27152                 break;
27153             case 'picture' :
27154                 this.beforeSelectFile(e);
27155                 break;
27156             case 'trash' :
27157                 this.trash(e);
27158                 break;
27159             case 'crop' :
27160                 this.crop(e);
27161                 break;
27162             case 'download' :
27163                 this.download(e);
27164                 break;
27165             default :
27166                 break;
27167         }
27168         
27169         this.fireEvent('footerbuttonclick', this, type);
27170     },
27171     
27172     beforeSelectFile : function(e)
27173     {
27174         e.preventDefault();
27175         
27176         if(this.fireEvent('beforeselectfile', this) != false){
27177             this.selectorEl.dom.click();
27178         }
27179     },
27180     
27181     onFileSelected : function(e)
27182     {
27183         e.preventDefault();
27184         
27185         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27186             return;
27187         }
27188         
27189         var file = this.selectorEl.dom.files[0];
27190         
27191         if(this.fireEvent('inspect', this, file) != false){
27192             this.prepare(file);
27193         }
27194         
27195     },
27196     
27197     trash : function(e)
27198     {
27199         this.fireEvent('trash', this);
27200     },
27201     
27202     download : function(e)
27203     {
27204         this.fireEvent('download', this);
27205     },
27206     
27207     loadCanvas : function(src)
27208     {   
27209         if(this.fireEvent('beforeloadcanvas', this, src) != false){
27210             
27211             this.reset();
27212             
27213             this.imageEl = document.createElement('img');
27214             
27215             var _this = this;
27216             
27217             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27218             
27219             this.imageEl.src = src;
27220         }
27221     },
27222     
27223     onLoadCanvas : function()
27224     {   
27225         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27226         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27227         
27228         this.bodyEl.un('click', this.beforeSelectFile, this);
27229         
27230         this.notifyEl.hide();
27231         this.thumbEl.show();
27232         this.footerEl.show();
27233         
27234         this.baseRotateLevel();
27235         
27236         if(this.isDocument){
27237             this.setThumbBoxSize();
27238         }
27239         
27240         this.setThumbBoxPosition();
27241         
27242         this.baseScaleLevel();
27243         
27244         this.draw();
27245         
27246         this.resize();
27247         
27248         this.canvasLoaded = true;
27249         
27250         if(this.loadMask){
27251             this.maskEl.unmask();
27252         }
27253         
27254     },
27255     
27256     setCanvasPosition : function()
27257     {   
27258         if(!this.canvasEl){
27259             return;
27260         }
27261         
27262         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27263         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27264         
27265         this.previewEl.setLeft(pw);
27266         this.previewEl.setTop(ph);
27267         
27268     },
27269     
27270     onMouseDown : function(e)
27271     {   
27272         e.stopEvent();
27273         
27274         this.dragable = true;
27275         this.pinching = false;
27276         
27277         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27278             this.dragable = false;
27279             return;
27280         }
27281         
27282         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27283         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27284         
27285     },
27286     
27287     onMouseMove : function(e)
27288     {   
27289         e.stopEvent();
27290         
27291         if(!this.canvasLoaded){
27292             return;
27293         }
27294         
27295         if (!this.dragable){
27296             return;
27297         }
27298         
27299         var minX = Math.ceil(this.thumbEl.getLeft(true));
27300         var minY = Math.ceil(this.thumbEl.getTop(true));
27301         
27302         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27303         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27304         
27305         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27306         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27307         
27308         x = x - this.mouseX;
27309         y = y - this.mouseY;
27310         
27311         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27312         var bgY = Math.ceil(y + this.previewEl.getTop(true));
27313         
27314         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27315         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27316         
27317         this.previewEl.setLeft(bgX);
27318         this.previewEl.setTop(bgY);
27319         
27320         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27321         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27322     },
27323     
27324     onMouseUp : function(e)
27325     {   
27326         e.stopEvent();
27327         
27328         this.dragable = false;
27329     },
27330     
27331     onMouseWheel : function(e)
27332     {   
27333         e.stopEvent();
27334         
27335         this.startScale = this.scale;
27336         
27337         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27338         
27339         if(!this.zoomable()){
27340             this.scale = this.startScale;
27341             return;
27342         }
27343         
27344         this.draw();
27345         
27346         return;
27347     },
27348     
27349     zoomable : function()
27350     {
27351         var minScale = this.thumbEl.getWidth() / this.minWidth;
27352         
27353         if(this.minWidth < this.minHeight){
27354             minScale = this.thumbEl.getHeight() / this.minHeight;
27355         }
27356         
27357         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27358         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27359         
27360         if(
27361                 this.isDocument &&
27362                 (this.rotate == 0 || this.rotate == 180) && 
27363                 (
27364                     width > this.imageEl.OriginWidth || 
27365                     height > this.imageEl.OriginHeight ||
27366                     (width < this.minWidth && height < this.minHeight)
27367                 )
27368         ){
27369             return false;
27370         }
27371         
27372         if(
27373                 this.isDocument &&
27374                 (this.rotate == 90 || this.rotate == 270) && 
27375                 (
27376                     width > this.imageEl.OriginWidth || 
27377                     height > this.imageEl.OriginHeight ||
27378                     (width < this.minHeight && height < this.minWidth)
27379                 )
27380         ){
27381             return false;
27382         }
27383         
27384         if(
27385                 !this.isDocument &&
27386                 (this.rotate == 0 || this.rotate == 180) && 
27387                 (
27388                     width < this.minWidth || 
27389                     width > this.imageEl.OriginWidth || 
27390                     height < this.minHeight || 
27391                     height > this.imageEl.OriginHeight
27392                 )
27393         ){
27394             return false;
27395         }
27396         
27397         if(
27398                 !this.isDocument &&
27399                 (this.rotate == 90 || this.rotate == 270) && 
27400                 (
27401                     width < this.minHeight || 
27402                     width > this.imageEl.OriginWidth || 
27403                     height < this.minWidth || 
27404                     height > this.imageEl.OriginHeight
27405                 )
27406         ){
27407             return false;
27408         }
27409         
27410         return true;
27411         
27412     },
27413     
27414     onRotateLeft : function(e)
27415     {   
27416         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27417             
27418             var minScale = this.thumbEl.getWidth() / this.minWidth;
27419             
27420             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27421             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27422             
27423             this.startScale = this.scale;
27424             
27425             while (this.getScaleLevel() < minScale){
27426             
27427                 this.scale = this.scale + 1;
27428                 
27429                 if(!this.zoomable()){
27430                     break;
27431                 }
27432                 
27433                 if(
27434                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27435                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27436                 ){
27437                     continue;
27438                 }
27439                 
27440                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27441
27442                 this.draw();
27443                 
27444                 return;
27445             }
27446             
27447             this.scale = this.startScale;
27448             
27449             this.onRotateFail();
27450             
27451             return false;
27452         }
27453         
27454         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27455
27456         if(this.isDocument){
27457             this.setThumbBoxSize();
27458             this.setThumbBoxPosition();
27459             this.setCanvasPosition();
27460         }
27461         
27462         this.draw();
27463         
27464         this.fireEvent('rotate', this, 'left');
27465         
27466     },
27467     
27468     onRotateRight : function(e)
27469     {
27470         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27471             
27472             var minScale = this.thumbEl.getWidth() / this.minWidth;
27473         
27474             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27475             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27476             
27477             this.startScale = this.scale;
27478             
27479             while (this.getScaleLevel() < minScale){
27480             
27481                 this.scale = this.scale + 1;
27482                 
27483                 if(!this.zoomable()){
27484                     break;
27485                 }
27486                 
27487                 if(
27488                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27489                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27490                 ){
27491                     continue;
27492                 }
27493                 
27494                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27495
27496                 this.draw();
27497                 
27498                 return;
27499             }
27500             
27501             this.scale = this.startScale;
27502             
27503             this.onRotateFail();
27504             
27505             return false;
27506         }
27507         
27508         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27509
27510         if(this.isDocument){
27511             this.setThumbBoxSize();
27512             this.setThumbBoxPosition();
27513             this.setCanvasPosition();
27514         }
27515         
27516         this.draw();
27517         
27518         this.fireEvent('rotate', this, 'right');
27519     },
27520     
27521     onRotateFail : function()
27522     {
27523         this.errorEl.show(true);
27524         
27525         var _this = this;
27526         
27527         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27528     },
27529     
27530     draw : function()
27531     {
27532         this.previewEl.dom.innerHTML = '';
27533         
27534         var canvasEl = document.createElement("canvas");
27535         
27536         var contextEl = canvasEl.getContext("2d");
27537         
27538         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27539         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27540         var center = this.imageEl.OriginWidth / 2;
27541         
27542         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27543             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27544             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27545             center = this.imageEl.OriginHeight / 2;
27546         }
27547         
27548         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27549         
27550         contextEl.translate(center, center);
27551         contextEl.rotate(this.rotate * Math.PI / 180);
27552
27553         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27554         
27555         this.canvasEl = document.createElement("canvas");
27556         
27557         this.contextEl = this.canvasEl.getContext("2d");
27558         
27559         switch (this.rotate) {
27560             case 0 :
27561                 
27562                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27563                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27564                 
27565                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27566                 
27567                 break;
27568             case 90 : 
27569                 
27570                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27571                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27572                 
27573                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27574                     this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27575                     break;
27576                 }
27577                 
27578                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27579                 
27580                 break;
27581             case 180 :
27582                 
27583                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27584                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27585                 
27586                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27587                     this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27588                     break;
27589                 }
27590                 
27591                 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27592                 
27593                 break;
27594             case 270 :
27595                 
27596                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27597                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27598         
27599                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27600                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27601                     break;
27602                 }
27603                 
27604                 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27605                 
27606                 break;
27607             default : 
27608                 break;
27609         }
27610         
27611         this.previewEl.appendChild(this.canvasEl);
27612         
27613         this.setCanvasPosition();
27614     },
27615     
27616     crop : function()
27617     {
27618         if(!this.canvasLoaded){
27619             return;
27620         }
27621         
27622         var imageCanvas = document.createElement("canvas");
27623         
27624         var imageContext = imageCanvas.getContext("2d");
27625         
27626         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27627         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27628         
27629         var center = imageCanvas.width / 2;
27630         
27631         imageContext.translate(center, center);
27632         
27633         imageContext.rotate(this.rotate * Math.PI / 180);
27634         
27635         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27636         
27637         var canvas = document.createElement("canvas");
27638         
27639         var context = canvas.getContext("2d");
27640                 
27641         canvas.width = this.minWidth;
27642         canvas.height = this.minHeight;
27643
27644         switch (this.rotate) {
27645             case 0 :
27646                 
27647                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27648                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27649                 
27650                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27651                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27652                 
27653                 var targetWidth = this.minWidth - 2 * x;
27654                 var targetHeight = this.minHeight - 2 * y;
27655                 
27656                 var scale = 1;
27657                 
27658                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27659                     scale = targetWidth / width;
27660                 }
27661                 
27662                 if(x > 0 && y == 0){
27663                     scale = targetHeight / height;
27664                 }
27665                 
27666                 if(x > 0 && y > 0){
27667                     scale = targetWidth / width;
27668                     
27669                     if(width < height){
27670                         scale = targetHeight / height;
27671                     }
27672                 }
27673                 
27674                 context.scale(scale, scale);
27675                 
27676                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27677                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27678
27679                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27680                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27681
27682                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27683                 
27684                 break;
27685             case 90 : 
27686                 
27687                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27688                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27689                 
27690                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27691                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27692                 
27693                 var targetWidth = this.minWidth - 2 * x;
27694                 var targetHeight = this.minHeight - 2 * y;
27695                 
27696                 var scale = 1;
27697                 
27698                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27699                     scale = targetWidth / width;
27700                 }
27701                 
27702                 if(x > 0 && y == 0){
27703                     scale = targetHeight / height;
27704                 }
27705                 
27706                 if(x > 0 && y > 0){
27707                     scale = targetWidth / width;
27708                     
27709                     if(width < height){
27710                         scale = targetHeight / height;
27711                     }
27712                 }
27713                 
27714                 context.scale(scale, scale);
27715                 
27716                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27717                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27718
27719                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27720                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27721                 
27722                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27723                 
27724                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27725                 
27726                 break;
27727             case 180 :
27728                 
27729                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27730                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27731                 
27732                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27733                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27734                 
27735                 var targetWidth = this.minWidth - 2 * x;
27736                 var targetHeight = this.minHeight - 2 * y;
27737                 
27738                 var scale = 1;
27739                 
27740                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27741                     scale = targetWidth / width;
27742                 }
27743                 
27744                 if(x > 0 && y == 0){
27745                     scale = targetHeight / height;
27746                 }
27747                 
27748                 if(x > 0 && y > 0){
27749                     scale = targetWidth / width;
27750                     
27751                     if(width < height){
27752                         scale = targetHeight / height;
27753                     }
27754                 }
27755                 
27756                 context.scale(scale, scale);
27757                 
27758                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27759                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27760
27761                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27762                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27763
27764                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27765                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27766                 
27767                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27768                 
27769                 break;
27770             case 270 :
27771                 
27772                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27773                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27774                 
27775                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27776                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27777                 
27778                 var targetWidth = this.minWidth - 2 * x;
27779                 var targetHeight = this.minHeight - 2 * y;
27780                 
27781                 var scale = 1;
27782                 
27783                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27784                     scale = targetWidth / width;
27785                 }
27786                 
27787                 if(x > 0 && y == 0){
27788                     scale = targetHeight / height;
27789                 }
27790                 
27791                 if(x > 0 && y > 0){
27792                     scale = targetWidth / width;
27793                     
27794                     if(width < height){
27795                         scale = targetHeight / height;
27796                     }
27797                 }
27798                 
27799                 context.scale(scale, scale);
27800                 
27801                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27802                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27803
27804                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27805                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27806                 
27807                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27808                 
27809                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27810                 
27811                 break;
27812             default : 
27813                 break;
27814         }
27815         
27816         this.cropData = canvas.toDataURL(this.cropType);
27817         
27818         if(this.fireEvent('crop', this, this.cropData) !== false){
27819             this.process(this.file, this.cropData);
27820         }
27821         
27822         return;
27823         
27824     },
27825     
27826     setThumbBoxSize : function()
27827     {
27828         var width, height;
27829         
27830         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27831             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27832             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27833             
27834             this.minWidth = width;
27835             this.minHeight = height;
27836             
27837             if(this.rotate == 90 || this.rotate == 270){
27838                 this.minWidth = height;
27839                 this.minHeight = width;
27840             }
27841         }
27842         
27843         height = 300;
27844         width = Math.ceil(this.minWidth * height / this.minHeight);
27845         
27846         if(this.minWidth > this.minHeight){
27847             width = 300;
27848             height = Math.ceil(this.minHeight * width / this.minWidth);
27849         }
27850         
27851         this.thumbEl.setStyle({
27852             width : width + 'px',
27853             height : height + 'px'
27854         });
27855
27856         return;
27857             
27858     },
27859     
27860     setThumbBoxPosition : function()
27861     {
27862         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27863         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27864         
27865         this.thumbEl.setLeft(x);
27866         this.thumbEl.setTop(y);
27867         
27868     },
27869     
27870     baseRotateLevel : function()
27871     {
27872         this.baseRotate = 1;
27873         
27874         if(
27875                 typeof(this.exif) != 'undefined' &&
27876                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27877                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27878         ){
27879             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27880         }
27881         
27882         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27883         
27884     },
27885     
27886     baseScaleLevel : function()
27887     {
27888         var width, height;
27889         
27890         if(this.isDocument){
27891             
27892             if(this.baseRotate == 6 || this.baseRotate == 8){
27893             
27894                 height = this.thumbEl.getHeight();
27895                 this.baseScale = height / this.imageEl.OriginWidth;
27896
27897                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27898                     width = this.thumbEl.getWidth();
27899                     this.baseScale = width / this.imageEl.OriginHeight;
27900                 }
27901
27902                 return;
27903             }
27904
27905             height = this.thumbEl.getHeight();
27906             this.baseScale = height / this.imageEl.OriginHeight;
27907
27908             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27909                 width = this.thumbEl.getWidth();
27910                 this.baseScale = width / this.imageEl.OriginWidth;
27911             }
27912
27913             return;
27914         }
27915         
27916         if(this.baseRotate == 6 || this.baseRotate == 8){
27917             
27918             width = this.thumbEl.getHeight();
27919             this.baseScale = width / this.imageEl.OriginHeight;
27920             
27921             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27922                 height = this.thumbEl.getWidth();
27923                 this.baseScale = height / this.imageEl.OriginHeight;
27924             }
27925             
27926             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27927                 height = this.thumbEl.getWidth();
27928                 this.baseScale = height / this.imageEl.OriginHeight;
27929                 
27930                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27931                     width = this.thumbEl.getHeight();
27932                     this.baseScale = width / this.imageEl.OriginWidth;
27933                 }
27934             }
27935             
27936             return;
27937         }
27938         
27939         width = this.thumbEl.getWidth();
27940         this.baseScale = width / this.imageEl.OriginWidth;
27941         
27942         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27943             height = this.thumbEl.getHeight();
27944             this.baseScale = height / this.imageEl.OriginHeight;
27945         }
27946         
27947         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27948             
27949             height = this.thumbEl.getHeight();
27950             this.baseScale = height / this.imageEl.OriginHeight;
27951             
27952             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27953                 width = this.thumbEl.getWidth();
27954                 this.baseScale = width / this.imageEl.OriginWidth;
27955             }
27956             
27957         }
27958         
27959         return;
27960     },
27961     
27962     getScaleLevel : function()
27963     {
27964         return this.baseScale * Math.pow(1.1, this.scale);
27965     },
27966     
27967     onTouchStart : function(e)
27968     {
27969         if(!this.canvasLoaded){
27970             this.beforeSelectFile(e);
27971             return;
27972         }
27973         
27974         var touches = e.browserEvent.touches;
27975         
27976         if(!touches){
27977             return;
27978         }
27979         
27980         if(touches.length == 1){
27981             this.onMouseDown(e);
27982             return;
27983         }
27984         
27985         if(touches.length != 2){
27986             return;
27987         }
27988         
27989         var coords = [];
27990         
27991         for(var i = 0, finger; finger = touches[i]; i++){
27992             coords.push(finger.pageX, finger.pageY);
27993         }
27994         
27995         var x = Math.pow(coords[0] - coords[2], 2);
27996         var y = Math.pow(coords[1] - coords[3], 2);
27997         
27998         this.startDistance = Math.sqrt(x + y);
27999         
28000         this.startScale = this.scale;
28001         
28002         this.pinching = true;
28003         this.dragable = false;
28004         
28005     },
28006     
28007     onTouchMove : function(e)
28008     {
28009         if(!this.pinching && !this.dragable){
28010             return;
28011         }
28012         
28013         var touches = e.browserEvent.touches;
28014         
28015         if(!touches){
28016             return;
28017         }
28018         
28019         if(this.dragable){
28020             this.onMouseMove(e);
28021             return;
28022         }
28023         
28024         var coords = [];
28025         
28026         for(var i = 0, finger; finger = touches[i]; i++){
28027             coords.push(finger.pageX, finger.pageY);
28028         }
28029         
28030         var x = Math.pow(coords[0] - coords[2], 2);
28031         var y = Math.pow(coords[1] - coords[3], 2);
28032         
28033         this.endDistance = Math.sqrt(x + y);
28034         
28035         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28036         
28037         if(!this.zoomable()){
28038             this.scale = this.startScale;
28039             return;
28040         }
28041         
28042         this.draw();
28043         
28044     },
28045     
28046     onTouchEnd : function(e)
28047     {
28048         this.pinching = false;
28049         this.dragable = false;
28050         
28051     },
28052     
28053     process : function(file, crop)
28054     {
28055         if(this.loadMask){
28056             this.maskEl.mask(this.loadingText);
28057         }
28058         
28059         this.xhr = new XMLHttpRequest();
28060         
28061         file.xhr = this.xhr;
28062
28063         this.xhr.open(this.method, this.url, true);
28064         
28065         var headers = {
28066             "Accept": "application/json",
28067             "Cache-Control": "no-cache",
28068             "X-Requested-With": "XMLHttpRequest"
28069         };
28070         
28071         for (var headerName in headers) {
28072             var headerValue = headers[headerName];
28073             if (headerValue) {
28074                 this.xhr.setRequestHeader(headerName, headerValue);
28075             }
28076         }
28077         
28078         var _this = this;
28079         
28080         this.xhr.onload = function()
28081         {
28082             _this.xhrOnLoad(_this.xhr);
28083         }
28084         
28085         this.xhr.onerror = function()
28086         {
28087             _this.xhrOnError(_this.xhr);
28088         }
28089         
28090         var formData = new FormData();
28091
28092         formData.append('returnHTML', 'NO');
28093         
28094         if(crop){
28095             formData.append('crop', crop);
28096         }
28097         
28098         if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28099             formData.append(this.paramName, file, file.name);
28100         }
28101         
28102         if(typeof(file.filename) != 'undefined'){
28103             formData.append('filename', file.filename);
28104         }
28105         
28106         if(typeof(file.mimetype) != 'undefined'){
28107             formData.append('mimetype', file.mimetype);
28108         }
28109         
28110         if(this.fireEvent('arrange', this, formData) != false){
28111             this.xhr.send(formData);
28112         };
28113     },
28114     
28115     xhrOnLoad : function(xhr)
28116     {
28117         if(this.loadMask){
28118             this.maskEl.unmask();
28119         }
28120         
28121         if (xhr.readyState !== 4) {
28122             this.fireEvent('exception', this, xhr);
28123             return;
28124         }
28125
28126         var response = Roo.decode(xhr.responseText);
28127         
28128         if(!response.success){
28129             this.fireEvent('exception', this, xhr);
28130             return;
28131         }
28132         
28133         var response = Roo.decode(xhr.responseText);
28134         
28135         this.fireEvent('upload', this, response);
28136         
28137     },
28138     
28139     xhrOnError : function()
28140     {
28141         if(this.loadMask){
28142             this.maskEl.unmask();
28143         }
28144         
28145         Roo.log('xhr on error');
28146         
28147         var response = Roo.decode(xhr.responseText);
28148           
28149         Roo.log(response);
28150         
28151     },
28152     
28153     prepare : function(file)
28154     {   
28155         if(this.loadMask){
28156             this.maskEl.mask(this.loadingText);
28157         }
28158         
28159         this.file = false;
28160         this.exif = {};
28161         
28162         if(typeof(file) === 'string'){
28163             this.loadCanvas(file);
28164             return;
28165         }
28166         
28167         if(!file || !this.urlAPI){
28168             return;
28169         }
28170         
28171         this.file = file;
28172         this.cropType = file.type;
28173         
28174         var _this = this;
28175         
28176         if(this.fireEvent('prepare', this, this.file) != false){
28177             
28178             var reader = new FileReader();
28179             
28180             reader.onload = function (e) {
28181                 if (e.target.error) {
28182                     Roo.log(e.target.error);
28183                     return;
28184                 }
28185                 
28186                 var buffer = e.target.result,
28187                     dataView = new DataView(buffer),
28188                     offset = 2,
28189                     maxOffset = dataView.byteLength - 4,
28190                     markerBytes,
28191                     markerLength;
28192                 
28193                 if (dataView.getUint16(0) === 0xffd8) {
28194                     while (offset < maxOffset) {
28195                         markerBytes = dataView.getUint16(offset);
28196                         
28197                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28198                             markerLength = dataView.getUint16(offset + 2) + 2;
28199                             if (offset + markerLength > dataView.byteLength) {
28200                                 Roo.log('Invalid meta data: Invalid segment size.');
28201                                 break;
28202                             }
28203                             
28204                             if(markerBytes == 0xffe1){
28205                                 _this.parseExifData(
28206                                     dataView,
28207                                     offset,
28208                                     markerLength
28209                                 );
28210                             }
28211                             
28212                             offset += markerLength;
28213                             
28214                             continue;
28215                         }
28216                         
28217                         break;
28218                     }
28219                     
28220                 }
28221                 
28222                 var url = _this.urlAPI.createObjectURL(_this.file);
28223                 
28224                 _this.loadCanvas(url);
28225                 
28226                 return;
28227             }
28228             
28229             reader.readAsArrayBuffer(this.file);
28230             
28231         }
28232         
28233     },
28234     
28235     parseExifData : function(dataView, offset, length)
28236     {
28237         var tiffOffset = offset + 10,
28238             littleEndian,
28239             dirOffset;
28240     
28241         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28242             // No Exif data, might be XMP data instead
28243             return;
28244         }
28245         
28246         // Check for the ASCII code for "Exif" (0x45786966):
28247         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28248             // No Exif data, might be XMP data instead
28249             return;
28250         }
28251         if (tiffOffset + 8 > dataView.byteLength) {
28252             Roo.log('Invalid Exif data: Invalid segment size.');
28253             return;
28254         }
28255         // Check for the two null bytes:
28256         if (dataView.getUint16(offset + 8) !== 0x0000) {
28257             Roo.log('Invalid Exif data: Missing byte alignment offset.');
28258             return;
28259         }
28260         // Check the byte alignment:
28261         switch (dataView.getUint16(tiffOffset)) {
28262         case 0x4949:
28263             littleEndian = true;
28264             break;
28265         case 0x4D4D:
28266             littleEndian = false;
28267             break;
28268         default:
28269             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28270             return;
28271         }
28272         // Check for the TIFF tag marker (0x002A):
28273         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28274             Roo.log('Invalid Exif data: Missing TIFF marker.');
28275             return;
28276         }
28277         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28278         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28279         
28280         this.parseExifTags(
28281             dataView,
28282             tiffOffset,
28283             tiffOffset + dirOffset,
28284             littleEndian
28285         );
28286     },
28287     
28288     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28289     {
28290         var tagsNumber,
28291             dirEndOffset,
28292             i;
28293         if (dirOffset + 6 > dataView.byteLength) {
28294             Roo.log('Invalid Exif data: Invalid directory offset.');
28295             return;
28296         }
28297         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28298         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28299         if (dirEndOffset + 4 > dataView.byteLength) {
28300             Roo.log('Invalid Exif data: Invalid directory size.');
28301             return;
28302         }
28303         for (i = 0; i < tagsNumber; i += 1) {
28304             this.parseExifTag(
28305                 dataView,
28306                 tiffOffset,
28307                 dirOffset + 2 + 12 * i, // tag offset
28308                 littleEndian
28309             );
28310         }
28311         // Return the offset to the next directory:
28312         return dataView.getUint32(dirEndOffset, littleEndian);
28313     },
28314     
28315     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
28316     {
28317         var tag = dataView.getUint16(offset, littleEndian);
28318         
28319         this.exif[tag] = this.getExifValue(
28320             dataView,
28321             tiffOffset,
28322             offset,
28323             dataView.getUint16(offset + 2, littleEndian), // tag type
28324             dataView.getUint32(offset + 4, littleEndian), // tag length
28325             littleEndian
28326         );
28327     },
28328     
28329     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28330     {
28331         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28332             tagSize,
28333             dataOffset,
28334             values,
28335             i,
28336             str,
28337             c;
28338     
28339         if (!tagType) {
28340             Roo.log('Invalid Exif data: Invalid tag type.');
28341             return;
28342         }
28343         
28344         tagSize = tagType.size * length;
28345         // Determine if the value is contained in the dataOffset bytes,
28346         // or if the value at the dataOffset is a pointer to the actual data:
28347         dataOffset = tagSize > 4 ?
28348                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28349         if (dataOffset + tagSize > dataView.byteLength) {
28350             Roo.log('Invalid Exif data: Invalid data offset.');
28351             return;
28352         }
28353         if (length === 1) {
28354             return tagType.getValue(dataView, dataOffset, littleEndian);
28355         }
28356         values = [];
28357         for (i = 0; i < length; i += 1) {
28358             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28359         }
28360         
28361         if (tagType.ascii) {
28362             str = '';
28363             // Concatenate the chars:
28364             for (i = 0; i < values.length; i += 1) {
28365                 c = values[i];
28366                 // Ignore the terminating NULL byte(s):
28367                 if (c === '\u0000') {
28368                     break;
28369                 }
28370                 str += c;
28371             }
28372             return str;
28373         }
28374         return values;
28375     }
28376     
28377 });
28378
28379 Roo.apply(Roo.bootstrap.UploadCropbox, {
28380     tags : {
28381         'Orientation': 0x0112
28382     },
28383     
28384     Orientation: {
28385             1: 0, //'top-left',
28386 //            2: 'top-right',
28387             3: 180, //'bottom-right',
28388 //            4: 'bottom-left',
28389 //            5: 'left-top',
28390             6: 90, //'right-top',
28391 //            7: 'right-bottom',
28392             8: 270 //'left-bottom'
28393     },
28394     
28395     exifTagTypes : {
28396         // byte, 8-bit unsigned int:
28397         1: {
28398             getValue: function (dataView, dataOffset) {
28399                 return dataView.getUint8(dataOffset);
28400             },
28401             size: 1
28402         },
28403         // ascii, 8-bit byte:
28404         2: {
28405             getValue: function (dataView, dataOffset) {
28406                 return String.fromCharCode(dataView.getUint8(dataOffset));
28407             },
28408             size: 1,
28409             ascii: true
28410         },
28411         // short, 16 bit int:
28412         3: {
28413             getValue: function (dataView, dataOffset, littleEndian) {
28414                 return dataView.getUint16(dataOffset, littleEndian);
28415             },
28416             size: 2
28417         },
28418         // long, 32 bit int:
28419         4: {
28420             getValue: function (dataView, dataOffset, littleEndian) {
28421                 return dataView.getUint32(dataOffset, littleEndian);
28422             },
28423             size: 4
28424         },
28425         // rational = two long values, first is numerator, second is denominator:
28426         5: {
28427             getValue: function (dataView, dataOffset, littleEndian) {
28428                 return dataView.getUint32(dataOffset, littleEndian) /
28429                     dataView.getUint32(dataOffset + 4, littleEndian);
28430             },
28431             size: 8
28432         },
28433         // slong, 32 bit signed int:
28434         9: {
28435             getValue: function (dataView, dataOffset, littleEndian) {
28436                 return dataView.getInt32(dataOffset, littleEndian);
28437             },
28438             size: 4
28439         },
28440         // srational, two slongs, first is numerator, second is denominator:
28441         10: {
28442             getValue: function (dataView, dataOffset, littleEndian) {
28443                 return dataView.getInt32(dataOffset, littleEndian) /
28444                     dataView.getInt32(dataOffset + 4, littleEndian);
28445             },
28446             size: 8
28447         }
28448     },
28449     
28450     footer : {
28451         STANDARD : [
28452             {
28453                 tag : 'div',
28454                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28455                 action : 'rotate-left',
28456                 cn : [
28457                     {
28458                         tag : 'button',
28459                         cls : 'btn btn-default',
28460                         html : '<i class="fa fa-undo"></i>'
28461                     }
28462                 ]
28463             },
28464             {
28465                 tag : 'div',
28466                 cls : 'btn-group roo-upload-cropbox-picture',
28467                 action : 'picture',
28468                 cn : [
28469                     {
28470                         tag : 'button',
28471                         cls : 'btn btn-default',
28472                         html : '<i class="fa fa-picture-o"></i>'
28473                     }
28474                 ]
28475             },
28476             {
28477                 tag : 'div',
28478                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28479                 action : 'rotate-right',
28480                 cn : [
28481                     {
28482                         tag : 'button',
28483                         cls : 'btn btn-default',
28484                         html : '<i class="fa fa-repeat"></i>'
28485                     }
28486                 ]
28487             }
28488         ],
28489         DOCUMENT : [
28490             {
28491                 tag : 'div',
28492                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28493                 action : 'rotate-left',
28494                 cn : [
28495                     {
28496                         tag : 'button',
28497                         cls : 'btn btn-default',
28498                         html : '<i class="fa fa-undo"></i>'
28499                     }
28500                 ]
28501             },
28502             {
28503                 tag : 'div',
28504                 cls : 'btn-group roo-upload-cropbox-download',
28505                 action : 'download',
28506                 cn : [
28507                     {
28508                         tag : 'button',
28509                         cls : 'btn btn-default',
28510                         html : '<i class="fa fa-download"></i>'
28511                     }
28512                 ]
28513             },
28514             {
28515                 tag : 'div',
28516                 cls : 'btn-group roo-upload-cropbox-crop',
28517                 action : 'crop',
28518                 cn : [
28519                     {
28520                         tag : 'button',
28521                         cls : 'btn btn-default',
28522                         html : '<i class="fa fa-crop"></i>'
28523                     }
28524                 ]
28525             },
28526             {
28527                 tag : 'div',
28528                 cls : 'btn-group roo-upload-cropbox-trash',
28529                 action : 'trash',
28530                 cn : [
28531                     {
28532                         tag : 'button',
28533                         cls : 'btn btn-default',
28534                         html : '<i class="fa fa-trash"></i>'
28535                     }
28536                 ]
28537             },
28538             {
28539                 tag : 'div',
28540                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28541                 action : 'rotate-right',
28542                 cn : [
28543                     {
28544                         tag : 'button',
28545                         cls : 'btn btn-default',
28546                         html : '<i class="fa fa-repeat"></i>'
28547                     }
28548                 ]
28549             }
28550         ],
28551         ROTATOR : [
28552             {
28553                 tag : 'div',
28554                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28555                 action : 'rotate-left',
28556                 cn : [
28557                     {
28558                         tag : 'button',
28559                         cls : 'btn btn-default',
28560                         html : '<i class="fa fa-undo"></i>'
28561                     }
28562                 ]
28563             },
28564             {
28565                 tag : 'div',
28566                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28567                 action : 'rotate-right',
28568                 cn : [
28569                     {
28570                         tag : 'button',
28571                         cls : 'btn btn-default',
28572                         html : '<i class="fa fa-repeat"></i>'
28573                     }
28574                 ]
28575             }
28576         ]
28577     }
28578 });
28579
28580 /*
28581 * Licence: LGPL
28582 */
28583
28584 /**
28585  * @class Roo.bootstrap.DocumentManager
28586  * @extends Roo.bootstrap.Component
28587  * Bootstrap DocumentManager class
28588  * @cfg {String} paramName default 'imageUpload'
28589  * @cfg {String} toolTipName default 'filename'
28590  * @cfg {String} method default POST
28591  * @cfg {String} url action url
28592  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28593  * @cfg {Boolean} multiple multiple upload default true
28594  * @cfg {Number} thumbSize default 300
28595  * @cfg {String} fieldLabel
28596  * @cfg {Number} labelWidth default 4
28597  * @cfg {String} labelAlign (left|top) default left
28598  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28599 * @cfg {Number} labellg set the width of label (1-12)
28600  * @cfg {Number} labelmd set the width of label (1-12)
28601  * @cfg {Number} labelsm set the width of label (1-12)
28602  * @cfg {Number} labelxs set the width of label (1-12)
28603  * 
28604  * @constructor
28605  * Create a new DocumentManager
28606  * @param {Object} config The config object
28607  */
28608
28609 Roo.bootstrap.DocumentManager = function(config){
28610     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28611     
28612     this.files = [];
28613     this.delegates = [];
28614     
28615     this.addEvents({
28616         /**
28617          * @event initial
28618          * Fire when initial the DocumentManager
28619          * @param {Roo.bootstrap.DocumentManager} this
28620          */
28621         "initial" : true,
28622         /**
28623          * @event inspect
28624          * inspect selected file
28625          * @param {Roo.bootstrap.DocumentManager} this
28626          * @param {File} file
28627          */
28628         "inspect" : true,
28629         /**
28630          * @event exception
28631          * Fire when xhr load exception
28632          * @param {Roo.bootstrap.DocumentManager} this
28633          * @param {XMLHttpRequest} xhr
28634          */
28635         "exception" : true,
28636         /**
28637          * @event afterupload
28638          * Fire when xhr load exception
28639          * @param {Roo.bootstrap.DocumentManager} this
28640          * @param {XMLHttpRequest} xhr
28641          */
28642         "afterupload" : true,
28643         /**
28644          * @event prepare
28645          * prepare the form data
28646          * @param {Roo.bootstrap.DocumentManager} this
28647          * @param {Object} formData
28648          */
28649         "prepare" : true,
28650         /**
28651          * @event remove
28652          * Fire when remove the file
28653          * @param {Roo.bootstrap.DocumentManager} this
28654          * @param {Object} file
28655          */
28656         "remove" : true,
28657         /**
28658          * @event refresh
28659          * Fire after refresh the file
28660          * @param {Roo.bootstrap.DocumentManager} this
28661          */
28662         "refresh" : true,
28663         /**
28664          * @event click
28665          * Fire after click the image
28666          * @param {Roo.bootstrap.DocumentManager} this
28667          * @param {Object} file
28668          */
28669         "click" : true,
28670         /**
28671          * @event edit
28672          * Fire when upload a image and editable set to true
28673          * @param {Roo.bootstrap.DocumentManager} this
28674          * @param {Object} file
28675          */
28676         "edit" : true,
28677         /**
28678          * @event beforeselectfile
28679          * Fire before select file
28680          * @param {Roo.bootstrap.DocumentManager} this
28681          */
28682         "beforeselectfile" : true,
28683         /**
28684          * @event process
28685          * Fire before process file
28686          * @param {Roo.bootstrap.DocumentManager} this
28687          * @param {Object} file
28688          */
28689         "process" : true,
28690         /**
28691          * @event previewrendered
28692          * Fire when preview rendered
28693          * @param {Roo.bootstrap.DocumentManager} this
28694          * @param {Object} file
28695          */
28696         "previewrendered" : true
28697         
28698     });
28699 };
28700
28701 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
28702     
28703     boxes : 0,
28704     inputName : '',
28705     thumbSize : 300,
28706     multiple : true,
28707     files : false,
28708     method : 'POST',
28709     url : '',
28710     paramName : 'imageUpload',
28711     toolTipName : 'filename',
28712     fieldLabel : '',
28713     labelWidth : 4,
28714     labelAlign : 'left',
28715     editable : true,
28716     delegates : false,
28717     xhr : false, 
28718     
28719     labellg : 0,
28720     labelmd : 0,
28721     labelsm : 0,
28722     labelxs : 0,
28723     
28724     getAutoCreate : function()
28725     {   
28726         var managerWidget = {
28727             tag : 'div',
28728             cls : 'roo-document-manager',
28729             cn : [
28730                 {
28731                     tag : 'input',
28732                     cls : 'roo-document-manager-selector',
28733                     type : 'file'
28734                 },
28735                 {
28736                     tag : 'div',
28737                     cls : 'roo-document-manager-uploader',
28738                     cn : [
28739                         {
28740                             tag : 'div',
28741                             cls : 'roo-document-manager-upload-btn',
28742                             html : '<i class="fa fa-plus"></i>'
28743                         }
28744                     ]
28745                     
28746                 }
28747             ]
28748         };
28749         
28750         var content = [
28751             {
28752                 tag : 'div',
28753                 cls : 'column col-md-12',
28754                 cn : managerWidget
28755             }
28756         ];
28757         
28758         if(this.fieldLabel.length){
28759             
28760             content = [
28761                 {
28762                     tag : 'div',
28763                     cls : 'column col-md-12',
28764                     html : this.fieldLabel
28765                 },
28766                 {
28767                     tag : 'div',
28768                     cls : 'column col-md-12',
28769                     cn : managerWidget
28770                 }
28771             ];
28772
28773             if(this.labelAlign == 'left'){
28774                 content = [
28775                     {
28776                         tag : 'div',
28777                         cls : 'column',
28778                         html : this.fieldLabel
28779                     },
28780                     {
28781                         tag : 'div',
28782                         cls : 'column',
28783                         cn : managerWidget
28784                     }
28785                 ];
28786                 
28787                 if(this.labelWidth > 12){
28788                     content[0].style = "width: " + this.labelWidth + 'px';
28789                 }
28790
28791                 if(this.labelWidth < 13 && this.labelmd == 0){
28792                     this.labelmd = this.labelWidth;
28793                 }
28794
28795                 if(this.labellg > 0){
28796                     content[0].cls += ' col-lg-' + this.labellg;
28797                     content[1].cls += ' col-lg-' + (12 - this.labellg);
28798                 }
28799
28800                 if(this.labelmd > 0){
28801                     content[0].cls += ' col-md-' + this.labelmd;
28802                     content[1].cls += ' col-md-' + (12 - this.labelmd);
28803                 }
28804
28805                 if(this.labelsm > 0){
28806                     content[0].cls += ' col-sm-' + this.labelsm;
28807                     content[1].cls += ' col-sm-' + (12 - this.labelsm);
28808                 }
28809
28810                 if(this.labelxs > 0){
28811                     content[0].cls += ' col-xs-' + this.labelxs;
28812                     content[1].cls += ' col-xs-' + (12 - this.labelxs);
28813                 }
28814                 
28815             }
28816         }
28817         
28818         var cfg = {
28819             tag : 'div',
28820             cls : 'row clearfix',
28821             cn : content
28822         };
28823         
28824         return cfg;
28825         
28826     },
28827     
28828     initEvents : function()
28829     {
28830         this.managerEl = this.el.select('.roo-document-manager', true).first();
28831         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28832         
28833         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28834         this.selectorEl.hide();
28835         
28836         if(this.multiple){
28837             this.selectorEl.attr('multiple', 'multiple');
28838         }
28839         
28840         this.selectorEl.on('change', this.onFileSelected, this);
28841         
28842         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28843         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28844         
28845         this.uploader.on('click', this.onUploaderClick, this);
28846         
28847         this.renderProgressDialog();
28848         
28849         var _this = this;
28850         
28851         window.addEventListener("resize", function() { _this.refresh(); } );
28852         
28853         this.fireEvent('initial', this);
28854     },
28855     
28856     renderProgressDialog : function()
28857     {
28858         var _this = this;
28859         
28860         this.progressDialog = new Roo.bootstrap.Modal({
28861             cls : 'roo-document-manager-progress-dialog',
28862             allow_close : false,
28863             title : '',
28864             buttons : [
28865                 {
28866                     name  :'cancel',
28867                     weight : 'danger',
28868                     html : 'Cancel'
28869                 }
28870             ], 
28871             listeners : { 
28872                 btnclick : function() {
28873                     _this.uploadCancel();
28874                     this.hide();
28875                 }
28876             }
28877         });
28878          
28879         this.progressDialog.render(Roo.get(document.body));
28880          
28881         this.progress = new Roo.bootstrap.Progress({
28882             cls : 'roo-document-manager-progress',
28883             active : true,
28884             striped : true
28885         });
28886         
28887         this.progress.render(this.progressDialog.getChildContainer());
28888         
28889         this.progressBar = new Roo.bootstrap.ProgressBar({
28890             cls : 'roo-document-manager-progress-bar',
28891             aria_valuenow : 0,
28892             aria_valuemin : 0,
28893             aria_valuemax : 12,
28894             panel : 'success'
28895         });
28896         
28897         this.progressBar.render(this.progress.getChildContainer());
28898     },
28899     
28900     onUploaderClick : function(e)
28901     {
28902         e.preventDefault();
28903      
28904         if(this.fireEvent('beforeselectfile', this) != false){
28905             this.selectorEl.dom.click();
28906         }
28907         
28908     },
28909     
28910     onFileSelected : function(e)
28911     {
28912         e.preventDefault();
28913         
28914         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28915             return;
28916         }
28917         
28918         Roo.each(this.selectorEl.dom.files, function(file){
28919             if(this.fireEvent('inspect', this, file) != false){
28920                 this.files.push(file);
28921             }
28922         }, this);
28923         
28924         this.queue();
28925         
28926     },
28927     
28928     queue : function()
28929     {
28930         this.selectorEl.dom.value = '';
28931         
28932         if(!this.files || !this.files.length){
28933             return;
28934         }
28935         
28936         if(this.boxes > 0 && this.files.length > this.boxes){
28937             this.files = this.files.slice(0, this.boxes);
28938         }
28939         
28940         this.uploader.show();
28941         
28942         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28943             this.uploader.hide();
28944         }
28945         
28946         var _this = this;
28947         
28948         var files = [];
28949         
28950         var docs = [];
28951         
28952         Roo.each(this.files, function(file){
28953             
28954             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28955                 var f = this.renderPreview(file);
28956                 files.push(f);
28957                 return;
28958             }
28959             
28960             if(file.type.indexOf('image') != -1){
28961                 this.delegates.push(
28962                     (function(){
28963                         _this.process(file);
28964                     }).createDelegate(this)
28965                 );
28966         
28967                 return;
28968             }
28969             
28970             docs.push(
28971                 (function(){
28972                     _this.process(file);
28973                 }).createDelegate(this)
28974             );
28975             
28976         }, this);
28977         
28978         this.files = files;
28979         
28980         this.delegates = this.delegates.concat(docs);
28981         
28982         if(!this.delegates.length){
28983             this.refresh();
28984             return;
28985         }
28986         
28987         this.progressBar.aria_valuemax = this.delegates.length;
28988         
28989         this.arrange();
28990         
28991         return;
28992     },
28993     
28994     arrange : function()
28995     {
28996         if(!this.delegates.length){
28997             this.progressDialog.hide();
28998             this.refresh();
28999             return;
29000         }
29001         
29002         var delegate = this.delegates.shift();
29003         
29004         this.progressDialog.show();
29005         
29006         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29007         
29008         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29009         
29010         delegate();
29011     },
29012     
29013     refresh : function()
29014     {
29015         this.uploader.show();
29016         
29017         if(this.boxes > 0 && this.files.length > this.boxes - 1){
29018             this.uploader.hide();
29019         }
29020         
29021         Roo.isTouch ? this.closable(false) : this.closable(true);
29022         
29023         this.fireEvent('refresh', this);
29024     },
29025     
29026     onRemove : function(e, el, o)
29027     {
29028         e.preventDefault();
29029         
29030         this.fireEvent('remove', this, o);
29031         
29032     },
29033     
29034     remove : function(o)
29035     {
29036         var files = [];
29037         
29038         Roo.each(this.files, function(file){
29039             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29040                 files.push(file);
29041                 return;
29042             }
29043
29044             o.target.remove();
29045
29046         }, this);
29047         
29048         this.files = files;
29049         
29050         this.refresh();
29051     },
29052     
29053     clear : function()
29054     {
29055         Roo.each(this.files, function(file){
29056             if(!file.target){
29057                 return;
29058             }
29059             
29060             file.target.remove();
29061
29062         }, this);
29063         
29064         this.files = [];
29065         
29066         this.refresh();
29067     },
29068     
29069     onClick : function(e, el, o)
29070     {
29071         e.preventDefault();
29072         
29073         this.fireEvent('click', this, o);
29074         
29075     },
29076     
29077     closable : function(closable)
29078     {
29079         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29080             
29081             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29082             
29083             if(closable){
29084                 el.show();
29085                 return;
29086             }
29087             
29088             el.hide();
29089             
29090         }, this);
29091     },
29092     
29093     xhrOnLoad : function(xhr)
29094     {
29095         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29096             el.remove();
29097         }, this);
29098         
29099         if (xhr.readyState !== 4) {
29100             this.arrange();
29101             this.fireEvent('exception', this, xhr);
29102             return;
29103         }
29104
29105         var response = Roo.decode(xhr.responseText);
29106         
29107         if(!response.success){
29108             this.arrange();
29109             this.fireEvent('exception', this, xhr);
29110             return;
29111         }
29112         
29113         var file = this.renderPreview(response.data);
29114         
29115         this.files.push(file);
29116         
29117         this.arrange();
29118         
29119         this.fireEvent('afterupload', this, xhr);
29120         
29121     },
29122     
29123     xhrOnError : function(xhr)
29124     {
29125         Roo.log('xhr on error');
29126         
29127         var response = Roo.decode(xhr.responseText);
29128           
29129         Roo.log(response);
29130         
29131         this.arrange();
29132     },
29133     
29134     process : function(file)
29135     {
29136         if(this.fireEvent('process', this, file) !== false){
29137             if(this.editable && file.type.indexOf('image') != -1){
29138                 this.fireEvent('edit', this, file);
29139                 return;
29140             }
29141
29142             this.uploadStart(file, false);
29143
29144             return;
29145         }
29146         
29147     },
29148     
29149     uploadStart : function(file, crop)
29150     {
29151         this.xhr = new XMLHttpRequest();
29152         
29153         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29154             this.arrange();
29155             return;
29156         }
29157         
29158         file.xhr = this.xhr;
29159             
29160         this.managerEl.createChild({
29161             tag : 'div',
29162             cls : 'roo-document-manager-loading',
29163             cn : [
29164                 {
29165                     tag : 'div',
29166                     tooltip : file.name,
29167                     cls : 'roo-document-manager-thumb',
29168                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29169                 }
29170             ]
29171
29172         });
29173
29174         this.xhr.open(this.method, this.url, true);
29175         
29176         var headers = {
29177             "Accept": "application/json",
29178             "Cache-Control": "no-cache",
29179             "X-Requested-With": "XMLHttpRequest"
29180         };
29181         
29182         for (var headerName in headers) {
29183             var headerValue = headers[headerName];
29184             if (headerValue) {
29185                 this.xhr.setRequestHeader(headerName, headerValue);
29186             }
29187         }
29188         
29189         var _this = this;
29190         
29191         this.xhr.onload = function()
29192         {
29193             _this.xhrOnLoad(_this.xhr);
29194         }
29195         
29196         this.xhr.onerror = function()
29197         {
29198             _this.xhrOnError(_this.xhr);
29199         }
29200         
29201         var formData = new FormData();
29202
29203         formData.append('returnHTML', 'NO');
29204         
29205         if(crop){
29206             formData.append('crop', crop);
29207         }
29208         
29209         formData.append(this.paramName, file, file.name);
29210         
29211         var options = {
29212             file : file, 
29213             manually : false
29214         };
29215         
29216         if(this.fireEvent('prepare', this, formData, options) != false){
29217             
29218             if(options.manually){
29219                 return;
29220             }
29221             
29222             this.xhr.send(formData);
29223             return;
29224         };
29225         
29226         this.uploadCancel();
29227     },
29228     
29229     uploadCancel : function()
29230     {
29231         if (this.xhr) {
29232             this.xhr.abort();
29233         }
29234         
29235         this.delegates = [];
29236         
29237         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29238             el.remove();
29239         }, this);
29240         
29241         this.arrange();
29242     },
29243     
29244     renderPreview : function(file)
29245     {
29246         if(typeof(file.target) != 'undefined' && file.target){
29247             return file;
29248         }
29249         
29250         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29251         
29252         var previewEl = this.managerEl.createChild({
29253             tag : 'div',
29254             cls : 'roo-document-manager-preview',
29255             cn : [
29256                 {
29257                     tag : 'div',
29258                     tooltip : file[this.toolTipName],
29259                     cls : 'roo-document-manager-thumb',
29260                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29261                 },
29262                 {
29263                     tag : 'button',
29264                     cls : 'close',
29265                     html : '<i class="fa fa-times-circle"></i>'
29266                 }
29267             ]
29268         });
29269
29270         var close = previewEl.select('button.close', true).first();
29271
29272         close.on('click', this.onRemove, this, file);
29273
29274         file.target = previewEl;
29275
29276         var image = previewEl.select('img', true).first();
29277         
29278         var _this = this;
29279         
29280         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29281         
29282         image.on('click', this.onClick, this, file);
29283         
29284         this.fireEvent('previewrendered', this, file);
29285         
29286         return file;
29287         
29288     },
29289     
29290     onPreviewLoad : function(file, image)
29291     {
29292         if(typeof(file.target) == 'undefined' || !file.target){
29293             return;
29294         }
29295         
29296         var width = image.dom.naturalWidth || image.dom.width;
29297         var height = image.dom.naturalHeight || image.dom.height;
29298         
29299         if(width > height){
29300             file.target.addClass('wide');
29301             return;
29302         }
29303         
29304         file.target.addClass('tall');
29305         return;
29306         
29307     },
29308     
29309     uploadFromSource : function(file, crop)
29310     {
29311         this.xhr = new XMLHttpRequest();
29312         
29313         this.managerEl.createChild({
29314             tag : 'div',
29315             cls : 'roo-document-manager-loading',
29316             cn : [
29317                 {
29318                     tag : 'div',
29319                     tooltip : file.name,
29320                     cls : 'roo-document-manager-thumb',
29321                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29322                 }
29323             ]
29324
29325         });
29326
29327         this.xhr.open(this.method, this.url, true);
29328         
29329         var headers = {
29330             "Accept": "application/json",
29331             "Cache-Control": "no-cache",
29332             "X-Requested-With": "XMLHttpRequest"
29333         };
29334         
29335         for (var headerName in headers) {
29336             var headerValue = headers[headerName];
29337             if (headerValue) {
29338                 this.xhr.setRequestHeader(headerName, headerValue);
29339             }
29340         }
29341         
29342         var _this = this;
29343         
29344         this.xhr.onload = function()
29345         {
29346             _this.xhrOnLoad(_this.xhr);
29347         }
29348         
29349         this.xhr.onerror = function()
29350         {
29351             _this.xhrOnError(_this.xhr);
29352         }
29353         
29354         var formData = new FormData();
29355
29356         formData.append('returnHTML', 'NO');
29357         
29358         formData.append('crop', crop);
29359         
29360         if(typeof(file.filename) != 'undefined'){
29361             formData.append('filename', file.filename);
29362         }
29363         
29364         if(typeof(file.mimetype) != 'undefined'){
29365             formData.append('mimetype', file.mimetype);
29366         }
29367         
29368         Roo.log(formData);
29369         
29370         if(this.fireEvent('prepare', this, formData) != false){
29371             this.xhr.send(formData);
29372         };
29373     }
29374 });
29375
29376 /*
29377 * Licence: LGPL
29378 */
29379
29380 /**
29381  * @class Roo.bootstrap.DocumentViewer
29382  * @extends Roo.bootstrap.Component
29383  * Bootstrap DocumentViewer class
29384  * @cfg {Boolean} showDownload (true|false) show download button (default true)
29385  * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29386  * 
29387  * @constructor
29388  * Create a new DocumentViewer
29389  * @param {Object} config The config object
29390  */
29391
29392 Roo.bootstrap.DocumentViewer = function(config){
29393     Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29394     
29395     this.addEvents({
29396         /**
29397          * @event initial
29398          * Fire after initEvent
29399          * @param {Roo.bootstrap.DocumentViewer} this
29400          */
29401         "initial" : true,
29402         /**
29403          * @event click
29404          * Fire after click
29405          * @param {Roo.bootstrap.DocumentViewer} this
29406          */
29407         "click" : true,
29408         /**
29409          * @event download
29410          * Fire after download button
29411          * @param {Roo.bootstrap.DocumentViewer} this
29412          */
29413         "download" : true,
29414         /**
29415          * @event trash
29416          * Fire after trash button
29417          * @param {Roo.bootstrap.DocumentViewer} this
29418          */
29419         "trash" : true
29420         
29421     });
29422 };
29423
29424 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
29425     
29426     showDownload : true,
29427     
29428     showTrash : true,
29429     
29430     getAutoCreate : function()
29431     {
29432         var cfg = {
29433             tag : 'div',
29434             cls : 'roo-document-viewer',
29435             cn : [
29436                 {
29437                     tag : 'div',
29438                     cls : 'roo-document-viewer-body',
29439                     cn : [
29440                         {
29441                             tag : 'div',
29442                             cls : 'roo-document-viewer-thumb',
29443                             cn : [
29444                                 {
29445                                     tag : 'img',
29446                                     cls : 'roo-document-viewer-image'
29447                                 }
29448                             ]
29449                         }
29450                     ]
29451                 },
29452                 {
29453                     tag : 'div',
29454                     cls : 'roo-document-viewer-footer',
29455                     cn : {
29456                         tag : 'div',
29457                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29458                         cn : [
29459                             {
29460                                 tag : 'div',
29461                                 cls : 'btn-group roo-document-viewer-download',
29462                                 cn : [
29463                                     {
29464                                         tag : 'button',
29465                                         cls : 'btn btn-default',
29466                                         html : '<i class="fa fa-download"></i>'
29467                                     }
29468                                 ]
29469                             },
29470                             {
29471                                 tag : 'div',
29472                                 cls : 'btn-group roo-document-viewer-trash',
29473                                 cn : [
29474                                     {
29475                                         tag : 'button',
29476                                         cls : 'btn btn-default',
29477                                         html : '<i class="fa fa-trash"></i>'
29478                                     }
29479                                 ]
29480                             }
29481                         ]
29482                     }
29483                 }
29484             ]
29485         };
29486         
29487         return cfg;
29488     },
29489     
29490     initEvents : function()
29491     {
29492         this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29493         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29494         
29495         this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29496         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29497         
29498         this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29499         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29500         
29501         this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29502         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29503         
29504         this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29505         this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29506         
29507         this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29508         this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29509         
29510         this.bodyEl.on('click', this.onClick, this);
29511         this.downloadBtn.on('click', this.onDownload, this);
29512         this.trashBtn.on('click', this.onTrash, this);
29513         
29514         this.downloadBtn.hide();
29515         this.trashBtn.hide();
29516         
29517         if(this.showDownload){
29518             this.downloadBtn.show();
29519         }
29520         
29521         if(this.showTrash){
29522             this.trashBtn.show();
29523         }
29524         
29525         if(!this.showDownload && !this.showTrash) {
29526             this.footerEl.hide();
29527         }
29528         
29529     },
29530     
29531     initial : function()
29532     {
29533         this.fireEvent('initial', this);
29534         
29535     },
29536     
29537     onClick : function(e)
29538     {
29539         e.preventDefault();
29540         
29541         this.fireEvent('click', this);
29542     },
29543     
29544     onDownload : function(e)
29545     {
29546         e.preventDefault();
29547         
29548         this.fireEvent('download', this);
29549     },
29550     
29551     onTrash : function(e)
29552     {
29553         e.preventDefault();
29554         
29555         this.fireEvent('trash', this);
29556     }
29557     
29558 });
29559 /*
29560  * - LGPL
29561  *
29562  * nav progress bar
29563  * 
29564  */
29565
29566 /**
29567  * @class Roo.bootstrap.NavProgressBar
29568  * @extends Roo.bootstrap.Component
29569  * Bootstrap NavProgressBar class
29570  * 
29571  * @constructor
29572  * Create a new nav progress bar
29573  * @param {Object} config The config object
29574  */
29575
29576 Roo.bootstrap.NavProgressBar = function(config){
29577     Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29578
29579     this.bullets = this.bullets || [];
29580    
29581 //    Roo.bootstrap.NavProgressBar.register(this);
29582      this.addEvents({
29583         /**
29584              * @event changed
29585              * Fires when the active item changes
29586              * @param {Roo.bootstrap.NavProgressBar} this
29587              * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29588              * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
29589          */
29590         'changed': true
29591      });
29592     
29593 };
29594
29595 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
29596     
29597     bullets : [],
29598     barItems : [],
29599     
29600     getAutoCreate : function()
29601     {
29602         var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29603         
29604         cfg = {
29605             tag : 'div',
29606             cls : 'roo-navigation-bar-group',
29607             cn : [
29608                 {
29609                     tag : 'div',
29610                     cls : 'roo-navigation-top-bar'
29611                 },
29612                 {
29613                     tag : 'div',
29614                     cls : 'roo-navigation-bullets-bar',
29615                     cn : [
29616                         {
29617                             tag : 'ul',
29618                             cls : 'roo-navigation-bar'
29619                         }
29620                     ]
29621                 },
29622                 
29623                 {
29624                     tag : 'div',
29625                     cls : 'roo-navigation-bottom-bar'
29626                 }
29627             ]
29628             
29629         };
29630         
29631         return cfg;
29632         
29633     },
29634     
29635     initEvents: function() 
29636     {
29637         
29638     },
29639     
29640     onRender : function(ct, position) 
29641     {
29642         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29643         
29644         if(this.bullets.length){
29645             Roo.each(this.bullets, function(b){
29646                this.addItem(b);
29647             }, this);
29648         }
29649         
29650         this.format();
29651         
29652     },
29653     
29654     addItem : function(cfg)
29655     {
29656         var item = new Roo.bootstrap.NavProgressItem(cfg);
29657         
29658         item.parentId = this.id;
29659         item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29660         
29661         if(cfg.html){
29662             var top = new Roo.bootstrap.Element({
29663                 tag : 'div',
29664                 cls : 'roo-navigation-bar-text'
29665             });
29666             
29667             var bottom = new Roo.bootstrap.Element({
29668                 tag : 'div',
29669                 cls : 'roo-navigation-bar-text'
29670             });
29671             
29672             top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29673             bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29674             
29675             var topText = new Roo.bootstrap.Element({
29676                 tag : 'span',
29677                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29678             });
29679             
29680             var bottomText = new Roo.bootstrap.Element({
29681                 tag : 'span',
29682                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29683             });
29684             
29685             topText.onRender(top.el, null);
29686             bottomText.onRender(bottom.el, null);
29687             
29688             item.topEl = top;
29689             item.bottomEl = bottom;
29690         }
29691         
29692         this.barItems.push(item);
29693         
29694         return item;
29695     },
29696     
29697     getActive : function()
29698     {
29699         var active = false;
29700         
29701         Roo.each(this.barItems, function(v){
29702             
29703             if (!v.isActive()) {
29704                 return;
29705             }
29706             
29707             active = v;
29708             return false;
29709             
29710         });
29711         
29712         return active;
29713     },
29714     
29715     setActiveItem : function(item)
29716     {
29717         var prev = false;
29718         
29719         Roo.each(this.barItems, function(v){
29720             if (v.rid == item.rid) {
29721                 return ;
29722             }
29723             
29724             if (v.isActive()) {
29725                 v.setActive(false);
29726                 prev = v;
29727             }
29728         });
29729
29730         item.setActive(true);
29731         
29732         this.fireEvent('changed', this, item, prev);
29733     },
29734     
29735     getBarItem: function(rid)
29736     {
29737         var ret = false;
29738         
29739         Roo.each(this.barItems, function(e) {
29740             if (e.rid != rid) {
29741                 return;
29742             }
29743             
29744             ret =  e;
29745             return false;
29746         });
29747         
29748         return ret;
29749     },
29750     
29751     indexOfItem : function(item)
29752     {
29753         var index = false;
29754         
29755         Roo.each(this.barItems, function(v, i){
29756             
29757             if (v.rid != item.rid) {
29758                 return;
29759             }
29760             
29761             index = i;
29762             return false
29763         });
29764         
29765         return index;
29766     },
29767     
29768     setActiveNext : function()
29769     {
29770         var i = this.indexOfItem(this.getActive());
29771         
29772         if (i > this.barItems.length) {
29773             return;
29774         }
29775         
29776         this.setActiveItem(this.barItems[i+1]);
29777     },
29778     
29779     setActivePrev : function()
29780     {
29781         var i = this.indexOfItem(this.getActive());
29782         
29783         if (i  < 1) {
29784             return;
29785         }
29786         
29787         this.setActiveItem(this.barItems[i-1]);
29788     },
29789     
29790     format : function()
29791     {
29792         if(!this.barItems.length){
29793             return;
29794         }
29795      
29796         var width = 100 / this.barItems.length;
29797         
29798         Roo.each(this.barItems, function(i){
29799             i.el.setStyle('width', width + '%');
29800             i.topEl.el.setStyle('width', width + '%');
29801             i.bottomEl.el.setStyle('width', width + '%');
29802         }, this);
29803         
29804     }
29805     
29806 });
29807 /*
29808  * - LGPL
29809  *
29810  * Nav Progress Item
29811  * 
29812  */
29813
29814 /**
29815  * @class Roo.bootstrap.NavProgressItem
29816  * @extends Roo.bootstrap.Component
29817  * Bootstrap NavProgressItem class
29818  * @cfg {String} rid the reference id
29819  * @cfg {Boolean} active (true|false) Is item active default false
29820  * @cfg {Boolean} disabled (true|false) Is item active default false
29821  * @cfg {String} html
29822  * @cfg {String} position (top|bottom) text position default bottom
29823  * @cfg {String} icon show icon instead of number
29824  * 
29825  * @constructor
29826  * Create a new NavProgressItem
29827  * @param {Object} config The config object
29828  */
29829 Roo.bootstrap.NavProgressItem = function(config){
29830     Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29831     this.addEvents({
29832         // raw events
29833         /**
29834          * @event click
29835          * The raw click event for the entire grid.
29836          * @param {Roo.bootstrap.NavProgressItem} this
29837          * @param {Roo.EventObject} e
29838          */
29839         "click" : true
29840     });
29841    
29842 };
29843
29844 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
29845     
29846     rid : '',
29847     active : false,
29848     disabled : false,
29849     html : '',
29850     position : 'bottom',
29851     icon : false,
29852     
29853     getAutoCreate : function()
29854     {
29855         var iconCls = 'roo-navigation-bar-item-icon';
29856         
29857         iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29858         
29859         var cfg = {
29860             tag: 'li',
29861             cls: 'roo-navigation-bar-item',
29862             cn : [
29863                 {
29864                     tag : 'i',
29865                     cls : iconCls
29866                 }
29867             ]
29868         };
29869         
29870         if(this.active){
29871             cfg.cls += ' active';
29872         }
29873         if(this.disabled){
29874             cfg.cls += ' disabled';
29875         }
29876         
29877         return cfg;
29878     },
29879     
29880     disable : function()
29881     {
29882         this.setDisabled(true);
29883     },
29884     
29885     enable : function()
29886     {
29887         this.setDisabled(false);
29888     },
29889     
29890     initEvents: function() 
29891     {
29892         this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29893         
29894         this.iconEl.on('click', this.onClick, this);
29895     },
29896     
29897     onClick : function(e)
29898     {
29899         e.preventDefault();
29900         
29901         if(this.disabled){
29902             return;
29903         }
29904         
29905         if(this.fireEvent('click', this, e) === false){
29906             return;
29907         };
29908         
29909         this.parent().setActiveItem(this);
29910     },
29911     
29912     isActive: function () 
29913     {
29914         return this.active;
29915     },
29916     
29917     setActive : function(state)
29918     {
29919         if(this.active == state){
29920             return;
29921         }
29922         
29923         this.active = state;
29924         
29925         if (state) {
29926             this.el.addClass('active');
29927             return;
29928         }
29929         
29930         this.el.removeClass('active');
29931         
29932         return;
29933     },
29934     
29935     setDisabled : function(state)
29936     {
29937         if(this.disabled == state){
29938             return;
29939         }
29940         
29941         this.disabled = state;
29942         
29943         if (state) {
29944             this.el.addClass('disabled');
29945             return;
29946         }
29947         
29948         this.el.removeClass('disabled');
29949     },
29950     
29951     tooltipEl : function()
29952     {
29953         return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29954     }
29955 });
29956  
29957
29958  /*
29959  * - LGPL
29960  *
29961  * FieldLabel
29962  * 
29963  */
29964
29965 /**
29966  * @class Roo.bootstrap.FieldLabel
29967  * @extends Roo.bootstrap.Component
29968  * Bootstrap FieldLabel class
29969  * @cfg {String} html contents of the element
29970  * @cfg {String} tag tag of the element default label
29971  * @cfg {String} cls class of the element
29972  * @cfg {String} target label target 
29973  * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29974  * @cfg {String} invalidClass default "text-warning"
29975  * @cfg {String} validClass default "text-success"
29976  * @cfg {String} iconTooltip default "This field is required"
29977  * @cfg {String} indicatorpos (left|right) default left
29978  * 
29979  * @constructor
29980  * Create a new FieldLabel
29981  * @param {Object} config The config object
29982  */
29983
29984 Roo.bootstrap.FieldLabel = function(config){
29985     Roo.bootstrap.Element.superclass.constructor.call(this, config);
29986     
29987     this.addEvents({
29988             /**
29989              * @event invalid
29990              * Fires after the field has been marked as invalid.
29991              * @param {Roo.form.FieldLabel} this
29992              * @param {String} msg The validation message
29993              */
29994             invalid : true,
29995             /**
29996              * @event valid
29997              * Fires after the field has been validated with no errors.
29998              * @param {Roo.form.FieldLabel} this
29999              */
30000             valid : true
30001         });
30002 };
30003
30004 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
30005     
30006     tag: 'label',
30007     cls: '',
30008     html: '',
30009     target: '',
30010     allowBlank : true,
30011     invalidClass : 'has-warning',
30012     validClass : 'has-success',
30013     iconTooltip : 'This field is required',
30014     indicatorpos : 'left',
30015     
30016     getAutoCreate : function(){
30017         
30018         var cfg = {
30019             tag : this.tag,
30020             cls : 'roo-bootstrap-field-label ' + this.cls,
30021             for : this.target,
30022             cn : [
30023                 {
30024                     tag : 'i',
30025                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
30026                     tooltip : this.iconTooltip
30027                 },
30028                 {
30029                     tag : 'span',
30030                     html : this.html
30031                 }
30032             ] 
30033         };
30034         
30035         if(this.indicatorpos == 'right'){
30036             var cfg = {
30037                 tag : this.tag,
30038                 cls : 'roo-bootstrap-field-label ' + this.cls,
30039                 for : this.target,
30040                 cn : [
30041                     {
30042                         tag : 'span',
30043                         html : this.html
30044                     },
30045                     {
30046                         tag : 'i',
30047                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30048                         tooltip : this.iconTooltip
30049                     }
30050                 ] 
30051             };
30052         }
30053         
30054         return cfg;
30055     },
30056     
30057     initEvents: function() 
30058     {
30059         Roo.bootstrap.Element.superclass.initEvents.call(this);
30060         
30061         this.indicator = this.indicatorEl();
30062         
30063         if(this.indicator){
30064             this.indicator.removeClass('visible');
30065             this.indicator.addClass('invisible');
30066         }
30067         
30068         Roo.bootstrap.FieldLabel.register(this);
30069     },
30070     
30071     indicatorEl : function()
30072     {
30073         var indicator = this.el.select('i.roo-required-indicator',true).first();
30074         
30075         if(!indicator){
30076             return false;
30077         }
30078         
30079         return indicator;
30080         
30081     },
30082     
30083     /**
30084      * Mark this field as valid
30085      */
30086     markValid : function()
30087     {
30088         if(this.indicator){
30089             this.indicator.removeClass('visible');
30090             this.indicator.addClass('invisible');
30091         }
30092         
30093         this.el.removeClass(this.invalidClass);
30094         
30095         this.el.addClass(this.validClass);
30096         
30097         this.fireEvent('valid', this);
30098     },
30099     
30100     /**
30101      * Mark this field as invalid
30102      * @param {String} msg The validation message
30103      */
30104     markInvalid : function(msg)
30105     {
30106         if(this.indicator){
30107             this.indicator.removeClass('invisible');
30108             this.indicator.addClass('visible');
30109         }
30110         
30111         this.el.removeClass(this.validClass);
30112         
30113         this.el.addClass(this.invalidClass);
30114         
30115         this.fireEvent('invalid', this, msg);
30116     }
30117     
30118    
30119 });
30120
30121 Roo.apply(Roo.bootstrap.FieldLabel, {
30122     
30123     groups: {},
30124     
30125      /**
30126     * register a FieldLabel Group
30127     * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30128     */
30129     register : function(label)
30130     {
30131         if(this.groups.hasOwnProperty(label.target)){
30132             return;
30133         }
30134      
30135         this.groups[label.target] = label;
30136         
30137     },
30138     /**
30139     * fetch a FieldLabel Group based on the target
30140     * @param {string} target
30141     * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30142     */
30143     get: function(target) {
30144         if (typeof(this.groups[target]) == 'undefined') {
30145             return false;
30146         }
30147         
30148         return this.groups[target] ;
30149     }
30150 });
30151
30152  
30153
30154  /*
30155  * - LGPL
30156  *
30157  * page DateSplitField.
30158  * 
30159  */
30160
30161
30162 /**
30163  * @class Roo.bootstrap.DateSplitField
30164  * @extends Roo.bootstrap.Component
30165  * Bootstrap DateSplitField class
30166  * @cfg {string} fieldLabel - the label associated
30167  * @cfg {Number} labelWidth set the width of label (0-12)
30168  * @cfg {String} labelAlign (top|left)
30169  * @cfg {Boolean} dayAllowBlank (true|false) default false
30170  * @cfg {Boolean} monthAllowBlank (true|false) default false
30171  * @cfg {Boolean} yearAllowBlank (true|false) default false
30172  * @cfg {string} dayPlaceholder 
30173  * @cfg {string} monthPlaceholder
30174  * @cfg {string} yearPlaceholder
30175  * @cfg {string} dayFormat default 'd'
30176  * @cfg {string} monthFormat default 'm'
30177  * @cfg {string} yearFormat default 'Y'
30178  * @cfg {Number} labellg set the width of label (1-12)
30179  * @cfg {Number} labelmd set the width of label (1-12)
30180  * @cfg {Number} labelsm set the width of label (1-12)
30181  * @cfg {Number} labelxs set the width of label (1-12)
30182
30183  *     
30184  * @constructor
30185  * Create a new DateSplitField
30186  * @param {Object} config The config object
30187  */
30188
30189 Roo.bootstrap.DateSplitField = function(config){
30190     Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30191     
30192     this.addEvents({
30193         // raw events
30194          /**
30195          * @event years
30196          * getting the data of years
30197          * @param {Roo.bootstrap.DateSplitField} this
30198          * @param {Object} years
30199          */
30200         "years" : true,
30201         /**
30202          * @event days
30203          * getting the data of days
30204          * @param {Roo.bootstrap.DateSplitField} this
30205          * @param {Object} days
30206          */
30207         "days" : true,
30208         /**
30209          * @event invalid
30210          * Fires after the field has been marked as invalid.
30211          * @param {Roo.form.Field} this
30212          * @param {String} msg The validation message
30213          */
30214         invalid : true,
30215        /**
30216          * @event valid
30217          * Fires after the field has been validated with no errors.
30218          * @param {Roo.form.Field} this
30219          */
30220         valid : true
30221     });
30222 };
30223
30224 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
30225     
30226     fieldLabel : '',
30227     labelAlign : 'top',
30228     labelWidth : 3,
30229     dayAllowBlank : false,
30230     monthAllowBlank : false,
30231     yearAllowBlank : false,
30232     dayPlaceholder : '',
30233     monthPlaceholder : '',
30234     yearPlaceholder : '',
30235     dayFormat : 'd',
30236     monthFormat : 'm',
30237     yearFormat : 'Y',
30238     isFormField : true,
30239     labellg : 0,
30240     labelmd : 0,
30241     labelsm : 0,
30242     labelxs : 0,
30243     
30244     getAutoCreate : function()
30245     {
30246         var cfg = {
30247             tag : 'div',
30248             cls : 'row roo-date-split-field-group',
30249             cn : [
30250                 {
30251                     tag : 'input',
30252                     type : 'hidden',
30253                     cls : 'form-hidden-field roo-date-split-field-group-value',
30254                     name : this.name
30255                 }
30256             ]
30257         };
30258         
30259         var labelCls = 'col-md-12';
30260         var contentCls = 'col-md-4';
30261         
30262         if(this.fieldLabel){
30263             
30264             var label = {
30265                 tag : 'div',
30266                 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30267                 cn : [
30268                     {
30269                         tag : 'label',
30270                         html : this.fieldLabel
30271                     }
30272                 ]
30273             };
30274             
30275             if(this.labelAlign == 'left'){
30276             
30277                 if(this.labelWidth > 12){
30278                     label.style = "width: " + this.labelWidth + 'px';
30279                 }
30280
30281                 if(this.labelWidth < 13 && this.labelmd == 0){
30282                     this.labelmd = this.labelWidth;
30283                 }
30284
30285                 if(this.labellg > 0){
30286                     labelCls = ' col-lg-' + this.labellg;
30287                     contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30288                 }
30289
30290                 if(this.labelmd > 0){
30291                     labelCls = ' col-md-' + this.labelmd;
30292                     contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30293                 }
30294
30295                 if(this.labelsm > 0){
30296                     labelCls = ' col-sm-' + this.labelsm;
30297                     contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30298                 }
30299
30300                 if(this.labelxs > 0){
30301                     labelCls = ' col-xs-' + this.labelxs;
30302                     contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30303                 }
30304             }
30305             
30306             label.cls += ' ' + labelCls;
30307             
30308             cfg.cn.push(label);
30309         }
30310         
30311         Roo.each(['day', 'month', 'year'], function(t){
30312             cfg.cn.push({
30313                 tag : 'div',
30314                 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30315             });
30316         }, this);
30317         
30318         return cfg;
30319     },
30320     
30321     inputEl: function ()
30322     {
30323         return this.el.select('.roo-date-split-field-group-value', true).first();
30324     },
30325     
30326     onRender : function(ct, position) 
30327     {
30328         var _this = this;
30329         
30330         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30331         
30332         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30333         
30334         this.dayField = new Roo.bootstrap.ComboBox({
30335             allowBlank : this.dayAllowBlank,
30336             alwaysQuery : true,
30337             displayField : 'value',
30338             editable : false,
30339             fieldLabel : '',
30340             forceSelection : true,
30341             mode : 'local',
30342             placeholder : this.dayPlaceholder,
30343             selectOnFocus : true,
30344             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30345             triggerAction : 'all',
30346             typeAhead : true,
30347             valueField : 'value',
30348             store : new Roo.data.SimpleStore({
30349                 data : (function() {    
30350                     var days = [];
30351                     _this.fireEvent('days', _this, days);
30352                     return days;
30353                 })(),
30354                 fields : [ 'value' ]
30355             }),
30356             listeners : {
30357                 select : function (_self, record, index)
30358                 {
30359                     _this.setValue(_this.getValue());
30360                 }
30361             }
30362         });
30363
30364         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30365         
30366         this.monthField = new Roo.bootstrap.MonthField({
30367             after : '<i class=\"fa fa-calendar\"></i>',
30368             allowBlank : this.monthAllowBlank,
30369             placeholder : this.monthPlaceholder,
30370             readOnly : true,
30371             listeners : {
30372                 render : function (_self)
30373                 {
30374                     this.el.select('span.input-group-addon', true).first().on('click', function(e){
30375                         e.preventDefault();
30376                         _self.focus();
30377                     });
30378                 },
30379                 select : function (_self, oldvalue, newvalue)
30380                 {
30381                     _this.setValue(_this.getValue());
30382                 }
30383             }
30384         });
30385         
30386         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30387         
30388         this.yearField = new Roo.bootstrap.ComboBox({
30389             allowBlank : this.yearAllowBlank,
30390             alwaysQuery : true,
30391             displayField : 'value',
30392             editable : false,
30393             fieldLabel : '',
30394             forceSelection : true,
30395             mode : 'local',
30396             placeholder : this.yearPlaceholder,
30397             selectOnFocus : true,
30398             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30399             triggerAction : 'all',
30400             typeAhead : true,
30401             valueField : 'value',
30402             store : new Roo.data.SimpleStore({
30403                 data : (function() {
30404                     var years = [];
30405                     _this.fireEvent('years', _this, years);
30406                     return years;
30407                 })(),
30408                 fields : [ 'value' ]
30409             }),
30410             listeners : {
30411                 select : function (_self, record, index)
30412                 {
30413                     _this.setValue(_this.getValue());
30414                 }
30415             }
30416         });
30417
30418         this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30419     },
30420     
30421     setValue : function(v, format)
30422     {
30423         this.inputEl.dom.value = v;
30424         
30425         var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30426         
30427         var d = Date.parseDate(v, f);
30428         
30429         if(!d){
30430             this.validate();
30431             return;
30432         }
30433         
30434         this.setDay(d.format(this.dayFormat));
30435         this.setMonth(d.format(this.monthFormat));
30436         this.setYear(d.format(this.yearFormat));
30437         
30438         this.validate();
30439         
30440         return;
30441     },
30442     
30443     setDay : function(v)
30444     {
30445         this.dayField.setValue(v);
30446         this.inputEl.dom.value = this.getValue();
30447         this.validate();
30448         return;
30449     },
30450     
30451     setMonth : function(v)
30452     {
30453         this.monthField.setValue(v, true);
30454         this.inputEl.dom.value = this.getValue();
30455         this.validate();
30456         return;
30457     },
30458     
30459     setYear : function(v)
30460     {
30461         this.yearField.setValue(v);
30462         this.inputEl.dom.value = this.getValue();
30463         this.validate();
30464         return;
30465     },
30466     
30467     getDay : function()
30468     {
30469         return this.dayField.getValue();
30470     },
30471     
30472     getMonth : function()
30473     {
30474         return this.monthField.getValue();
30475     },
30476     
30477     getYear : function()
30478     {
30479         return this.yearField.getValue();
30480     },
30481     
30482     getValue : function()
30483     {
30484         var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30485         
30486         var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30487         
30488         return date;
30489     },
30490     
30491     reset : function()
30492     {
30493         this.setDay('');
30494         this.setMonth('');
30495         this.setYear('');
30496         this.inputEl.dom.value = '';
30497         this.validate();
30498         return;
30499     },
30500     
30501     validate : function()
30502     {
30503         var d = this.dayField.validate();
30504         var m = this.monthField.validate();
30505         var y = this.yearField.validate();
30506         
30507         var valid = true;
30508         
30509         if(
30510                 (!this.dayAllowBlank && !d) ||
30511                 (!this.monthAllowBlank && !m) ||
30512                 (!this.yearAllowBlank && !y)
30513         ){
30514             valid = false;
30515         }
30516         
30517         if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30518             return valid;
30519         }
30520         
30521         if(valid){
30522             this.markValid();
30523             return valid;
30524         }
30525         
30526         this.markInvalid();
30527         
30528         return valid;
30529     },
30530     
30531     markValid : function()
30532     {
30533         
30534         var label = this.el.select('label', true).first();
30535         var icon = this.el.select('i.fa-star', true).first();
30536
30537         if(label && icon){
30538             icon.remove();
30539         }
30540         
30541         this.fireEvent('valid', this);
30542     },
30543     
30544      /**
30545      * Mark this field as invalid
30546      * @param {String} msg The validation message
30547      */
30548     markInvalid : function(msg)
30549     {
30550         
30551         var label = this.el.select('label', true).first();
30552         var icon = this.el.select('i.fa-star', true).first();
30553
30554         if(label && !icon){
30555             this.el.select('.roo-date-split-field-label', true).createChild({
30556                 tag : 'i',
30557                 cls : 'text-danger fa fa-lg fa-star',
30558                 tooltip : 'This field is required',
30559                 style : 'margin-right:5px;'
30560             }, label, true);
30561         }
30562         
30563         this.fireEvent('invalid', this, msg);
30564     },
30565     
30566     clearInvalid : function()
30567     {
30568         var label = this.el.select('label', true).first();
30569         var icon = this.el.select('i.fa-star', true).first();
30570
30571         if(label && icon){
30572             icon.remove();
30573         }
30574         
30575         this.fireEvent('valid', this);
30576     },
30577     
30578     getName: function()
30579     {
30580         return this.name;
30581     }
30582     
30583 });
30584
30585  /**
30586  *
30587  * This is based on 
30588  * http://masonry.desandro.com
30589  *
30590  * The idea is to render all the bricks based on vertical width...
30591  *
30592  * The original code extends 'outlayer' - we might need to use that....
30593  * 
30594  */
30595
30596
30597 /**
30598  * @class Roo.bootstrap.LayoutMasonry
30599  * @extends Roo.bootstrap.Component
30600  * Bootstrap Layout Masonry class
30601  * 
30602  * @constructor
30603  * Create a new Element
30604  * @param {Object} config The config object
30605  */
30606
30607 Roo.bootstrap.LayoutMasonry = function(config){
30608     
30609     Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30610     
30611     this.bricks = [];
30612     
30613     Roo.bootstrap.LayoutMasonry.register(this);
30614     
30615     this.addEvents({
30616         // raw events
30617         /**
30618          * @event layout
30619          * Fire after layout the items
30620          * @param {Roo.bootstrap.LayoutMasonry} this
30621          * @param {Roo.EventObject} e
30622          */
30623         "layout" : true
30624     });
30625     
30626 };
30627
30628 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component,  {
30629     
30630     /**
30631      * @cfg {Boolean} isLayoutInstant = no animation?
30632      */   
30633     isLayoutInstant : false, // needed?
30634    
30635     /**
30636      * @cfg {Number} boxWidth  width of the columns
30637      */   
30638     boxWidth : 450,
30639     
30640       /**
30641      * @cfg {Number} boxHeight  - 0 for square, or fix it at a certian height
30642      */   
30643     boxHeight : 0,
30644     
30645     /**
30646      * @cfg {Number} padWidth padding below box..
30647      */   
30648     padWidth : 10, 
30649     
30650     /**
30651      * @cfg {Number} gutter gutter width..
30652      */   
30653     gutter : 10,
30654     
30655      /**
30656      * @cfg {Number} maxCols maximum number of columns
30657      */   
30658     
30659     maxCols: 0,
30660     
30661     /**
30662      * @cfg {Boolean} isAutoInitial defalut true
30663      */   
30664     isAutoInitial : true, 
30665     
30666     containerWidth: 0,
30667     
30668     /**
30669      * @cfg {Boolean} isHorizontal defalut false
30670      */   
30671     isHorizontal : false, 
30672
30673     currentSize : null,
30674     
30675     tag: 'div',
30676     
30677     cls: '',
30678     
30679     bricks: null, //CompositeElement
30680     
30681     cols : 1,
30682     
30683     _isLayoutInited : false,
30684     
30685 //    isAlternative : false, // only use for vertical layout...
30686     
30687     /**
30688      * @cfg {Number} alternativePadWidth padding below box..
30689      */   
30690     alternativePadWidth : 50,
30691     
30692     selectedBrick : [],
30693     
30694     getAutoCreate : function(){
30695         
30696         var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30697         
30698         var cfg = {
30699             tag: this.tag,
30700             cls: 'blog-masonary-wrapper ' + this.cls,
30701             cn : {
30702                 cls : 'mas-boxes masonary'
30703             }
30704         };
30705         
30706         return cfg;
30707     },
30708     
30709     getChildContainer: function( )
30710     {
30711         if (this.boxesEl) {
30712             return this.boxesEl;
30713         }
30714         
30715         this.boxesEl = this.el.select('.mas-boxes').first();
30716         
30717         return this.boxesEl;
30718     },
30719     
30720     
30721     initEvents : function()
30722     {
30723         var _this = this;
30724         
30725         if(this.isAutoInitial){
30726             Roo.log('hook children rendered');
30727             this.on('childrenrendered', function() {
30728                 Roo.log('children rendered');
30729                 _this.initial();
30730             } ,this);
30731         }
30732     },
30733     
30734     initial : function()
30735     {
30736         this.selectedBrick = [];
30737         
30738         this.currentSize = this.el.getBox(true);
30739         
30740         Roo.EventManager.onWindowResize(this.resize, this); 
30741
30742         if(!this.isAutoInitial){
30743             this.layout();
30744             return;
30745         }
30746         
30747         this.layout();
30748         
30749         return;
30750         //this.layout.defer(500,this);
30751         
30752     },
30753     
30754     resize : function()
30755     {
30756         var cs = this.el.getBox(true);
30757         
30758         if (
30759                 this.currentSize.width == cs.width && 
30760                 this.currentSize.x == cs.x && 
30761                 this.currentSize.height == cs.height && 
30762                 this.currentSize.y == cs.y 
30763         ) {
30764             Roo.log("no change in with or X or Y");
30765             return;
30766         }
30767         
30768         this.currentSize = cs;
30769         
30770         this.layout();
30771         
30772     },
30773     
30774     layout : function()
30775     {   
30776         this._resetLayout();
30777         
30778         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30779         
30780         this.layoutItems( isInstant );
30781       
30782         this._isLayoutInited = true;
30783         
30784         this.fireEvent('layout', this);
30785         
30786     },
30787     
30788     _resetLayout : function()
30789     {
30790         if(this.isHorizontal){
30791             this.horizontalMeasureColumns();
30792             return;
30793         }
30794         
30795         this.verticalMeasureColumns();
30796         
30797     },
30798     
30799     verticalMeasureColumns : function()
30800     {
30801         this.getContainerWidth();
30802         
30803 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30804 //            this.colWidth = Math.floor(this.containerWidth * 0.8);
30805 //            return;
30806 //        }
30807         
30808         var boxWidth = this.boxWidth + this.padWidth;
30809         
30810         if(this.containerWidth < this.boxWidth){
30811             boxWidth = this.containerWidth
30812         }
30813         
30814         var containerWidth = this.containerWidth;
30815         
30816         var cols = Math.floor(containerWidth / boxWidth);
30817         
30818         this.cols = Math.max( cols, 1 );
30819         
30820         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30821         
30822         var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30823         
30824         var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30825         
30826         this.colWidth = boxWidth + avail - this.padWidth;
30827         
30828         this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30829         this.unitHeight = this.boxHeight > 0 ? this.boxHeight  : this.unitWidth;
30830     },
30831     
30832     horizontalMeasureColumns : function()
30833     {
30834         this.getContainerWidth();
30835         
30836         var boxWidth = this.boxWidth;
30837         
30838         if(this.containerWidth < boxWidth){
30839             boxWidth = this.containerWidth;
30840         }
30841         
30842         this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30843         
30844         this.el.setHeight(boxWidth);
30845         
30846     },
30847     
30848     getContainerWidth : function()
30849     {
30850         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
30851     },
30852     
30853     layoutItems : function( isInstant )
30854     {
30855         Roo.log(this.bricks);
30856         
30857         var items = Roo.apply([], this.bricks);
30858         
30859         if(this.isHorizontal){
30860             this._horizontalLayoutItems( items , isInstant );
30861             return;
30862         }
30863         
30864 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30865 //            this._verticalAlternativeLayoutItems( items , isInstant );
30866 //            return;
30867 //        }
30868         
30869         this._verticalLayoutItems( items , isInstant );
30870         
30871     },
30872     
30873     _verticalLayoutItems : function ( items , isInstant)
30874     {
30875         if ( !items || !items.length ) {
30876             return;
30877         }
30878         
30879         var standard = [
30880             ['xs', 'xs', 'xs', 'tall'],
30881             ['xs', 'xs', 'tall'],
30882             ['xs', 'xs', 'sm'],
30883             ['xs', 'xs', 'xs'],
30884             ['xs', 'tall'],
30885             ['xs', 'sm'],
30886             ['xs', 'xs'],
30887             ['xs'],
30888             
30889             ['sm', 'xs', 'xs'],
30890             ['sm', 'xs'],
30891             ['sm'],
30892             
30893             ['tall', 'xs', 'xs', 'xs'],
30894             ['tall', 'xs', 'xs'],
30895             ['tall', 'xs'],
30896             ['tall']
30897             
30898         ];
30899         
30900         var queue = [];
30901         
30902         var boxes = [];
30903         
30904         var box = [];
30905         
30906         Roo.each(items, function(item, k){
30907             
30908             switch (item.size) {
30909                 // these layouts take up a full box,
30910                 case 'md' :
30911                 case 'md-left' :
30912                 case 'md-right' :
30913                 case 'wide' :
30914                     
30915                     if(box.length){
30916                         boxes.push(box);
30917                         box = [];
30918                     }
30919                     
30920                     boxes.push([item]);
30921                     
30922                     break;
30923                     
30924                 case 'xs' :
30925                 case 'sm' :
30926                 case 'tall' :
30927                     
30928                     box.push(item);
30929                     
30930                     break;
30931                 default :
30932                     break;
30933                     
30934             }
30935             
30936         }, this);
30937         
30938         if(box.length){
30939             boxes.push(box);
30940             box = [];
30941         }
30942         
30943         var filterPattern = function(box, length)
30944         {
30945             if(!box.length){
30946                 return;
30947             }
30948             
30949             var match = false;
30950             
30951             var pattern = box.slice(0, length);
30952             
30953             var format = [];
30954             
30955             Roo.each(pattern, function(i){
30956                 format.push(i.size);
30957             }, this);
30958             
30959             Roo.each(standard, function(s){
30960                 
30961                 if(String(s) != String(format)){
30962                     return;
30963                 }
30964                 
30965                 match = true;
30966                 return false;
30967                 
30968             }, this);
30969             
30970             if(!match && length == 1){
30971                 return;
30972             }
30973             
30974             if(!match){
30975                 filterPattern(box, length - 1);
30976                 return;
30977             }
30978                 
30979             queue.push(pattern);
30980
30981             box = box.slice(length, box.length);
30982
30983             filterPattern(box, 4);
30984
30985             return;
30986             
30987         }
30988         
30989         Roo.each(boxes, function(box, k){
30990             
30991             if(!box.length){
30992                 return;
30993             }
30994             
30995             if(box.length == 1){
30996                 queue.push(box);
30997                 return;
30998             }
30999             
31000             filterPattern(box, 4);
31001             
31002         }, this);
31003         
31004         this._processVerticalLayoutQueue( queue, isInstant );
31005         
31006     },
31007     
31008 //    _verticalAlternativeLayoutItems : function( items , isInstant )
31009 //    {
31010 //        if ( !items || !items.length ) {
31011 //            return;
31012 //        }
31013 //
31014 //        this._processVerticalAlternativeLayoutQueue( items, isInstant );
31015 //        
31016 //    },
31017     
31018     _horizontalLayoutItems : function ( items , isInstant)
31019     {
31020         if ( !items || !items.length || items.length < 3) {
31021             return;
31022         }
31023         
31024         items.reverse();
31025         
31026         var eItems = items.slice(0, 3);
31027         
31028         items = items.slice(3, items.length);
31029         
31030         var standard = [
31031             ['xs', 'xs', 'xs', 'wide'],
31032             ['xs', 'xs', 'wide'],
31033             ['xs', 'xs', 'sm'],
31034             ['xs', 'xs', 'xs'],
31035             ['xs', 'wide'],
31036             ['xs', 'sm'],
31037             ['xs', 'xs'],
31038             ['xs'],
31039             
31040             ['sm', 'xs', 'xs'],
31041             ['sm', 'xs'],
31042             ['sm'],
31043             
31044             ['wide', 'xs', 'xs', 'xs'],
31045             ['wide', 'xs', 'xs'],
31046             ['wide', 'xs'],
31047             ['wide'],
31048             
31049             ['wide-thin']
31050         ];
31051         
31052         var queue = [];
31053         
31054         var boxes = [];
31055         
31056         var box = [];
31057         
31058         Roo.each(items, function(item, k){
31059             
31060             switch (item.size) {
31061                 case 'md' :
31062                 case 'md-left' :
31063                 case 'md-right' :
31064                 case 'tall' :
31065                     
31066                     if(box.length){
31067                         boxes.push(box);
31068                         box = [];
31069                     }
31070                     
31071                     boxes.push([item]);
31072                     
31073                     break;
31074                     
31075                 case 'xs' :
31076                 case 'sm' :
31077                 case 'wide' :
31078                 case 'wide-thin' :
31079                     
31080                     box.push(item);
31081                     
31082                     break;
31083                 default :
31084                     break;
31085                     
31086             }
31087             
31088         }, this);
31089         
31090         if(box.length){
31091             boxes.push(box);
31092             box = [];
31093         }
31094         
31095         var filterPattern = function(box, length)
31096         {
31097             if(!box.length){
31098                 return;
31099             }
31100             
31101             var match = false;
31102             
31103             var pattern = box.slice(0, length);
31104             
31105             var format = [];
31106             
31107             Roo.each(pattern, function(i){
31108                 format.push(i.size);
31109             }, this);
31110             
31111             Roo.each(standard, function(s){
31112                 
31113                 if(String(s) != String(format)){
31114                     return;
31115                 }
31116                 
31117                 match = true;
31118                 return false;
31119                 
31120             }, this);
31121             
31122             if(!match && length == 1){
31123                 return;
31124             }
31125             
31126             if(!match){
31127                 filterPattern(box, length - 1);
31128                 return;
31129             }
31130                 
31131             queue.push(pattern);
31132
31133             box = box.slice(length, box.length);
31134
31135             filterPattern(box, 4);
31136
31137             return;
31138             
31139         }
31140         
31141         Roo.each(boxes, function(box, k){
31142             
31143             if(!box.length){
31144                 return;
31145             }
31146             
31147             if(box.length == 1){
31148                 queue.push(box);
31149                 return;
31150             }
31151             
31152             filterPattern(box, 4);
31153             
31154         }, this);
31155         
31156         
31157         var prune = [];
31158         
31159         var pos = this.el.getBox(true);
31160         
31161         var minX = pos.x;
31162         
31163         var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31164         
31165         var hit_end = false;
31166         
31167         Roo.each(queue, function(box){
31168             
31169             if(hit_end){
31170                 
31171                 Roo.each(box, function(b){
31172                 
31173                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31174                     b.el.hide();
31175
31176                 }, this);
31177
31178                 return;
31179             }
31180             
31181             var mx = 0;
31182             
31183             Roo.each(box, function(b){
31184                 
31185                 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31186                 b.el.show();
31187
31188                 mx = Math.max(mx, b.x);
31189                 
31190             }, this);
31191             
31192             maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31193             
31194             if(maxX < minX){
31195                 
31196                 Roo.each(box, function(b){
31197                 
31198                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31199                     b.el.hide();
31200                     
31201                 }, this);
31202                 
31203                 hit_end = true;
31204                 
31205                 return;
31206             }
31207             
31208             prune.push(box);
31209             
31210         }, this);
31211         
31212         this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31213     },
31214     
31215     /** Sets position of item in DOM
31216     * @param {Element} item
31217     * @param {Number} x - horizontal position
31218     * @param {Number} y - vertical position
31219     * @param {Boolean} isInstant - disables transitions
31220     */
31221     _processVerticalLayoutQueue : function( queue, isInstant )
31222     {
31223         var pos = this.el.getBox(true);
31224         var x = pos.x;
31225         var y = pos.y;
31226         var maxY = [];
31227         
31228         for (var i = 0; i < this.cols; i++){
31229             maxY[i] = pos.y;
31230         }
31231         
31232         Roo.each(queue, function(box, k){
31233             
31234             var col = k % this.cols;
31235             
31236             Roo.each(box, function(b,kk){
31237                 
31238                 b.el.position('absolute');
31239                 
31240                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31241                 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31242                 
31243                 if(b.size == 'md-left' || b.size == 'md-right'){
31244                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31245                     height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31246                 }
31247                 
31248                 b.el.setWidth(width);
31249                 b.el.setHeight(height);
31250                 // iframe?
31251                 b.el.select('iframe',true).setSize(width,height);
31252                 
31253             }, this);
31254             
31255             for (var i = 0; i < this.cols; i++){
31256                 
31257                 if(maxY[i] < maxY[col]){
31258                     col = i;
31259                     continue;
31260                 }
31261                 
31262                 col = Math.min(col, i);
31263                 
31264             }
31265             
31266             x = pos.x + col * (this.colWidth + this.padWidth);
31267             
31268             y = maxY[col];
31269             
31270             var positions = [];
31271             
31272             switch (box.length){
31273                 case 1 :
31274                     positions = this.getVerticalOneBoxColPositions(x, y, box);
31275                     break;
31276                 case 2 :
31277                     positions = this.getVerticalTwoBoxColPositions(x, y, box);
31278                     break;
31279                 case 3 :
31280                     positions = this.getVerticalThreeBoxColPositions(x, y, box);
31281                     break;
31282                 case 4 :
31283                     positions = this.getVerticalFourBoxColPositions(x, y, box);
31284                     break;
31285                 default :
31286                     break;
31287             }
31288             
31289             Roo.each(box, function(b,kk){
31290                 
31291                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31292                 
31293                 var sz = b.el.getSize();
31294                 
31295                 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31296                 
31297             }, this);
31298             
31299         }, this);
31300         
31301         var mY = 0;
31302         
31303         for (var i = 0; i < this.cols; i++){
31304             mY = Math.max(mY, maxY[i]);
31305         }
31306         
31307         this.el.setHeight(mY - pos.y);
31308         
31309     },
31310     
31311 //    _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31312 //    {
31313 //        var pos = this.el.getBox(true);
31314 //        var x = pos.x;
31315 //        var y = pos.y;
31316 //        var maxX = pos.right;
31317 //        
31318 //        var maxHeight = 0;
31319 //        
31320 //        Roo.each(items, function(item, k){
31321 //            
31322 //            var c = k % 2;
31323 //            
31324 //            item.el.position('absolute');
31325 //                
31326 //            var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31327 //
31328 //            item.el.setWidth(width);
31329 //
31330 //            var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31331 //
31332 //            item.el.setHeight(height);
31333 //            
31334 //            if(c == 0){
31335 //                item.el.setXY([x, y], isInstant ? false : true);
31336 //            } else {
31337 //                item.el.setXY([maxX - width, y], isInstant ? false : true);
31338 //            }
31339 //            
31340 //            y = y + height + this.alternativePadWidth;
31341 //            
31342 //            maxHeight = maxHeight + height + this.alternativePadWidth;
31343 //            
31344 //        }, this);
31345 //        
31346 //        this.el.setHeight(maxHeight);
31347 //        
31348 //    },
31349     
31350     _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31351     {
31352         var pos = this.el.getBox(true);
31353         
31354         var minX = pos.x;
31355         var minY = pos.y;
31356         
31357         var maxX = pos.right;
31358         
31359         this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31360         
31361         var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31362         
31363         Roo.each(queue, function(box, k){
31364             
31365             Roo.each(box, function(b, kk){
31366                 
31367                 b.el.position('absolute');
31368                 
31369                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31370                 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31371                 
31372                 if(b.size == 'md-left' || b.size == 'md-right'){
31373                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31374                     height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31375                 }
31376                 
31377                 b.el.setWidth(width);
31378                 b.el.setHeight(height);
31379                 
31380             }, this);
31381             
31382             if(!box.length){
31383                 return;
31384             }
31385             
31386             var positions = [];
31387             
31388             switch (box.length){
31389                 case 1 :
31390                     positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31391                     break;
31392                 case 2 :
31393                     positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31394                     break;
31395                 case 3 :
31396                     positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31397                     break;
31398                 case 4 :
31399                     positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31400                     break;
31401                 default :
31402                     break;
31403             }
31404             
31405             Roo.each(box, function(b,kk){
31406                 
31407                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31408                 
31409                 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31410                 
31411             }, this);
31412             
31413         }, this);
31414         
31415     },
31416     
31417     _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31418     {
31419         Roo.each(eItems, function(b,k){
31420             
31421             b.size = (k == 0) ? 'sm' : 'xs';
31422             b.x = (k == 0) ? 2 : 1;
31423             b.y = (k == 0) ? 2 : 1;
31424             
31425             b.el.position('absolute');
31426             
31427             var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31428                 
31429             b.el.setWidth(width);
31430             
31431             var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31432             
31433             b.el.setHeight(height);
31434             
31435         }, this);
31436
31437         var positions = [];
31438         
31439         positions.push({
31440             x : maxX - this.unitWidth * 2 - this.gutter,
31441             y : minY
31442         });
31443         
31444         positions.push({
31445             x : maxX - this.unitWidth,
31446             y : minY + (this.unitWidth + this.gutter) * 2
31447         });
31448         
31449         positions.push({
31450             x : maxX - this.unitWidth * 3 - this.gutter * 2,
31451             y : minY
31452         });
31453         
31454         Roo.each(eItems, function(b,k){
31455             
31456             b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31457
31458         }, this);
31459         
31460     },
31461     
31462     getVerticalOneBoxColPositions : function(x, y, box)
31463     {
31464         var pos = [];
31465         
31466         var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31467         
31468         if(box[0].size == 'md-left'){
31469             rand = 0;
31470         }
31471         
31472         if(box[0].size == 'md-right'){
31473             rand = 1;
31474         }
31475         
31476         pos.push({
31477             x : x + (this.unitWidth + this.gutter) * rand,
31478             y : y
31479         });
31480         
31481         return pos;
31482     },
31483     
31484     getVerticalTwoBoxColPositions : function(x, y, box)
31485     {
31486         var pos = [];
31487         
31488         if(box[0].size == 'xs'){
31489             
31490             pos.push({
31491                 x : x,
31492                 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31493             });
31494
31495             pos.push({
31496                 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31497                 y : y
31498             });
31499             
31500             return pos;
31501             
31502         }
31503         
31504         pos.push({
31505             x : x,
31506             y : y
31507         });
31508
31509         pos.push({
31510             x : x + (this.unitWidth + this.gutter) * 2,
31511             y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31512         });
31513         
31514         return pos;
31515         
31516     },
31517     
31518     getVerticalThreeBoxColPositions : function(x, y, box)
31519     {
31520         var pos = [];
31521         
31522         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31523             
31524             pos.push({
31525                 x : x,
31526                 y : y
31527             });
31528
31529             pos.push({
31530                 x : x + (this.unitWidth + this.gutter) * 1,
31531                 y : y
31532             });
31533             
31534             pos.push({
31535                 x : x + (this.unitWidth + this.gutter) * 2,
31536                 y : y
31537             });
31538             
31539             return pos;
31540             
31541         }
31542         
31543         if(box[0].size == 'xs' && box[1].size == 'xs'){
31544             
31545             pos.push({
31546                 x : x,
31547                 y : y
31548             });
31549
31550             pos.push({
31551                 x : x,
31552                 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31553             });
31554             
31555             pos.push({
31556                 x : x + (this.unitWidth + this.gutter) * 1,
31557                 y : y
31558             });
31559             
31560             return pos;
31561             
31562         }
31563         
31564         pos.push({
31565             x : x,
31566             y : y
31567         });
31568
31569         pos.push({
31570             x : x + (this.unitWidth + this.gutter) * 2,
31571             y : y
31572         });
31573
31574         pos.push({
31575             x : x + (this.unitWidth + this.gutter) * 2,
31576             y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31577         });
31578             
31579         return pos;
31580         
31581     },
31582     
31583     getVerticalFourBoxColPositions : function(x, y, box)
31584     {
31585         var pos = [];
31586         
31587         if(box[0].size == 'xs'){
31588             
31589             pos.push({
31590                 x : x,
31591                 y : y
31592             });
31593
31594             pos.push({
31595                 x : x,
31596                 y : y + (this.unitHeight + this.gutter) * 1
31597             });
31598             
31599             pos.push({
31600                 x : x,
31601                 y : y + (this.unitHeight + this.gutter) * 2
31602             });
31603             
31604             pos.push({
31605                 x : x + (this.unitWidth + this.gutter) * 1,
31606                 y : y
31607             });
31608             
31609             return pos;
31610             
31611         }
31612         
31613         pos.push({
31614             x : x,
31615             y : y
31616         });
31617
31618         pos.push({
31619             x : x + (this.unitWidth + this.gutter) * 2,
31620             y : y
31621         });
31622
31623         pos.push({
31624             x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31625             y : y + (this.unitHeight + this.gutter) * 1
31626         });
31627
31628         pos.push({
31629             x : x + (this.unitWidth + this.gutter) * 2,
31630             y : y + (this.unitWidth + this.gutter) * 2
31631         });
31632
31633         return pos;
31634         
31635     },
31636     
31637     getHorizontalOneBoxColPositions : function(maxX, minY, box)
31638     {
31639         var pos = [];
31640         
31641         if(box[0].size == 'md-left'){
31642             pos.push({
31643                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31644                 y : minY
31645             });
31646             
31647             return pos;
31648         }
31649         
31650         if(box[0].size == 'md-right'){
31651             pos.push({
31652                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31653                 y : minY + (this.unitWidth + this.gutter) * 1
31654             });
31655             
31656             return pos;
31657         }
31658         
31659         var rand = Math.floor(Math.random() * (4 - box[0].y));
31660         
31661         pos.push({
31662             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31663             y : minY + (this.unitWidth + this.gutter) * rand
31664         });
31665         
31666         return pos;
31667         
31668     },
31669     
31670     getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31671     {
31672         var pos = [];
31673         
31674         if(box[0].size == 'xs'){
31675             
31676             pos.push({
31677                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31678                 y : minY
31679             });
31680
31681             pos.push({
31682                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31683                 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31684             });
31685             
31686             return pos;
31687             
31688         }
31689         
31690         pos.push({
31691             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31692             y : minY
31693         });
31694
31695         pos.push({
31696             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31697             y : minY + (this.unitWidth + this.gutter) * 2
31698         });
31699         
31700         return pos;
31701         
31702     },
31703     
31704     getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31705     {
31706         var pos = [];
31707         
31708         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31709             
31710             pos.push({
31711                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31712                 y : minY
31713             });
31714
31715             pos.push({
31716                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31717                 y : minY + (this.unitWidth + this.gutter) * 1
31718             });
31719             
31720             pos.push({
31721                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31722                 y : minY + (this.unitWidth + this.gutter) * 2
31723             });
31724             
31725             return pos;
31726             
31727         }
31728         
31729         if(box[0].size == 'xs' && box[1].size == 'xs'){
31730             
31731             pos.push({
31732                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31733                 y : minY
31734             });
31735
31736             pos.push({
31737                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31738                 y : minY
31739             });
31740             
31741             pos.push({
31742                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31743                 y : minY + (this.unitWidth + this.gutter) * 1
31744             });
31745             
31746             return pos;
31747             
31748         }
31749         
31750         pos.push({
31751             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31752             y : minY
31753         });
31754
31755         pos.push({
31756             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31757             y : minY + (this.unitWidth + this.gutter) * 2
31758         });
31759
31760         pos.push({
31761             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31762             y : minY + (this.unitWidth + this.gutter) * 2
31763         });
31764             
31765         return pos;
31766         
31767     },
31768     
31769     getHorizontalFourBoxColPositions : function(maxX, minY, box)
31770     {
31771         var pos = [];
31772         
31773         if(box[0].size == 'xs'){
31774             
31775             pos.push({
31776                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31777                 y : minY
31778             });
31779
31780             pos.push({
31781                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31782                 y : minY
31783             });
31784             
31785             pos.push({
31786                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31787                 y : minY
31788             });
31789             
31790             pos.push({
31791                 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31792                 y : minY + (this.unitWidth + this.gutter) * 1
31793             });
31794             
31795             return pos;
31796             
31797         }
31798         
31799         pos.push({
31800             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31801             y : minY
31802         });
31803         
31804         pos.push({
31805             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31806             y : minY + (this.unitWidth + this.gutter) * 2
31807         });
31808         
31809         pos.push({
31810             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31811             y : minY + (this.unitWidth + this.gutter) * 2
31812         });
31813         
31814         pos.push({
31815             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31816             y : minY + (this.unitWidth + this.gutter) * 2
31817         });
31818
31819         return pos;
31820         
31821     },
31822     
31823     /**
31824     * remove a Masonry Brick
31825     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31826     */
31827     removeBrick : function(brick_id)
31828     {
31829         if (!brick_id) {
31830             return;
31831         }
31832         
31833         for (var i = 0; i<this.bricks.length; i++) {
31834             if (this.bricks[i].id == brick_id) {
31835                 this.bricks.splice(i,1);
31836                 this.el.dom.removeChild(Roo.get(brick_id).dom);
31837                 this.initial();
31838             }
31839         }
31840     },
31841     
31842     /**
31843     * adds a Masonry Brick
31844     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31845     */
31846     addBrick : function(cfg)
31847     {
31848         var cn = new Roo.bootstrap.MasonryBrick(cfg);
31849         //this.register(cn);
31850         cn.parentId = this.id;
31851         cn.onRender(this.el, null);
31852         return cn;
31853     },
31854     
31855     /**
31856     * register a Masonry Brick
31857     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31858     */
31859     
31860     register : function(brick)
31861     {
31862         this.bricks.push(brick);
31863         brick.masonryId = this.id;
31864     },
31865     
31866     /**
31867     * clear all the Masonry Brick
31868     */
31869     clearAll : function()
31870     {
31871         this.bricks = [];
31872         //this.getChildContainer().dom.innerHTML = "";
31873         this.el.dom.innerHTML = '';
31874     },
31875     
31876     getSelected : function()
31877     {
31878         if (!this.selectedBrick) {
31879             return false;
31880         }
31881         
31882         return this.selectedBrick;
31883     }
31884 });
31885
31886 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31887     
31888     groups: {},
31889      /**
31890     * register a Masonry Layout
31891     * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31892     */
31893     
31894     register : function(layout)
31895     {
31896         this.groups[layout.id] = layout;
31897     },
31898     /**
31899     * fetch a  Masonry Layout based on the masonry layout ID
31900     * @param {string} the masonry layout to add
31901     * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31902     */
31903     
31904     get: function(layout_id) {
31905         if (typeof(this.groups[layout_id]) == 'undefined') {
31906             return false;
31907         }
31908         return this.groups[layout_id] ;
31909     }
31910     
31911     
31912     
31913 });
31914
31915  
31916
31917  /**
31918  *
31919  * This is based on 
31920  * http://masonry.desandro.com
31921  *
31922  * The idea is to render all the bricks based on vertical width...
31923  *
31924  * The original code extends 'outlayer' - we might need to use that....
31925  * 
31926  */
31927
31928
31929 /**
31930  * @class Roo.bootstrap.LayoutMasonryAuto
31931  * @extends Roo.bootstrap.Component
31932  * Bootstrap Layout Masonry class
31933  * 
31934  * @constructor
31935  * Create a new Element
31936  * @param {Object} config The config object
31937  */
31938
31939 Roo.bootstrap.LayoutMasonryAuto = function(config){
31940     Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31941 };
31942
31943 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component,  {
31944     
31945       /**
31946      * @cfg {Boolean} isFitWidth  - resize the width..
31947      */   
31948     isFitWidth : false,  // options..
31949     /**
31950      * @cfg {Boolean} isOriginLeft = left align?
31951      */   
31952     isOriginLeft : true,
31953     /**
31954      * @cfg {Boolean} isOriginTop = top align?
31955      */   
31956     isOriginTop : false,
31957     /**
31958      * @cfg {Boolean} isLayoutInstant = no animation?
31959      */   
31960     isLayoutInstant : false, // needed?
31961     /**
31962      * @cfg {Boolean} isResizingContainer = not sure if this is used..
31963      */   
31964     isResizingContainer : true,
31965     /**
31966      * @cfg {Number} columnWidth  width of the columns 
31967      */   
31968     
31969     columnWidth : 0,
31970     
31971     /**
31972      * @cfg {Number} maxCols maximum number of columns
31973      */   
31974     
31975     maxCols: 0,
31976     /**
31977      * @cfg {Number} padHeight padding below box..
31978      */   
31979     
31980     padHeight : 10, 
31981     
31982     /**
31983      * @cfg {Boolean} isAutoInitial defalut true
31984      */   
31985     
31986     isAutoInitial : true, 
31987     
31988     // private?
31989     gutter : 0,
31990     
31991     containerWidth: 0,
31992     initialColumnWidth : 0,
31993     currentSize : null,
31994     
31995     colYs : null, // array.
31996     maxY : 0,
31997     padWidth: 10,
31998     
31999     
32000     tag: 'div',
32001     cls: '',
32002     bricks: null, //CompositeElement
32003     cols : 0, // array?
32004     // element : null, // wrapped now this.el
32005     _isLayoutInited : null, 
32006     
32007     
32008     getAutoCreate : function(){
32009         
32010         var cfg = {
32011             tag: this.tag,
32012             cls: 'blog-masonary-wrapper ' + this.cls,
32013             cn : {
32014                 cls : 'mas-boxes masonary'
32015             }
32016         };
32017         
32018         return cfg;
32019     },
32020     
32021     getChildContainer: function( )
32022     {
32023         if (this.boxesEl) {
32024             return this.boxesEl;
32025         }
32026         
32027         this.boxesEl = this.el.select('.mas-boxes').first();
32028         
32029         return this.boxesEl;
32030     },
32031     
32032     
32033     initEvents : function()
32034     {
32035         var _this = this;
32036         
32037         if(this.isAutoInitial){
32038             Roo.log('hook children rendered');
32039             this.on('childrenrendered', function() {
32040                 Roo.log('children rendered');
32041                 _this.initial();
32042             } ,this);
32043         }
32044         
32045     },
32046     
32047     initial : function()
32048     {
32049         this.reloadItems();
32050
32051         this.currentSize = this.el.getBox(true);
32052
32053         /// was window resize... - let's see if this works..
32054         Roo.EventManager.onWindowResize(this.resize, this); 
32055
32056         if(!this.isAutoInitial){
32057             this.layout();
32058             return;
32059         }
32060         
32061         this.layout.defer(500,this);
32062     },
32063     
32064     reloadItems: function()
32065     {
32066         this.bricks = this.el.select('.masonry-brick', true);
32067         
32068         this.bricks.each(function(b) {
32069             //Roo.log(b.getSize());
32070             if (!b.attr('originalwidth')) {
32071                 b.attr('originalwidth',  b.getSize().width);
32072             }
32073             
32074         });
32075         
32076         Roo.log(this.bricks.elements.length);
32077     },
32078     
32079     resize : function()
32080     {
32081         Roo.log('resize');
32082         var cs = this.el.getBox(true);
32083         
32084         if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32085             Roo.log("no change in with or X");
32086             return;
32087         }
32088         this.currentSize = cs;
32089         this.layout();
32090     },
32091     
32092     layout : function()
32093     {
32094          Roo.log('layout');
32095         this._resetLayout();
32096         //this._manageStamps();
32097       
32098         // don't animate first layout
32099         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32100         this.layoutItems( isInstant );
32101       
32102         // flag for initalized
32103         this._isLayoutInited = true;
32104     },
32105     
32106     layoutItems : function( isInstant )
32107     {
32108         //var items = this._getItemsForLayout( this.items );
32109         // original code supports filtering layout items.. we just ignore it..
32110         
32111         this._layoutItems( this.bricks , isInstant );
32112       
32113         this._postLayout();
32114     },
32115     _layoutItems : function ( items , isInstant)
32116     {
32117        //this.fireEvent( 'layout', this, items );
32118     
32119
32120         if ( !items || !items.elements.length ) {
32121           // no items, emit event with empty array
32122             return;
32123         }
32124
32125         var queue = [];
32126         items.each(function(item) {
32127             Roo.log("layout item");
32128             Roo.log(item);
32129             // get x/y object from method
32130             var position = this._getItemLayoutPosition( item );
32131             // enqueue
32132             position.item = item;
32133             position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32134             queue.push( position );
32135         }, this);
32136       
32137         this._processLayoutQueue( queue );
32138     },
32139     /** Sets position of item in DOM
32140     * @param {Element} item
32141     * @param {Number} x - horizontal position
32142     * @param {Number} y - vertical position
32143     * @param {Boolean} isInstant - disables transitions
32144     */
32145     _processLayoutQueue : function( queue )
32146     {
32147         for ( var i=0, len = queue.length; i < len; i++ ) {
32148             var obj = queue[i];
32149             obj.item.position('absolute');
32150             obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32151         }
32152     },
32153       
32154     
32155     /**
32156     * Any logic you want to do after each layout,
32157     * i.e. size the container
32158     */
32159     _postLayout : function()
32160     {
32161         this.resizeContainer();
32162     },
32163     
32164     resizeContainer : function()
32165     {
32166         if ( !this.isResizingContainer ) {
32167             return;
32168         }
32169         var size = this._getContainerSize();
32170         if ( size ) {
32171             this.el.setSize(size.width,size.height);
32172             this.boxesEl.setSize(size.width,size.height);
32173         }
32174     },
32175     
32176     
32177     
32178     _resetLayout : function()
32179     {
32180         //this.getSize();  // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32181         this.colWidth = this.el.getWidth();
32182         //this.gutter = this.el.getWidth(); 
32183         
32184         this.measureColumns();
32185
32186         // reset column Y
32187         var i = this.cols;
32188         this.colYs = [];
32189         while (i--) {
32190             this.colYs.push( 0 );
32191         }
32192     
32193         this.maxY = 0;
32194     },
32195
32196     measureColumns : function()
32197     {
32198         this.getContainerWidth();
32199       // if columnWidth is 0, default to outerWidth of first item
32200         if ( !this.columnWidth ) {
32201             var firstItem = this.bricks.first();
32202             Roo.log(firstItem);
32203             this.columnWidth  = this.containerWidth;
32204             if (firstItem && firstItem.attr('originalwidth') ) {
32205                 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32206             }
32207             // columnWidth fall back to item of first element
32208             Roo.log("set column width?");
32209                         this.initialColumnWidth = this.columnWidth  ;
32210
32211             // if first elem has no width, default to size of container
32212             
32213         }
32214         
32215         
32216         if (this.initialColumnWidth) {
32217             this.columnWidth = this.initialColumnWidth;
32218         }
32219         
32220         
32221             
32222         // column width is fixed at the top - however if container width get's smaller we should
32223         // reduce it...
32224         
32225         // this bit calcs how man columns..
32226             
32227         var columnWidth = this.columnWidth += this.gutter;
32228       
32229         // calculate columns
32230         var containerWidth = this.containerWidth + this.gutter;
32231         
32232         var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32233         // fix rounding errors, typically with gutters
32234         var excess = columnWidth - containerWidth % columnWidth;
32235         
32236         
32237         // if overshoot is less than a pixel, round up, otherwise floor it
32238         var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32239         cols = Math[ mathMethod ]( cols );
32240         this.cols = Math.max( cols, 1 );
32241         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32242         
32243          // padding positioning..
32244         var totalColWidth = this.cols * this.columnWidth;
32245         var padavail = this.containerWidth - totalColWidth;
32246         // so for 2 columns - we need 3 'pads'
32247         
32248         var padNeeded = (1+this.cols) * this.padWidth;
32249         
32250         var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32251         
32252         this.columnWidth += padExtra
32253         //this.padWidth = Math.floor(padavail /  ( this.cols));
32254         
32255         // adjust colum width so that padding is fixed??
32256         
32257         // we have 3 columns ... total = width * 3
32258         // we have X left over... that should be used by 
32259         
32260         //if (this.expandC) {
32261             
32262         //}
32263         
32264         
32265         
32266     },
32267     
32268     getContainerWidth : function()
32269     {
32270        /* // container is parent if fit width
32271         var container = this.isFitWidth ? this.element.parentNode : this.element;
32272         // check that this.size and size are there
32273         // IE8 triggers resize on body size change, so they might not be
32274         
32275         var size = getSize( container );  //FIXME
32276         this.containerWidth = size && size.innerWidth; //FIXME
32277         */
32278          
32279         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
32280         
32281     },
32282     
32283     _getItemLayoutPosition : function( item )  // what is item?
32284     {
32285         // we resize the item to our columnWidth..
32286       
32287         item.setWidth(this.columnWidth);
32288         item.autoBoxAdjust  = false;
32289         
32290         var sz = item.getSize();
32291  
32292         // how many columns does this brick span
32293         var remainder = this.containerWidth % this.columnWidth;
32294         
32295         var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32296         // round if off by 1 pixel, otherwise use ceil
32297         var colSpan = Math[ mathMethod ]( sz.width  / this.columnWidth );
32298         colSpan = Math.min( colSpan, this.cols );
32299         
32300         // normally this should be '1' as we dont' currently allow multi width columns..
32301         
32302         var colGroup = this._getColGroup( colSpan );
32303         // get the minimum Y value from the columns
32304         var minimumY = Math.min.apply( Math, colGroup );
32305         Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32306         
32307         var shortColIndex = colGroup.indexOf(  minimumY ); // broken on ie8..?? probably...
32308          
32309         // position the brick
32310         var position = {
32311             x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32312             y: this.currentSize.y + minimumY + this.padHeight
32313         };
32314         
32315         Roo.log(position);
32316         // apply setHeight to necessary columns
32317         var setHeight = minimumY + sz.height + this.padHeight;
32318         //Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32319         
32320         var setSpan = this.cols + 1 - colGroup.length;
32321         for ( var i = 0; i < setSpan; i++ ) {
32322           this.colYs[ shortColIndex + i ] = setHeight ;
32323         }
32324       
32325         return position;
32326     },
32327     
32328     /**
32329      * @param {Number} colSpan - number of columns the element spans
32330      * @returns {Array} colGroup
32331      */
32332     _getColGroup : function( colSpan )
32333     {
32334         if ( colSpan < 2 ) {
32335           // if brick spans only one column, use all the column Ys
32336           return this.colYs;
32337         }
32338       
32339         var colGroup = [];
32340         // how many different places could this brick fit horizontally
32341         var groupCount = this.cols + 1 - colSpan;
32342         // for each group potential horizontal position
32343         for ( var i = 0; i < groupCount; i++ ) {
32344           // make an array of colY values for that one group
32345           var groupColYs = this.colYs.slice( i, i + colSpan );
32346           // and get the max value of the array
32347           colGroup[i] = Math.max.apply( Math, groupColYs );
32348         }
32349         return colGroup;
32350     },
32351     /*
32352     _manageStamp : function( stamp )
32353     {
32354         var stampSize =  stamp.getSize();
32355         var offset = stamp.getBox();
32356         // get the columns that this stamp affects
32357         var firstX = this.isOriginLeft ? offset.x : offset.right;
32358         var lastX = firstX + stampSize.width;
32359         var firstCol = Math.floor( firstX / this.columnWidth );
32360         firstCol = Math.max( 0, firstCol );
32361         
32362         var lastCol = Math.floor( lastX / this.columnWidth );
32363         // lastCol should not go over if multiple of columnWidth #425
32364         lastCol -= lastX % this.columnWidth ? 0 : 1;
32365         lastCol = Math.min( this.cols - 1, lastCol );
32366         
32367         // set colYs to bottom of the stamp
32368         var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32369             stampSize.height;
32370             
32371         for ( var i = firstCol; i <= lastCol; i++ ) {
32372           this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32373         }
32374     },
32375     */
32376     
32377     _getContainerSize : function()
32378     {
32379         this.maxY = Math.max.apply( Math, this.colYs );
32380         var size = {
32381             height: this.maxY
32382         };
32383       
32384         if ( this.isFitWidth ) {
32385             size.width = this._getContainerFitWidth();
32386         }
32387       
32388         return size;
32389     },
32390     
32391     _getContainerFitWidth : function()
32392     {
32393         var unusedCols = 0;
32394         // count unused columns
32395         var i = this.cols;
32396         while ( --i ) {
32397           if ( this.colYs[i] !== 0 ) {
32398             break;
32399           }
32400           unusedCols++;
32401         }
32402         // fit container to columns that have been used
32403         return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32404     },
32405     
32406     needsResizeLayout : function()
32407     {
32408         var previousWidth = this.containerWidth;
32409         this.getContainerWidth();
32410         return previousWidth !== this.containerWidth;
32411     }
32412  
32413 });
32414
32415  
32416
32417  /*
32418  * - LGPL
32419  *
32420  * element
32421  * 
32422  */
32423
32424 /**
32425  * @class Roo.bootstrap.MasonryBrick
32426  * @extends Roo.bootstrap.Component
32427  * Bootstrap MasonryBrick class
32428  * 
32429  * @constructor
32430  * Create a new MasonryBrick
32431  * @param {Object} config The config object
32432  */
32433
32434 Roo.bootstrap.MasonryBrick = function(config){
32435     
32436     Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32437     
32438     Roo.bootstrap.MasonryBrick.register(this);
32439     
32440     this.addEvents({
32441         // raw events
32442         /**
32443          * @event click
32444          * When a MasonryBrick is clcik
32445          * @param {Roo.bootstrap.MasonryBrick} this
32446          * @param {Roo.EventObject} e
32447          */
32448         "click" : true
32449     });
32450 };
32451
32452 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component,  {
32453     
32454     /**
32455      * @cfg {String} title
32456      */   
32457     title : '',
32458     /**
32459      * @cfg {String} html
32460      */   
32461     html : '',
32462     /**
32463      * @cfg {String} bgimage
32464      */   
32465     bgimage : '',
32466     /**
32467      * @cfg {String} videourl
32468      */   
32469     videourl : '',
32470     /**
32471      * @cfg {String} cls
32472      */   
32473     cls : '',
32474     /**
32475      * @cfg {String} href
32476      */   
32477     href : '',
32478     /**
32479      * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32480      */   
32481     size : 'xs',
32482     
32483     /**
32484      * @cfg {String} placetitle (center|bottom)
32485      */   
32486     placetitle : '',
32487     
32488     /**
32489      * @cfg {Boolean} isFitContainer defalut true
32490      */   
32491     isFitContainer : true, 
32492     
32493     /**
32494      * @cfg {Boolean} preventDefault defalut false
32495      */   
32496     preventDefault : false, 
32497     
32498     /**
32499      * @cfg {Boolean} inverse defalut false
32500      */   
32501     maskInverse : false, 
32502     
32503     getAutoCreate : function()
32504     {
32505         if(!this.isFitContainer){
32506             return this.getSplitAutoCreate();
32507         }
32508         
32509         var cls = 'masonry-brick masonry-brick-full';
32510         
32511         if(this.href.length){
32512             cls += ' masonry-brick-link';
32513         }
32514         
32515         if(this.bgimage.length){
32516             cls += ' masonry-brick-image';
32517         }
32518         
32519         if(this.maskInverse){
32520             cls += ' mask-inverse';
32521         }
32522         
32523         if(!this.html.length && !this.maskInverse && !this.videourl.length){
32524             cls += ' enable-mask';
32525         }
32526         
32527         if(this.size){
32528             cls += ' masonry-' + this.size + '-brick';
32529         }
32530         
32531         if(this.placetitle.length){
32532             
32533             switch (this.placetitle) {
32534                 case 'center' :
32535                     cls += ' masonry-center-title';
32536                     break;
32537                 case 'bottom' :
32538                     cls += ' masonry-bottom-title';
32539                     break;
32540                 default:
32541                     break;
32542             }
32543             
32544         } else {
32545             if(!this.html.length && !this.bgimage.length){
32546                 cls += ' masonry-center-title';
32547             }
32548
32549             if(!this.html.length && this.bgimage.length){
32550                 cls += ' masonry-bottom-title';
32551             }
32552         }
32553         
32554         if(this.cls){
32555             cls += ' ' + this.cls;
32556         }
32557         
32558         var cfg = {
32559             tag: (this.href.length) ? 'a' : 'div',
32560             cls: cls,
32561             cn: [
32562                 {
32563                     tag: 'div',
32564                     cls: 'masonry-brick-mask'
32565                 },
32566                 {
32567                     tag: 'div',
32568                     cls: 'masonry-brick-paragraph',
32569                     cn: []
32570                 }
32571             ]
32572         };
32573         
32574         if(this.href.length){
32575             cfg.href = this.href;
32576         }
32577         
32578         var cn = cfg.cn[1].cn;
32579         
32580         if(this.title.length){
32581             cn.push({
32582                 tag: 'h4',
32583                 cls: 'masonry-brick-title',
32584                 html: this.title
32585             });
32586         }
32587         
32588         if(this.html.length){
32589             cn.push({
32590                 tag: 'p',
32591                 cls: 'masonry-brick-text',
32592                 html: this.html
32593             });
32594         }
32595         
32596         if (!this.title.length && !this.html.length) {
32597             cfg.cn[1].cls += ' hide';
32598         }
32599         
32600         if(this.bgimage.length){
32601             cfg.cn.push({
32602                 tag: 'img',
32603                 cls: 'masonry-brick-image-view',
32604                 src: this.bgimage
32605             });
32606         }
32607         
32608         if(this.videourl.length){
32609             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32610             // youtube support only?
32611             cfg.cn.push({
32612                 tag: 'iframe',
32613                 cls: 'masonry-brick-image-view',
32614                 src: vurl,
32615                 frameborder : 0,
32616                 allowfullscreen : true
32617             });
32618         }
32619         
32620         return cfg;
32621         
32622     },
32623     
32624     getSplitAutoCreate : function()
32625     {
32626         var cls = 'masonry-brick masonry-brick-split';
32627         
32628         if(this.href.length){
32629             cls += ' masonry-brick-link';
32630         }
32631         
32632         if(this.bgimage.length){
32633             cls += ' masonry-brick-image';
32634         }
32635         
32636         if(this.size){
32637             cls += ' masonry-' + this.size + '-brick';
32638         }
32639         
32640         switch (this.placetitle) {
32641             case 'center' :
32642                 cls += ' masonry-center-title';
32643                 break;
32644             case 'bottom' :
32645                 cls += ' masonry-bottom-title';
32646                 break;
32647             default:
32648                 if(!this.bgimage.length){
32649                     cls += ' masonry-center-title';
32650                 }
32651
32652                 if(this.bgimage.length){
32653                     cls += ' masonry-bottom-title';
32654                 }
32655                 break;
32656         }
32657         
32658         if(this.cls){
32659             cls += ' ' + this.cls;
32660         }
32661         
32662         var cfg = {
32663             tag: (this.href.length) ? 'a' : 'div',
32664             cls: cls,
32665             cn: [
32666                 {
32667                     tag: 'div',
32668                     cls: 'masonry-brick-split-head',
32669                     cn: [
32670                         {
32671                             tag: 'div',
32672                             cls: 'masonry-brick-paragraph',
32673                             cn: []
32674                         }
32675                     ]
32676                 },
32677                 {
32678                     tag: 'div',
32679                     cls: 'masonry-brick-split-body',
32680                     cn: []
32681                 }
32682             ]
32683         };
32684         
32685         if(this.href.length){
32686             cfg.href = this.href;
32687         }
32688         
32689         if(this.title.length){
32690             cfg.cn[0].cn[0].cn.push({
32691                 tag: 'h4',
32692                 cls: 'masonry-brick-title',
32693                 html: this.title
32694             });
32695         }
32696         
32697         if(this.html.length){
32698             cfg.cn[1].cn.push({
32699                 tag: 'p',
32700                 cls: 'masonry-brick-text',
32701                 html: this.html
32702             });
32703         }
32704
32705         if(this.bgimage.length){
32706             cfg.cn[0].cn.push({
32707                 tag: 'img',
32708                 cls: 'masonry-brick-image-view',
32709                 src: this.bgimage
32710             });
32711         }
32712         
32713         if(this.videourl.length){
32714             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32715             // youtube support only?
32716             cfg.cn[0].cn.cn.push({
32717                 tag: 'iframe',
32718                 cls: 'masonry-brick-image-view',
32719                 src: vurl,
32720                 frameborder : 0,
32721                 allowfullscreen : true
32722             });
32723         }
32724         
32725         return cfg;
32726     },
32727     
32728     initEvents: function() 
32729     {
32730         switch (this.size) {
32731             case 'xs' :
32732                 this.x = 1;
32733                 this.y = 1;
32734                 break;
32735             case 'sm' :
32736                 this.x = 2;
32737                 this.y = 2;
32738                 break;
32739             case 'md' :
32740             case 'md-left' :
32741             case 'md-right' :
32742                 this.x = 3;
32743                 this.y = 3;
32744                 break;
32745             case 'tall' :
32746                 this.x = 2;
32747                 this.y = 3;
32748                 break;
32749             case 'wide' :
32750                 this.x = 3;
32751                 this.y = 2;
32752                 break;
32753             case 'wide-thin' :
32754                 this.x = 3;
32755                 this.y = 1;
32756                 break;
32757                         
32758             default :
32759                 break;
32760         }
32761         
32762         if(Roo.isTouch){
32763             this.el.on('touchstart', this.onTouchStart, this);
32764             this.el.on('touchmove', this.onTouchMove, this);
32765             this.el.on('touchend', this.onTouchEnd, this);
32766             this.el.on('contextmenu', this.onContextMenu, this);
32767         } else {
32768             this.el.on('mouseenter'  ,this.enter, this);
32769             this.el.on('mouseleave', this.leave, this);
32770             this.el.on('click', this.onClick, this);
32771         }
32772         
32773         if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32774             this.parent().bricks.push(this);   
32775         }
32776         
32777     },
32778     
32779     onClick: function(e, el)
32780     {
32781         var time = this.endTimer - this.startTimer;
32782         // Roo.log(e.preventDefault());
32783         if(Roo.isTouch){
32784             if(time > 1000){
32785                 e.preventDefault();
32786                 return;
32787             }
32788         }
32789         
32790         if(!this.preventDefault){
32791             return;
32792         }
32793         
32794         e.preventDefault();
32795         
32796         if (this.activeClass != '') {
32797             this.selectBrick();
32798         }
32799         
32800         this.fireEvent('click', this, e);
32801     },
32802     
32803     enter: function(e, el)
32804     {
32805         e.preventDefault();
32806         
32807         if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32808             return;
32809         }
32810         
32811         if(this.bgimage.length && this.html.length){
32812             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32813         }
32814     },
32815     
32816     leave: function(e, el)
32817     {
32818         e.preventDefault();
32819         
32820         if(!this.isFitContainer || this.maskInverse  || this.videourl.length){
32821             return;
32822         }
32823         
32824         if(this.bgimage.length && this.html.length){
32825             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32826         }
32827     },
32828     
32829     onTouchStart: function(e, el)
32830     {
32831 //        e.preventDefault();
32832         
32833         this.touchmoved = false;
32834         
32835         if(!this.isFitContainer){
32836             return;
32837         }
32838         
32839         if(!this.bgimage.length || !this.html.length){
32840             return;
32841         }
32842         
32843         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32844         
32845         this.timer = new Date().getTime();
32846         
32847     },
32848     
32849     onTouchMove: function(e, el)
32850     {
32851         this.touchmoved = true;
32852     },
32853     
32854     onContextMenu : function(e,el)
32855     {
32856         e.preventDefault();
32857         e.stopPropagation();
32858         return false;
32859     },
32860     
32861     onTouchEnd: function(e, el)
32862     {
32863 //        e.preventDefault();
32864         
32865         if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32866         
32867             this.leave(e,el);
32868             
32869             return;
32870         }
32871         
32872         if(!this.bgimage.length || !this.html.length){
32873             
32874             if(this.href.length){
32875                 window.location.href = this.href;
32876             }
32877             
32878             return;
32879         }
32880         
32881         if(!this.isFitContainer){
32882             return;
32883         }
32884         
32885         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32886         
32887         window.location.href = this.href;
32888     },
32889     
32890     //selection on single brick only
32891     selectBrick : function() {
32892         
32893         if (!this.parentId) {
32894             return;
32895         }
32896         
32897         var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32898         var index = m.selectedBrick.indexOf(this.id);
32899         
32900         if ( index > -1) {
32901             m.selectedBrick.splice(index,1);
32902             this.el.removeClass(this.activeClass);
32903             return;
32904         }
32905         
32906         for(var i = 0; i < m.selectedBrick.length; i++) {
32907             var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32908             b.el.removeClass(b.activeClass);
32909         }
32910         
32911         m.selectedBrick = [];
32912         
32913         m.selectedBrick.push(this.id);
32914         this.el.addClass(this.activeClass);
32915         return;
32916     },
32917     
32918     isSelected : function(){
32919         return this.el.hasClass(this.activeClass);
32920         
32921     }
32922 });
32923
32924 Roo.apply(Roo.bootstrap.MasonryBrick, {
32925     
32926     //groups: {},
32927     groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32928      /**
32929     * register a Masonry Brick
32930     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32931     */
32932     
32933     register : function(brick)
32934     {
32935         //this.groups[brick.id] = brick;
32936         this.groups.add(brick.id, brick);
32937     },
32938     /**
32939     * fetch a  masonry brick based on the masonry brick ID
32940     * @param {string} the masonry brick to add
32941     * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32942     */
32943     
32944     get: function(brick_id) 
32945     {
32946         // if (typeof(this.groups[brick_id]) == 'undefined') {
32947         //     return false;
32948         // }
32949         // return this.groups[brick_id] ;
32950         
32951         if(this.groups.key(brick_id)) {
32952             return this.groups.key(brick_id);
32953         }
32954         
32955         return false;
32956     }
32957     
32958     
32959     
32960 });
32961
32962  /*
32963  * - LGPL
32964  *
32965  * element
32966  * 
32967  */
32968
32969 /**
32970  * @class Roo.bootstrap.Brick
32971  * @extends Roo.bootstrap.Component
32972  * Bootstrap Brick class
32973  * 
32974  * @constructor
32975  * Create a new Brick
32976  * @param {Object} config The config object
32977  */
32978
32979 Roo.bootstrap.Brick = function(config){
32980     Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32981     
32982     this.addEvents({
32983         // raw events
32984         /**
32985          * @event click
32986          * When a Brick is click
32987          * @param {Roo.bootstrap.Brick} this
32988          * @param {Roo.EventObject} e
32989          */
32990         "click" : true
32991     });
32992 };
32993
32994 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
32995     
32996     /**
32997      * @cfg {String} title
32998      */   
32999     title : '',
33000     /**
33001      * @cfg {String} html
33002      */   
33003     html : '',
33004     /**
33005      * @cfg {String} bgimage
33006      */   
33007     bgimage : '',
33008     /**
33009      * @cfg {String} cls
33010      */   
33011     cls : '',
33012     /**
33013      * @cfg {String} href
33014      */   
33015     href : '',
33016     /**
33017      * @cfg {String} video
33018      */   
33019     video : '',
33020     /**
33021      * @cfg {Boolean} square
33022      */   
33023     square : true,
33024     
33025     getAutoCreate : function()
33026     {
33027         var cls = 'roo-brick';
33028         
33029         if(this.href.length){
33030             cls += ' roo-brick-link';
33031         }
33032         
33033         if(this.bgimage.length){
33034             cls += ' roo-brick-image';
33035         }
33036         
33037         if(!this.html.length && !this.bgimage.length){
33038             cls += ' roo-brick-center-title';
33039         }
33040         
33041         if(!this.html.length && this.bgimage.length){
33042             cls += ' roo-brick-bottom-title';
33043         }
33044         
33045         if(this.cls){
33046             cls += ' ' + this.cls;
33047         }
33048         
33049         var cfg = {
33050             tag: (this.href.length) ? 'a' : 'div',
33051             cls: cls,
33052             cn: [
33053                 {
33054                     tag: 'div',
33055                     cls: 'roo-brick-paragraph',
33056                     cn: []
33057                 }
33058             ]
33059         };
33060         
33061         if(this.href.length){
33062             cfg.href = this.href;
33063         }
33064         
33065         var cn = cfg.cn[0].cn;
33066         
33067         if(this.title.length){
33068             cn.push({
33069                 tag: 'h4',
33070                 cls: 'roo-brick-title',
33071                 html: this.title
33072             });
33073         }
33074         
33075         if(this.html.length){
33076             cn.push({
33077                 tag: 'p',
33078                 cls: 'roo-brick-text',
33079                 html: this.html
33080             });
33081         } else {
33082             cn.cls += ' hide';
33083         }
33084         
33085         if(this.bgimage.length){
33086             cfg.cn.push({
33087                 tag: 'img',
33088                 cls: 'roo-brick-image-view',
33089                 src: this.bgimage
33090             });
33091         }
33092         
33093         return cfg;
33094     },
33095     
33096     initEvents: function() 
33097     {
33098         if(this.title.length || this.html.length){
33099             this.el.on('mouseenter'  ,this.enter, this);
33100             this.el.on('mouseleave', this.leave, this);
33101         }
33102         
33103         Roo.EventManager.onWindowResize(this.resize, this); 
33104         
33105         if(this.bgimage.length){
33106             this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33107             this.imageEl.on('load', this.onImageLoad, this);
33108             return;
33109         }
33110         
33111         this.resize();
33112     },
33113     
33114     onImageLoad : function()
33115     {
33116         this.resize();
33117     },
33118     
33119     resize : function()
33120     {
33121         var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33122         
33123         paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33124         
33125         if(this.bgimage.length){
33126             var image = this.el.select('.roo-brick-image-view', true).first();
33127             
33128             image.setWidth(paragraph.getWidth());
33129             
33130             if(this.square){
33131                 image.setHeight(paragraph.getWidth());
33132             }
33133             
33134             this.el.setHeight(image.getHeight());
33135             paragraph.setHeight(image.getHeight());
33136             
33137         }
33138         
33139     },
33140     
33141     enter: function(e, el)
33142     {
33143         e.preventDefault();
33144         
33145         if(this.bgimage.length){
33146             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33147             this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33148         }
33149     },
33150     
33151     leave: function(e, el)
33152     {
33153         e.preventDefault();
33154         
33155         if(this.bgimage.length){
33156             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33157             this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33158         }
33159     }
33160     
33161 });
33162
33163  
33164
33165  /*
33166  * - LGPL
33167  *
33168  * Number field 
33169  */
33170
33171 /**
33172  * @class Roo.bootstrap.NumberField
33173  * @extends Roo.bootstrap.Input
33174  * Bootstrap NumberField class
33175  * 
33176  * 
33177  * 
33178  * 
33179  * @constructor
33180  * Create a new NumberField
33181  * @param {Object} config The config object
33182  */
33183
33184 Roo.bootstrap.NumberField = function(config){
33185     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33186 };
33187
33188 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33189     
33190     /**
33191      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33192      */
33193     allowDecimals : true,
33194     /**
33195      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33196      */
33197     decimalSeparator : ".",
33198     /**
33199      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33200      */
33201     decimalPrecision : 2,
33202     /**
33203      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33204      */
33205     allowNegative : true,
33206     
33207     /**
33208      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33209      */
33210     allowZero: true,
33211     /**
33212      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33213      */
33214     minValue : Number.NEGATIVE_INFINITY,
33215     /**
33216      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33217      */
33218     maxValue : Number.MAX_VALUE,
33219     /**
33220      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33221      */
33222     minText : "The minimum value for this field is {0}",
33223     /**
33224      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33225      */
33226     maxText : "The maximum value for this field is {0}",
33227     /**
33228      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
33229      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33230      */
33231     nanText : "{0} is not a valid number",
33232     /**
33233      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33234      */
33235     castInt : true,
33236     /**
33237      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33238      */
33239     thousandsDelimiter : false,
33240     /**
33241      * @cfg {String} valueAlign alignment of value
33242      */
33243     valueAlign : "left",
33244
33245     getAutoCreate : function()
33246     {
33247         var hiddenInput = {
33248             tag: 'input',
33249             type: 'hidden',
33250             id: Roo.id(),
33251             cls: 'hidden-number-input'
33252         };
33253         
33254         if (this.name) {
33255             hiddenInput.name = this.name;
33256         }
33257         
33258         this.name = '';
33259         
33260         var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33261         
33262         this.name = hiddenInput.name;
33263         
33264         if(cfg.cn.length > 0) {
33265             cfg.cn.push(hiddenInput);
33266         }
33267         
33268         return cfg;
33269     },
33270
33271     // private
33272     initEvents : function()
33273     {   
33274         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33275         
33276         var allowed = "0123456789";
33277         
33278         if(this.allowDecimals){
33279             allowed += this.decimalSeparator;
33280         }
33281         
33282         if(this.allowNegative){
33283             allowed += "-";
33284         }
33285         
33286         if(this.thousandsDelimiter) {
33287             allowed += ",";
33288         }
33289         
33290         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33291         
33292         var keyPress = function(e){
33293             
33294             var k = e.getKey();
33295             
33296             var c = e.getCharCode();
33297             
33298             if(
33299                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33300                     allowed.indexOf(String.fromCharCode(c)) === -1
33301             ){
33302                 e.stopEvent();
33303                 return;
33304             }
33305             
33306             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33307                 return;
33308             }
33309             
33310             if(allowed.indexOf(String.fromCharCode(c)) === -1){
33311                 e.stopEvent();
33312             }
33313         };
33314         
33315         this.el.on("keypress", keyPress, this);
33316     },
33317     
33318     validateValue : function(value)
33319     {
33320         
33321         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33322             return false;
33323         }
33324         
33325         var num = this.parseValue(value);
33326         
33327         if(isNaN(num)){
33328             this.markInvalid(String.format(this.nanText, value));
33329             return false;
33330         }
33331         
33332         if(num < this.minValue){
33333             this.markInvalid(String.format(this.minText, this.minValue));
33334             return false;
33335         }
33336         
33337         if(num > this.maxValue){
33338             this.markInvalid(String.format(this.maxText, this.maxValue));
33339             return false;
33340         }
33341         
33342         return true;
33343     },
33344
33345     getValue : function()
33346     {
33347         var v = this.hiddenEl().getValue();
33348         
33349         return this.fixPrecision(this.parseValue(v));
33350     },
33351
33352     parseValue : function(value)
33353     {
33354         if(this.thousandsDelimiter) {
33355             value += "";
33356             r = new RegExp(",", "g");
33357             value = value.replace(r, "");
33358         }
33359         
33360         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33361         return isNaN(value) ? '' : value;
33362     },
33363
33364     fixPrecision : function(value)
33365     {
33366         if(this.thousandsDelimiter) {
33367             value += "";
33368             r = new RegExp(",", "g");
33369             value = value.replace(r, "");
33370         }
33371         
33372         var nan = isNaN(value);
33373         
33374         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33375             return nan ? '' : value;
33376         }
33377         return parseFloat(value).toFixed(this.decimalPrecision);
33378     },
33379
33380     setValue : function(v)
33381     {
33382         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33383         
33384         this.value = v;
33385         
33386         if(this.rendered){
33387             
33388             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33389             
33390             this.inputEl().dom.value = (v == '') ? '' :
33391                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33392             
33393             if(!this.allowZero && v === '0') {
33394                 this.hiddenEl().dom.value = '';
33395                 this.inputEl().dom.value = '';
33396             }
33397             
33398             this.validate();
33399         }
33400     },
33401
33402     decimalPrecisionFcn : function(v)
33403     {
33404         return Math.floor(v);
33405     },
33406
33407     beforeBlur : function()
33408     {
33409         if(!this.castInt){
33410             return;
33411         }
33412         
33413         var v = this.parseValue(this.getRawValue());
33414         
33415         if(v || v === 0){
33416             this.setValue(v);
33417         }
33418     },
33419     
33420     hiddenEl : function()
33421     {
33422         return this.el.select('input.hidden-number-input',true).first();
33423     }
33424     
33425 });
33426
33427  
33428
33429 /*
33430 * Licence: LGPL
33431 */
33432
33433 /**
33434  * @class Roo.bootstrap.DocumentSlider
33435  * @extends Roo.bootstrap.Component
33436  * Bootstrap DocumentSlider class
33437  * 
33438  * @constructor
33439  * Create a new DocumentViewer
33440  * @param {Object} config The config object
33441  */
33442
33443 Roo.bootstrap.DocumentSlider = function(config){
33444     Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33445     
33446     this.files = [];
33447     
33448     this.addEvents({
33449         /**
33450          * @event initial
33451          * Fire after initEvent
33452          * @param {Roo.bootstrap.DocumentSlider} this
33453          */
33454         "initial" : true,
33455         /**
33456          * @event update
33457          * Fire after update
33458          * @param {Roo.bootstrap.DocumentSlider} this
33459          */
33460         "update" : true,
33461         /**
33462          * @event click
33463          * Fire after click
33464          * @param {Roo.bootstrap.DocumentSlider} this
33465          */
33466         "click" : true
33467     });
33468 };
33469
33470 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
33471     
33472     files : false,
33473     
33474     indicator : 0,
33475     
33476     getAutoCreate : function()
33477     {
33478         var cfg = {
33479             tag : 'div',
33480             cls : 'roo-document-slider',
33481             cn : [
33482                 {
33483                     tag : 'div',
33484                     cls : 'roo-document-slider-header',
33485                     cn : [
33486                         {
33487                             tag : 'div',
33488                             cls : 'roo-document-slider-header-title'
33489                         }
33490                     ]
33491                 },
33492                 {
33493                     tag : 'div',
33494                     cls : 'roo-document-slider-body',
33495                     cn : [
33496                         {
33497                             tag : 'div',
33498                             cls : 'roo-document-slider-prev',
33499                             cn : [
33500                                 {
33501                                     tag : 'i',
33502                                     cls : 'fa fa-chevron-left'
33503                                 }
33504                             ]
33505                         },
33506                         {
33507                             tag : 'div',
33508                             cls : 'roo-document-slider-thumb',
33509                             cn : [
33510                                 {
33511                                     tag : 'img',
33512                                     cls : 'roo-document-slider-image'
33513                                 }
33514                             ]
33515                         },
33516                         {
33517                             tag : 'div',
33518                             cls : 'roo-document-slider-next',
33519                             cn : [
33520                                 {
33521                                     tag : 'i',
33522                                     cls : 'fa fa-chevron-right'
33523                                 }
33524                             ]
33525                         }
33526                     ]
33527                 }
33528             ]
33529         };
33530         
33531         return cfg;
33532     },
33533     
33534     initEvents : function()
33535     {
33536         this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33537         this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33538         
33539         this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33540         this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33541         
33542         this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33543         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33544         
33545         this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33546         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33547         
33548         this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33549         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33550         
33551         this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33552         this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33553         
33554         this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33555         this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33556         
33557         this.thumbEl.on('click', this.onClick, this);
33558         
33559         this.prevIndicator.on('click', this.prev, this);
33560         
33561         this.nextIndicator.on('click', this.next, this);
33562         
33563     },
33564     
33565     initial : function()
33566     {
33567         if(this.files.length){
33568             this.indicator = 1;
33569             this.update()
33570         }
33571         
33572         this.fireEvent('initial', this);
33573     },
33574     
33575     update : function()
33576     {
33577         this.imageEl.attr('src', this.files[this.indicator - 1]);
33578         
33579         this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33580         
33581         this.prevIndicator.show();
33582         
33583         if(this.indicator == 1){
33584             this.prevIndicator.hide();
33585         }
33586         
33587         this.nextIndicator.show();
33588         
33589         if(this.indicator == this.files.length){
33590             this.nextIndicator.hide();
33591         }
33592         
33593         this.thumbEl.scrollTo('top');
33594         
33595         this.fireEvent('update', this);
33596     },
33597     
33598     onClick : function(e)
33599     {
33600         e.preventDefault();
33601         
33602         this.fireEvent('click', this);
33603     },
33604     
33605     prev : function(e)
33606     {
33607         e.preventDefault();
33608         
33609         this.indicator = Math.max(1, this.indicator - 1);
33610         
33611         this.update();
33612     },
33613     
33614     next : function(e)
33615     {
33616         e.preventDefault();
33617         
33618         this.indicator = Math.min(this.files.length, this.indicator + 1);
33619         
33620         this.update();
33621     }
33622 });
33623 /*
33624  * - LGPL
33625  *
33626  * RadioSet
33627  *
33628  *
33629  */
33630
33631 /**
33632  * @class Roo.bootstrap.RadioSet
33633  * @extends Roo.bootstrap.Input
33634  * Bootstrap RadioSet class
33635  * @cfg {String} indicatorpos (left|right) default left
33636  * @cfg {Boolean} inline (true|false) inline the element (default true)
33637  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33638  * @constructor
33639  * Create a new RadioSet
33640  * @param {Object} config The config object
33641  */
33642
33643 Roo.bootstrap.RadioSet = function(config){
33644     
33645     Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33646     
33647     this.radioes = [];
33648     
33649     Roo.bootstrap.RadioSet.register(this);
33650     
33651     this.addEvents({
33652         /**
33653         * @event check
33654         * Fires when the element is checked or unchecked.
33655         * @param {Roo.bootstrap.RadioSet} this This radio
33656         * @param {Roo.bootstrap.Radio} item The checked item
33657         */
33658        check : true,
33659        /**
33660         * @event click
33661         * Fires when the element is click.
33662         * @param {Roo.bootstrap.RadioSet} this This radio set
33663         * @param {Roo.bootstrap.Radio} item The checked item
33664         * @param {Roo.EventObject} e The event object
33665         */
33666        click : true
33667     });
33668     
33669 };
33670
33671 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
33672
33673     radioes : false,
33674     
33675     inline : true,
33676     
33677     weight : '',
33678     
33679     indicatorpos : 'left',
33680     
33681     getAutoCreate : function()
33682     {
33683         var label = {
33684             tag : 'label',
33685             cls : 'roo-radio-set-label',
33686             cn : [
33687                 {
33688                     tag : 'span',
33689                     html : this.fieldLabel
33690                 }
33691             ]
33692         };
33693         
33694         if(this.indicatorpos == 'left'){
33695             label.cn.unshift({
33696                 tag : 'i',
33697                 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33698                 tooltip : 'This field is required'
33699             });
33700         } else {
33701             label.cn.push({
33702                 tag : 'i',
33703                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33704                 tooltip : 'This field is required'
33705             });
33706         }
33707         
33708         var items = {
33709             tag : 'div',
33710             cls : 'roo-radio-set-items'
33711         };
33712         
33713         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33714         
33715         if (align === 'left' && this.fieldLabel.length) {
33716             
33717             items = {
33718                 cls : "roo-radio-set-right", 
33719                 cn: [
33720                     items
33721                 ]
33722             };
33723             
33724             if(this.labelWidth > 12){
33725                 label.style = "width: " + this.labelWidth + 'px';
33726             }
33727             
33728             if(this.labelWidth < 13 && this.labelmd == 0){
33729                 this.labelmd = this.labelWidth;
33730             }
33731             
33732             if(this.labellg > 0){
33733                 label.cls += ' col-lg-' + this.labellg;
33734                 items.cls += ' col-lg-' + (12 - this.labellg);
33735             }
33736             
33737             if(this.labelmd > 0){
33738                 label.cls += ' col-md-' + this.labelmd;
33739                 items.cls += ' col-md-' + (12 - this.labelmd);
33740             }
33741             
33742             if(this.labelsm > 0){
33743                 label.cls += ' col-sm-' + this.labelsm;
33744                 items.cls += ' col-sm-' + (12 - this.labelsm);
33745             }
33746             
33747             if(this.labelxs > 0){
33748                 label.cls += ' col-xs-' + this.labelxs;
33749                 items.cls += ' col-xs-' + (12 - this.labelxs);
33750             }
33751         }
33752         
33753         var cfg = {
33754             tag : 'div',
33755             cls : 'roo-radio-set',
33756             cn : [
33757                 {
33758                     tag : 'input',
33759                     cls : 'roo-radio-set-input',
33760                     type : 'hidden',
33761                     name : this.name,
33762                     value : this.value ? this.value :  ''
33763                 },
33764                 label,
33765                 items
33766             ]
33767         };
33768         
33769         if(this.weight.length){
33770             cfg.cls += ' roo-radio-' + this.weight;
33771         }
33772         
33773         if(this.inline) {
33774             cfg.cls += ' roo-radio-set-inline';
33775         }
33776         
33777         var settings=this;
33778         ['xs','sm','md','lg'].map(function(size){
33779             if (settings[size]) {
33780                 cfg.cls += ' col-' + size + '-' + settings[size];
33781             }
33782         });
33783         
33784         return cfg;
33785         
33786     },
33787
33788     initEvents : function()
33789     {
33790         this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33791         this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33792         
33793         if(!this.fieldLabel.length){
33794             this.labelEl.hide();
33795         }
33796         
33797         this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33798         this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33799         
33800         this.indicator = this.indicatorEl();
33801         
33802         if(this.indicator){
33803             this.indicator.addClass('invisible');
33804         }
33805         
33806         this.originalValue = this.getValue();
33807         
33808     },
33809     
33810     inputEl: function ()
33811     {
33812         return this.el.select('.roo-radio-set-input', true).first();
33813     },
33814     
33815     getChildContainer : function()
33816     {
33817         return this.itemsEl;
33818     },
33819     
33820     register : function(item)
33821     {
33822         this.radioes.push(item);
33823         
33824     },
33825     
33826     validate : function()
33827     {   
33828         if(this.getVisibilityEl().hasClass('hidden')){
33829             return true;
33830         }
33831         
33832         var valid = false;
33833         
33834         Roo.each(this.radioes, function(i){
33835             if(!i.checked){
33836                 return;
33837             }
33838             
33839             valid = true;
33840             return false;
33841         });
33842         
33843         if(this.allowBlank) {
33844             return true;
33845         }
33846         
33847         if(this.disabled || valid){
33848             this.markValid();
33849             return true;
33850         }
33851         
33852         this.markInvalid();
33853         return false;
33854         
33855     },
33856     
33857     markValid : function()
33858     {
33859         if(this.labelEl.isVisible(true)){
33860             this.indicatorEl().removeClass('visible');
33861             this.indicatorEl().addClass('invisible');
33862         }
33863         
33864         this.el.removeClass([this.invalidClass, this.validClass]);
33865         this.el.addClass(this.validClass);
33866         
33867         this.fireEvent('valid', this);
33868     },
33869     
33870     markInvalid : function(msg)
33871     {
33872         if(this.allowBlank || this.disabled){
33873             return;
33874         }
33875         
33876         if(this.labelEl.isVisible(true)){
33877             this.indicatorEl().removeClass('invisible');
33878             this.indicatorEl().addClass('visible');
33879         }
33880         
33881         this.el.removeClass([this.invalidClass, this.validClass]);
33882         this.el.addClass(this.invalidClass);
33883         
33884         this.fireEvent('invalid', this, msg);
33885         
33886     },
33887     
33888     setValue : function(v, suppressEvent)
33889     {   
33890         if(this.value === v){
33891             return;
33892         }
33893         
33894         this.value = v;
33895         
33896         if(this.rendered){
33897             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33898         }
33899         
33900         Roo.each(this.radioes, function(i){
33901             i.checked = false;
33902             i.el.removeClass('checked');
33903         });
33904         
33905         Roo.each(this.radioes, function(i){
33906             
33907             if(i.value === v || i.value.toString() === v.toString()){
33908                 i.checked = true;
33909                 i.el.addClass('checked');
33910                 
33911                 if(suppressEvent !== true){
33912                     this.fireEvent('check', this, i);
33913                 }
33914                 
33915                 return false;
33916             }
33917             
33918         }, this);
33919         
33920         this.validate();
33921     },
33922     
33923     clearInvalid : function(){
33924         
33925         if(!this.el || this.preventMark){
33926             return;
33927         }
33928         
33929         this.el.removeClass([this.invalidClass]);
33930         
33931         this.fireEvent('valid', this);
33932     }
33933     
33934 });
33935
33936 Roo.apply(Roo.bootstrap.RadioSet, {
33937     
33938     groups: {},
33939     
33940     register : function(set)
33941     {
33942         this.groups[set.name] = set;
33943     },
33944     
33945     get: function(name) 
33946     {
33947         if (typeof(this.groups[name]) == 'undefined') {
33948             return false;
33949         }
33950         
33951         return this.groups[name] ;
33952     }
33953     
33954 });
33955 /*
33956  * Based on:
33957  * Ext JS Library 1.1.1
33958  * Copyright(c) 2006-2007, Ext JS, LLC.
33959  *
33960  * Originally Released Under LGPL - original licence link has changed is not relivant.
33961  *
33962  * Fork - LGPL
33963  * <script type="text/javascript">
33964  */
33965
33966
33967 /**
33968  * @class Roo.bootstrap.SplitBar
33969  * @extends Roo.util.Observable
33970  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33971  * <br><br>
33972  * Usage:
33973  * <pre><code>
33974 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33975                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33976 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33977 split.minSize = 100;
33978 split.maxSize = 600;
33979 split.animate = true;
33980 split.on('moved', splitterMoved);
33981 </code></pre>
33982  * @constructor
33983  * Create a new SplitBar
33984  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
33985  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
33986  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33987  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
33988                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33989                         position of the SplitBar).
33990  */
33991 Roo.bootstrap.SplitBar = function(cfg){
33992     
33993     /** @private */
33994     
33995     //{
33996     //  dragElement : elm
33997     //  resizingElement: el,
33998         // optional..
33999     //    orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34000     //    placement : Roo.bootstrap.SplitBar.LEFT  ,
34001         // existingProxy ???
34002     //}
34003     
34004     this.el = Roo.get(cfg.dragElement, true);
34005     this.el.dom.unselectable = "on";
34006     /** @private */
34007     this.resizingEl = Roo.get(cfg.resizingElement, true);
34008
34009     /**
34010      * @private
34011      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34012      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34013      * @type Number
34014      */
34015     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34016     
34017     /**
34018      * The minimum size of the resizing element. (Defaults to 0)
34019      * @type Number
34020      */
34021     this.minSize = 0;
34022     
34023     /**
34024      * The maximum size of the resizing element. (Defaults to 2000)
34025      * @type Number
34026      */
34027     this.maxSize = 2000;
34028     
34029     /**
34030      * Whether to animate the transition to the new size
34031      * @type Boolean
34032      */
34033     this.animate = false;
34034     
34035     /**
34036      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34037      * @type Boolean
34038      */
34039     this.useShim = false;
34040     
34041     /** @private */
34042     this.shim = null;
34043     
34044     if(!cfg.existingProxy){
34045         /** @private */
34046         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34047     }else{
34048         this.proxy = Roo.get(cfg.existingProxy).dom;
34049     }
34050     /** @private */
34051     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34052     
34053     /** @private */
34054     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34055     
34056     /** @private */
34057     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34058     
34059     /** @private */
34060     this.dragSpecs = {};
34061     
34062     /**
34063      * @private The adapter to use to positon and resize elements
34064      */
34065     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34066     this.adapter.init(this);
34067     
34068     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34069         /** @private */
34070         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34071         this.el.addClass("roo-splitbar-h");
34072     }else{
34073         /** @private */
34074         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34075         this.el.addClass("roo-splitbar-v");
34076     }
34077     
34078     this.addEvents({
34079         /**
34080          * @event resize
34081          * Fires when the splitter is moved (alias for {@link #event-moved})
34082          * @param {Roo.bootstrap.SplitBar} this
34083          * @param {Number} newSize the new width or height
34084          */
34085         "resize" : true,
34086         /**
34087          * @event moved
34088          * Fires when the splitter is moved
34089          * @param {Roo.bootstrap.SplitBar} this
34090          * @param {Number} newSize the new width or height
34091          */
34092         "moved" : true,
34093         /**
34094          * @event beforeresize
34095          * Fires before the splitter is dragged
34096          * @param {Roo.bootstrap.SplitBar} this
34097          */
34098         "beforeresize" : true,
34099
34100         "beforeapply" : true
34101     });
34102
34103     Roo.util.Observable.call(this);
34104 };
34105
34106 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34107     onStartProxyDrag : function(x, y){
34108         this.fireEvent("beforeresize", this);
34109         if(!this.overlay){
34110             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "roo-drag-overlay", html: "&#160;"}, true);
34111             o.unselectable();
34112             o.enableDisplayMode("block");
34113             // all splitbars share the same overlay
34114             Roo.bootstrap.SplitBar.prototype.overlay = o;
34115         }
34116         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34117         this.overlay.show();
34118         Roo.get(this.proxy).setDisplayed("block");
34119         var size = this.adapter.getElementSize(this);
34120         this.activeMinSize = this.getMinimumSize();;
34121         this.activeMaxSize = this.getMaximumSize();;
34122         var c1 = size - this.activeMinSize;
34123         var c2 = Math.max(this.activeMaxSize - size, 0);
34124         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34125             this.dd.resetConstraints();
34126             this.dd.setXConstraint(
34127                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
34128                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34129             );
34130             this.dd.setYConstraint(0, 0);
34131         }else{
34132             this.dd.resetConstraints();
34133             this.dd.setXConstraint(0, 0);
34134             this.dd.setYConstraint(
34135                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
34136                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34137             );
34138          }
34139         this.dragSpecs.startSize = size;
34140         this.dragSpecs.startPoint = [x, y];
34141         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34142     },
34143     
34144     /** 
34145      * @private Called after the drag operation by the DDProxy
34146      */
34147     onEndProxyDrag : function(e){
34148         Roo.get(this.proxy).setDisplayed(false);
34149         var endPoint = Roo.lib.Event.getXY(e);
34150         if(this.overlay){
34151             this.overlay.hide();
34152         }
34153         var newSize;
34154         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34155             newSize = this.dragSpecs.startSize + 
34156                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34157                     endPoint[0] - this.dragSpecs.startPoint[0] :
34158                     this.dragSpecs.startPoint[0] - endPoint[0]
34159                 );
34160         }else{
34161             newSize = this.dragSpecs.startSize + 
34162                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34163                     endPoint[1] - this.dragSpecs.startPoint[1] :
34164                     this.dragSpecs.startPoint[1] - endPoint[1]
34165                 );
34166         }
34167         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34168         if(newSize != this.dragSpecs.startSize){
34169             if(this.fireEvent('beforeapply', this, newSize) !== false){
34170                 this.adapter.setElementSize(this, newSize);
34171                 this.fireEvent("moved", this, newSize);
34172                 this.fireEvent("resize", this, newSize);
34173             }
34174         }
34175     },
34176     
34177     /**
34178      * Get the adapter this SplitBar uses
34179      * @return The adapter object
34180      */
34181     getAdapter : function(){
34182         return this.adapter;
34183     },
34184     
34185     /**
34186      * Set the adapter this SplitBar uses
34187      * @param {Object} adapter A SplitBar adapter object
34188      */
34189     setAdapter : function(adapter){
34190         this.adapter = adapter;
34191         this.adapter.init(this);
34192     },
34193     
34194     /**
34195      * Gets the minimum size for the resizing element
34196      * @return {Number} The minimum size
34197      */
34198     getMinimumSize : function(){
34199         return this.minSize;
34200     },
34201     
34202     /**
34203      * Sets the minimum size for the resizing element
34204      * @param {Number} minSize The minimum size
34205      */
34206     setMinimumSize : function(minSize){
34207         this.minSize = minSize;
34208     },
34209     
34210     /**
34211      * Gets the maximum size for the resizing element
34212      * @return {Number} The maximum size
34213      */
34214     getMaximumSize : function(){
34215         return this.maxSize;
34216     },
34217     
34218     /**
34219      * Sets the maximum size for the resizing element
34220      * @param {Number} maxSize The maximum size
34221      */
34222     setMaximumSize : function(maxSize){
34223         this.maxSize = maxSize;
34224     },
34225     
34226     /**
34227      * Sets the initialize size for the resizing element
34228      * @param {Number} size The initial size
34229      */
34230     setCurrentSize : function(size){
34231         var oldAnimate = this.animate;
34232         this.animate = false;
34233         this.adapter.setElementSize(this, size);
34234         this.animate = oldAnimate;
34235     },
34236     
34237     /**
34238      * Destroy this splitbar. 
34239      * @param {Boolean} removeEl True to remove the element
34240      */
34241     destroy : function(removeEl){
34242         if(this.shim){
34243             this.shim.remove();
34244         }
34245         this.dd.unreg();
34246         this.proxy.parentNode.removeChild(this.proxy);
34247         if(removeEl){
34248             this.el.remove();
34249         }
34250     }
34251 });
34252
34253 /**
34254  * @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.
34255  */
34256 Roo.bootstrap.SplitBar.createProxy = function(dir){
34257     var proxy = new Roo.Element(document.createElement("div"));
34258     proxy.unselectable();
34259     var cls = 'roo-splitbar-proxy';
34260     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34261     document.body.appendChild(proxy.dom);
34262     return proxy.dom;
34263 };
34264
34265 /** 
34266  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34267  * Default Adapter. It assumes the splitter and resizing element are not positioned
34268  * elements and only gets/sets the width of the element. Generally used for table based layouts.
34269  */
34270 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34271 };
34272
34273 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34274     // do nothing for now
34275     init : function(s){
34276     
34277     },
34278     /**
34279      * Called before drag operations to get the current size of the resizing element. 
34280      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34281      */
34282      getElementSize : function(s){
34283         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34284             return s.resizingEl.getWidth();
34285         }else{
34286             return s.resizingEl.getHeight();
34287         }
34288     },
34289     
34290     /**
34291      * Called after drag operations to set the size of the resizing element.
34292      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34293      * @param {Number} newSize The new size to set
34294      * @param {Function} onComplete A function to be invoked when resizing is complete
34295      */
34296     setElementSize : function(s, newSize, onComplete){
34297         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34298             if(!s.animate){
34299                 s.resizingEl.setWidth(newSize);
34300                 if(onComplete){
34301                     onComplete(s, newSize);
34302                 }
34303             }else{
34304                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34305             }
34306         }else{
34307             
34308             if(!s.animate){
34309                 s.resizingEl.setHeight(newSize);
34310                 if(onComplete){
34311                     onComplete(s, newSize);
34312                 }
34313             }else{
34314                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34315             }
34316         }
34317     }
34318 };
34319
34320 /** 
34321  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34322  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34323  * Adapter that  moves the splitter element to align with the resized sizing element. 
34324  * Used with an absolute positioned SplitBar.
34325  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34326  * document.body, make sure you assign an id to the body element.
34327  */
34328 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34329     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34330     this.container = Roo.get(container);
34331 };
34332
34333 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34334     init : function(s){
34335         this.basic.init(s);
34336     },
34337     
34338     getElementSize : function(s){
34339         return this.basic.getElementSize(s);
34340     },
34341     
34342     setElementSize : function(s, newSize, onComplete){
34343         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34344     },
34345     
34346     moveSplitter : function(s){
34347         var yes = Roo.bootstrap.SplitBar;
34348         switch(s.placement){
34349             case yes.LEFT:
34350                 s.el.setX(s.resizingEl.getRight());
34351                 break;
34352             case yes.RIGHT:
34353                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34354                 break;
34355             case yes.TOP:
34356                 s.el.setY(s.resizingEl.getBottom());
34357                 break;
34358             case yes.BOTTOM:
34359                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34360                 break;
34361         }
34362     }
34363 };
34364
34365 /**
34366  * Orientation constant - Create a vertical SplitBar
34367  * @static
34368  * @type Number
34369  */
34370 Roo.bootstrap.SplitBar.VERTICAL = 1;
34371
34372 /**
34373  * Orientation constant - Create a horizontal SplitBar
34374  * @static
34375  * @type Number
34376  */
34377 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34378
34379 /**
34380  * Placement constant - The resizing element is to the left of the splitter element
34381  * @static
34382  * @type Number
34383  */
34384 Roo.bootstrap.SplitBar.LEFT = 1;
34385
34386 /**
34387  * Placement constant - The resizing element is to the right of the splitter element
34388  * @static
34389  * @type Number
34390  */
34391 Roo.bootstrap.SplitBar.RIGHT = 2;
34392
34393 /**
34394  * Placement constant - The resizing element is positioned above the splitter element
34395  * @static
34396  * @type Number
34397  */
34398 Roo.bootstrap.SplitBar.TOP = 3;
34399
34400 /**
34401  * Placement constant - The resizing element is positioned under splitter element
34402  * @static
34403  * @type Number
34404  */
34405 Roo.bootstrap.SplitBar.BOTTOM = 4;
34406 Roo.namespace("Roo.bootstrap.layout");/*
34407  * Based on:
34408  * Ext JS Library 1.1.1
34409  * Copyright(c) 2006-2007, Ext JS, LLC.
34410  *
34411  * Originally Released Under LGPL - original licence link has changed is not relivant.
34412  *
34413  * Fork - LGPL
34414  * <script type="text/javascript">
34415  */
34416
34417 /**
34418  * @class Roo.bootstrap.layout.Manager
34419  * @extends Roo.bootstrap.Component
34420  * Base class for layout managers.
34421  */
34422 Roo.bootstrap.layout.Manager = function(config)
34423 {
34424     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34425
34426
34427
34428
34429
34430     /** false to disable window resize monitoring @type Boolean */
34431     this.monitorWindowResize = true;
34432     this.regions = {};
34433     this.addEvents({
34434         /**
34435          * @event layout
34436          * Fires when a layout is performed.
34437          * @param {Roo.LayoutManager} this
34438          */
34439         "layout" : true,
34440         /**
34441          * @event regionresized
34442          * Fires when the user resizes a region.
34443          * @param {Roo.LayoutRegion} region The resized region
34444          * @param {Number} newSize The new size (width for east/west, height for north/south)
34445          */
34446         "regionresized" : true,
34447         /**
34448          * @event regioncollapsed
34449          * Fires when a region is collapsed.
34450          * @param {Roo.LayoutRegion} region The collapsed region
34451          */
34452         "regioncollapsed" : true,
34453         /**
34454          * @event regionexpanded
34455          * Fires when a region is expanded.
34456          * @param {Roo.LayoutRegion} region The expanded region
34457          */
34458         "regionexpanded" : true
34459     });
34460     this.updating = false;
34461
34462     if (config.el) {
34463         this.el = Roo.get(config.el);
34464         this.initEvents();
34465     }
34466
34467 };
34468
34469 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34470
34471
34472     regions : null,
34473
34474     monitorWindowResize : true,
34475
34476
34477     updating : false,
34478
34479
34480     onRender : function(ct, position)
34481     {
34482         if(!this.el){
34483             this.el = Roo.get(ct);
34484             this.initEvents();
34485         }
34486         //this.fireEvent('render',this);
34487     },
34488
34489
34490     initEvents: function()
34491     {
34492
34493
34494         // ie scrollbar fix
34495         if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34496             document.body.scroll = "no";
34497         }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34498             this.el.position('relative');
34499         }
34500         this.id = this.el.id;
34501         this.el.addClass("roo-layout-container");
34502         Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34503         if(this.el.dom != document.body ) {
34504             this.el.on('resize', this.layout,this);
34505             this.el.on('show', this.layout,this);
34506         }
34507
34508     },
34509
34510     /**
34511      * Returns true if this layout is currently being updated
34512      * @return {Boolean}
34513      */
34514     isUpdating : function(){
34515         return this.updating;
34516     },
34517
34518     /**
34519      * Suspend the LayoutManager from doing auto-layouts while
34520      * making multiple add or remove calls
34521      */
34522     beginUpdate : function(){
34523         this.updating = true;
34524     },
34525
34526     /**
34527      * Restore auto-layouts and optionally disable the manager from performing a layout
34528      * @param {Boolean} noLayout true to disable a layout update
34529      */
34530     endUpdate : function(noLayout){
34531         this.updating = false;
34532         if(!noLayout){
34533             this.layout();
34534         }
34535     },
34536
34537     layout: function(){
34538         // abstract...
34539     },
34540
34541     onRegionResized : function(region, newSize){
34542         this.fireEvent("regionresized", region, newSize);
34543         this.layout();
34544     },
34545
34546     onRegionCollapsed : function(region){
34547         this.fireEvent("regioncollapsed", region);
34548     },
34549
34550     onRegionExpanded : function(region){
34551         this.fireEvent("regionexpanded", region);
34552     },
34553
34554     /**
34555      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34556      * performs box-model adjustments.
34557      * @return {Object} The size as an object {width: (the width), height: (the height)}
34558      */
34559     getViewSize : function()
34560     {
34561         var size;
34562         if(this.el.dom != document.body){
34563             size = this.el.getSize();
34564         }else{
34565             size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34566         }
34567         size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34568         size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34569         return size;
34570     },
34571
34572     /**
34573      * Returns the Element this layout is bound to.
34574      * @return {Roo.Element}
34575      */
34576     getEl : function(){
34577         return this.el;
34578     },
34579
34580     /**
34581      * Returns the specified region.
34582      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34583      * @return {Roo.LayoutRegion}
34584      */
34585     getRegion : function(target){
34586         return this.regions[target.toLowerCase()];
34587     },
34588
34589     onWindowResize : function(){
34590         if(this.monitorWindowResize){
34591             this.layout();
34592         }
34593     }
34594 });
34595 /*
34596  * Based on:
34597  * Ext JS Library 1.1.1
34598  * Copyright(c) 2006-2007, Ext JS, LLC.
34599  *
34600  * Originally Released Under LGPL - original licence link has changed is not relivant.
34601  *
34602  * Fork - LGPL
34603  * <script type="text/javascript">
34604  */
34605 /**
34606  * @class Roo.bootstrap.layout.Border
34607  * @extends Roo.bootstrap.layout.Manager
34608  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34609  * please see: examples/bootstrap/nested.html<br><br>
34610  
34611 <b>The container the layout is rendered into can be either the body element or any other element.
34612 If it is not the body element, the container needs to either be an absolute positioned element,
34613 or you will need to add "position:relative" to the css of the container.  You will also need to specify
34614 the container size if it is not the body element.</b>
34615
34616 * @constructor
34617 * Create a new Border
34618 * @param {Object} config Configuration options
34619  */
34620 Roo.bootstrap.layout.Border = function(config){
34621     config = config || {};
34622     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34623     
34624     
34625     
34626     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34627         if(config[region]){
34628             config[region].region = region;
34629             this.addRegion(config[region]);
34630         }
34631     },this);
34632     
34633 };
34634
34635 Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
34636
34637 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34638     /**
34639      * Creates and adds a new region if it doesn't already exist.
34640      * @param {String} target The target region key (north, south, east, west or center).
34641      * @param {Object} config The regions config object
34642      * @return {BorderLayoutRegion} The new region
34643      */
34644     addRegion : function(config)
34645     {
34646         if(!this.regions[config.region]){
34647             var r = this.factory(config);
34648             this.bindRegion(r);
34649         }
34650         return this.regions[config.region];
34651     },
34652
34653     // private (kinda)
34654     bindRegion : function(r){
34655         this.regions[r.config.region] = r;
34656         
34657         r.on("visibilitychange",    this.layout, this);
34658         r.on("paneladded",          this.layout, this);
34659         r.on("panelremoved",        this.layout, this);
34660         r.on("invalidated",         this.layout, this);
34661         r.on("resized",             this.onRegionResized, this);
34662         r.on("collapsed",           this.onRegionCollapsed, this);
34663         r.on("expanded",            this.onRegionExpanded, this);
34664     },
34665
34666     /**
34667      * Performs a layout update.
34668      */
34669     layout : function()
34670     {
34671         if(this.updating) {
34672             return;
34673         }
34674         
34675         // render all the rebions if they have not been done alreayd?
34676         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34677             if(this.regions[region] && !this.regions[region].bodyEl){
34678                 this.regions[region].onRender(this.el)
34679             }
34680         },this);
34681         
34682         var size = this.getViewSize();
34683         var w = size.width;
34684         var h = size.height;
34685         var centerW = w;
34686         var centerH = h;
34687         var centerY = 0;
34688         var centerX = 0;
34689         //var x = 0, y = 0;
34690
34691         var rs = this.regions;
34692         var north = rs["north"];
34693         var south = rs["south"]; 
34694         var west = rs["west"];
34695         var east = rs["east"];
34696         var center = rs["center"];
34697         //if(this.hideOnLayout){ // not supported anymore
34698             //c.el.setStyle("display", "none");
34699         //}
34700         if(north && north.isVisible()){
34701             var b = north.getBox();
34702             var m = north.getMargins();
34703             b.width = w - (m.left+m.right);
34704             b.x = m.left;
34705             b.y = m.top;
34706             centerY = b.height + b.y + m.bottom;
34707             centerH -= centerY;
34708             north.updateBox(this.safeBox(b));
34709         }
34710         if(south && south.isVisible()){
34711             var b = south.getBox();
34712             var m = south.getMargins();
34713             b.width = w - (m.left+m.right);
34714             b.x = m.left;
34715             var totalHeight = (b.height + m.top + m.bottom);
34716             b.y = h - totalHeight + m.top;
34717             centerH -= totalHeight;
34718             south.updateBox(this.safeBox(b));
34719         }
34720         if(west && west.isVisible()){
34721             var b = west.getBox();
34722             var m = west.getMargins();
34723             b.height = centerH - (m.top+m.bottom);
34724             b.x = m.left;
34725             b.y = centerY + m.top;
34726             var totalWidth = (b.width + m.left + m.right);
34727             centerX += totalWidth;
34728             centerW -= totalWidth;
34729             west.updateBox(this.safeBox(b));
34730         }
34731         if(east && east.isVisible()){
34732             var b = east.getBox();
34733             var m = east.getMargins();
34734             b.height = centerH - (m.top+m.bottom);
34735             var totalWidth = (b.width + m.left + m.right);
34736             b.x = w - totalWidth + m.left;
34737             b.y = centerY + m.top;
34738             centerW -= totalWidth;
34739             east.updateBox(this.safeBox(b));
34740         }
34741         if(center){
34742             var m = center.getMargins();
34743             var centerBox = {
34744                 x: centerX + m.left,
34745                 y: centerY + m.top,
34746                 width: centerW - (m.left+m.right),
34747                 height: centerH - (m.top+m.bottom)
34748             };
34749             //if(this.hideOnLayout){
34750                 //center.el.setStyle("display", "block");
34751             //}
34752             center.updateBox(this.safeBox(centerBox));
34753         }
34754         this.el.repaint();
34755         this.fireEvent("layout", this);
34756     },
34757
34758     // private
34759     safeBox : function(box){
34760         box.width = Math.max(0, box.width);
34761         box.height = Math.max(0, box.height);
34762         return box;
34763     },
34764
34765     /**
34766      * Adds a ContentPanel (or subclass) to this layout.
34767      * @param {String} target The target region key (north, south, east, west or center).
34768      * @param {Roo.ContentPanel} panel The panel to add
34769      * @return {Roo.ContentPanel} The added panel
34770      */
34771     add : function(target, panel){
34772          
34773         target = target.toLowerCase();
34774         return this.regions[target].add(panel);
34775     },
34776
34777     /**
34778      * Remove a ContentPanel (or subclass) to this layout.
34779      * @param {String} target The target region key (north, south, east, west or center).
34780      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34781      * @return {Roo.ContentPanel} The removed panel
34782      */
34783     remove : function(target, panel){
34784         target = target.toLowerCase();
34785         return this.regions[target].remove(panel);
34786     },
34787
34788     /**
34789      * Searches all regions for a panel with the specified id
34790      * @param {String} panelId
34791      * @return {Roo.ContentPanel} The panel or null if it wasn't found
34792      */
34793     findPanel : function(panelId){
34794         var rs = this.regions;
34795         for(var target in rs){
34796             if(typeof rs[target] != "function"){
34797                 var p = rs[target].getPanel(panelId);
34798                 if(p){
34799                     return p;
34800                 }
34801             }
34802         }
34803         return null;
34804     },
34805
34806     /**
34807      * Searches all regions for a panel with the specified id and activates (shows) it.
34808      * @param {String/ContentPanel} panelId The panels id or the panel itself
34809      * @return {Roo.ContentPanel} The shown panel or null
34810      */
34811     showPanel : function(panelId) {
34812       var rs = this.regions;
34813       for(var target in rs){
34814          var r = rs[target];
34815          if(typeof r != "function"){
34816             if(r.hasPanel(panelId)){
34817                return r.showPanel(panelId);
34818             }
34819          }
34820       }
34821       return null;
34822    },
34823
34824    /**
34825      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34826      * @param {Roo.state.Provider} provider (optional) An alternate state provider
34827      */
34828    /*
34829     restoreState : function(provider){
34830         if(!provider){
34831             provider = Roo.state.Manager;
34832         }
34833         var sm = new Roo.LayoutStateManager();
34834         sm.init(this, provider);
34835     },
34836 */
34837  
34838  
34839     /**
34840      * Adds a xtype elements to the layout.
34841      * <pre><code>
34842
34843 layout.addxtype({
34844        xtype : 'ContentPanel',
34845        region: 'west',
34846        items: [ .... ]
34847    }
34848 );
34849
34850 layout.addxtype({
34851         xtype : 'NestedLayoutPanel',
34852         region: 'west',
34853         layout: {
34854            center: { },
34855            west: { }   
34856         },
34857         items : [ ... list of content panels or nested layout panels.. ]
34858    }
34859 );
34860 </code></pre>
34861      * @param {Object} cfg Xtype definition of item to add.
34862      */
34863     addxtype : function(cfg)
34864     {
34865         // basically accepts a pannel...
34866         // can accept a layout region..!?!?
34867         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34868         
34869         
34870         // theory?  children can only be panels??
34871         
34872         //if (!cfg.xtype.match(/Panel$/)) {
34873         //    return false;
34874         //}
34875         var ret = false;
34876         
34877         if (typeof(cfg.region) == 'undefined') {
34878             Roo.log("Failed to add Panel, region was not set");
34879             Roo.log(cfg);
34880             return false;
34881         }
34882         var region = cfg.region;
34883         delete cfg.region;
34884         
34885           
34886         var xitems = [];
34887         if (cfg.items) {
34888             xitems = cfg.items;
34889             delete cfg.items;
34890         }
34891         var nb = false;
34892         
34893         switch(cfg.xtype) 
34894         {
34895             case 'Content':  // ContentPanel (el, cfg)
34896             case 'Scroll':  // ContentPanel (el, cfg)
34897             case 'View': 
34898                 cfg.autoCreate = true;
34899                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34900                 //} else {
34901                 //    var el = this.el.createChild();
34902                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34903                 //}
34904                 
34905                 this.add(region, ret);
34906                 break;
34907             
34908             /*
34909             case 'TreePanel': // our new panel!
34910                 cfg.el = this.el.createChild();
34911                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34912                 this.add(region, ret);
34913                 break;
34914             */
34915             
34916             case 'Nest': 
34917                 // create a new Layout (which is  a Border Layout...
34918                 
34919                 var clayout = cfg.layout;
34920                 clayout.el  = this.el.createChild();
34921                 clayout.items   = clayout.items  || [];
34922                 
34923                 delete cfg.layout;
34924                 
34925                 // replace this exitems with the clayout ones..
34926                 xitems = clayout.items;
34927                  
34928                 // force background off if it's in center...
34929                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34930                     cfg.background = false;
34931                 }
34932                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
34933                 
34934                 
34935                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34936                 //console.log('adding nested layout panel '  + cfg.toSource());
34937                 this.add(region, ret);
34938                 nb = {}; /// find first...
34939                 break;
34940             
34941             case 'Grid':
34942                 
34943                 // needs grid and region
34944                 
34945                 //var el = this.getRegion(region).el.createChild();
34946                 /*
34947                  *var el = this.el.createChild();
34948                 // create the grid first...
34949                 cfg.grid.container = el;
34950                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34951                 */
34952                 
34953                 if (region == 'center' && this.active ) {
34954                     cfg.background = false;
34955                 }
34956                 
34957                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34958                 
34959                 this.add(region, ret);
34960                 /*
34961                 if (cfg.background) {
34962                     // render grid on panel activation (if panel background)
34963                     ret.on('activate', function(gp) {
34964                         if (!gp.grid.rendered) {
34965                     //        gp.grid.render(el);
34966                         }
34967                     });
34968                 } else {
34969                   //  cfg.grid.render(el);
34970                 }
34971                 */
34972                 break;
34973            
34974            
34975             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34976                 // it was the old xcomponent building that caused this before.
34977                 // espeically if border is the top element in the tree.
34978                 ret = this;
34979                 break; 
34980                 
34981                     
34982                 
34983                 
34984                 
34985             default:
34986                 /*
34987                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34988                     
34989                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34990                     this.add(region, ret);
34991                 } else {
34992                 */
34993                     Roo.log(cfg);
34994                     throw "Can not add '" + cfg.xtype + "' to Border";
34995                     return null;
34996              
34997                                 
34998              
34999         }
35000         this.beginUpdate();
35001         // add children..
35002         var region = '';
35003         var abn = {};
35004         Roo.each(xitems, function(i)  {
35005             region = nb && i.region ? i.region : false;
35006             
35007             var add = ret.addxtype(i);
35008            
35009             if (region) {
35010                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35011                 if (!i.background) {
35012                     abn[region] = nb[region] ;
35013                 }
35014             }
35015             
35016         });
35017         this.endUpdate();
35018
35019         // make the last non-background panel active..
35020         //if (nb) { Roo.log(abn); }
35021         if (nb) {
35022             
35023             for(var r in abn) {
35024                 region = this.getRegion(r);
35025                 if (region) {
35026                     // tried using nb[r], but it does not work..
35027                      
35028                     region.showPanel(abn[r]);
35029                    
35030                 }
35031             }
35032         }
35033         return ret;
35034         
35035     },
35036     
35037     
35038 // private
35039     factory : function(cfg)
35040     {
35041         
35042         var validRegions = Roo.bootstrap.layout.Border.regions;
35043
35044         var target = cfg.region;
35045         cfg.mgr = this;
35046         
35047         var r = Roo.bootstrap.layout;
35048         Roo.log(target);
35049         switch(target){
35050             case "north":
35051                 return new r.North(cfg);
35052             case "south":
35053                 return new r.South(cfg);
35054             case "east":
35055                 return new r.East(cfg);
35056             case "west":
35057                 return new r.West(cfg);
35058             case "center":
35059                 return new r.Center(cfg);
35060         }
35061         throw 'Layout region "'+target+'" not supported.';
35062     }
35063     
35064     
35065 });
35066  /*
35067  * Based on:
35068  * Ext JS Library 1.1.1
35069  * Copyright(c) 2006-2007, Ext JS, LLC.
35070  *
35071  * Originally Released Under LGPL - original licence link has changed is not relivant.
35072  *
35073  * Fork - LGPL
35074  * <script type="text/javascript">
35075  */
35076  
35077 /**
35078  * @class Roo.bootstrap.layout.Basic
35079  * @extends Roo.util.Observable
35080  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35081  * and does not have a titlebar, tabs or any other features. All it does is size and position 
35082  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35083  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35084  * @cfg {string}   region  the region that it inhabits..
35085  * @cfg {bool}   skipConfig skip config?
35086  * 
35087
35088  */
35089 Roo.bootstrap.layout.Basic = function(config){
35090     
35091     this.mgr = config.mgr;
35092     
35093     this.position = config.region;
35094     
35095     var skipConfig = config.skipConfig;
35096     
35097     this.events = {
35098         /**
35099          * @scope Roo.BasicLayoutRegion
35100          */
35101         
35102         /**
35103          * @event beforeremove
35104          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35105          * @param {Roo.LayoutRegion} this
35106          * @param {Roo.ContentPanel} panel The panel
35107          * @param {Object} e The cancel event object
35108          */
35109         "beforeremove" : true,
35110         /**
35111          * @event invalidated
35112          * Fires when the layout for this region is changed.
35113          * @param {Roo.LayoutRegion} this
35114          */
35115         "invalidated" : true,
35116         /**
35117          * @event visibilitychange
35118          * Fires when this region is shown or hidden 
35119          * @param {Roo.LayoutRegion} this
35120          * @param {Boolean} visibility true or false
35121          */
35122         "visibilitychange" : true,
35123         /**
35124          * @event paneladded
35125          * Fires when a panel is added. 
35126          * @param {Roo.LayoutRegion} this
35127          * @param {Roo.ContentPanel} panel The panel
35128          */
35129         "paneladded" : true,
35130         /**
35131          * @event panelremoved
35132          * Fires when a panel is removed. 
35133          * @param {Roo.LayoutRegion} this
35134          * @param {Roo.ContentPanel} panel The panel
35135          */
35136         "panelremoved" : true,
35137         /**
35138          * @event beforecollapse
35139          * Fires when this region before collapse.
35140          * @param {Roo.LayoutRegion} this
35141          */
35142         "beforecollapse" : true,
35143         /**
35144          * @event collapsed
35145          * Fires when this region is collapsed.
35146          * @param {Roo.LayoutRegion} this
35147          */
35148         "collapsed" : true,
35149         /**
35150          * @event expanded
35151          * Fires when this region is expanded.
35152          * @param {Roo.LayoutRegion} this
35153          */
35154         "expanded" : true,
35155         /**
35156          * @event slideshow
35157          * Fires when this region is slid into view.
35158          * @param {Roo.LayoutRegion} this
35159          */
35160         "slideshow" : true,
35161         /**
35162          * @event slidehide
35163          * Fires when this region slides out of view. 
35164          * @param {Roo.LayoutRegion} this
35165          */
35166         "slidehide" : true,
35167         /**
35168          * @event panelactivated
35169          * Fires when a panel is activated. 
35170          * @param {Roo.LayoutRegion} this
35171          * @param {Roo.ContentPanel} panel The activated panel
35172          */
35173         "panelactivated" : true,
35174         /**
35175          * @event resized
35176          * Fires when the user resizes this region. 
35177          * @param {Roo.LayoutRegion} this
35178          * @param {Number} newSize The new size (width for east/west, height for north/south)
35179          */
35180         "resized" : true
35181     };
35182     /** A collection of panels in this region. @type Roo.util.MixedCollection */
35183     this.panels = new Roo.util.MixedCollection();
35184     this.panels.getKey = this.getPanelId.createDelegate(this);
35185     this.box = null;
35186     this.activePanel = null;
35187     // ensure listeners are added...
35188     
35189     if (config.listeners || config.events) {
35190         Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35191             listeners : config.listeners || {},
35192             events : config.events || {}
35193         });
35194     }
35195     
35196     if(skipConfig !== true){
35197         this.applyConfig(config);
35198     }
35199 };
35200
35201 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35202 {
35203     getPanelId : function(p){
35204         return p.getId();
35205     },
35206     
35207     applyConfig : function(config){
35208         this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35209         this.config = config;
35210         
35211     },
35212     
35213     /**
35214      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
35215      * the width, for horizontal (north, south) the height.
35216      * @param {Number} newSize The new width or height
35217      */
35218     resizeTo : function(newSize){
35219         var el = this.el ? this.el :
35220                  (this.activePanel ? this.activePanel.getEl() : null);
35221         if(el){
35222             switch(this.position){
35223                 case "east":
35224                 case "west":
35225                     el.setWidth(newSize);
35226                     this.fireEvent("resized", this, newSize);
35227                 break;
35228                 case "north":
35229                 case "south":
35230                     el.setHeight(newSize);
35231                     this.fireEvent("resized", this, newSize);
35232                 break;                
35233             }
35234         }
35235     },
35236     
35237     getBox : function(){
35238         return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35239     },
35240     
35241     getMargins : function(){
35242         return this.margins;
35243     },
35244     
35245     updateBox : function(box){
35246         this.box = box;
35247         var el = this.activePanel.getEl();
35248         el.dom.style.left = box.x + "px";
35249         el.dom.style.top = box.y + "px";
35250         this.activePanel.setSize(box.width, box.height);
35251     },
35252     
35253     /**
35254      * Returns the container element for this region.
35255      * @return {Roo.Element}
35256      */
35257     getEl : function(){
35258         return this.activePanel;
35259     },
35260     
35261     /**
35262      * Returns true if this region is currently visible.
35263      * @return {Boolean}
35264      */
35265     isVisible : function(){
35266         return this.activePanel ? true : false;
35267     },
35268     
35269     setActivePanel : function(panel){
35270         panel = this.getPanel(panel);
35271         if(this.activePanel && this.activePanel != panel){
35272             this.activePanel.setActiveState(false);
35273             this.activePanel.getEl().setLeftTop(-10000,-10000);
35274         }
35275         this.activePanel = panel;
35276         panel.setActiveState(true);
35277         if(this.box){
35278             panel.setSize(this.box.width, this.box.height);
35279         }
35280         this.fireEvent("panelactivated", this, panel);
35281         this.fireEvent("invalidated");
35282     },
35283     
35284     /**
35285      * Show the specified panel.
35286      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35287      * @return {Roo.ContentPanel} The shown panel or null
35288      */
35289     showPanel : function(panel){
35290         panel = this.getPanel(panel);
35291         if(panel){
35292             this.setActivePanel(panel);
35293         }
35294         return panel;
35295     },
35296     
35297     /**
35298      * Get the active panel for this region.
35299      * @return {Roo.ContentPanel} The active panel or null
35300      */
35301     getActivePanel : function(){
35302         return this.activePanel;
35303     },
35304     
35305     /**
35306      * Add the passed ContentPanel(s)
35307      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35308      * @return {Roo.ContentPanel} The panel added (if only one was added)
35309      */
35310     add : function(panel){
35311         if(arguments.length > 1){
35312             for(var i = 0, len = arguments.length; i < len; i++) {
35313                 this.add(arguments[i]);
35314             }
35315             return null;
35316         }
35317         if(this.hasPanel(panel)){
35318             this.showPanel(panel);
35319             return panel;
35320         }
35321         var el = panel.getEl();
35322         if(el.dom.parentNode != this.mgr.el.dom){
35323             this.mgr.el.dom.appendChild(el.dom);
35324         }
35325         if(panel.setRegion){
35326             panel.setRegion(this);
35327         }
35328         this.panels.add(panel);
35329         el.setStyle("position", "absolute");
35330         if(!panel.background){
35331             this.setActivePanel(panel);
35332             if(this.config.initialSize && this.panels.getCount()==1){
35333                 this.resizeTo(this.config.initialSize);
35334             }
35335         }
35336         this.fireEvent("paneladded", this, panel);
35337         return panel;
35338     },
35339     
35340     /**
35341      * Returns true if the panel is in this region.
35342      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35343      * @return {Boolean}
35344      */
35345     hasPanel : function(panel){
35346         if(typeof panel == "object"){ // must be panel obj
35347             panel = panel.getId();
35348         }
35349         return this.getPanel(panel) ? true : false;
35350     },
35351     
35352     /**
35353      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35354      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35355      * @param {Boolean} preservePanel Overrides the config preservePanel option
35356      * @return {Roo.ContentPanel} The panel that was removed
35357      */
35358     remove : function(panel, preservePanel){
35359         panel = this.getPanel(panel);
35360         if(!panel){
35361             return null;
35362         }
35363         var e = {};
35364         this.fireEvent("beforeremove", this, panel, e);
35365         if(e.cancel === true){
35366             return null;
35367         }
35368         var panelId = panel.getId();
35369         this.panels.removeKey(panelId);
35370         return panel;
35371     },
35372     
35373     /**
35374      * Returns the panel specified or null if it's not in this region.
35375      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35376      * @return {Roo.ContentPanel}
35377      */
35378     getPanel : function(id){
35379         if(typeof id == "object"){ // must be panel obj
35380             return id;
35381         }
35382         return this.panels.get(id);
35383     },
35384     
35385     /**
35386      * Returns this regions position (north/south/east/west/center).
35387      * @return {String} 
35388      */
35389     getPosition: function(){
35390         return this.position;    
35391     }
35392 });/*
35393  * Based on:
35394  * Ext JS Library 1.1.1
35395  * Copyright(c) 2006-2007, Ext JS, LLC.
35396  *
35397  * Originally Released Under LGPL - original licence link has changed is not relivant.
35398  *
35399  * Fork - LGPL
35400  * <script type="text/javascript">
35401  */
35402  
35403 /**
35404  * @class Roo.bootstrap.layout.Region
35405  * @extends Roo.bootstrap.layout.Basic
35406  * This class represents a region in a layout manager.
35407  
35408  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35409  * @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})
35410  * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
35411  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
35412  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
35413  * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
35414  * @cfg {String}    title           The title for the region (overrides panel titles)
35415  * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
35416  * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35417  * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
35418  * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35419  * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
35420  * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35421  *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
35422  * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
35423  * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
35424  * @cfg {String}    overflow       (hidden|visible) if you have menus in the region, then you need to set this to visible.
35425
35426  * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
35427  * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
35428  * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
35429  * @cfg {Number}    width           For East/West panels
35430  * @cfg {Number}    height          For North/South panels
35431  * @cfg {Boolean}   split           To show the splitter
35432  * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
35433  * 
35434  * @cfg {string}   cls             Extra CSS classes to add to region
35435  * 
35436  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35437  * @cfg {string}   region  the region that it inhabits..
35438  *
35439
35440  * @xxxcfg {Boolean}   collapsible     DISABLED False to disable collapsing (defaults to true)
35441  * @xxxcfg {Boolean}   collapsed       DISABLED True to set the initial display to collapsed (defaults to false)
35442
35443  * @xxxcfg {String}    collapsedTitle  DISABLED Optional string message to display in the collapsed block of a north or south region
35444  * @xxxxcfg {Boolean}   floatable       DISABLED False to disable floating (defaults to true)
35445  * @xxxxcfg {Boolean}   showPin         True to show a pin button NOT SUPPORTED YET
35446  */
35447 Roo.bootstrap.layout.Region = function(config)
35448 {
35449     this.applyConfig(config);
35450
35451     var mgr = config.mgr;
35452     var pos = config.region;
35453     config.skipConfig = true;
35454     Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35455     
35456     if (mgr.el) {
35457         this.onRender(mgr.el);   
35458     }
35459      
35460     this.visible = true;
35461     this.collapsed = false;
35462     this.unrendered_panels = [];
35463 };
35464
35465 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35466
35467     position: '', // set by wrapper (eg. north/south etc..)
35468     unrendered_panels : null,  // unrendered panels.
35469     createBody : function(){
35470         /** This region's body element 
35471         * @type Roo.Element */
35472         this.bodyEl = this.el.createChild({
35473                 tag: "div",
35474                 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35475         });
35476     },
35477
35478     onRender: function(ctr, pos)
35479     {
35480         var dh = Roo.DomHelper;
35481         /** This region's container element 
35482         * @type Roo.Element */
35483         this.el = dh.append(ctr.dom, {
35484                 tag: "div",
35485                 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35486             }, true);
35487         /** This region's title element 
35488         * @type Roo.Element */
35489     
35490         this.titleEl = dh.append(this.el.dom,
35491             {
35492                     tag: "div",
35493                     unselectable: "on",
35494                     cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35495                     children:[
35496                         {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
35497                         {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35498                     ]}, true);
35499         
35500         this.titleEl.enableDisplayMode();
35501         /** This region's title text element 
35502         * @type HTMLElement */
35503         this.titleTextEl = this.titleEl.dom.firstChild;
35504         this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35505         /*
35506         this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35507         this.closeBtn.enableDisplayMode();
35508         this.closeBtn.on("click", this.closeClicked, this);
35509         this.closeBtn.hide();
35510     */
35511         this.createBody(this.config);
35512         if(this.config.hideWhenEmpty){
35513             this.hide();
35514             this.on("paneladded", this.validateVisibility, this);
35515             this.on("panelremoved", this.validateVisibility, this);
35516         }
35517         if(this.autoScroll){
35518             this.bodyEl.setStyle("overflow", "auto");
35519         }else{
35520             this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35521         }
35522         //if(c.titlebar !== false){
35523             if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35524                 this.titleEl.hide();
35525             }else{
35526                 this.titleEl.show();
35527                 if(this.config.title){
35528                     this.titleTextEl.innerHTML = this.config.title;
35529                 }
35530             }
35531         //}
35532         if(this.config.collapsed){
35533             this.collapse(true);
35534         }
35535         if(this.config.hidden){
35536             this.hide();
35537         }
35538         
35539         if (this.unrendered_panels && this.unrendered_panels.length) {
35540             for (var i =0;i< this.unrendered_panels.length; i++) {
35541                 this.add(this.unrendered_panels[i]);
35542             }
35543             this.unrendered_panels = null;
35544             
35545         }
35546         
35547     },
35548     
35549     applyConfig : function(c)
35550     {
35551         /*
35552          *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35553             var dh = Roo.DomHelper;
35554             if(c.titlebar !== false){
35555                 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35556                 this.collapseBtn.on("click", this.collapse, this);
35557                 this.collapseBtn.enableDisplayMode();
35558                 /*
35559                 if(c.showPin === true || this.showPin){
35560                     this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35561                     this.stickBtn.enableDisplayMode();
35562                     this.stickBtn.on("click", this.expand, this);
35563                     this.stickBtn.hide();
35564                 }
35565                 
35566             }
35567             */
35568             /** This region's collapsed element
35569             * @type Roo.Element */
35570             /*
35571              *
35572             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35573                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35574             ]}, true);
35575             
35576             if(c.floatable !== false){
35577                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35578                this.collapsedEl.on("click", this.collapseClick, this);
35579             }
35580
35581             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35582                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35583                    id: "message", unselectable: "on", style:{"float":"left"}});
35584                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35585              }
35586             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35587             this.expandBtn.on("click", this.expand, this);
35588             
35589         }
35590         
35591         if(this.collapseBtn){
35592             this.collapseBtn.setVisible(c.collapsible == true);
35593         }
35594         
35595         this.cmargins = c.cmargins || this.cmargins ||
35596                          (this.position == "west" || this.position == "east" ?
35597                              {top: 0, left: 2, right:2, bottom: 0} :
35598                              {top: 2, left: 0, right:0, bottom: 2});
35599         */
35600         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35601         
35602         
35603         this.bottomTabs = c.tabPosition != "top";
35604         
35605         this.autoScroll = c.autoScroll || false;
35606         
35607         
35608        
35609         
35610         this.duration = c.duration || .30;
35611         this.slideDuration = c.slideDuration || .45;
35612         this.config = c;
35613        
35614     },
35615     /**
35616      * Returns true if this region is currently visible.
35617      * @return {Boolean}
35618      */
35619     isVisible : function(){
35620         return this.visible;
35621     },
35622
35623     /**
35624      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35625      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
35626      */
35627     //setCollapsedTitle : function(title){
35628     //    title = title || "&#160;";
35629      //   if(this.collapsedTitleTextEl){
35630       //      this.collapsedTitleTextEl.innerHTML = title;
35631        // }
35632     //},
35633
35634     getBox : function(){
35635         var b;
35636       //  if(!this.collapsed){
35637             b = this.el.getBox(false, true);
35638        // }else{
35639           //  b = this.collapsedEl.getBox(false, true);
35640         //}
35641         return b;
35642     },
35643
35644     getMargins : function(){
35645         return this.margins;
35646         //return this.collapsed ? this.cmargins : this.margins;
35647     },
35648 /*
35649     highlight : function(){
35650         this.el.addClass("x-layout-panel-dragover");
35651     },
35652
35653     unhighlight : function(){
35654         this.el.removeClass("x-layout-panel-dragover");
35655     },
35656 */
35657     updateBox : function(box)
35658     {
35659         if (!this.bodyEl) {
35660             return; // not rendered yet..
35661         }
35662         
35663         this.box = box;
35664         if(!this.collapsed){
35665             this.el.dom.style.left = box.x + "px";
35666             this.el.dom.style.top = box.y + "px";
35667             this.updateBody(box.width, box.height);
35668         }else{
35669             this.collapsedEl.dom.style.left = box.x + "px";
35670             this.collapsedEl.dom.style.top = box.y + "px";
35671             this.collapsedEl.setSize(box.width, box.height);
35672         }
35673         if(this.tabs){
35674             this.tabs.autoSizeTabs();
35675         }
35676     },
35677
35678     updateBody : function(w, h)
35679     {
35680         if(w !== null){
35681             this.el.setWidth(w);
35682             w -= this.el.getBorderWidth("rl");
35683             if(this.config.adjustments){
35684                 w += this.config.adjustments[0];
35685             }
35686         }
35687         if(h !== null && h > 0){
35688             this.el.setHeight(h);
35689             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35690             h -= this.el.getBorderWidth("tb");
35691             if(this.config.adjustments){
35692                 h += this.config.adjustments[1];
35693             }
35694             this.bodyEl.setHeight(h);
35695             if(this.tabs){
35696                 h = this.tabs.syncHeight(h);
35697             }
35698         }
35699         if(this.panelSize){
35700             w = w !== null ? w : this.panelSize.width;
35701             h = h !== null ? h : this.panelSize.height;
35702         }
35703         if(this.activePanel){
35704             var el = this.activePanel.getEl();
35705             w = w !== null ? w : el.getWidth();
35706             h = h !== null ? h : el.getHeight();
35707             this.panelSize = {width: w, height: h};
35708             this.activePanel.setSize(w, h);
35709         }
35710         if(Roo.isIE && this.tabs){
35711             this.tabs.el.repaint();
35712         }
35713     },
35714
35715     /**
35716      * Returns the container element for this region.
35717      * @return {Roo.Element}
35718      */
35719     getEl : function(){
35720         return this.el;
35721     },
35722
35723     /**
35724      * Hides this region.
35725      */
35726     hide : function(){
35727         //if(!this.collapsed){
35728             this.el.dom.style.left = "-2000px";
35729             this.el.hide();
35730         //}else{
35731          //   this.collapsedEl.dom.style.left = "-2000px";
35732          //   this.collapsedEl.hide();
35733        // }
35734         this.visible = false;
35735         this.fireEvent("visibilitychange", this, false);
35736     },
35737
35738     /**
35739      * Shows this region if it was previously hidden.
35740      */
35741     show : function(){
35742         //if(!this.collapsed){
35743             this.el.show();
35744         //}else{
35745         //    this.collapsedEl.show();
35746        // }
35747         this.visible = true;
35748         this.fireEvent("visibilitychange", this, true);
35749     },
35750 /*
35751     closeClicked : function(){
35752         if(this.activePanel){
35753             this.remove(this.activePanel);
35754         }
35755     },
35756
35757     collapseClick : function(e){
35758         if(this.isSlid){
35759            e.stopPropagation();
35760            this.slideIn();
35761         }else{
35762            e.stopPropagation();
35763            this.slideOut();
35764         }
35765     },
35766 */
35767     /**
35768      * Collapses this region.
35769      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35770      */
35771     /*
35772     collapse : function(skipAnim, skipCheck = false){
35773         if(this.collapsed) {
35774             return;
35775         }
35776         
35777         if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35778             
35779             this.collapsed = true;
35780             if(this.split){
35781                 this.split.el.hide();
35782             }
35783             if(this.config.animate && skipAnim !== true){
35784                 this.fireEvent("invalidated", this);
35785                 this.animateCollapse();
35786             }else{
35787                 this.el.setLocation(-20000,-20000);
35788                 this.el.hide();
35789                 this.collapsedEl.show();
35790                 this.fireEvent("collapsed", this);
35791                 this.fireEvent("invalidated", this);
35792             }
35793         }
35794         
35795     },
35796 */
35797     animateCollapse : function(){
35798         // overridden
35799     },
35800
35801     /**
35802      * Expands this region if it was previously collapsed.
35803      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35804      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35805      */
35806     /*
35807     expand : function(e, skipAnim){
35808         if(e) {
35809             e.stopPropagation();
35810         }
35811         if(!this.collapsed || this.el.hasActiveFx()) {
35812             return;
35813         }
35814         if(this.isSlid){
35815             this.afterSlideIn();
35816             skipAnim = true;
35817         }
35818         this.collapsed = false;
35819         if(this.config.animate && skipAnim !== true){
35820             this.animateExpand();
35821         }else{
35822             this.el.show();
35823             if(this.split){
35824                 this.split.el.show();
35825             }
35826             this.collapsedEl.setLocation(-2000,-2000);
35827             this.collapsedEl.hide();
35828             this.fireEvent("invalidated", this);
35829             this.fireEvent("expanded", this);
35830         }
35831     },
35832 */
35833     animateExpand : function(){
35834         // overridden
35835     },
35836
35837     initTabs : function()
35838     {
35839         //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35840         
35841         var ts = new Roo.bootstrap.panel.Tabs({
35842                 el: this.bodyEl.dom,
35843                 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35844                 disableTooltips: this.config.disableTabTips,
35845                 toolbar : this.config.toolbar
35846             });
35847         
35848         if(this.config.hideTabs){
35849             ts.stripWrap.setDisplayed(false);
35850         }
35851         this.tabs = ts;
35852         ts.resizeTabs = this.config.resizeTabs === true;
35853         ts.minTabWidth = this.config.minTabWidth || 40;
35854         ts.maxTabWidth = this.config.maxTabWidth || 250;
35855         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35856         ts.monitorResize = false;
35857         //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35858         ts.bodyEl.addClass('roo-layout-tabs-body');
35859         this.panels.each(this.initPanelAsTab, this);
35860     },
35861
35862     initPanelAsTab : function(panel){
35863         var ti = this.tabs.addTab(
35864             panel.getEl().id,
35865             panel.getTitle(),
35866             null,
35867             this.config.closeOnTab && panel.isClosable(),
35868             panel.tpl
35869         );
35870         if(panel.tabTip !== undefined){
35871             ti.setTooltip(panel.tabTip);
35872         }
35873         ti.on("activate", function(){
35874               this.setActivePanel(panel);
35875         }, this);
35876         
35877         if(this.config.closeOnTab){
35878             ti.on("beforeclose", function(t, e){
35879                 e.cancel = true;
35880                 this.remove(panel);
35881             }, this);
35882         }
35883         
35884         panel.tabItem = ti;
35885         
35886         return ti;
35887     },
35888
35889     updatePanelTitle : function(panel, title)
35890     {
35891         if(this.activePanel == panel){
35892             this.updateTitle(title);
35893         }
35894         if(this.tabs){
35895             var ti = this.tabs.getTab(panel.getEl().id);
35896             ti.setText(title);
35897             if(panel.tabTip !== undefined){
35898                 ti.setTooltip(panel.tabTip);
35899             }
35900         }
35901     },
35902
35903     updateTitle : function(title){
35904         if(this.titleTextEl && !this.config.title){
35905             this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
35906         }
35907     },
35908
35909     setActivePanel : function(panel)
35910     {
35911         panel = this.getPanel(panel);
35912         if(this.activePanel && this.activePanel != panel){
35913             if(this.activePanel.setActiveState(false) === false){
35914                 return;
35915             }
35916         }
35917         this.activePanel = panel;
35918         panel.setActiveState(true);
35919         if(this.panelSize){
35920             panel.setSize(this.panelSize.width, this.panelSize.height);
35921         }
35922         if(this.closeBtn){
35923             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35924         }
35925         this.updateTitle(panel.getTitle());
35926         if(this.tabs){
35927             this.fireEvent("invalidated", this);
35928         }
35929         this.fireEvent("panelactivated", this, panel);
35930     },
35931
35932     /**
35933      * Shows the specified panel.
35934      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35935      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35936      */
35937     showPanel : function(panel)
35938     {
35939         panel = this.getPanel(panel);
35940         if(panel){
35941             if(this.tabs){
35942                 var tab = this.tabs.getTab(panel.getEl().id);
35943                 if(tab.isHidden()){
35944                     this.tabs.unhideTab(tab.id);
35945                 }
35946                 tab.activate();
35947             }else{
35948                 this.setActivePanel(panel);
35949             }
35950         }
35951         return panel;
35952     },
35953
35954     /**
35955      * Get the active panel for this region.
35956      * @return {Roo.ContentPanel} The active panel or null
35957      */
35958     getActivePanel : function(){
35959         return this.activePanel;
35960     },
35961
35962     validateVisibility : function(){
35963         if(this.panels.getCount() < 1){
35964             this.updateTitle("&#160;");
35965             this.closeBtn.hide();
35966             this.hide();
35967         }else{
35968             if(!this.isVisible()){
35969                 this.show();
35970             }
35971         }
35972     },
35973
35974     /**
35975      * Adds the passed ContentPanel(s) to this region.
35976      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35977      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35978      */
35979     add : function(panel)
35980     {
35981         if(arguments.length > 1){
35982             for(var i = 0, len = arguments.length; i < len; i++) {
35983                 this.add(arguments[i]);
35984             }
35985             return null;
35986         }
35987         
35988         // if we have not been rendered yet, then we can not really do much of this..
35989         if (!this.bodyEl) {
35990             this.unrendered_panels.push(panel);
35991             return panel;
35992         }
35993         
35994         
35995         
35996         
35997         if(this.hasPanel(panel)){
35998             this.showPanel(panel);
35999             return panel;
36000         }
36001         panel.setRegion(this);
36002         this.panels.add(panel);
36003        /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36004             // sinle panel - no tab...?? would it not be better to render it with the tabs,
36005             // and hide them... ???
36006             this.bodyEl.dom.appendChild(panel.getEl().dom);
36007             if(panel.background !== true){
36008                 this.setActivePanel(panel);
36009             }
36010             this.fireEvent("paneladded", this, panel);
36011             return panel;
36012         }
36013         */
36014         if(!this.tabs){
36015             this.initTabs();
36016         }else{
36017             this.initPanelAsTab(panel);
36018         }
36019         
36020         
36021         if(panel.background !== true){
36022             this.tabs.activate(panel.getEl().id);
36023         }
36024         this.fireEvent("paneladded", this, panel);
36025         return panel;
36026     },
36027
36028     /**
36029      * Hides the tab for the specified panel.
36030      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36031      */
36032     hidePanel : function(panel){
36033         if(this.tabs && (panel = this.getPanel(panel))){
36034             this.tabs.hideTab(panel.getEl().id);
36035         }
36036     },
36037
36038     /**
36039      * Unhides the tab for a previously hidden panel.
36040      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36041      */
36042     unhidePanel : function(panel){
36043         if(this.tabs && (panel = this.getPanel(panel))){
36044             this.tabs.unhideTab(panel.getEl().id);
36045         }
36046     },
36047
36048     clearPanels : function(){
36049         while(this.panels.getCount() > 0){
36050              this.remove(this.panels.first());
36051         }
36052     },
36053
36054     /**
36055      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36056      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36057      * @param {Boolean} preservePanel Overrides the config preservePanel option
36058      * @return {Roo.ContentPanel} The panel that was removed
36059      */
36060     remove : function(panel, preservePanel)
36061     {
36062         panel = this.getPanel(panel);
36063         if(!panel){
36064             return null;
36065         }
36066         var e = {};
36067         this.fireEvent("beforeremove", this, panel, e);
36068         if(e.cancel === true){
36069             return null;
36070         }
36071         preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36072         var panelId = panel.getId();
36073         this.panels.removeKey(panelId);
36074         if(preservePanel){
36075             document.body.appendChild(panel.getEl().dom);
36076         }
36077         if(this.tabs){
36078             this.tabs.removeTab(panel.getEl().id);
36079         }else if (!preservePanel){
36080             this.bodyEl.dom.removeChild(panel.getEl().dom);
36081         }
36082         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36083             var p = this.panels.first();
36084             var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36085             tempEl.appendChild(p.getEl().dom);
36086             this.bodyEl.update("");
36087             this.bodyEl.dom.appendChild(p.getEl().dom);
36088             tempEl = null;
36089             this.updateTitle(p.getTitle());
36090             this.tabs = null;
36091             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36092             this.setActivePanel(p);
36093         }
36094         panel.setRegion(null);
36095         if(this.activePanel == panel){
36096             this.activePanel = null;
36097         }
36098         if(this.config.autoDestroy !== false && preservePanel !== true){
36099             try{panel.destroy();}catch(e){}
36100         }
36101         this.fireEvent("panelremoved", this, panel);
36102         return panel;
36103     },
36104
36105     /**
36106      * Returns the TabPanel component used by this region
36107      * @return {Roo.TabPanel}
36108      */
36109     getTabs : function(){
36110         return this.tabs;
36111     },
36112
36113     createTool : function(parentEl, className){
36114         var btn = Roo.DomHelper.append(parentEl, {
36115             tag: "div",
36116             cls: "x-layout-tools-button",
36117             children: [ {
36118                 tag: "div",
36119                 cls: "roo-layout-tools-button-inner " + className,
36120                 html: "&#160;"
36121             }]
36122         }, true);
36123         btn.addClassOnOver("roo-layout-tools-button-over");
36124         return btn;
36125     }
36126 });/*
36127  * Based on:
36128  * Ext JS Library 1.1.1
36129  * Copyright(c) 2006-2007, Ext JS, LLC.
36130  *
36131  * Originally Released Under LGPL - original licence link has changed is not relivant.
36132  *
36133  * Fork - LGPL
36134  * <script type="text/javascript">
36135  */
36136  
36137
36138
36139 /**
36140  * @class Roo.SplitLayoutRegion
36141  * @extends Roo.LayoutRegion
36142  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36143  */
36144 Roo.bootstrap.layout.Split = function(config){
36145     this.cursor = config.cursor;
36146     Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36147 };
36148
36149 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36150 {
36151     splitTip : "Drag to resize.",
36152     collapsibleSplitTip : "Drag to resize. Double click to hide.",
36153     useSplitTips : false,
36154
36155     applyConfig : function(config){
36156         Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36157     },
36158     
36159     onRender : function(ctr,pos) {
36160         
36161         Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36162         if(!this.config.split){
36163             return;
36164         }
36165         if(!this.split){
36166             
36167             var splitEl = Roo.DomHelper.append(ctr.dom,  {
36168                             tag: "div",
36169                             id: this.el.id + "-split",
36170                             cls: "roo-layout-split roo-layout-split-"+this.position,
36171                             html: "&#160;"
36172             });
36173             /** The SplitBar for this region 
36174             * @type Roo.SplitBar */
36175             // does not exist yet...
36176             Roo.log([this.position, this.orientation]);
36177             
36178             this.split = new Roo.bootstrap.SplitBar({
36179                 dragElement : splitEl,
36180                 resizingElement: this.el,
36181                 orientation : this.orientation
36182             });
36183             
36184             this.split.on("moved", this.onSplitMove, this);
36185             this.split.useShim = this.config.useShim === true;
36186             this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36187             if(this.useSplitTips){
36188                 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36189             }
36190             //if(config.collapsible){
36191             //    this.split.el.on("dblclick", this.collapse,  this);
36192             //}
36193         }
36194         if(typeof this.config.minSize != "undefined"){
36195             this.split.minSize = this.config.minSize;
36196         }
36197         if(typeof this.config.maxSize != "undefined"){
36198             this.split.maxSize = this.config.maxSize;
36199         }
36200         if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36201             this.hideSplitter();
36202         }
36203         
36204     },
36205
36206     getHMaxSize : function(){
36207          var cmax = this.config.maxSize || 10000;
36208          var center = this.mgr.getRegion("center");
36209          return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36210     },
36211
36212     getVMaxSize : function(){
36213          var cmax = this.config.maxSize || 10000;
36214          var center = this.mgr.getRegion("center");
36215          return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36216     },
36217
36218     onSplitMove : function(split, newSize){
36219         this.fireEvent("resized", this, newSize);
36220     },
36221     
36222     /** 
36223      * Returns the {@link Roo.SplitBar} for this region.
36224      * @return {Roo.SplitBar}
36225      */
36226     getSplitBar : function(){
36227         return this.split;
36228     },
36229     
36230     hide : function(){
36231         this.hideSplitter();
36232         Roo.bootstrap.layout.Split.superclass.hide.call(this);
36233     },
36234
36235     hideSplitter : function(){
36236         if(this.split){
36237             this.split.el.setLocation(-2000,-2000);
36238             this.split.el.hide();
36239         }
36240     },
36241
36242     show : function(){
36243         if(this.split){
36244             this.split.el.show();
36245         }
36246         Roo.bootstrap.layout.Split.superclass.show.call(this);
36247     },
36248     
36249     beforeSlide: function(){
36250         if(Roo.isGecko){// firefox overflow auto bug workaround
36251             this.bodyEl.clip();
36252             if(this.tabs) {
36253                 this.tabs.bodyEl.clip();
36254             }
36255             if(this.activePanel){
36256                 this.activePanel.getEl().clip();
36257                 
36258                 if(this.activePanel.beforeSlide){
36259                     this.activePanel.beforeSlide();
36260                 }
36261             }
36262         }
36263     },
36264     
36265     afterSlide : function(){
36266         if(Roo.isGecko){// firefox overflow auto bug workaround
36267             this.bodyEl.unclip();
36268             if(this.tabs) {
36269                 this.tabs.bodyEl.unclip();
36270             }
36271             if(this.activePanel){
36272                 this.activePanel.getEl().unclip();
36273                 if(this.activePanel.afterSlide){
36274                     this.activePanel.afterSlide();
36275                 }
36276             }
36277         }
36278     },
36279
36280     initAutoHide : function(){
36281         if(this.autoHide !== false){
36282             if(!this.autoHideHd){
36283                 var st = new Roo.util.DelayedTask(this.slideIn, this);
36284                 this.autoHideHd = {
36285                     "mouseout": function(e){
36286                         if(!e.within(this.el, true)){
36287                             st.delay(500);
36288                         }
36289                     },
36290                     "mouseover" : function(e){
36291                         st.cancel();
36292                     },
36293                     scope : this
36294                 };
36295             }
36296             this.el.on(this.autoHideHd);
36297         }
36298     },
36299
36300     clearAutoHide : function(){
36301         if(this.autoHide !== false){
36302             this.el.un("mouseout", this.autoHideHd.mouseout);
36303             this.el.un("mouseover", this.autoHideHd.mouseover);
36304         }
36305     },
36306
36307     clearMonitor : function(){
36308         Roo.get(document).un("click", this.slideInIf, this);
36309     },
36310
36311     // these names are backwards but not changed for compat
36312     slideOut : function(){
36313         if(this.isSlid || this.el.hasActiveFx()){
36314             return;
36315         }
36316         this.isSlid = true;
36317         if(this.collapseBtn){
36318             this.collapseBtn.hide();
36319         }
36320         this.closeBtnState = this.closeBtn.getStyle('display');
36321         this.closeBtn.hide();
36322         if(this.stickBtn){
36323             this.stickBtn.show();
36324         }
36325         this.el.show();
36326         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36327         this.beforeSlide();
36328         this.el.setStyle("z-index", 10001);
36329         this.el.slideIn(this.getSlideAnchor(), {
36330             callback: function(){
36331                 this.afterSlide();
36332                 this.initAutoHide();
36333                 Roo.get(document).on("click", this.slideInIf, this);
36334                 this.fireEvent("slideshow", this);
36335             },
36336             scope: this,
36337             block: true
36338         });
36339     },
36340
36341     afterSlideIn : function(){
36342         this.clearAutoHide();
36343         this.isSlid = false;
36344         this.clearMonitor();
36345         this.el.setStyle("z-index", "");
36346         if(this.collapseBtn){
36347             this.collapseBtn.show();
36348         }
36349         this.closeBtn.setStyle('display', this.closeBtnState);
36350         if(this.stickBtn){
36351             this.stickBtn.hide();
36352         }
36353         this.fireEvent("slidehide", this);
36354     },
36355
36356     slideIn : function(cb){
36357         if(!this.isSlid || this.el.hasActiveFx()){
36358             Roo.callback(cb);
36359             return;
36360         }
36361         this.isSlid = false;
36362         this.beforeSlide();
36363         this.el.slideOut(this.getSlideAnchor(), {
36364             callback: function(){
36365                 this.el.setLeftTop(-10000, -10000);
36366                 this.afterSlide();
36367                 this.afterSlideIn();
36368                 Roo.callback(cb);
36369             },
36370             scope: this,
36371             block: true
36372         });
36373     },
36374     
36375     slideInIf : function(e){
36376         if(!e.within(this.el)){
36377             this.slideIn();
36378         }
36379     },
36380
36381     animateCollapse : function(){
36382         this.beforeSlide();
36383         this.el.setStyle("z-index", 20000);
36384         var anchor = this.getSlideAnchor();
36385         this.el.slideOut(anchor, {
36386             callback : function(){
36387                 this.el.setStyle("z-index", "");
36388                 this.collapsedEl.slideIn(anchor, {duration:.3});
36389                 this.afterSlide();
36390                 this.el.setLocation(-10000,-10000);
36391                 this.el.hide();
36392                 this.fireEvent("collapsed", this);
36393             },
36394             scope: this,
36395             block: true
36396         });
36397     },
36398
36399     animateExpand : function(){
36400         this.beforeSlide();
36401         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36402         this.el.setStyle("z-index", 20000);
36403         this.collapsedEl.hide({
36404             duration:.1
36405         });
36406         this.el.slideIn(this.getSlideAnchor(), {
36407             callback : function(){
36408                 this.el.setStyle("z-index", "");
36409                 this.afterSlide();
36410                 if(this.split){
36411                     this.split.el.show();
36412                 }
36413                 this.fireEvent("invalidated", this);
36414                 this.fireEvent("expanded", this);
36415             },
36416             scope: this,
36417             block: true
36418         });
36419     },
36420
36421     anchors : {
36422         "west" : "left",
36423         "east" : "right",
36424         "north" : "top",
36425         "south" : "bottom"
36426     },
36427
36428     sanchors : {
36429         "west" : "l",
36430         "east" : "r",
36431         "north" : "t",
36432         "south" : "b"
36433     },
36434
36435     canchors : {
36436         "west" : "tl-tr",
36437         "east" : "tr-tl",
36438         "north" : "tl-bl",
36439         "south" : "bl-tl"
36440     },
36441
36442     getAnchor : function(){
36443         return this.anchors[this.position];
36444     },
36445
36446     getCollapseAnchor : function(){
36447         return this.canchors[this.position];
36448     },
36449
36450     getSlideAnchor : function(){
36451         return this.sanchors[this.position];
36452     },
36453
36454     getAlignAdj : function(){
36455         var cm = this.cmargins;
36456         switch(this.position){
36457             case "west":
36458                 return [0, 0];
36459             break;
36460             case "east":
36461                 return [0, 0];
36462             break;
36463             case "north":
36464                 return [0, 0];
36465             break;
36466             case "south":
36467                 return [0, 0];
36468             break;
36469         }
36470     },
36471
36472     getExpandAdj : function(){
36473         var c = this.collapsedEl, cm = this.cmargins;
36474         switch(this.position){
36475             case "west":
36476                 return [-(cm.right+c.getWidth()+cm.left), 0];
36477             break;
36478             case "east":
36479                 return [cm.right+c.getWidth()+cm.left, 0];
36480             break;
36481             case "north":
36482                 return [0, -(cm.top+cm.bottom+c.getHeight())];
36483             break;
36484             case "south":
36485                 return [0, cm.top+cm.bottom+c.getHeight()];
36486             break;
36487         }
36488     }
36489 });/*
36490  * Based on:
36491  * Ext JS Library 1.1.1
36492  * Copyright(c) 2006-2007, Ext JS, LLC.
36493  *
36494  * Originally Released Under LGPL - original licence link has changed is not relivant.
36495  *
36496  * Fork - LGPL
36497  * <script type="text/javascript">
36498  */
36499 /*
36500  * These classes are private internal classes
36501  */
36502 Roo.bootstrap.layout.Center = function(config){
36503     config.region = "center";
36504     Roo.bootstrap.layout.Region.call(this, config);
36505     this.visible = true;
36506     this.minWidth = config.minWidth || 20;
36507     this.minHeight = config.minHeight || 20;
36508 };
36509
36510 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36511     hide : function(){
36512         // center panel can't be hidden
36513     },
36514     
36515     show : function(){
36516         // center panel can't be hidden
36517     },
36518     
36519     getMinWidth: function(){
36520         return this.minWidth;
36521     },
36522     
36523     getMinHeight: function(){
36524         return this.minHeight;
36525     }
36526 });
36527
36528
36529
36530
36531  
36532
36533
36534
36535
36536
36537 Roo.bootstrap.layout.North = function(config)
36538 {
36539     config.region = 'north';
36540     config.cursor = 'n-resize';
36541     
36542     Roo.bootstrap.layout.Split.call(this, config);
36543     
36544     
36545     if(this.split){
36546         this.split.placement = Roo.bootstrap.SplitBar.TOP;
36547         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36548         this.split.el.addClass("roo-layout-split-v");
36549     }
36550     var size = config.initialSize || config.height;
36551     if(typeof size != "undefined"){
36552         this.el.setHeight(size);
36553     }
36554 };
36555 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36556 {
36557     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36558     
36559     
36560     
36561     getBox : function(){
36562         if(this.collapsed){
36563             return this.collapsedEl.getBox();
36564         }
36565         var box = this.el.getBox();
36566         if(this.split){
36567             box.height += this.split.el.getHeight();
36568         }
36569         return box;
36570     },
36571     
36572     updateBox : function(box){
36573         if(this.split && !this.collapsed){
36574             box.height -= this.split.el.getHeight();
36575             this.split.el.setLeft(box.x);
36576             this.split.el.setTop(box.y+box.height);
36577             this.split.el.setWidth(box.width);
36578         }
36579         if(this.collapsed){
36580             this.updateBody(box.width, null);
36581         }
36582         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36583     }
36584 });
36585
36586
36587
36588
36589
36590 Roo.bootstrap.layout.South = function(config){
36591     config.region = 'south';
36592     config.cursor = 's-resize';
36593     Roo.bootstrap.layout.Split.call(this, config);
36594     if(this.split){
36595         this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36596         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36597         this.split.el.addClass("roo-layout-split-v");
36598     }
36599     var size = config.initialSize || config.height;
36600     if(typeof size != "undefined"){
36601         this.el.setHeight(size);
36602     }
36603 };
36604
36605 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36606     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36607     getBox : function(){
36608         if(this.collapsed){
36609             return this.collapsedEl.getBox();
36610         }
36611         var box = this.el.getBox();
36612         if(this.split){
36613             var sh = this.split.el.getHeight();
36614             box.height += sh;
36615             box.y -= sh;
36616         }
36617         return box;
36618     },
36619     
36620     updateBox : function(box){
36621         if(this.split && !this.collapsed){
36622             var sh = this.split.el.getHeight();
36623             box.height -= sh;
36624             box.y += sh;
36625             this.split.el.setLeft(box.x);
36626             this.split.el.setTop(box.y-sh);
36627             this.split.el.setWidth(box.width);
36628         }
36629         if(this.collapsed){
36630             this.updateBody(box.width, null);
36631         }
36632         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36633     }
36634 });
36635
36636 Roo.bootstrap.layout.East = function(config){
36637     config.region = "east";
36638     config.cursor = "e-resize";
36639     Roo.bootstrap.layout.Split.call(this, config);
36640     if(this.split){
36641         this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36642         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36643         this.split.el.addClass("roo-layout-split-h");
36644     }
36645     var size = config.initialSize || config.width;
36646     if(typeof size != "undefined"){
36647         this.el.setWidth(size);
36648     }
36649 };
36650 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36651     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36652     getBox : function(){
36653         if(this.collapsed){
36654             return this.collapsedEl.getBox();
36655         }
36656         var box = this.el.getBox();
36657         if(this.split){
36658             var sw = this.split.el.getWidth();
36659             box.width += sw;
36660             box.x -= sw;
36661         }
36662         return box;
36663     },
36664
36665     updateBox : function(box){
36666         if(this.split && !this.collapsed){
36667             var sw = this.split.el.getWidth();
36668             box.width -= sw;
36669             this.split.el.setLeft(box.x);
36670             this.split.el.setTop(box.y);
36671             this.split.el.setHeight(box.height);
36672             box.x += sw;
36673         }
36674         if(this.collapsed){
36675             this.updateBody(null, box.height);
36676         }
36677         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36678     }
36679 });
36680
36681 Roo.bootstrap.layout.West = function(config){
36682     config.region = "west";
36683     config.cursor = "w-resize";
36684     
36685     Roo.bootstrap.layout.Split.call(this, config);
36686     if(this.split){
36687         this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36688         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36689         this.split.el.addClass("roo-layout-split-h");
36690     }
36691     
36692 };
36693 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36694     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36695     
36696     onRender: function(ctr, pos)
36697     {
36698         Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36699         var size = this.config.initialSize || this.config.width;
36700         if(typeof size != "undefined"){
36701             this.el.setWidth(size);
36702         }
36703     },
36704     
36705     getBox : function(){
36706         if(this.collapsed){
36707             return this.collapsedEl.getBox();
36708         }
36709         var box = this.el.getBox();
36710         if(this.split){
36711             box.width += this.split.el.getWidth();
36712         }
36713         return box;
36714     },
36715     
36716     updateBox : function(box){
36717         if(this.split && !this.collapsed){
36718             var sw = this.split.el.getWidth();
36719             box.width -= sw;
36720             this.split.el.setLeft(box.x+box.width);
36721             this.split.el.setTop(box.y);
36722             this.split.el.setHeight(box.height);
36723         }
36724         if(this.collapsed){
36725             this.updateBody(null, box.height);
36726         }
36727         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36728     }
36729 });
36730 Roo.namespace("Roo.bootstrap.panel");/*
36731  * Based on:
36732  * Ext JS Library 1.1.1
36733  * Copyright(c) 2006-2007, Ext JS, LLC.
36734  *
36735  * Originally Released Under LGPL - original licence link has changed is not relivant.
36736  *
36737  * Fork - LGPL
36738  * <script type="text/javascript">
36739  */
36740 /**
36741  * @class Roo.ContentPanel
36742  * @extends Roo.util.Observable
36743  * A basic ContentPanel element.
36744  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
36745  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
36746  * @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
36747  * @cfg {Boolean}   closable      True if the panel can be closed/removed
36748  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
36749  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36750  * @cfg {Toolbar}   toolbar       A toolbar for this panel
36751  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
36752  * @cfg {String} title          The title for this panel
36753  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36754  * @cfg {String} url            Calls {@link #setUrl} with this value
36755  * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36756  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
36757  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
36758  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
36759  * @cfg {Boolean} badges render the badges
36760
36761  * @constructor
36762  * Create a new ContentPanel.
36763  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36764  * @param {String/Object} config A string to set only the title or a config object
36765  * @param {String} content (optional) Set the HTML content for this panel
36766  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36767  */
36768 Roo.bootstrap.panel.Content = function( config){
36769     
36770     this.tpl = config.tpl || false;
36771     
36772     var el = config.el;
36773     var content = config.content;
36774
36775     if(config.autoCreate){ // xtype is available if this is called from factory
36776         el = Roo.id();
36777     }
36778     this.el = Roo.get(el);
36779     if(!this.el && config && config.autoCreate){
36780         if(typeof config.autoCreate == "object"){
36781             if(!config.autoCreate.id){
36782                 config.autoCreate.id = config.id||el;
36783             }
36784             this.el = Roo.DomHelper.append(document.body,
36785                         config.autoCreate, true);
36786         }else{
36787             var elcfg =  {   tag: "div",
36788                             cls: "roo-layout-inactive-content",
36789                             id: config.id||el
36790                             };
36791             if (config.html) {
36792                 elcfg.html = config.html;
36793                 
36794             }
36795                         
36796             this.el = Roo.DomHelper.append(document.body, elcfg , true);
36797         }
36798     } 
36799     this.closable = false;
36800     this.loaded = false;
36801     this.active = false;
36802    
36803       
36804     if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36805         
36806         this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36807         
36808         this.wrapEl = this.el; //this.el.wrap();
36809         var ti = [];
36810         if (config.toolbar.items) {
36811             ti = config.toolbar.items ;
36812             delete config.toolbar.items ;
36813         }
36814         
36815         var nitems = [];
36816         this.toolbar.render(this.wrapEl, 'before');
36817         for(var i =0;i < ti.length;i++) {
36818           //  Roo.log(['add child', items[i]]);
36819             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36820         }
36821         this.toolbar.items = nitems;
36822         this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36823         delete config.toolbar;
36824         
36825     }
36826     /*
36827     // xtype created footer. - not sure if will work as we normally have to render first..
36828     if (this.footer && !this.footer.el && this.footer.xtype) {
36829         if (!this.wrapEl) {
36830             this.wrapEl = this.el.wrap();
36831         }
36832     
36833         this.footer.container = this.wrapEl.createChild();
36834          
36835         this.footer = Roo.factory(this.footer, Roo);
36836         
36837     }
36838     */
36839     
36840      if(typeof config == "string"){
36841         this.title = config;
36842     }else{
36843         Roo.apply(this, config);
36844     }
36845     
36846     if(this.resizeEl){
36847         this.resizeEl = Roo.get(this.resizeEl, true);
36848     }else{
36849         this.resizeEl = this.el;
36850     }
36851     // handle view.xtype
36852     
36853  
36854     
36855     
36856     this.addEvents({
36857         /**
36858          * @event activate
36859          * Fires when this panel is activated. 
36860          * @param {Roo.ContentPanel} this
36861          */
36862         "activate" : true,
36863         /**
36864          * @event deactivate
36865          * Fires when this panel is activated. 
36866          * @param {Roo.ContentPanel} this
36867          */
36868         "deactivate" : true,
36869
36870         /**
36871          * @event resize
36872          * Fires when this panel is resized if fitToFrame is true.
36873          * @param {Roo.ContentPanel} this
36874          * @param {Number} width The width after any component adjustments
36875          * @param {Number} height The height after any component adjustments
36876          */
36877         "resize" : true,
36878         
36879          /**
36880          * @event render
36881          * Fires when this tab is created
36882          * @param {Roo.ContentPanel} this
36883          */
36884         "render" : true
36885         
36886         
36887         
36888     });
36889     
36890
36891     
36892     
36893     if(this.autoScroll){
36894         this.resizeEl.setStyle("overflow", "auto");
36895     } else {
36896         // fix randome scrolling
36897         //this.el.on('scroll', function() {
36898         //    Roo.log('fix random scolling');
36899         //    this.scrollTo('top',0); 
36900         //});
36901     }
36902     content = content || this.content;
36903     if(content){
36904         this.setContent(content);
36905     }
36906     if(config && config.url){
36907         this.setUrl(this.url, this.params, this.loadOnce);
36908     }
36909     
36910     
36911     
36912     Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36913     
36914     if (this.view && typeof(this.view.xtype) != 'undefined') {
36915         this.view.el = this.el.appendChild(document.createElement("div"));
36916         this.view = Roo.factory(this.view); 
36917         this.view.render  &&  this.view.render(false, '');  
36918     }
36919     
36920     
36921     this.fireEvent('render', this);
36922 };
36923
36924 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36925     
36926     tabTip : '',
36927     
36928     setRegion : function(region){
36929         this.region = region;
36930         this.setActiveClass(region && !this.background);
36931     },
36932     
36933     
36934     setActiveClass: function(state)
36935     {
36936         if(state){
36937            this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36938            this.el.setStyle('position','relative');
36939         }else{
36940            this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36941            this.el.setStyle('position', 'absolute');
36942         } 
36943     },
36944     
36945     /**
36946      * Returns the toolbar for this Panel if one was configured. 
36947      * @return {Roo.Toolbar} 
36948      */
36949     getToolbar : function(){
36950         return this.toolbar;
36951     },
36952     
36953     setActiveState : function(active)
36954     {
36955         this.active = active;
36956         this.setActiveClass(active);
36957         if(!active){
36958             if(this.fireEvent("deactivate", this) === false){
36959                 return false;
36960             }
36961             return true;
36962         }
36963         this.fireEvent("activate", this);
36964         return true;
36965     },
36966     /**
36967      * Updates this panel's element
36968      * @param {String} content The new content
36969      * @param {Boolean} loadScripts (optional) true to look for and process scripts
36970     */
36971     setContent : function(content, loadScripts){
36972         this.el.update(content, loadScripts);
36973     },
36974
36975     ignoreResize : function(w, h){
36976         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36977             return true;
36978         }else{
36979             this.lastSize = {width: w, height: h};
36980             return false;
36981         }
36982     },
36983     /**
36984      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36985      * @return {Roo.UpdateManager} The UpdateManager
36986      */
36987     getUpdateManager : function(){
36988         return this.el.getUpdateManager();
36989     },
36990      /**
36991      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36992      * @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:
36993 <pre><code>
36994 panel.load({
36995     url: "your-url.php",
36996     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36997     callback: yourFunction,
36998     scope: yourObject, //(optional scope)
36999     discardUrl: false,
37000     nocache: false,
37001     text: "Loading...",
37002     timeout: 30,
37003     scripts: false
37004 });
37005 </code></pre>
37006      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37007      * 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.
37008      * @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}
37009      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37010      * @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.
37011      * @return {Roo.ContentPanel} this
37012      */
37013     load : function(){
37014         var um = this.el.getUpdateManager();
37015         um.update.apply(um, arguments);
37016         return this;
37017     },
37018
37019
37020     /**
37021      * 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.
37022      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37023      * @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)
37024      * @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)
37025      * @return {Roo.UpdateManager} The UpdateManager
37026      */
37027     setUrl : function(url, params, loadOnce){
37028         if(this.refreshDelegate){
37029             this.removeListener("activate", this.refreshDelegate);
37030         }
37031         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37032         this.on("activate", this.refreshDelegate);
37033         return this.el.getUpdateManager();
37034     },
37035     
37036     _handleRefresh : function(url, params, loadOnce){
37037         if(!loadOnce || !this.loaded){
37038             var updater = this.el.getUpdateManager();
37039             updater.update(url, params, this._setLoaded.createDelegate(this));
37040         }
37041     },
37042     
37043     _setLoaded : function(){
37044         this.loaded = true;
37045     }, 
37046     
37047     /**
37048      * Returns this panel's id
37049      * @return {String} 
37050      */
37051     getId : function(){
37052         return this.el.id;
37053     },
37054     
37055     /** 
37056      * Returns this panel's element - used by regiosn to add.
37057      * @return {Roo.Element} 
37058      */
37059     getEl : function(){
37060         return this.wrapEl || this.el;
37061     },
37062     
37063    
37064     
37065     adjustForComponents : function(width, height)
37066     {
37067         //Roo.log('adjustForComponents ');
37068         if(this.resizeEl != this.el){
37069             width -= this.el.getFrameWidth('lr');
37070             height -= this.el.getFrameWidth('tb');
37071         }
37072         if(this.toolbar){
37073             var te = this.toolbar.getEl();
37074             te.setWidth(width);
37075             height -= te.getHeight();
37076         }
37077         if(this.footer){
37078             var te = this.footer.getEl();
37079             te.setWidth(width);
37080             height -= te.getHeight();
37081         }
37082         
37083         
37084         if(this.adjustments){
37085             width += this.adjustments[0];
37086             height += this.adjustments[1];
37087         }
37088         return {"width": width, "height": height};
37089     },
37090     
37091     setSize : function(width, height){
37092         if(this.fitToFrame && !this.ignoreResize(width, height)){
37093             if(this.fitContainer && this.resizeEl != this.el){
37094                 this.el.setSize(width, height);
37095             }
37096             var size = this.adjustForComponents(width, height);
37097             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37098             this.fireEvent('resize', this, size.width, size.height);
37099         }
37100     },
37101     
37102     /**
37103      * Returns this panel's title
37104      * @return {String} 
37105      */
37106     getTitle : function(){
37107         
37108         if (typeof(this.title) != 'object') {
37109             return this.title;
37110         }
37111         
37112         var t = '';
37113         for (var k in this.title) {
37114             if (!this.title.hasOwnProperty(k)) {
37115                 continue;
37116             }
37117             
37118             if (k.indexOf('-') >= 0) {
37119                 var s = k.split('-');
37120                 for (var i = 0; i<s.length; i++) {
37121                     t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37122                 }
37123             } else {
37124                 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37125             }
37126         }
37127         return t;
37128     },
37129     
37130     /**
37131      * Set this panel's title
37132      * @param {String} title
37133      */
37134     setTitle : function(title){
37135         this.title = title;
37136         if(this.region){
37137             this.region.updatePanelTitle(this, title);
37138         }
37139     },
37140     
37141     /**
37142      * Returns true is this panel was configured to be closable
37143      * @return {Boolean} 
37144      */
37145     isClosable : function(){
37146         return this.closable;
37147     },
37148     
37149     beforeSlide : function(){
37150         this.el.clip();
37151         this.resizeEl.clip();
37152     },
37153     
37154     afterSlide : function(){
37155         this.el.unclip();
37156         this.resizeEl.unclip();
37157     },
37158     
37159     /**
37160      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
37161      *   Will fail silently if the {@link #setUrl} method has not been called.
37162      *   This does not activate the panel, just updates its content.
37163      */
37164     refresh : function(){
37165         if(this.refreshDelegate){
37166            this.loaded = false;
37167            this.refreshDelegate();
37168         }
37169     },
37170     
37171     /**
37172      * Destroys this panel
37173      */
37174     destroy : function(){
37175         this.el.removeAllListeners();
37176         var tempEl = document.createElement("span");
37177         tempEl.appendChild(this.el.dom);
37178         tempEl.innerHTML = "";
37179         this.el.remove();
37180         this.el = null;
37181     },
37182     
37183     /**
37184      * form - if the content panel contains a form - this is a reference to it.
37185      * @type {Roo.form.Form}
37186      */
37187     form : false,
37188     /**
37189      * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37190      *    This contains a reference to it.
37191      * @type {Roo.View}
37192      */
37193     view : false,
37194     
37195       /**
37196      * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37197      * <pre><code>
37198
37199 layout.addxtype({
37200        xtype : 'Form',
37201        items: [ .... ]
37202    }
37203 );
37204
37205 </code></pre>
37206      * @param {Object} cfg Xtype definition of item to add.
37207      */
37208     
37209     
37210     getChildContainer: function () {
37211         return this.getEl();
37212     }
37213     
37214     
37215     /*
37216         var  ret = new Roo.factory(cfg);
37217         return ret;
37218         
37219         
37220         // add form..
37221         if (cfg.xtype.match(/^Form$/)) {
37222             
37223             var el;
37224             //if (this.footer) {
37225             //    el = this.footer.container.insertSibling(false, 'before');
37226             //} else {
37227                 el = this.el.createChild();
37228             //}
37229
37230             this.form = new  Roo.form.Form(cfg);
37231             
37232             
37233             if ( this.form.allItems.length) {
37234                 this.form.render(el.dom);
37235             }
37236             return this.form;
37237         }
37238         // should only have one of theses..
37239         if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37240             // views.. should not be just added - used named prop 'view''
37241             
37242             cfg.el = this.el.appendChild(document.createElement("div"));
37243             // factory?
37244             
37245             var ret = new Roo.factory(cfg);
37246              
37247              ret.render && ret.render(false, ''); // render blank..
37248             this.view = ret;
37249             return ret;
37250         }
37251         return false;
37252     }
37253     \*/
37254 });
37255  
37256 /**
37257  * @class Roo.bootstrap.panel.Grid
37258  * @extends Roo.bootstrap.panel.Content
37259  * @constructor
37260  * Create a new GridPanel.
37261  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37262  * @param {Object} config A the config object
37263   
37264  */
37265
37266
37267
37268 Roo.bootstrap.panel.Grid = function(config)
37269 {
37270     
37271       
37272     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37273         {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37274
37275     config.el = this.wrapper;
37276     //this.el = this.wrapper;
37277     
37278       if (config.container) {
37279         // ctor'ed from a Border/panel.grid
37280         
37281         
37282         this.wrapper.setStyle("overflow", "hidden");
37283         this.wrapper.addClass('roo-grid-container');
37284
37285     }
37286     
37287     
37288     if(config.toolbar){
37289         var tool_el = this.wrapper.createChild();    
37290         this.toolbar = Roo.factory(config.toolbar);
37291         var ti = [];
37292         if (config.toolbar.items) {
37293             ti = config.toolbar.items ;
37294             delete config.toolbar.items ;
37295         }
37296         
37297         var nitems = [];
37298         this.toolbar.render(tool_el);
37299         for(var i =0;i < ti.length;i++) {
37300           //  Roo.log(['add child', items[i]]);
37301             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37302         }
37303         this.toolbar.items = nitems;
37304         
37305         delete config.toolbar;
37306     }
37307     
37308     Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37309     config.grid.scrollBody = true;;
37310     config.grid.monitorWindowResize = false; // turn off autosizing
37311     config.grid.autoHeight = false;
37312     config.grid.autoWidth = false;
37313     
37314     this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37315     
37316     if (config.background) {
37317         // render grid on panel activation (if panel background)
37318         this.on('activate', function(gp) {
37319             if (!gp.grid.rendered) {
37320                 gp.grid.render(this.wrapper);
37321                 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");   
37322             }
37323         });
37324             
37325     } else {
37326         this.grid.render(this.wrapper);
37327         this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");               
37328
37329     }
37330     //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37331     // ??? needed ??? config.el = this.wrapper;
37332     
37333     
37334     
37335   
37336     // xtype created footer. - not sure if will work as we normally have to render first..
37337     if (this.footer && !this.footer.el && this.footer.xtype) {
37338         
37339         var ctr = this.grid.getView().getFooterPanel(true);
37340         this.footer.dataSource = this.grid.dataSource;
37341         this.footer = Roo.factory(this.footer, Roo);
37342         this.footer.render(ctr);
37343         
37344     }
37345     
37346     
37347     
37348     
37349      
37350 };
37351
37352 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37353     getId : function(){
37354         return this.grid.id;
37355     },
37356     
37357     /**
37358      * Returns the grid for this panel
37359      * @return {Roo.bootstrap.Table} 
37360      */
37361     getGrid : function(){
37362         return this.grid;    
37363     },
37364     
37365     setSize : function(width, height){
37366         if(!this.ignoreResize(width, height)){
37367             var grid = this.grid;
37368             var size = this.adjustForComponents(width, height);
37369             var gridel = grid.getGridEl();
37370             gridel.setSize(size.width, size.height);
37371             /*
37372             var thd = grid.getGridEl().select('thead',true).first();
37373             var tbd = grid.getGridEl().select('tbody', true).first();
37374             if (tbd) {
37375                 tbd.setSize(width, height - thd.getHeight());
37376             }
37377             */
37378             grid.autoSize();
37379         }
37380     },
37381      
37382     
37383     
37384     beforeSlide : function(){
37385         this.grid.getView().scroller.clip();
37386     },
37387     
37388     afterSlide : function(){
37389         this.grid.getView().scroller.unclip();
37390     },
37391     
37392     destroy : function(){
37393         this.grid.destroy();
37394         delete this.grid;
37395         Roo.bootstrap.panel.Grid.superclass.destroy.call(this); 
37396     }
37397 });
37398
37399 /**
37400  * @class Roo.bootstrap.panel.Nest
37401  * @extends Roo.bootstrap.panel.Content
37402  * @constructor
37403  * Create a new Panel, that can contain a layout.Border.
37404  * 
37405  * 
37406  * @param {Roo.BorderLayout} layout The layout for this panel
37407  * @param {String/Object} config A string to set only the title or a config object
37408  */
37409 Roo.bootstrap.panel.Nest = function(config)
37410 {
37411     // construct with only one argument..
37412     /* FIXME - implement nicer consturctors
37413     if (layout.layout) {
37414         config = layout;
37415         layout = config.layout;
37416         delete config.layout;
37417     }
37418     if (layout.xtype && !layout.getEl) {
37419         // then layout needs constructing..
37420         layout = Roo.factory(layout, Roo);
37421     }
37422     */
37423     
37424     config.el =  config.layout.getEl();
37425     
37426     Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37427     
37428     config.layout.monitorWindowResize = false; // turn off autosizing
37429     this.layout = config.layout;
37430     this.layout.getEl().addClass("roo-layout-nested-layout");
37431     
37432     
37433     
37434     
37435 };
37436
37437 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37438
37439     setSize : function(width, height){
37440         if(!this.ignoreResize(width, height)){
37441             var size = this.adjustForComponents(width, height);
37442             var el = this.layout.getEl();
37443             if (size.height < 1) {
37444                 el.setWidth(size.width);   
37445             } else {
37446                 el.setSize(size.width, size.height);
37447             }
37448             var touch = el.dom.offsetWidth;
37449             this.layout.layout();
37450             // ie requires a double layout on the first pass
37451             if(Roo.isIE && !this.initialized){
37452                 this.initialized = true;
37453                 this.layout.layout();
37454             }
37455         }
37456     },
37457     
37458     // activate all subpanels if not currently active..
37459     
37460     setActiveState : function(active){
37461         this.active = active;
37462         this.setActiveClass(active);
37463         
37464         if(!active){
37465             this.fireEvent("deactivate", this);
37466             return;
37467         }
37468         
37469         this.fireEvent("activate", this);
37470         // not sure if this should happen before or after..
37471         if (!this.layout) {
37472             return; // should not happen..
37473         }
37474         var reg = false;
37475         for (var r in this.layout.regions) {
37476             reg = this.layout.getRegion(r);
37477             if (reg.getActivePanel()) {
37478                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
37479                 reg.setActivePanel(reg.getActivePanel());
37480                 continue;
37481             }
37482             if (!reg.panels.length) {
37483                 continue;
37484             }
37485             reg.showPanel(reg.getPanel(0));
37486         }
37487         
37488         
37489         
37490         
37491     },
37492     
37493     /**
37494      * Returns the nested BorderLayout for this panel
37495      * @return {Roo.BorderLayout} 
37496      */
37497     getLayout : function(){
37498         return this.layout;
37499     },
37500     
37501      /**
37502      * Adds a xtype elements to the layout of the nested panel
37503      * <pre><code>
37504
37505 panel.addxtype({
37506        xtype : 'ContentPanel',
37507        region: 'west',
37508        items: [ .... ]
37509    }
37510 );
37511
37512 panel.addxtype({
37513         xtype : 'NestedLayoutPanel',
37514         region: 'west',
37515         layout: {
37516            center: { },
37517            west: { }   
37518         },
37519         items : [ ... list of content panels or nested layout panels.. ]
37520    }
37521 );
37522 </code></pre>
37523      * @param {Object} cfg Xtype definition of item to add.
37524      */
37525     addxtype : function(cfg) {
37526         return this.layout.addxtype(cfg);
37527     
37528     }
37529 });        /*
37530  * Based on:
37531  * Ext JS Library 1.1.1
37532  * Copyright(c) 2006-2007, Ext JS, LLC.
37533  *
37534  * Originally Released Under LGPL - original licence link has changed is not relivant.
37535  *
37536  * Fork - LGPL
37537  * <script type="text/javascript">
37538  */
37539 /**
37540  * @class Roo.TabPanel
37541  * @extends Roo.util.Observable
37542  * A lightweight tab container.
37543  * <br><br>
37544  * Usage:
37545  * <pre><code>
37546 // basic tabs 1, built from existing content
37547 var tabs = new Roo.TabPanel("tabs1");
37548 tabs.addTab("script", "View Script");
37549 tabs.addTab("markup", "View Markup");
37550 tabs.activate("script");
37551
37552 // more advanced tabs, built from javascript
37553 var jtabs = new Roo.TabPanel("jtabs");
37554 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37555
37556 // set up the UpdateManager
37557 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37558 var updater = tab2.getUpdateManager();
37559 updater.setDefaultUrl("ajax1.htm");
37560 tab2.on('activate', updater.refresh, updater, true);
37561
37562 // Use setUrl for Ajax loading
37563 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37564 tab3.setUrl("ajax2.htm", null, true);
37565
37566 // Disabled tab
37567 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37568 tab4.disable();
37569
37570 jtabs.activate("jtabs-1");
37571  * </code></pre>
37572  * @constructor
37573  * Create a new TabPanel.
37574  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37575  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37576  */
37577 Roo.bootstrap.panel.Tabs = function(config){
37578     /**
37579     * The container element for this TabPanel.
37580     * @type Roo.Element
37581     */
37582     this.el = Roo.get(config.el);
37583     delete config.el;
37584     if(config){
37585         if(typeof config == "boolean"){
37586             this.tabPosition = config ? "bottom" : "top";
37587         }else{
37588             Roo.apply(this, config);
37589         }
37590     }
37591     
37592     if(this.tabPosition == "bottom"){
37593         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37594         this.el.addClass("roo-tabs-bottom");
37595     }
37596     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37597     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37598     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37599     if(Roo.isIE){
37600         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37601     }
37602     if(this.tabPosition != "bottom"){
37603         /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37604          * @type Roo.Element
37605          */
37606         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37607         this.el.addClass("roo-tabs-top");
37608     }
37609     this.items = [];
37610
37611     this.bodyEl.setStyle("position", "relative");
37612
37613     this.active = null;
37614     this.activateDelegate = this.activate.createDelegate(this);
37615
37616     this.addEvents({
37617         /**
37618          * @event tabchange
37619          * Fires when the active tab changes
37620          * @param {Roo.TabPanel} this
37621          * @param {Roo.TabPanelItem} activePanel The new active tab
37622          */
37623         "tabchange": true,
37624         /**
37625          * @event beforetabchange
37626          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37627          * @param {Roo.TabPanel} this
37628          * @param {Object} e Set cancel to true on this object to cancel the tab change
37629          * @param {Roo.TabPanelItem} tab The tab being changed to
37630          */
37631         "beforetabchange" : true
37632     });
37633
37634     Roo.EventManager.onWindowResize(this.onResize, this);
37635     this.cpad = this.el.getPadding("lr");
37636     this.hiddenCount = 0;
37637
37638
37639     // toolbar on the tabbar support...
37640     if (this.toolbar) {
37641         alert("no toolbar support yet");
37642         this.toolbar  = false;
37643         /*
37644         var tcfg = this.toolbar;
37645         tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
37646         this.toolbar = new Roo.Toolbar(tcfg);
37647         if (Roo.isSafari) {
37648             var tbl = tcfg.container.child('table', true);
37649             tbl.setAttribute('width', '100%');
37650         }
37651         */
37652         
37653     }
37654    
37655
37656
37657     Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37658 };
37659
37660 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37661     /*
37662      *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37663      */
37664     tabPosition : "top",
37665     /*
37666      *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37667      */
37668     currentTabWidth : 0,
37669     /*
37670      *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37671      */
37672     minTabWidth : 40,
37673     /*
37674      *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37675      */
37676     maxTabWidth : 250,
37677     /*
37678      *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37679      */
37680     preferredTabWidth : 175,
37681     /*
37682      *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37683      */
37684     resizeTabs : false,
37685     /*
37686      *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37687      */
37688     monitorResize : true,
37689     /*
37690      *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
37691      */
37692     toolbar : false,
37693
37694     /**
37695      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37696      * @param {String} id The id of the div to use <b>or create</b>
37697      * @param {String} text The text for the tab
37698      * @param {String} content (optional) Content to put in the TabPanelItem body
37699      * @param {Boolean} closable (optional) True to create a close icon on the tab
37700      * @return {Roo.TabPanelItem} The created TabPanelItem
37701      */
37702     addTab : function(id, text, content, closable, tpl)
37703     {
37704         var item = new Roo.bootstrap.panel.TabItem({
37705             panel: this,
37706             id : id,
37707             text : text,
37708             closable : closable,
37709             tpl : tpl
37710         });
37711         this.addTabItem(item);
37712         if(content){
37713             item.setContent(content);
37714         }
37715         return item;
37716     },
37717
37718     /**
37719      * Returns the {@link Roo.TabPanelItem} with the specified id/index
37720      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37721      * @return {Roo.TabPanelItem}
37722      */
37723     getTab : function(id){
37724         return this.items[id];
37725     },
37726
37727     /**
37728      * Hides the {@link Roo.TabPanelItem} with the specified id/index
37729      * @param {String/Number} id The id or index of the TabPanelItem to hide.
37730      */
37731     hideTab : function(id){
37732         var t = this.items[id];
37733         if(!t.isHidden()){
37734            t.setHidden(true);
37735            this.hiddenCount++;
37736            this.autoSizeTabs();
37737         }
37738     },
37739
37740     /**
37741      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37742      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37743      */
37744     unhideTab : function(id){
37745         var t = this.items[id];
37746         if(t.isHidden()){
37747            t.setHidden(false);
37748            this.hiddenCount--;
37749            this.autoSizeTabs();
37750         }
37751     },
37752
37753     /**
37754      * Adds an existing {@link Roo.TabPanelItem}.
37755      * @param {Roo.TabPanelItem} item The TabPanelItem to add
37756      */
37757     addTabItem : function(item){
37758         this.items[item.id] = item;
37759         this.items.push(item);
37760       //  if(this.resizeTabs){
37761     //       item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37762   //         this.autoSizeTabs();
37763 //        }else{
37764 //            item.autoSize();
37765        // }
37766     },
37767
37768     /**
37769      * Removes a {@link Roo.TabPanelItem}.
37770      * @param {String/Number} id The id or index of the TabPanelItem to remove.
37771      */
37772     removeTab : function(id){
37773         var items = this.items;
37774         var tab = items[id];
37775         if(!tab) { return; }
37776         var index = items.indexOf(tab);
37777         if(this.active == tab && items.length > 1){
37778             var newTab = this.getNextAvailable(index);
37779             if(newTab) {
37780                 newTab.activate();
37781             }
37782         }
37783         this.stripEl.dom.removeChild(tab.pnode.dom);
37784         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37785             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37786         }
37787         items.splice(index, 1);
37788         delete this.items[tab.id];
37789         tab.fireEvent("close", tab);
37790         tab.purgeListeners();
37791         this.autoSizeTabs();
37792     },
37793
37794     getNextAvailable : function(start){
37795         var items = this.items;
37796         var index = start;
37797         // look for a next tab that will slide over to
37798         // replace the one being removed
37799         while(index < items.length){
37800             var item = items[++index];
37801             if(item && !item.isHidden()){
37802                 return item;
37803             }
37804         }
37805         // if one isn't found select the previous tab (on the left)
37806         index = start;
37807         while(index >= 0){
37808             var item = items[--index];
37809             if(item && !item.isHidden()){
37810                 return item;
37811             }
37812         }
37813         return null;
37814     },
37815
37816     /**
37817      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37818      * @param {String/Number} id The id or index of the TabPanelItem to disable.
37819      */
37820     disableTab : function(id){
37821         var tab = this.items[id];
37822         if(tab && this.active != tab){
37823             tab.disable();
37824         }
37825     },
37826
37827     /**
37828      * Enables a {@link Roo.TabPanelItem} that is disabled.
37829      * @param {String/Number} id The id or index of the TabPanelItem to enable.
37830      */
37831     enableTab : function(id){
37832         var tab = this.items[id];
37833         tab.enable();
37834     },
37835
37836     /**
37837      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37838      * @param {String/Number} id The id or index of the TabPanelItem to activate.
37839      * @return {Roo.TabPanelItem} The TabPanelItem.
37840      */
37841     activate : function(id){
37842         var tab = this.items[id];
37843         if(!tab){
37844             return null;
37845         }
37846         if(tab == this.active || tab.disabled){
37847             return tab;
37848         }
37849         var e = {};
37850         this.fireEvent("beforetabchange", this, e, tab);
37851         if(e.cancel !== true && !tab.disabled){
37852             if(this.active){
37853                 this.active.hide();
37854             }
37855             this.active = this.items[id];
37856             this.active.show();
37857             this.fireEvent("tabchange", this, this.active);
37858         }
37859         return tab;
37860     },
37861
37862     /**
37863      * Gets the active {@link Roo.TabPanelItem}.
37864      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37865      */
37866     getActiveTab : function(){
37867         return this.active;
37868     },
37869
37870     /**
37871      * Updates the tab body element to fit the height of the container element
37872      * for overflow scrolling
37873      * @param {Number} targetHeight (optional) Override the starting height from the elements height
37874      */
37875     syncHeight : function(targetHeight){
37876         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37877         var bm = this.bodyEl.getMargins();
37878         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37879         this.bodyEl.setHeight(newHeight);
37880         return newHeight;
37881     },
37882
37883     onResize : function(){
37884         if(this.monitorResize){
37885             this.autoSizeTabs();
37886         }
37887     },
37888
37889     /**
37890      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37891      */
37892     beginUpdate : function(){
37893         this.updating = true;
37894     },
37895
37896     /**
37897      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37898      */
37899     endUpdate : function(){
37900         this.updating = false;
37901         this.autoSizeTabs();
37902     },
37903
37904     /**
37905      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37906      */
37907     autoSizeTabs : function(){
37908         var count = this.items.length;
37909         var vcount = count - this.hiddenCount;
37910         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37911             return;
37912         }
37913         var w = Math.max(this.el.getWidth() - this.cpad, 10);
37914         var availWidth = Math.floor(w / vcount);
37915         var b = this.stripBody;
37916         if(b.getWidth() > w){
37917             var tabs = this.items;
37918             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37919             if(availWidth < this.minTabWidth){
37920                 /*if(!this.sleft){    // incomplete scrolling code
37921                     this.createScrollButtons();
37922                 }
37923                 this.showScroll();
37924                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37925             }
37926         }else{
37927             if(this.currentTabWidth < this.preferredTabWidth){
37928                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37929             }
37930         }
37931     },
37932
37933     /**
37934      * Returns the number of tabs in this TabPanel.
37935      * @return {Number}
37936      */
37937      getCount : function(){
37938          return this.items.length;
37939      },
37940
37941     /**
37942      * Resizes all the tabs to the passed width
37943      * @param {Number} The new width
37944      */
37945     setTabWidth : function(width){
37946         this.currentTabWidth = width;
37947         for(var i = 0, len = this.items.length; i < len; i++) {
37948                 if(!this.items[i].isHidden()) {
37949                 this.items[i].setWidth(width);
37950             }
37951         }
37952     },
37953
37954     /**
37955      * Destroys this TabPanel
37956      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37957      */
37958     destroy : function(removeEl){
37959         Roo.EventManager.removeResizeListener(this.onResize, this);
37960         for(var i = 0, len = this.items.length; i < len; i++){
37961             this.items[i].purgeListeners();
37962         }
37963         if(removeEl === true){
37964             this.el.update("");
37965             this.el.remove();
37966         }
37967     },
37968     
37969     createStrip : function(container)
37970     {
37971         var strip = document.createElement("nav");
37972         strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37973         container.appendChild(strip);
37974         return strip;
37975     },
37976     
37977     createStripList : function(strip)
37978     {
37979         // div wrapper for retard IE
37980         // returns the "tr" element.
37981         strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37982         //'<div class="x-tabs-strip-wrap">'+
37983           //  '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37984           //  '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37985         return strip.firstChild; //.firstChild.firstChild.firstChild;
37986     },
37987     createBody : function(container)
37988     {
37989         var body = document.createElement("div");
37990         Roo.id(body, "tab-body");
37991         //Roo.fly(body).addClass("x-tabs-body");
37992         Roo.fly(body).addClass("tab-content");
37993         container.appendChild(body);
37994         return body;
37995     },
37996     createItemBody :function(bodyEl, id){
37997         var body = Roo.getDom(id);
37998         if(!body){
37999             body = document.createElement("div");
38000             body.id = id;
38001         }
38002         //Roo.fly(body).addClass("x-tabs-item-body");
38003         Roo.fly(body).addClass("tab-pane");
38004          bodyEl.insertBefore(body, bodyEl.firstChild);
38005         return body;
38006     },
38007     /** @private */
38008     createStripElements :  function(stripEl, text, closable, tpl)
38009     {
38010         var td = document.createElement("li"); // was td..
38011         
38012         
38013         //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38014         
38015         
38016         stripEl.appendChild(td);
38017         /*if(closable){
38018             td.className = "x-tabs-closable";
38019             if(!this.closeTpl){
38020                 this.closeTpl = new Roo.Template(
38021                    '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38022                    '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38023                    '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
38024                 );
38025             }
38026             var el = this.closeTpl.overwrite(td, {"text": text});
38027             var close = el.getElementsByTagName("div")[0];
38028             var inner = el.getElementsByTagName("em")[0];
38029             return {"el": el, "close": close, "inner": inner};
38030         } else {
38031         */
38032         // not sure what this is..
38033 //            if(!this.tabTpl){
38034                 //this.tabTpl = new Roo.Template(
38035                 //   '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38036                 //   '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38037                 //);
38038 //                this.tabTpl = new Roo.Template(
38039 //                   '<a href="#">' +
38040 //                   '<span unselectable="on"' +
38041 //                            (this.disableTooltips ? '' : ' title="{text}"') +
38042 //                            ' >{text}</span></a>'
38043 //                );
38044 //                
38045 //            }
38046
38047
38048             var template = tpl || this.tabTpl || false;
38049             
38050             if(!template){
38051                 
38052                 template = new Roo.Template(
38053                    '<a href="#">' +
38054                    '<span unselectable="on"' +
38055                             (this.disableTooltips ? '' : ' title="{text}"') +
38056                             ' >{text}</span></a>'
38057                 );
38058             }
38059             
38060             switch (typeof(template)) {
38061                 case 'object' :
38062                     break;
38063                 case 'string' :
38064                     template = new Roo.Template(template);
38065                     break;
38066                 default :
38067                     break;
38068             }
38069             
38070             var el = template.overwrite(td, {"text": text});
38071             
38072             var inner = el.getElementsByTagName("span")[0];
38073             
38074             return {"el": el, "inner": inner};
38075             
38076     }
38077         
38078     
38079 });
38080
38081 /**
38082  * @class Roo.TabPanelItem
38083  * @extends Roo.util.Observable
38084  * Represents an individual item (tab plus body) in a TabPanel.
38085  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38086  * @param {String} id The id of this TabPanelItem
38087  * @param {String} text The text for the tab of this TabPanelItem
38088  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38089  */
38090 Roo.bootstrap.panel.TabItem = function(config){
38091     /**
38092      * The {@link Roo.TabPanel} this TabPanelItem belongs to
38093      * @type Roo.TabPanel
38094      */
38095     this.tabPanel = config.panel;
38096     /**
38097      * The id for this TabPanelItem
38098      * @type String
38099      */
38100     this.id = config.id;
38101     /** @private */
38102     this.disabled = false;
38103     /** @private */
38104     this.text = config.text;
38105     /** @private */
38106     this.loaded = false;
38107     this.closable = config.closable;
38108
38109     /**
38110      * The body element for this TabPanelItem.
38111      * @type Roo.Element
38112      */
38113     this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38114     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38115     this.bodyEl.setStyle("display", "block");
38116     this.bodyEl.setStyle("zoom", "1");
38117     //this.hideAction();
38118
38119     var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38120     /** @private */
38121     this.el = Roo.get(els.el);
38122     this.inner = Roo.get(els.inner, true);
38123     this.textEl = Roo.get(this.el.dom.firstChild, true);
38124     this.pnode = Roo.get(els.el.parentNode, true);
38125 //    this.el.on("mousedown", this.onTabMouseDown, this);
38126     this.el.on("click", this.onTabClick, this);
38127     /** @private */
38128     if(config.closable){
38129         var c = Roo.get(els.close, true);
38130         c.dom.title = this.closeText;
38131         c.addClassOnOver("close-over");
38132         c.on("click", this.closeClick, this);
38133      }
38134
38135     this.addEvents({
38136          /**
38137          * @event activate
38138          * Fires when this tab becomes the active tab.
38139          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38140          * @param {Roo.TabPanelItem} this
38141          */
38142         "activate": true,
38143         /**
38144          * @event beforeclose
38145          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38146          * @param {Roo.TabPanelItem} this
38147          * @param {Object} e Set cancel to true on this object to cancel the close.
38148          */
38149         "beforeclose": true,
38150         /**
38151          * @event close
38152          * Fires when this tab is closed.
38153          * @param {Roo.TabPanelItem} this
38154          */
38155          "close": true,
38156         /**
38157          * @event deactivate
38158          * Fires when this tab is no longer the active tab.
38159          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38160          * @param {Roo.TabPanelItem} this
38161          */
38162          "deactivate" : true
38163     });
38164     this.hidden = false;
38165
38166     Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38167 };
38168
38169 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38170            {
38171     purgeListeners : function(){
38172        Roo.util.Observable.prototype.purgeListeners.call(this);
38173        this.el.removeAllListeners();
38174     },
38175     /**
38176      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38177      */
38178     show : function(){
38179         this.pnode.addClass("active");
38180         this.showAction();
38181         if(Roo.isOpera){
38182             this.tabPanel.stripWrap.repaint();
38183         }
38184         this.fireEvent("activate", this.tabPanel, this);
38185     },
38186
38187     /**
38188      * Returns true if this tab is the active tab.
38189      * @return {Boolean}
38190      */
38191     isActive : function(){
38192         return this.tabPanel.getActiveTab() == this;
38193     },
38194
38195     /**
38196      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38197      */
38198     hide : function(){
38199         this.pnode.removeClass("active");
38200         this.hideAction();
38201         this.fireEvent("deactivate", this.tabPanel, this);
38202     },
38203
38204     hideAction : function(){
38205         this.bodyEl.hide();
38206         this.bodyEl.setStyle("position", "absolute");
38207         this.bodyEl.setLeft("-20000px");
38208         this.bodyEl.setTop("-20000px");
38209     },
38210
38211     showAction : function(){
38212         this.bodyEl.setStyle("position", "relative");
38213         this.bodyEl.setTop("");
38214         this.bodyEl.setLeft("");
38215         this.bodyEl.show();
38216     },
38217
38218     /**
38219      * Set the tooltip for the tab.
38220      * @param {String} tooltip The tab's tooltip
38221      */
38222     setTooltip : function(text){
38223         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38224             this.textEl.dom.qtip = text;
38225             this.textEl.dom.removeAttribute('title');
38226         }else{
38227             this.textEl.dom.title = text;
38228         }
38229     },
38230
38231     onTabClick : function(e){
38232         e.preventDefault();
38233         this.tabPanel.activate(this.id);
38234     },
38235
38236     onTabMouseDown : function(e){
38237         e.preventDefault();
38238         this.tabPanel.activate(this.id);
38239     },
38240 /*
38241     getWidth : function(){
38242         return this.inner.getWidth();
38243     },
38244
38245     setWidth : function(width){
38246         var iwidth = width - this.pnode.getPadding("lr");
38247         this.inner.setWidth(iwidth);
38248         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38249         this.pnode.setWidth(width);
38250     },
38251 */
38252     /**
38253      * Show or hide the tab
38254      * @param {Boolean} hidden True to hide or false to show.
38255      */
38256     setHidden : function(hidden){
38257         this.hidden = hidden;
38258         this.pnode.setStyle("display", hidden ? "none" : "");
38259     },
38260
38261     /**
38262      * Returns true if this tab is "hidden"
38263      * @return {Boolean}
38264      */
38265     isHidden : function(){
38266         return this.hidden;
38267     },
38268
38269     /**
38270      * Returns the text for this tab
38271      * @return {String}
38272      */
38273     getText : function(){
38274         return this.text;
38275     },
38276     /*
38277     autoSize : function(){
38278         //this.el.beginMeasure();
38279         this.textEl.setWidth(1);
38280         /*
38281          *  #2804 [new] Tabs in Roojs
38282          *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38283          */
38284         //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38285         //this.el.endMeasure();
38286     //},
38287
38288     /**
38289      * Sets the text for the tab (Note: this also sets the tooltip text)
38290      * @param {String} text The tab's text and tooltip
38291      */
38292     setText : function(text){
38293         this.text = text;
38294         this.textEl.update(text);
38295         this.setTooltip(text);
38296         //if(!this.tabPanel.resizeTabs){
38297         //    this.autoSize();
38298         //}
38299     },
38300     /**
38301      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38302      */
38303     activate : function(){
38304         this.tabPanel.activate(this.id);
38305     },
38306
38307     /**
38308      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38309      */
38310     disable : function(){
38311         if(this.tabPanel.active != this){
38312             this.disabled = true;
38313             this.pnode.addClass("disabled");
38314         }
38315     },
38316
38317     /**
38318      * Enables this TabPanelItem if it was previously disabled.
38319      */
38320     enable : function(){
38321         this.disabled = false;
38322         this.pnode.removeClass("disabled");
38323     },
38324
38325     /**
38326      * Sets the content for this TabPanelItem.
38327      * @param {String} content The content
38328      * @param {Boolean} loadScripts true to look for and load scripts
38329      */
38330     setContent : function(content, loadScripts){
38331         this.bodyEl.update(content, loadScripts);
38332     },
38333
38334     /**
38335      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38336      * @return {Roo.UpdateManager} The UpdateManager
38337      */
38338     getUpdateManager : function(){
38339         return this.bodyEl.getUpdateManager();
38340     },
38341
38342     /**
38343      * Set a URL to be used to load the content for this TabPanelItem.
38344      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38345      * @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)
38346      * @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)
38347      * @return {Roo.UpdateManager} The UpdateManager
38348      */
38349     setUrl : function(url, params, loadOnce){
38350         if(this.refreshDelegate){
38351             this.un('activate', this.refreshDelegate);
38352         }
38353         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38354         this.on("activate", this.refreshDelegate);
38355         return this.bodyEl.getUpdateManager();
38356     },
38357
38358     /** @private */
38359     _handleRefresh : function(url, params, loadOnce){
38360         if(!loadOnce || !this.loaded){
38361             var updater = this.bodyEl.getUpdateManager();
38362             updater.update(url, params, this._setLoaded.createDelegate(this));
38363         }
38364     },
38365
38366     /**
38367      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
38368      *   Will fail silently if the setUrl method has not been called.
38369      *   This does not activate the panel, just updates its content.
38370      */
38371     refresh : function(){
38372         if(this.refreshDelegate){
38373            this.loaded = false;
38374            this.refreshDelegate();
38375         }
38376     },
38377
38378     /** @private */
38379     _setLoaded : function(){
38380         this.loaded = true;
38381     },
38382
38383     /** @private */
38384     closeClick : function(e){
38385         var o = {};
38386         e.stopEvent();
38387         this.fireEvent("beforeclose", this, o);
38388         if(o.cancel !== true){
38389             this.tabPanel.removeTab(this.id);
38390         }
38391     },
38392     /**
38393      * The text displayed in the tooltip for the close icon.
38394      * @type String
38395      */
38396     closeText : "Close this tab"
38397 });
38398 /**
38399 *    This script refer to:
38400 *    Title: International Telephone Input
38401 *    Author: Jack O'Connor
38402 *    Code version:  v12.1.12
38403 *    Availability: https://github.com/jackocnr/intl-tel-input.git
38404 **/
38405
38406 Roo.bootstrap.PhoneInputData = function() {
38407     var d = [
38408       [
38409         "Afghanistan (‫افغانستان‬‎)",
38410         "af",
38411         "93"
38412       ],
38413       [
38414         "Albania (Shqipëri)",
38415         "al",
38416         "355"
38417       ],
38418       [
38419         "Algeria (‫الجزائر‬‎)",
38420         "dz",
38421         "213"
38422       ],
38423       [
38424         "American Samoa",
38425         "as",
38426         "1684"
38427       ],
38428       [
38429         "Andorra",
38430         "ad",
38431         "376"
38432       ],
38433       [
38434         "Angola",
38435         "ao",
38436         "244"
38437       ],
38438       [
38439         "Anguilla",
38440         "ai",
38441         "1264"
38442       ],
38443       [
38444         "Antigua and Barbuda",
38445         "ag",
38446         "1268"
38447       ],
38448       [
38449         "Argentina",
38450         "ar",
38451         "54"
38452       ],
38453       [
38454         "Armenia (Հայաստան)",
38455         "am",
38456         "374"
38457       ],
38458       [
38459         "Aruba",
38460         "aw",
38461         "297"
38462       ],
38463       [
38464         "Australia",
38465         "au",
38466         "61",
38467         0
38468       ],
38469       [
38470         "Austria (Österreich)",
38471         "at",
38472         "43"
38473       ],
38474       [
38475         "Azerbaijan (Azərbaycan)",
38476         "az",
38477         "994"
38478       ],
38479       [
38480         "Bahamas",
38481         "bs",
38482         "1242"
38483       ],
38484       [
38485         "Bahrain (‫البحرين‬‎)",
38486         "bh",
38487         "973"
38488       ],
38489       [
38490         "Bangladesh (বাংলাদেশ)",
38491         "bd",
38492         "880"
38493       ],
38494       [
38495         "Barbados",
38496         "bb",
38497         "1246"
38498       ],
38499       [
38500         "Belarus (Беларусь)",
38501         "by",
38502         "375"
38503       ],
38504       [
38505         "Belgium (België)",
38506         "be",
38507         "32"
38508       ],
38509       [
38510         "Belize",
38511         "bz",
38512         "501"
38513       ],
38514       [
38515         "Benin (Bénin)",
38516         "bj",
38517         "229"
38518       ],
38519       [
38520         "Bermuda",
38521         "bm",
38522         "1441"
38523       ],
38524       [
38525         "Bhutan (འབྲུག)",
38526         "bt",
38527         "975"
38528       ],
38529       [
38530         "Bolivia",
38531         "bo",
38532         "591"
38533       ],
38534       [
38535         "Bosnia and Herzegovina (Босна и Херцеговина)",
38536         "ba",
38537         "387"
38538       ],
38539       [
38540         "Botswana",
38541         "bw",
38542         "267"
38543       ],
38544       [
38545         "Brazil (Brasil)",
38546         "br",
38547         "55"
38548       ],
38549       [
38550         "British Indian Ocean Territory",
38551         "io",
38552         "246"
38553       ],
38554       [
38555         "British Virgin Islands",
38556         "vg",
38557         "1284"
38558       ],
38559       [
38560         "Brunei",
38561         "bn",
38562         "673"
38563       ],
38564       [
38565         "Bulgaria (България)",
38566         "bg",
38567         "359"
38568       ],
38569       [
38570         "Burkina Faso",
38571         "bf",
38572         "226"
38573       ],
38574       [
38575         "Burundi (Uburundi)",
38576         "bi",
38577         "257"
38578       ],
38579       [
38580         "Cambodia (កម្ពុជា)",
38581         "kh",
38582         "855"
38583       ],
38584       [
38585         "Cameroon (Cameroun)",
38586         "cm",
38587         "237"
38588       ],
38589       [
38590         "Canada",
38591         "ca",
38592         "1",
38593         1,
38594         ["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"]
38595       ],
38596       [
38597         "Cape Verde (Kabu Verdi)",
38598         "cv",
38599         "238"
38600       ],
38601       [
38602         "Caribbean Netherlands",
38603         "bq",
38604         "599",
38605         1
38606       ],
38607       [
38608         "Cayman Islands",
38609         "ky",
38610         "1345"
38611       ],
38612       [
38613         "Central African Republic (République centrafricaine)",
38614         "cf",
38615         "236"
38616       ],
38617       [
38618         "Chad (Tchad)",
38619         "td",
38620         "235"
38621       ],
38622       [
38623         "Chile",
38624         "cl",
38625         "56"
38626       ],
38627       [
38628         "China (中国)",
38629         "cn",
38630         "86"
38631       ],
38632       [
38633         "Christmas Island",
38634         "cx",
38635         "61",
38636         2
38637       ],
38638       [
38639         "Cocos (Keeling) Islands",
38640         "cc",
38641         "61",
38642         1
38643       ],
38644       [
38645         "Colombia",
38646         "co",
38647         "57"
38648       ],
38649       [
38650         "Comoros (‫جزر القمر‬‎)",
38651         "km",
38652         "269"
38653       ],
38654       [
38655         "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38656         "cd",
38657         "243"
38658       ],
38659       [
38660         "Congo (Republic) (Congo-Brazzaville)",
38661         "cg",
38662         "242"
38663       ],
38664       [
38665         "Cook Islands",
38666         "ck",
38667         "682"
38668       ],
38669       [
38670         "Costa Rica",
38671         "cr",
38672         "506"
38673       ],
38674       [
38675         "Côte d’Ivoire",
38676         "ci",
38677         "225"
38678       ],
38679       [
38680         "Croatia (Hrvatska)",
38681         "hr",
38682         "385"
38683       ],
38684       [
38685         "Cuba",
38686         "cu",
38687         "53"
38688       ],
38689       [
38690         "Curaçao",
38691         "cw",
38692         "599",
38693         0
38694       ],
38695       [
38696         "Cyprus (Κύπρος)",
38697         "cy",
38698         "357"
38699       ],
38700       [
38701         "Czech Republic (Česká republika)",
38702         "cz",
38703         "420"
38704       ],
38705       [
38706         "Denmark (Danmark)",
38707         "dk",
38708         "45"
38709       ],
38710       [
38711         "Djibouti",
38712         "dj",
38713         "253"
38714       ],
38715       [
38716         "Dominica",
38717         "dm",
38718         "1767"
38719       ],
38720       [
38721         "Dominican Republic (República Dominicana)",
38722         "do",
38723         "1",
38724         2,
38725         ["809", "829", "849"]
38726       ],
38727       [
38728         "Ecuador",
38729         "ec",
38730         "593"
38731       ],
38732       [
38733         "Egypt (‫مصر‬‎)",
38734         "eg",
38735         "20"
38736       ],
38737       [
38738         "El Salvador",
38739         "sv",
38740         "503"
38741       ],
38742       [
38743         "Equatorial Guinea (Guinea Ecuatorial)",
38744         "gq",
38745         "240"
38746       ],
38747       [
38748         "Eritrea",
38749         "er",
38750         "291"
38751       ],
38752       [
38753         "Estonia (Eesti)",
38754         "ee",
38755         "372"
38756       ],
38757       [
38758         "Ethiopia",
38759         "et",
38760         "251"
38761       ],
38762       [
38763         "Falkland Islands (Islas Malvinas)",
38764         "fk",
38765         "500"
38766       ],
38767       [
38768         "Faroe Islands (Føroyar)",
38769         "fo",
38770         "298"
38771       ],
38772       [
38773         "Fiji",
38774         "fj",
38775         "679"
38776       ],
38777       [
38778         "Finland (Suomi)",
38779         "fi",
38780         "358",
38781         0
38782       ],
38783       [
38784         "France",
38785         "fr",
38786         "33"
38787       ],
38788       [
38789         "French Guiana (Guyane française)",
38790         "gf",
38791         "594"
38792       ],
38793       [
38794         "French Polynesia (Polynésie française)",
38795         "pf",
38796         "689"
38797       ],
38798       [
38799         "Gabon",
38800         "ga",
38801         "241"
38802       ],
38803       [
38804         "Gambia",
38805         "gm",
38806         "220"
38807       ],
38808       [
38809         "Georgia (საქართველო)",
38810         "ge",
38811         "995"
38812       ],
38813       [
38814         "Germany (Deutschland)",
38815         "de",
38816         "49"
38817       ],
38818       [
38819         "Ghana (Gaana)",
38820         "gh",
38821         "233"
38822       ],
38823       [
38824         "Gibraltar",
38825         "gi",
38826         "350"
38827       ],
38828       [
38829         "Greece (Ελλάδα)",
38830         "gr",
38831         "30"
38832       ],
38833       [
38834         "Greenland (Kalaallit Nunaat)",
38835         "gl",
38836         "299"
38837       ],
38838       [
38839         "Grenada",
38840         "gd",
38841         "1473"
38842       ],
38843       [
38844         "Guadeloupe",
38845         "gp",
38846         "590",
38847         0
38848       ],
38849       [
38850         "Guam",
38851         "gu",
38852         "1671"
38853       ],
38854       [
38855         "Guatemala",
38856         "gt",
38857         "502"
38858       ],
38859       [
38860         "Guernsey",
38861         "gg",
38862         "44",
38863         1
38864       ],
38865       [
38866         "Guinea (Guinée)",
38867         "gn",
38868         "224"
38869       ],
38870       [
38871         "Guinea-Bissau (Guiné Bissau)",
38872         "gw",
38873         "245"
38874       ],
38875       [
38876         "Guyana",
38877         "gy",
38878         "592"
38879       ],
38880       [
38881         "Haiti",
38882         "ht",
38883         "509"
38884       ],
38885       [
38886         "Honduras",
38887         "hn",
38888         "504"
38889       ],
38890       [
38891         "Hong Kong (香港)",
38892         "hk",
38893         "852"
38894       ],
38895       [
38896         "Hungary (Magyarország)",
38897         "hu",
38898         "36"
38899       ],
38900       [
38901         "Iceland (Ísland)",
38902         "is",
38903         "354"
38904       ],
38905       [
38906         "India (भारत)",
38907         "in",
38908         "91"
38909       ],
38910       [
38911         "Indonesia",
38912         "id",
38913         "62"
38914       ],
38915       [
38916         "Iran (‫ایران‬‎)",
38917         "ir",
38918         "98"
38919       ],
38920       [
38921         "Iraq (‫العراق‬‎)",
38922         "iq",
38923         "964"
38924       ],
38925       [
38926         "Ireland",
38927         "ie",
38928         "353"
38929       ],
38930       [
38931         "Isle of Man",
38932         "im",
38933         "44",
38934         2
38935       ],
38936       [
38937         "Israel (‫ישראל‬‎)",
38938         "il",
38939         "972"
38940       ],
38941       [
38942         "Italy (Italia)",
38943         "it",
38944         "39",
38945         0
38946       ],
38947       [
38948         "Jamaica",
38949         "jm",
38950         "1876"
38951       ],
38952       [
38953         "Japan (日本)",
38954         "jp",
38955         "81"
38956       ],
38957       [
38958         "Jersey",
38959         "je",
38960         "44",
38961         3
38962       ],
38963       [
38964         "Jordan (‫الأردن‬‎)",
38965         "jo",
38966         "962"
38967       ],
38968       [
38969         "Kazakhstan (Казахстан)",
38970         "kz",
38971         "7",
38972         1
38973       ],
38974       [
38975         "Kenya",
38976         "ke",
38977         "254"
38978       ],
38979       [
38980         "Kiribati",
38981         "ki",
38982         "686"
38983       ],
38984       [
38985         "Kosovo",
38986         "xk",
38987         "383"
38988       ],
38989       [
38990         "Kuwait (‫الكويت‬‎)",
38991         "kw",
38992         "965"
38993       ],
38994       [
38995         "Kyrgyzstan (Кыргызстан)",
38996         "kg",
38997         "996"
38998       ],
38999       [
39000         "Laos (ລາວ)",
39001         "la",
39002         "856"
39003       ],
39004       [
39005         "Latvia (Latvija)",
39006         "lv",
39007         "371"
39008       ],
39009       [
39010         "Lebanon (‫لبنان‬‎)",
39011         "lb",
39012         "961"
39013       ],
39014       [
39015         "Lesotho",
39016         "ls",
39017         "266"
39018       ],
39019       [
39020         "Liberia",
39021         "lr",
39022         "231"
39023       ],
39024       [
39025         "Libya (‫ليبيا‬‎)",
39026         "ly",
39027         "218"
39028       ],
39029       [
39030         "Liechtenstein",
39031         "li",
39032         "423"
39033       ],
39034       [
39035         "Lithuania (Lietuva)",
39036         "lt",
39037         "370"
39038       ],
39039       [
39040         "Luxembourg",
39041         "lu",
39042         "352"
39043       ],
39044       [
39045         "Macau (澳門)",
39046         "mo",
39047         "853"
39048       ],
39049       [
39050         "Macedonia (FYROM) (Македонија)",
39051         "mk",
39052         "389"
39053       ],
39054       [
39055         "Madagascar (Madagasikara)",
39056         "mg",
39057         "261"
39058       ],
39059       [
39060         "Malawi",
39061         "mw",
39062         "265"
39063       ],
39064       [
39065         "Malaysia",
39066         "my",
39067         "60"
39068       ],
39069       [
39070         "Maldives",
39071         "mv",
39072         "960"
39073       ],
39074       [
39075         "Mali",
39076         "ml",
39077         "223"
39078       ],
39079       [
39080         "Malta",
39081         "mt",
39082         "356"
39083       ],
39084       [
39085         "Marshall Islands",
39086         "mh",
39087         "692"
39088       ],
39089       [
39090         "Martinique",
39091         "mq",
39092         "596"
39093       ],
39094       [
39095         "Mauritania (‫موريتانيا‬‎)",
39096         "mr",
39097         "222"
39098       ],
39099       [
39100         "Mauritius (Moris)",
39101         "mu",
39102         "230"
39103       ],
39104       [
39105         "Mayotte",
39106         "yt",
39107         "262",
39108         1
39109       ],
39110       [
39111         "Mexico (México)",
39112         "mx",
39113         "52"
39114       ],
39115       [
39116         "Micronesia",
39117         "fm",
39118         "691"
39119       ],
39120       [
39121         "Moldova (Republica Moldova)",
39122         "md",
39123         "373"
39124       ],
39125       [
39126         "Monaco",
39127         "mc",
39128         "377"
39129       ],
39130       [
39131         "Mongolia (Монгол)",
39132         "mn",
39133         "976"
39134       ],
39135       [
39136         "Montenegro (Crna Gora)",
39137         "me",
39138         "382"
39139       ],
39140       [
39141         "Montserrat",
39142         "ms",
39143         "1664"
39144       ],
39145       [
39146         "Morocco (‫المغرب‬‎)",
39147         "ma",
39148         "212",
39149         0
39150       ],
39151       [
39152         "Mozambique (Moçambique)",
39153         "mz",
39154         "258"
39155       ],
39156       [
39157         "Myanmar (Burma) (မြန်မာ)",
39158         "mm",
39159         "95"
39160       ],
39161       [
39162         "Namibia (Namibië)",
39163         "na",
39164         "264"
39165       ],
39166       [
39167         "Nauru",
39168         "nr",
39169         "674"
39170       ],
39171       [
39172         "Nepal (नेपाल)",
39173         "np",
39174         "977"
39175       ],
39176       [
39177         "Netherlands (Nederland)",
39178         "nl",
39179         "31"
39180       ],
39181       [
39182         "New Caledonia (Nouvelle-Calédonie)",
39183         "nc",
39184         "687"
39185       ],
39186       [
39187         "New Zealand",
39188         "nz",
39189         "64"
39190       ],
39191       [
39192         "Nicaragua",
39193         "ni",
39194         "505"
39195       ],
39196       [
39197         "Niger (Nijar)",
39198         "ne",
39199         "227"
39200       ],
39201       [
39202         "Nigeria",
39203         "ng",
39204         "234"
39205       ],
39206       [
39207         "Niue",
39208         "nu",
39209         "683"
39210       ],
39211       [
39212         "Norfolk Island",
39213         "nf",
39214         "672"
39215       ],
39216       [
39217         "North Korea (조선 민주주의 인민 공화국)",
39218         "kp",
39219         "850"
39220       ],
39221       [
39222         "Northern Mariana Islands",
39223         "mp",
39224         "1670"
39225       ],
39226       [
39227         "Norway (Norge)",
39228         "no",
39229         "47",
39230         0
39231       ],
39232       [
39233         "Oman (‫عُمان‬‎)",
39234         "om",
39235         "968"
39236       ],
39237       [
39238         "Pakistan (‫پاکستان‬‎)",
39239         "pk",
39240         "92"
39241       ],
39242       [
39243         "Palau",
39244         "pw",
39245         "680"
39246       ],
39247       [
39248         "Palestine (‫فلسطين‬‎)",
39249         "ps",
39250         "970"
39251       ],
39252       [
39253         "Panama (Panamá)",
39254         "pa",
39255         "507"
39256       ],
39257       [
39258         "Papua New Guinea",
39259         "pg",
39260         "675"
39261       ],
39262       [
39263         "Paraguay",
39264         "py",
39265         "595"
39266       ],
39267       [
39268         "Peru (Perú)",
39269         "pe",
39270         "51"
39271       ],
39272       [
39273         "Philippines",
39274         "ph",
39275         "63"
39276       ],
39277       [
39278         "Poland (Polska)",
39279         "pl",
39280         "48"
39281       ],
39282       [
39283         "Portugal",
39284         "pt",
39285         "351"
39286       ],
39287       [
39288         "Puerto Rico",
39289         "pr",
39290         "1",
39291         3,
39292         ["787", "939"]
39293       ],
39294       [
39295         "Qatar (‫قطر‬‎)",
39296         "qa",
39297         "974"
39298       ],
39299       [
39300         "Réunion (La Réunion)",
39301         "re",
39302         "262",
39303         0
39304       ],
39305       [
39306         "Romania (România)",
39307         "ro",
39308         "40"
39309       ],
39310       [
39311         "Russia (Россия)",
39312         "ru",
39313         "7",
39314         0
39315       ],
39316       [
39317         "Rwanda",
39318         "rw",
39319         "250"
39320       ],
39321       [
39322         "Saint Barthélemy",
39323         "bl",
39324         "590",
39325         1
39326       ],
39327       [
39328         "Saint Helena",
39329         "sh",
39330         "290"
39331       ],
39332       [
39333         "Saint Kitts and Nevis",
39334         "kn",
39335         "1869"
39336       ],
39337       [
39338         "Saint Lucia",
39339         "lc",
39340         "1758"
39341       ],
39342       [
39343         "Saint Martin (Saint-Martin (partie française))",
39344         "mf",
39345         "590",
39346         2
39347       ],
39348       [
39349         "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39350         "pm",
39351         "508"
39352       ],
39353       [
39354         "Saint Vincent and the Grenadines",
39355         "vc",
39356         "1784"
39357       ],
39358       [
39359         "Samoa",
39360         "ws",
39361         "685"
39362       ],
39363       [
39364         "San Marino",
39365         "sm",
39366         "378"
39367       ],
39368       [
39369         "São Tomé and Príncipe (São Tomé e Príncipe)",
39370         "st",
39371         "239"
39372       ],
39373       [
39374         "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
39375         "sa",
39376         "966"
39377       ],
39378       [
39379         "Senegal (Sénégal)",
39380         "sn",
39381         "221"
39382       ],
39383       [
39384         "Serbia (Србија)",
39385         "rs",
39386         "381"
39387       ],
39388       [
39389         "Seychelles",
39390         "sc",
39391         "248"
39392       ],
39393       [
39394         "Sierra Leone",
39395         "sl",
39396         "232"
39397       ],
39398       [
39399         "Singapore",
39400         "sg",
39401         "65"
39402       ],
39403       [
39404         "Sint Maarten",
39405         "sx",
39406         "1721"
39407       ],
39408       [
39409         "Slovakia (Slovensko)",
39410         "sk",
39411         "421"
39412       ],
39413       [
39414         "Slovenia (Slovenija)",
39415         "si",
39416         "386"
39417       ],
39418       [
39419         "Solomon Islands",
39420         "sb",
39421         "677"
39422       ],
39423       [
39424         "Somalia (Soomaaliya)",
39425         "so",
39426         "252"
39427       ],
39428       [
39429         "South Africa",
39430         "za",
39431         "27"
39432       ],
39433       [
39434         "South Korea (대한민국)",
39435         "kr",
39436         "82"
39437       ],
39438       [
39439         "South Sudan (‫جنوب السودان‬‎)",
39440         "ss",
39441         "211"
39442       ],
39443       [
39444         "Spain (España)",
39445         "es",
39446         "34"
39447       ],
39448       [
39449         "Sri Lanka (ශ්‍රී ලංකාව)",
39450         "lk",
39451         "94"
39452       ],
39453       [
39454         "Sudan (‫السودان‬‎)",
39455         "sd",
39456         "249"
39457       ],
39458       [
39459         "Suriname",
39460         "sr",
39461         "597"
39462       ],
39463       [
39464         "Svalbard and Jan Mayen",
39465         "sj",
39466         "47",
39467         1
39468       ],
39469       [
39470         "Swaziland",
39471         "sz",
39472         "268"
39473       ],
39474       [
39475         "Sweden (Sverige)",
39476         "se",
39477         "46"
39478       ],
39479       [
39480         "Switzerland (Schweiz)",
39481         "ch",
39482         "41"
39483       ],
39484       [
39485         "Syria (‫سوريا‬‎)",
39486         "sy",
39487         "963"
39488       ],
39489       [
39490         "Taiwan (台灣)",
39491         "tw",
39492         "886"
39493       ],
39494       [
39495         "Tajikistan",
39496         "tj",
39497         "992"
39498       ],
39499       [
39500         "Tanzania",
39501         "tz",
39502         "255"
39503       ],
39504       [
39505         "Thailand (ไทย)",
39506         "th",
39507         "66"
39508       ],
39509       [
39510         "Timor-Leste",
39511         "tl",
39512         "670"
39513       ],
39514       [
39515         "Togo",
39516         "tg",
39517         "228"
39518       ],
39519       [
39520         "Tokelau",
39521         "tk",
39522         "690"
39523       ],
39524       [
39525         "Tonga",
39526         "to",
39527         "676"
39528       ],
39529       [
39530         "Trinidad and Tobago",
39531         "tt",
39532         "1868"
39533       ],
39534       [
39535         "Tunisia (‫تونس‬‎)",
39536         "tn",
39537         "216"
39538       ],
39539       [
39540         "Turkey (Türkiye)",
39541         "tr",
39542         "90"
39543       ],
39544       [
39545         "Turkmenistan",
39546         "tm",
39547         "993"
39548       ],
39549       [
39550         "Turks and Caicos Islands",
39551         "tc",
39552         "1649"
39553       ],
39554       [
39555         "Tuvalu",
39556         "tv",
39557         "688"
39558       ],
39559       [
39560         "U.S. Virgin Islands",
39561         "vi",
39562         "1340"
39563       ],
39564       [
39565         "Uganda",
39566         "ug",
39567         "256"
39568       ],
39569       [
39570         "Ukraine (Україна)",
39571         "ua",
39572         "380"
39573       ],
39574       [
39575         "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
39576         "ae",
39577         "971"
39578       ],
39579       [
39580         "United Kingdom",
39581         "gb",
39582         "44",
39583         0
39584       ],
39585       [
39586         "United States",
39587         "us",
39588         "1",
39589         0
39590       ],
39591       [
39592         "Uruguay",
39593         "uy",
39594         "598"
39595       ],
39596       [
39597         "Uzbekistan (Oʻzbekiston)",
39598         "uz",
39599         "998"
39600       ],
39601       [
39602         "Vanuatu",
39603         "vu",
39604         "678"
39605       ],
39606       [
39607         "Vatican City (Città del Vaticano)",
39608         "va",
39609         "39",
39610         1
39611       ],
39612       [
39613         "Venezuela",
39614         "ve",
39615         "58"
39616       ],
39617       [
39618         "Vietnam (Việt Nam)",
39619         "vn",
39620         "84"
39621       ],
39622       [
39623         "Wallis and Futuna (Wallis-et-Futuna)",
39624         "wf",
39625         "681"
39626       ],
39627       [
39628         "Western Sahara (‫الصحراء الغربية‬‎)",
39629         "eh",
39630         "212",
39631         1
39632       ],
39633       [
39634         "Yemen (‫اليمن‬‎)",
39635         "ye",
39636         "967"
39637       ],
39638       [
39639         "Zambia",
39640         "zm",
39641         "260"
39642       ],
39643       [
39644         "Zimbabwe",
39645         "zw",
39646         "263"
39647       ],
39648       [
39649         "Åland Islands",
39650         "ax",
39651         "358",
39652         1
39653       ]
39654   ];
39655   
39656   return d;
39657 }/**
39658 *    This script refer to:
39659 *    Title: International Telephone Input
39660 *    Author: Jack O'Connor
39661 *    Code version:  v12.1.12
39662 *    Availability: https://github.com/jackocnr/intl-tel-input.git
39663 **/
39664
39665 /**
39666  * @class Roo.bootstrap.PhoneInput
39667  * @extends Roo.bootstrap.TriggerField
39668  * An input with International dial-code selection
39669  
39670  * @cfg {String} defaultDialCode default '+852'
39671  * @cfg {Array} preferedCountries default []
39672   
39673  * @constructor
39674  * Create a new PhoneInput.
39675  * @param {Object} config Configuration options
39676  */
39677
39678 Roo.bootstrap.PhoneInput = function(config) {
39679     Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39680 };
39681
39682 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39683         
39684         listWidth: undefined,
39685         
39686         selectedClass: 'active',
39687         
39688         invalidClass : "has-warning",
39689         
39690         validClass: 'has-success',
39691         
39692         allowed: '0123456789',
39693         
39694         /**
39695          * @cfg {String} defaultDialCode The default dial code when initializing the input
39696          */
39697         defaultDialCode: '+852',
39698         
39699         /**
39700          * @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
39701          */
39702         preferedCountries: false,
39703         
39704         getAutoCreate : function()
39705         {
39706             var data = Roo.bootstrap.PhoneInputData();
39707             var align = this.labelAlign || this.parentLabelAlign();
39708             var id = Roo.id();
39709             
39710             this.allCountries = [];
39711             this.dialCodeMapping = [];
39712             
39713             for (var i = 0; i < data.length; i++) {
39714               var c = data[i];
39715               this.allCountries[i] = {
39716                 name: c[0],
39717                 iso2: c[1],
39718                 dialCode: c[2],
39719                 priority: c[3] || 0,
39720                 areaCodes: c[4] || null
39721               };
39722               this.dialCodeMapping[c[2]] = {
39723                   name: c[0],
39724                   iso2: c[1],
39725                   priority: c[3] || 0,
39726                   areaCodes: c[4] || null
39727               };
39728             }
39729             
39730             var cfg = {
39731                 cls: 'form-group',
39732                 cn: []
39733             };
39734             
39735             var input =  {
39736                 tag: 'input',
39737                 id : id,
39738                 cls : 'form-control tel-input',
39739                 autocomplete: 'new-password'
39740             };
39741             
39742             var hiddenInput = {
39743                 tag: 'input',
39744                 type: 'hidden',
39745                 cls: 'hidden-tel-input'
39746             };
39747             
39748             if (this.name) {
39749                 hiddenInput.name = this.name;
39750             }
39751             
39752             if (this.disabled) {
39753                 input.disabled = true;
39754             }
39755             
39756             var flag_container = {
39757                 tag: 'div',
39758                 cls: 'flag-box',
39759                 cn: [
39760                     {
39761                         tag: 'div',
39762                         cls: 'flag'
39763                     },
39764                     {
39765                         tag: 'div',
39766                         cls: 'caret'
39767                     }
39768                 ]
39769             };
39770             
39771             var box = {
39772                 tag: 'div',
39773                 cls: this.hasFeedback ? 'has-feedback' : '',
39774                 cn: [
39775                     hiddenInput,
39776                     input,
39777                     {
39778                         tag: 'input',
39779                         cls: 'dial-code-holder',
39780                         disabled: true
39781                     }
39782                 ]
39783             };
39784             
39785             var container = {
39786                 cls: 'roo-select2-container input-group',
39787                 cn: [
39788                     flag_container,
39789                     box
39790                 ]
39791             };
39792             
39793             if (this.fieldLabel.length) {
39794                 var indicator = {
39795                     tag: 'i',
39796                     tooltip: 'This field is required'
39797                 };
39798                 
39799                 var label = {
39800                     tag: 'label',
39801                     'for':  id,
39802                     cls: 'control-label',
39803                     cn: []
39804                 };
39805                 
39806                 var label_text = {
39807                     tag: 'span',
39808                     html: this.fieldLabel
39809                 };
39810                 
39811                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39812                 label.cn = [
39813                     indicator,
39814                     label_text
39815                 ];
39816                 
39817                 if(this.indicatorpos == 'right') {
39818                     indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39819                     label.cn = [
39820                         label_text,
39821                         indicator
39822                     ];
39823                 }
39824                 
39825                 if(align == 'left') {
39826                     container = {
39827                         tag: 'div',
39828                         cn: [
39829                             container
39830                         ]
39831                     };
39832                     
39833                     if(this.labelWidth > 12){
39834                         label.style = "width: " + this.labelWidth + 'px';
39835                     }
39836                     if(this.labelWidth < 13 && this.labelmd == 0){
39837                         this.labelmd = this.labelWidth;
39838                     }
39839                     if(this.labellg > 0){
39840                         label.cls += ' col-lg-' + this.labellg;
39841                         input.cls += ' col-lg-' + (12 - this.labellg);
39842                     }
39843                     if(this.labelmd > 0){
39844                         label.cls += ' col-md-' + this.labelmd;
39845                         container.cls += ' col-md-' + (12 - this.labelmd);
39846                     }
39847                     if(this.labelsm > 0){
39848                         label.cls += ' col-sm-' + this.labelsm;
39849                         container.cls += ' col-sm-' + (12 - this.labelsm);
39850                     }
39851                     if(this.labelxs > 0){
39852                         label.cls += ' col-xs-' + this.labelxs;
39853                         container.cls += ' col-xs-' + (12 - this.labelxs);
39854                     }
39855                 }
39856             }
39857             
39858             cfg.cn = [
39859                 label,
39860                 container
39861             ];
39862             
39863             var settings = this;
39864             
39865             ['xs','sm','md','lg'].map(function(size){
39866                 if (settings[size]) {
39867                     cfg.cls += ' col-' + size + '-' + settings[size];
39868                 }
39869             });
39870             
39871             this.store = new Roo.data.Store({
39872                 proxy : new Roo.data.MemoryProxy({}),
39873                 reader : new Roo.data.JsonReader({
39874                     fields : [
39875                         {
39876                             'name' : 'name',
39877                             'type' : 'string'
39878                         },
39879                         {
39880                             'name' : 'iso2',
39881                             'type' : 'string'
39882                         },
39883                         {
39884                             'name' : 'dialCode',
39885                             'type' : 'string'
39886                         },
39887                         {
39888                             'name' : 'priority',
39889                             'type' : 'string'
39890                         },
39891                         {
39892                             'name' : 'areaCodes',
39893                             'type' : 'string'
39894                         }
39895                     ]
39896                 })
39897             });
39898             
39899             if(!this.preferedCountries) {
39900                 this.preferedCountries = [
39901                     'hk',
39902                     'gb',
39903                     'us'
39904                 ];
39905             }
39906             
39907             var p = this.preferedCountries.reverse();
39908             
39909             if(p) {
39910                 for (var i = 0; i < p.length; i++) {
39911                     for (var j = 0; j < this.allCountries.length; j++) {
39912                         if(this.allCountries[j].iso2 == p[i]) {
39913                             var t = this.allCountries[j];
39914                             this.allCountries.splice(j,1);
39915                             this.allCountries.unshift(t);
39916                         }
39917                     } 
39918                 }
39919             }
39920             
39921             this.store.proxy.data = {
39922                 success: true,
39923                 data: this.allCountries
39924             };
39925             
39926             return cfg;
39927         },
39928         
39929         initEvents : function()
39930         {
39931             this.createList();
39932             Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39933             
39934             this.indicator = this.indicatorEl();
39935             this.flag = this.flagEl();
39936             this.dialCodeHolder = this.dialCodeHolderEl();
39937             
39938             this.trigger = this.el.select('div.flag-box',true).first();
39939             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39940             
39941             var _this = this;
39942             
39943             (function(){
39944                 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39945                 _this.list.setWidth(lw);
39946             }).defer(100);
39947             
39948             this.list.on('mouseover', this.onViewOver, this);
39949             this.list.on('mousemove', this.onViewMove, this);
39950             this.inputEl().on("keyup", this.onKeyUp, this);
39951             
39952             this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39953
39954             this.view = new Roo.View(this.list, this.tpl, {
39955                 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39956             });
39957             
39958             this.view.on('click', this.onViewClick, this);
39959             this.setValue(this.defaultDialCode);
39960         },
39961         
39962         onTriggerClick : function(e)
39963         {
39964             Roo.log('trigger click');
39965             if(this.disabled){
39966                 return;
39967             }
39968             
39969             if(this.isExpanded()){
39970                 this.collapse();
39971                 this.hasFocus = false;
39972             }else {
39973                 this.store.load({});
39974                 this.hasFocus = true;
39975                 this.expand();
39976             }
39977         },
39978         
39979         isExpanded : function()
39980         {
39981             return this.list.isVisible();
39982         },
39983         
39984         collapse : function()
39985         {
39986             if(!this.isExpanded()){
39987                 return;
39988             }
39989             this.list.hide();
39990             Roo.get(document).un('mousedown', this.collapseIf, this);
39991             Roo.get(document).un('mousewheel', this.collapseIf, this);
39992             this.fireEvent('collapse', this);
39993             this.validate();
39994         },
39995         
39996         expand : function()
39997         {
39998             Roo.log('expand');
39999
40000             if(this.isExpanded() || !this.hasFocus){
40001                 return;
40002             }
40003             
40004             var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40005             this.list.setWidth(lw);
40006             
40007             this.list.show();
40008             this.restrictHeight();
40009             
40010             Roo.get(document).on('mousedown', this.collapseIf, this);
40011             Roo.get(document).on('mousewheel', this.collapseIf, this);
40012             
40013             this.fireEvent('expand', this);
40014         },
40015         
40016         restrictHeight : function()
40017         {
40018             this.list.alignTo(this.inputEl(), this.listAlign);
40019             this.list.alignTo(this.inputEl(), this.listAlign);
40020         },
40021         
40022         onViewOver : function(e, t)
40023         {
40024             if(this.inKeyMode){
40025                 return;
40026             }
40027             var item = this.view.findItemFromChild(t);
40028             
40029             if(item){
40030                 var index = this.view.indexOf(item);
40031                 this.select(index, false);
40032             }
40033         },
40034
40035         // private
40036         onViewClick : function(view, doFocus, el, e)
40037         {
40038             var index = this.view.getSelectedIndexes()[0];
40039             
40040             var r = this.store.getAt(index);
40041             
40042             if(r){
40043                 this.onSelect(r, index);
40044             }
40045             if(doFocus !== false && !this.blockFocus){
40046                 this.inputEl().focus();
40047             }
40048         },
40049         
40050         onViewMove : function(e, t)
40051         {
40052             this.inKeyMode = false;
40053         },
40054         
40055         select : function(index, scrollIntoView)
40056         {
40057             this.selectedIndex = index;
40058             this.view.select(index);
40059             if(scrollIntoView !== false){
40060                 var el = this.view.getNode(index);
40061                 if(el){
40062                     this.list.scrollChildIntoView(el, false);
40063                 }
40064             }
40065         },
40066         
40067         createList : function()
40068         {
40069             this.list = Roo.get(document.body).createChild({
40070                 tag: 'ul',
40071                 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40072                 style: 'display:none'
40073             });
40074             
40075             this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40076         },
40077         
40078         collapseIf : function(e)
40079         {
40080             var in_combo  = e.within(this.el);
40081             var in_list =  e.within(this.list);
40082             var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40083             
40084             if (in_combo || in_list || is_list) {
40085                 return;
40086             }
40087             this.collapse();
40088         },
40089         
40090         onSelect : function(record, index)
40091         {
40092             if(this.fireEvent('beforeselect', this, record, index) !== false){
40093                 
40094                 this.setFlagClass(record.data.iso2);
40095                 this.setDialCode(record.data.dialCode);
40096                 this.hasFocus = false;
40097                 this.collapse();
40098                 this.fireEvent('select', this, record, index);
40099             }
40100         },
40101         
40102         flagEl : function()
40103         {
40104             var flag = this.el.select('div.flag',true).first();
40105             if(!flag){
40106                 return false;
40107             }
40108             return flag;
40109         },
40110         
40111         dialCodeHolderEl : function()
40112         {
40113             var d = this.el.select('input.dial-code-holder',true).first();
40114             if(!d){
40115                 return false;
40116             }
40117             return d;
40118         },
40119         
40120         setDialCode : function(v)
40121         {
40122             this.dialCodeHolder.dom.value = '+'+v;
40123         },
40124         
40125         setFlagClass : function(n)
40126         {
40127             this.flag.dom.className = 'flag '+n;
40128         },
40129         
40130         getValue : function()
40131         {
40132             var v = this.inputEl().getValue();
40133             if(this.dialCodeHolder) {
40134                 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40135             }
40136             return v;
40137         },
40138         
40139         setValue : function(v)
40140         {
40141             var d = this.getDialCode(v);
40142             
40143             //invalid dial code
40144             if(v.length == 0 || !d || d.length == 0) {
40145                 if(this.rendered){
40146                     this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40147                     this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40148                 }
40149                 return;
40150             }
40151             
40152             //valid dial code
40153             this.setFlagClass(this.dialCodeMapping[d].iso2);
40154             this.setDialCode(d);
40155             this.inputEl().dom.value = v.replace('+'+d,'');
40156             this.hiddenEl().dom.value = this.getValue();
40157             
40158             this.validate();
40159         },
40160         
40161         getDialCode : function(v)
40162         {
40163             v = v ||  '';
40164             
40165             if (v.length == 0) {
40166                 return this.dialCodeHolder.dom.value;
40167             }
40168             
40169             var dialCode = "";
40170             if (v.charAt(0) != "+") {
40171                 return false;
40172             }
40173             var numericChars = "";
40174             for (var i = 1; i < v.length; i++) {
40175               var c = v.charAt(i);
40176               if (!isNaN(c)) {
40177                 numericChars += c;
40178                 if (this.dialCodeMapping[numericChars]) {
40179                   dialCode = v.substr(1, i);
40180                 }
40181                 if (numericChars.length == 4) {
40182                   break;
40183                 }
40184               }
40185             }
40186             return dialCode;
40187         },
40188         
40189         reset : function()
40190         {
40191             this.setValue(this.defaultDialCode);
40192             this.validate();
40193         },
40194         
40195         hiddenEl : function()
40196         {
40197             return this.el.select('input.hidden-tel-input',true).first();
40198         },
40199         
40200         onKeyUp : function(e){
40201             
40202             var k = e.getKey();
40203             var c = e.getCharCode();
40204             
40205             if(
40206                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40207                     this.allowed.indexOf(String.fromCharCode(c)) === -1
40208             ){
40209                 e.stopEvent();
40210             }
40211             
40212             // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40213             //     return;
40214             // }
40215             if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40216                 e.stopEvent();
40217             }
40218             
40219             this.setValue(this.getValue());
40220         }
40221         
40222 });
40223 /**
40224  * @class Roo.bootstrap.MoneyField
40225  * @extends Roo.bootstrap.ComboBox
40226  * Bootstrap MoneyField class
40227  * 
40228  * @constructor
40229  * Create a new MoneyField.
40230  * @param {Object} config Configuration options
40231  */
40232
40233 Roo.bootstrap.MoneyField = function(config) {
40234     
40235     Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40236     
40237 };
40238
40239 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40240     
40241     /**
40242      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40243      */
40244     allowDecimals : true,
40245     /**
40246      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40247      */
40248     decimalSeparator : ".",
40249     /**
40250      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40251      */
40252     decimalPrecision : 0,
40253     /**
40254      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40255      */
40256     allowNegative : true,
40257     /**
40258      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40259      */
40260     allowZero: true,
40261     /**
40262      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40263      */
40264     minValue : Number.NEGATIVE_INFINITY,
40265     /**
40266      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40267      */
40268     maxValue : Number.MAX_VALUE,
40269     /**
40270      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40271      */
40272     minText : "The minimum value for this field is {0}",
40273     /**
40274      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40275      */
40276     maxText : "The maximum value for this field is {0}",
40277     /**
40278      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
40279      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40280      */
40281     nanText : "{0} is not a valid number",
40282     /**
40283      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40284      */
40285     castInt : true,
40286     /**
40287      * @cfg {String} defaults currency of the MoneyField
40288      * value should be in lkey
40289      */
40290     defaultCurrency : false,
40291     /**
40292      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40293      */
40294     thousandsDelimiter : false,
40295     
40296     
40297     inputlg : 9,
40298     inputmd : 9,
40299     inputsm : 9,
40300     inputxs : 6,
40301     
40302     store : false,
40303     
40304     getAutoCreate : function()
40305     {
40306         var align = this.labelAlign || this.parentLabelAlign();
40307         
40308         var id = Roo.id();
40309
40310         var cfg = {
40311             cls: 'form-group',
40312             cn: []
40313         };
40314
40315         var input =  {
40316             tag: 'input',
40317             id : id,
40318             cls : 'form-control roo-money-amount-input',
40319             autocomplete: 'new-password'
40320         };
40321         
40322         var hiddenInput = {
40323             tag: 'input',
40324             type: 'hidden',
40325             id: Roo.id(),
40326             cls: 'hidden-number-input'
40327         };
40328         
40329         if (this.name) {
40330             hiddenInput.name = this.name;
40331         }
40332
40333         if (this.disabled) {
40334             input.disabled = true;
40335         }
40336
40337         var clg = 12 - this.inputlg;
40338         var cmd = 12 - this.inputmd;
40339         var csm = 12 - this.inputsm;
40340         var cxs = 12 - this.inputxs;
40341         
40342         var container = {
40343             tag : 'div',
40344             cls : 'row roo-money-field',
40345             cn : [
40346                 {
40347                     tag : 'div',
40348                     cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40349                     cn : [
40350                         {
40351                             tag : 'div',
40352                             cls: 'roo-select2-container input-group',
40353                             cn: [
40354                                 {
40355                                     tag : 'input',
40356                                     cls : 'form-control roo-money-currency-input',
40357                                     autocomplete: 'new-password',
40358                                     readOnly : 1,
40359                                     name : this.currencyName
40360                                 },
40361                                 {
40362                                     tag :'span',
40363                                     cls : 'input-group-addon',
40364                                     cn : [
40365                                         {
40366                                             tag: 'span',
40367                                             cls: 'caret'
40368                                         }
40369                                     ]
40370                                 }
40371                             ]
40372                         }
40373                     ]
40374                 },
40375                 {
40376                     tag : 'div',
40377                     cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40378                     cn : [
40379                         {
40380                             tag: 'div',
40381                             cls: this.hasFeedback ? 'has-feedback' : '',
40382                             cn: [
40383                                 input
40384                             ]
40385                         }
40386                     ]
40387                 }
40388             ]
40389             
40390         };
40391         
40392         if (this.fieldLabel.length) {
40393             var indicator = {
40394                 tag: 'i',
40395                 tooltip: 'This field is required'
40396             };
40397
40398             var label = {
40399                 tag: 'label',
40400                 'for':  id,
40401                 cls: 'control-label',
40402                 cn: []
40403             };
40404
40405             var label_text = {
40406                 tag: 'span',
40407                 html: this.fieldLabel
40408             };
40409
40410             indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40411             label.cn = [
40412                 indicator,
40413                 label_text
40414             ];
40415
40416             if(this.indicatorpos == 'right') {
40417                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40418                 label.cn = [
40419                     label_text,
40420                     indicator
40421                 ];
40422             }
40423
40424             if(align == 'left') {
40425                 container = {
40426                     tag: 'div',
40427                     cn: [
40428                         container
40429                     ]
40430                 };
40431
40432                 if(this.labelWidth > 12){
40433                     label.style = "width: " + this.labelWidth + 'px';
40434                 }
40435                 if(this.labelWidth < 13 && this.labelmd == 0){
40436                     this.labelmd = this.labelWidth;
40437                 }
40438                 if(this.labellg > 0){
40439                     label.cls += ' col-lg-' + this.labellg;
40440                     input.cls += ' col-lg-' + (12 - this.labellg);
40441                 }
40442                 if(this.labelmd > 0){
40443                     label.cls += ' col-md-' + this.labelmd;
40444                     container.cls += ' col-md-' + (12 - this.labelmd);
40445                 }
40446                 if(this.labelsm > 0){
40447                     label.cls += ' col-sm-' + this.labelsm;
40448                     container.cls += ' col-sm-' + (12 - this.labelsm);
40449                 }
40450                 if(this.labelxs > 0){
40451                     label.cls += ' col-xs-' + this.labelxs;
40452                     container.cls += ' col-xs-' + (12 - this.labelxs);
40453                 }
40454             }
40455         }
40456
40457         cfg.cn = [
40458             label,
40459             container,
40460             hiddenInput
40461         ];
40462         
40463         var settings = this;
40464
40465         ['xs','sm','md','lg'].map(function(size){
40466             if (settings[size]) {
40467                 cfg.cls += ' col-' + size + '-' + settings[size];
40468             }
40469         });
40470         
40471         return cfg;
40472     },
40473     
40474     initEvents : function()
40475     {
40476         this.indicator = this.indicatorEl();
40477         
40478         this.initCurrencyEvent();
40479         
40480         this.initNumberEvent();
40481     },
40482     
40483     initCurrencyEvent : function()
40484     {
40485         if (!this.store) {
40486             throw "can not find store for combo";
40487         }
40488         
40489         this.store = Roo.factory(this.store, Roo.data);
40490         this.store.parent = this;
40491         
40492         this.createList();
40493         
40494         this.triggerEl = this.el.select('.input-group-addon', true).first();
40495         
40496         this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40497         
40498         var _this = this;
40499         
40500         (function(){
40501             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40502             _this.list.setWidth(lw);
40503         }).defer(100);
40504         
40505         this.list.on('mouseover', this.onViewOver, this);
40506         this.list.on('mousemove', this.onViewMove, this);
40507         this.list.on('scroll', this.onViewScroll, this);
40508         
40509         if(!this.tpl){
40510             this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40511         }
40512         
40513         this.view = new Roo.View(this.list, this.tpl, {
40514             singleSelect:true, store: this.store, selectedClass: this.selectedClass
40515         });
40516         
40517         this.view.on('click', this.onViewClick, this);
40518         
40519         this.store.on('beforeload', this.onBeforeLoad, this);
40520         this.store.on('load', this.onLoad, this);
40521         this.store.on('loadexception', this.onLoadException, this);
40522         
40523         this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40524             "up" : function(e){
40525                 this.inKeyMode = true;
40526                 this.selectPrev();
40527             },
40528
40529             "down" : function(e){
40530                 if(!this.isExpanded()){
40531                     this.onTriggerClick();
40532                 }else{
40533                     this.inKeyMode = true;
40534                     this.selectNext();
40535                 }
40536             },
40537
40538             "enter" : function(e){
40539                 this.collapse();
40540                 
40541                 if(this.fireEvent("specialkey", this, e)){
40542                     this.onViewClick(false);
40543                 }
40544                 
40545                 return true;
40546             },
40547
40548             "esc" : function(e){
40549                 this.collapse();
40550             },
40551
40552             "tab" : function(e){
40553                 this.collapse();
40554                 
40555                 if(this.fireEvent("specialkey", this, e)){
40556                     this.onViewClick(false);
40557                 }
40558                 
40559                 return true;
40560             },
40561
40562             scope : this,
40563
40564             doRelay : function(foo, bar, hname){
40565                 if(hname == 'down' || this.scope.isExpanded()){
40566                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40567                 }
40568                 return true;
40569             },
40570
40571             forceKeyDown: true
40572         });
40573         
40574         this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40575         
40576     },
40577     
40578     initNumberEvent : function(e)
40579     {
40580         this.inputEl().on("keydown" , this.fireKey,  this);
40581         this.inputEl().on("focus", this.onFocus,  this);
40582         this.inputEl().on("blur", this.onBlur,  this);
40583         
40584         this.inputEl().relayEvent('keyup', this);
40585         
40586         if(this.indicator){
40587             this.indicator.addClass('invisible');
40588         }
40589  
40590         this.originalValue = this.getValue();
40591         
40592         if(this.validationEvent == 'keyup'){
40593             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40594             this.inputEl().on('keyup', this.filterValidation, this);
40595         }
40596         else if(this.validationEvent !== false){
40597             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40598         }
40599         
40600         if(this.selectOnFocus){
40601             this.on("focus", this.preFocus, this);
40602             
40603         }
40604         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40605             this.inputEl().on("keypress", this.filterKeys, this);
40606         } else {
40607             this.inputEl().relayEvent('keypress', this);
40608         }
40609         
40610         var allowed = "0123456789";
40611         
40612         if(this.allowDecimals){
40613             allowed += this.decimalSeparator;
40614         }
40615         
40616         if(this.allowNegative){
40617             allowed += "-";
40618         }
40619         
40620         if(this.thousandsDelimiter) {
40621             allowed += ",";
40622         }
40623         
40624         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40625         
40626         var keyPress = function(e){
40627             
40628             var k = e.getKey();
40629             
40630             var c = e.getCharCode();
40631             
40632             if(
40633                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40634                     allowed.indexOf(String.fromCharCode(c)) === -1
40635             ){
40636                 e.stopEvent();
40637                 return;
40638             }
40639             
40640             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40641                 return;
40642             }
40643             
40644             if(allowed.indexOf(String.fromCharCode(c)) === -1){
40645                 e.stopEvent();
40646             }
40647         };
40648         
40649         this.inputEl().on("keypress", keyPress, this);
40650         
40651     },
40652     
40653     onTriggerClick : function(e)
40654     {   
40655         if(this.disabled){
40656             return;
40657         }
40658         
40659         this.page = 0;
40660         this.loadNext = false;
40661         
40662         if(this.isExpanded()){
40663             this.collapse();
40664             return;
40665         }
40666         
40667         this.hasFocus = true;
40668         
40669         if(this.triggerAction == 'all') {
40670             this.doQuery(this.allQuery, true);
40671             return;
40672         }
40673         
40674         this.doQuery(this.getRawValue());
40675     },
40676     
40677     getCurrency : function()
40678     {   
40679         var v = this.currencyEl().getValue();
40680         
40681         return v;
40682     },
40683     
40684     restrictHeight : function()
40685     {
40686         this.list.alignTo(this.currencyEl(), this.listAlign);
40687         this.list.alignTo(this.currencyEl(), this.listAlign);
40688     },
40689     
40690     onViewClick : function(view, doFocus, el, e)
40691     {
40692         var index = this.view.getSelectedIndexes()[0];
40693         
40694         var r = this.store.getAt(index);
40695         
40696         if(r){
40697             this.onSelect(r, index);
40698         }
40699     },
40700     
40701     onSelect : function(record, index){
40702         
40703         if(this.fireEvent('beforeselect', this, record, index) !== false){
40704         
40705             this.setFromCurrencyData(index > -1 ? record.data : false);
40706             
40707             this.collapse();
40708             
40709             this.fireEvent('select', this, record, index);
40710         }
40711     },
40712     
40713     setFromCurrencyData : function(o)
40714     {
40715         var currency = '';
40716         
40717         this.lastCurrency = o;
40718         
40719         if (this.currencyField) {
40720             currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40721         } else {
40722             Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
40723         }
40724         
40725         this.lastSelectionText = currency;
40726         
40727         //setting default currency
40728         if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40729             this.setCurrency(this.defaultCurrency);
40730             return;
40731         }
40732         
40733         this.setCurrency(currency);
40734     },
40735     
40736     setFromData : function(o)
40737     {
40738         var c = {};
40739         
40740         c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40741         
40742         this.setFromCurrencyData(c);
40743         
40744         var value = '';
40745         
40746         if (this.name) {
40747             value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40748         } else {
40749             Roo.log('no value set for '+ (this.name ? this.name : this.id));
40750         }
40751         
40752         this.setValue(value);
40753         
40754     },
40755     
40756     setCurrency : function(v)
40757     {   
40758         this.currencyValue = v;
40759         
40760         if(this.rendered){
40761             this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40762             this.validate();
40763         }
40764     },
40765     
40766     setValue : function(v)
40767     {
40768         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40769         
40770         this.value = v;
40771         
40772         if(this.rendered){
40773             
40774             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40775             
40776             this.inputEl().dom.value = (v == '') ? '' :
40777                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40778             
40779             if(!this.allowZero && v === '0') {
40780                 this.hiddenEl().dom.value = '';
40781                 this.inputEl().dom.value = '';
40782             }
40783             
40784             this.validate();
40785         }
40786     },
40787     
40788     getRawValue : function()
40789     {
40790         var v = this.inputEl().getValue();
40791         
40792         return v;
40793     },
40794     
40795     getValue : function()
40796     {
40797         return this.fixPrecision(this.parseValue(this.getRawValue()));
40798     },
40799     
40800     parseValue : function(value)
40801     {
40802         if(this.thousandsDelimiter) {
40803             value += "";
40804             r = new RegExp(",", "g");
40805             value = value.replace(r, "");
40806         }
40807         
40808         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40809         return isNaN(value) ? '' : value;
40810         
40811     },
40812     
40813     fixPrecision : function(value)
40814     {
40815         if(this.thousandsDelimiter) {
40816             value += "";
40817             r = new RegExp(",", "g");
40818             value = value.replace(r, "");
40819         }
40820         
40821         var nan = isNaN(value);
40822         
40823         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40824             return nan ? '' : value;
40825         }
40826         return parseFloat(value).toFixed(this.decimalPrecision);
40827     },
40828     
40829     decimalPrecisionFcn : function(v)
40830     {
40831         return Math.floor(v);
40832     },
40833     
40834     validateValue : function(value)
40835     {
40836         if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40837             return false;
40838         }
40839         
40840         var num = this.parseValue(value);
40841         
40842         if(isNaN(num)){
40843             this.markInvalid(String.format(this.nanText, value));
40844             return false;
40845         }
40846         
40847         if(num < this.minValue){
40848             this.markInvalid(String.format(this.minText, this.minValue));
40849             return false;
40850         }
40851         
40852         if(num > this.maxValue){
40853             this.markInvalid(String.format(this.maxText, this.maxValue));
40854             return false;
40855         }
40856         
40857         return true;
40858     },
40859     
40860     validate : function()
40861     {
40862         if(this.disabled || this.allowBlank){
40863             this.markValid();
40864             return true;
40865         }
40866         
40867         var currency = this.getCurrency();
40868         
40869         if(this.validateValue(this.getRawValue()) && currency.length){
40870             this.markValid();
40871             return true;
40872         }
40873         
40874         this.markInvalid();
40875         return false;
40876     },
40877     
40878     getName: function()
40879     {
40880         return this.name;
40881     },
40882     
40883     beforeBlur : function()
40884     {
40885         if(!this.castInt){
40886             return;
40887         }
40888         
40889         var v = this.parseValue(this.getRawValue());
40890         
40891         if(v || v == 0){
40892             this.setValue(v);
40893         }
40894     },
40895     
40896     onBlur : function()
40897     {
40898         this.beforeBlur();
40899         
40900         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40901             //this.el.removeClass(this.focusClass);
40902         }
40903         
40904         this.hasFocus = false;
40905         
40906         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40907             this.validate();
40908         }
40909         
40910         var v = this.getValue();
40911         
40912         if(String(v) !== String(this.startValue)){
40913             this.fireEvent('change', this, v, this.startValue);
40914         }
40915         
40916         this.fireEvent("blur", this);
40917     },
40918     
40919     inputEl : function()
40920     {
40921         return this.el.select('.roo-money-amount-input', true).first();
40922     },
40923     
40924     currencyEl : function()
40925     {
40926         return this.el.select('.roo-money-currency-input', true).first();
40927     },
40928     
40929     hiddenEl : function()
40930     {
40931         return this.el.select('input.hidden-number-input',true).first();
40932     }
40933     
40934 });