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         // if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2253         //     xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2254         // }
2255         
2256         xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2257         
2258         if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2259             this.el.setXY(xy);
2260         }
2261         
2262         this.focus();
2263         this.fireEvent("show", this);
2264     },
2265     
2266     focus : function(){
2267         return;
2268         if(!this.hidden){
2269             this.doFocus.defer(50, this);
2270         }
2271     },
2272
2273     doFocus : function(){
2274         if(!this.hidden){
2275             this.focusEl.focus();
2276         }
2277     },
2278
2279     /**
2280      * Hides this menu and optionally all parent menus
2281      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2282      */
2283     hide : function(deep)
2284     {
2285         
2286         this.hideMenuItems();
2287         if(this.el && this.isVisible()){
2288             this.fireEvent("beforehide", this);
2289             if(this.activeItem){
2290                 this.activeItem.deactivate();
2291                 this.activeItem = null;
2292             }
2293             this.triggerEl.removeClass('open');;
2294             this.hidden = true;
2295             this.fireEvent("hide", this);
2296         }
2297         if(deep === true && this.parentMenu){
2298             this.parentMenu.hide(true);
2299         }
2300     },
2301     
2302     onTriggerClick : function(e)
2303     {
2304         Roo.log('trigger click');
2305         
2306         var target = e.getTarget();
2307         
2308         Roo.log(target.nodeName.toLowerCase());
2309         
2310         if(target.nodeName.toLowerCase() === 'i'){
2311             e.preventDefault();
2312         }
2313         
2314     },
2315     
2316     onTriggerPress  : function(e)
2317     {
2318         Roo.log('trigger press');
2319         //Roo.log(e.getTarget());
2320        // Roo.log(this.triggerEl.dom);
2321        
2322         // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2323         var pel = Roo.get(e.getTarget());
2324         if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2325             Roo.log('is treeview or dropdown?');
2326             return;
2327         }
2328         
2329         if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2330             return;
2331         }
2332         
2333         if (this.isVisible()) {
2334             Roo.log('hide');
2335             this.hide();
2336         } else {
2337             Roo.log('show');
2338             this.show(this.triggerEl, false, false);
2339         }
2340         
2341         if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2342             e.stopEvent();
2343         }
2344         
2345     },
2346        
2347     
2348     hideMenuItems : function()
2349     {
2350         Roo.log("hide Menu Items");
2351         if (!this.el) { 
2352             return;
2353         }
2354         //$(backdrop).remove()
2355         this.el.select('.open',true).each(function(aa) {
2356             
2357             aa.removeClass('open');
2358           //var parent = getParent($(this))
2359           //var relatedTarget = { relatedTarget: this }
2360           
2361            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2362           //if (e.isDefaultPrevented()) return
2363            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2364         });
2365     },
2366     addxtypeChild : function (tree, cntr) {
2367         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2368           
2369         this.menuitems.add(comp);
2370         return comp;
2371
2372     },
2373     getEl : function()
2374     {
2375         Roo.log(this.el);
2376         return this.el;
2377     },
2378     
2379     clear : function()
2380     {
2381         this.getEl().dom.innerHTML = '';
2382         this.menuitems.clear();
2383     }
2384 });
2385
2386  
2387  /*
2388  * - LGPL
2389  *
2390  * menu item
2391  * 
2392  */
2393
2394
2395 /**
2396  * @class Roo.bootstrap.MenuItem
2397  * @extends Roo.bootstrap.Component
2398  * Bootstrap MenuItem class
2399  * @cfg {String} html the menu label
2400  * @cfg {String} href the link
2401  * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2402  * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2403  * @cfg {Boolean} active  used on sidebars to highlight active itesm
2404  * @cfg {String} fa favicon to show on left of menu item.
2405  * @cfg {Roo.bootsrap.Menu} menu the child menu.
2406  * 
2407  * 
2408  * @constructor
2409  * Create a new MenuItem
2410  * @param {Object} config The config object
2411  */
2412
2413
2414 Roo.bootstrap.MenuItem = function(config){
2415     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2416     this.addEvents({
2417         // raw events
2418         /**
2419          * @event click
2420          * The raw click event for the entire grid.
2421          * @param {Roo.bootstrap.MenuItem} this
2422          * @param {Roo.EventObject} e
2423          */
2424         "click" : true
2425     });
2426 };
2427
2428 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
2429     
2430     href : false,
2431     html : false,
2432     preventDefault: false,
2433     isContainer : false,
2434     active : false,
2435     fa: false,
2436     
2437     getAutoCreate : function(){
2438         
2439         if(this.isContainer){
2440             return {
2441                 tag: 'li',
2442                 cls: 'dropdown-menu-item'
2443             };
2444         }
2445         var ctag = {
2446             tag: 'span',
2447             html: 'Link'
2448         };
2449         
2450         var anc = {
2451             tag : 'a',
2452             href : '#',
2453             cn : [  ]
2454         };
2455         
2456         if (this.fa !== false) {
2457             anc.cn.push({
2458                 tag : 'i',
2459                 cls : 'fa fa-' + this.fa
2460             });
2461         }
2462         
2463         anc.cn.push(ctag);
2464         
2465         
2466         var cfg= {
2467             tag: 'li',
2468             cls: 'dropdown-menu-item',
2469             cn: [ anc ]
2470         };
2471         if (this.parent().type == 'treeview') {
2472             cfg.cls = 'treeview-menu';
2473         }
2474         if (this.active) {
2475             cfg.cls += ' active';
2476         }
2477         
2478         
2479         
2480         anc.href = this.href || cfg.cn[0].href ;
2481         ctag.html = this.html || cfg.cn[0].html ;
2482         return cfg;
2483     },
2484     
2485     initEvents: function()
2486     {
2487         if (this.parent().type == 'treeview') {
2488             this.el.select('a').on('click', this.onClick, this);
2489         }
2490         
2491         if (this.menu) {
2492             this.menu.parentType = this.xtype;
2493             this.menu.triggerEl = this.el;
2494             this.menu = this.addxtype(Roo.apply({}, this.menu));
2495         }
2496         
2497     },
2498     onClick : function(e)
2499     {
2500         Roo.log('item on click ');
2501         
2502         if(this.preventDefault){
2503             e.preventDefault();
2504         }
2505         //this.parent().hideMenuItems();
2506         
2507         this.fireEvent('click', this, e);
2508     },
2509     getEl : function()
2510     {
2511         return this.el;
2512     } 
2513 });
2514
2515  
2516
2517  /*
2518  * - LGPL
2519  *
2520  * menu separator
2521  * 
2522  */
2523
2524
2525 /**
2526  * @class Roo.bootstrap.MenuSeparator
2527  * @extends Roo.bootstrap.Component
2528  * Bootstrap MenuSeparator class
2529  * 
2530  * @constructor
2531  * Create a new MenuItem
2532  * @param {Object} config The config object
2533  */
2534
2535
2536 Roo.bootstrap.MenuSeparator = function(config){
2537     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2538 };
2539
2540 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2541     
2542     getAutoCreate : function(){
2543         var cfg = {
2544             cls: 'divider',
2545             tag : 'li'
2546         };
2547         
2548         return cfg;
2549     }
2550    
2551 });
2552
2553  
2554
2555  
2556 /*
2557 * Licence: LGPL
2558 */
2559
2560 /**
2561  * @class Roo.bootstrap.Modal
2562  * @extends Roo.bootstrap.Component
2563  * Bootstrap Modal class
2564  * @cfg {String} title Title of dialog
2565  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2566  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn
2567  * @cfg {Boolean} specificTitle default false
2568  * @cfg {Array} buttons Array of buttons or standard button set..
2569  * @cfg {String} buttonPosition (left|right|center) default right
2570  * @cfg {Boolean} animate default true
2571  * @cfg {Boolean} allow_close default true
2572  * @cfg {Boolean} fitwindow default false
2573  * @cfg {String} size (sm|lg) default empty
2574  *
2575  *
2576  * @constructor
2577  * Create a new Modal Dialog
2578  * @param {Object} config The config object
2579  */
2580
2581 Roo.bootstrap.Modal = function(config){
2582     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2583     this.addEvents({
2584         // raw events
2585         /**
2586          * @event btnclick
2587          * The raw btnclick event for the button
2588          * @param {Roo.EventObject} e
2589          */
2590         "btnclick" : true,
2591         /**
2592          * @event resize
2593          * Fire when dialog resize
2594          * @param {Roo.bootstrap.Modal} this
2595          * @param {Roo.EventObject} e
2596          */
2597         "resize" : true
2598     });
2599     this.buttons = this.buttons || [];
2600
2601     if (this.tmpl) {
2602         this.tmpl = Roo.factory(this.tmpl);
2603     }
2604
2605 };
2606
2607 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2608
2609     title : 'test dialog',
2610
2611     buttons : false,
2612
2613     // set on load...
2614
2615     html: false,
2616
2617     tmp: false,
2618
2619     specificTitle: false,
2620
2621     buttonPosition: 'right',
2622
2623     allow_close : true,
2624
2625     animate : true,
2626
2627     fitwindow: false,
2628
2629
2630      // private
2631     dialogEl: false,
2632     bodyEl:  false,
2633     footerEl:  false,
2634     titleEl:  false,
2635     closeEl:  false,
2636
2637     size: '',
2638
2639
2640     onRender : function(ct, position)
2641     {
2642         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2643
2644         if(!this.el){
2645             var cfg = Roo.apply({},  this.getAutoCreate());
2646             cfg.id = Roo.id();
2647             //if(!cfg.name){
2648             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2649             //}
2650             //if (!cfg.name.length) {
2651             //    delete cfg.name;
2652            // }
2653             if (this.cls) {
2654                 cfg.cls += ' ' + this.cls;
2655             }
2656             if (this.style) {
2657                 cfg.style = this.style;
2658             }
2659             this.el = Roo.get(document.body).createChild(cfg, position);
2660         }
2661         //var type = this.el.dom.type;
2662
2663
2664         if(this.tabIndex !== undefined){
2665             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2666         }
2667
2668         this.dialogEl = this.el.select('.modal-dialog',true).first();
2669         this.bodyEl = this.el.select('.modal-body',true).first();
2670         this.closeEl = this.el.select('.modal-header .close', true).first();
2671         this.headerEl = this.el.select('.modal-header',true).first();
2672         this.titleEl = this.el.select('.modal-title',true).first();
2673         this.footerEl = this.el.select('.modal-footer',true).first();
2674
2675         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2676         
2677         //this.el.addClass("x-dlg-modal");
2678
2679         if (this.buttons.length) {
2680             Roo.each(this.buttons, function(bb) {
2681                 var b = Roo.apply({}, bb);
2682                 b.xns = b.xns || Roo.bootstrap;
2683                 b.xtype = b.xtype || 'Button';
2684                 if (typeof(b.listeners) == 'undefined') {
2685                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2686                 }
2687
2688                 var btn = Roo.factory(b);
2689
2690                 btn.render(this.el.select('.modal-footer div').first());
2691
2692             },this);
2693         }
2694         // render the children.
2695         var nitems = [];
2696
2697         if(typeof(this.items) != 'undefined'){
2698             var items = this.items;
2699             delete this.items;
2700
2701             for(var i =0;i < items.length;i++) {
2702                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2703             }
2704         }
2705
2706         this.items = nitems;
2707
2708         // where are these used - they used to be body/close/footer
2709
2710
2711         this.initEvents();
2712         //this.el.addClass([this.fieldClass, this.cls]);
2713
2714     },
2715
2716     getAutoCreate : function(){
2717
2718
2719         var bdy = {
2720                 cls : 'modal-body',
2721                 html : this.html || ''
2722         };
2723
2724         var title = {
2725             tag: 'h4',
2726             cls : 'modal-title',
2727             html : this.title
2728         };
2729
2730         if(this.specificTitle){
2731             title = this.title;
2732
2733         };
2734
2735         var header = [];
2736         if (this.allow_close) {
2737             header.push({
2738                 tag: 'button',
2739                 cls : 'close',
2740                 html : '&times'
2741             });
2742         }
2743
2744         header.push(title);
2745
2746         var size = '';
2747
2748         if(this.size.length){
2749             size = 'modal-' + this.size;
2750         }
2751
2752         var modal = {
2753             cls: "modal",
2754              cn : [
2755                 {
2756                     cls: "modal-dialog " + size,
2757                     cn : [
2758                         {
2759                             cls : "modal-content",
2760                             cn : [
2761                                 {
2762                                     cls : 'modal-header',
2763                                     cn : header
2764                                 },
2765                                 bdy,
2766                                 {
2767                                     cls : 'modal-footer',
2768                                     cn : [
2769                                         {
2770                                             tag: 'div',
2771                                             cls: 'btn-' + this.buttonPosition
2772                                         }
2773                                     ]
2774
2775                                 }
2776
2777
2778                             ]
2779
2780                         }
2781                     ]
2782
2783                 }
2784             ]
2785         };
2786
2787         if(this.animate){
2788             modal.cls += ' fade';
2789         }
2790
2791         return modal;
2792
2793     },
2794     getChildContainer : function() {
2795
2796          return this.bodyEl;
2797
2798     },
2799     getButtonContainer : function() {
2800          return this.el.select('.modal-footer div',true).first();
2801
2802     },
2803     initEvents : function()
2804     {
2805         if (this.allow_close) {
2806             this.closeEl.on('click', this.hide, this);
2807         }
2808         Roo.EventManager.onWindowResize(this.resize, this, true);
2809
2810
2811     },
2812
2813     resize : function()
2814     {
2815         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),  Roo.lib.Dom.getViewHeight(true));
2816         if (this.fitwindow) {
2817             var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2818             var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2819             this.setSize(w,h);
2820         }
2821     },
2822
2823     setSize : function(w,h)
2824     {
2825         if (!w && !h) {
2826             return;
2827         }
2828         this.resizeTo(w,h);
2829     },
2830
2831     show : function() {
2832
2833         if (!this.rendered) {
2834             this.render();
2835         }
2836
2837         //this.el.setStyle('display', 'block');
2838         this.el.removeClass('hideing');        
2839         this.el.addClass('show');
2840  
2841         if(this.animate){  // element has 'fade'  - so stuff happens after .3s ?- not sure why the delay?
2842             var _this = this;
2843             (function(){
2844                 this.el.addClass('in');
2845             }).defer(50, this);
2846         }else{
2847             this.el.addClass('in');
2848
2849         }
2850
2851         // not sure how we can show data in here..
2852         //if (this.tmpl) {
2853         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2854         //}
2855
2856         Roo.get(document.body).addClass("x-body-masked");
2857         
2858         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),   Roo.lib.Dom.getViewHeight(true));
2859         this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2860         this.maskEl.addClass('show');
2861         
2862         this.resize();
2863         
2864         this.fireEvent('show', this);
2865
2866         // set zindex here - otherwise it appears to be ignored...
2867         this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2868
2869         (function () {
2870             this.items.forEach( function(e) {
2871                 e.layout ? e.layout() : false;
2872
2873             });
2874         }).defer(100,this);
2875
2876     },
2877     hide : function()
2878     {
2879         if(this.fireEvent("beforehide", this) !== false){
2880             this.maskEl.removeClass('show');
2881             Roo.get(document.body).removeClass("x-body-masked");
2882             this.el.removeClass('in');
2883             this.el.select('.modal-dialog', true).first().setStyle('transform','');
2884
2885             if(this.animate){ // why
2886                 this.el.addClass('hideing');
2887                 (function(){
2888                     if (!this.el.hasClass('hideing')) {
2889                         return; // it's been shown again...
2890                     }
2891                     this.el.removeClass('show');
2892                     this.el.removeClass('hideing');
2893                 }).defer(150,this);
2894                 
2895             }else{
2896                  this.el.removeClass('show');
2897             }
2898             this.fireEvent('hide', this);
2899         }
2900     },
2901     isVisible : function()
2902     {
2903         
2904         return this.el.hasClass('show') && !this.el.hasClass('hideing');
2905         
2906     },
2907
2908     addButton : function(str, cb)
2909     {
2910
2911
2912         var b = Roo.apply({}, { html : str } );
2913         b.xns = b.xns || Roo.bootstrap;
2914         b.xtype = b.xtype || 'Button';
2915         if (typeof(b.listeners) == 'undefined') {
2916             b.listeners = { click : cb.createDelegate(this)  };
2917         }
2918
2919         var btn = Roo.factory(b);
2920
2921         btn.render(this.el.select('.modal-footer div').first());
2922
2923         return btn;
2924
2925     },
2926
2927     setDefaultButton : function(btn)
2928     {
2929         //this.el.select('.modal-footer').()
2930     },
2931     diff : false,
2932
2933     resizeTo: function(w,h)
2934     {
2935         // skip.. ?? why??
2936
2937         this.dialogEl.setWidth(w);
2938         if (this.diff === false) {
2939             this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2940         }
2941
2942         this.bodyEl.setHeight(h-this.diff);
2943
2944         this.fireEvent('resize', this);
2945
2946     },
2947     setContentSize  : function(w, h)
2948     {
2949
2950     },
2951     onButtonClick: function(btn,e)
2952     {
2953         //Roo.log([a,b,c]);
2954         this.fireEvent('btnclick', btn.name, e);
2955     },
2956      /**
2957      * Set the title of the Dialog
2958      * @param {String} str new Title
2959      */
2960     setTitle: function(str) {
2961         this.titleEl.dom.innerHTML = str;
2962     },
2963     /**
2964      * Set the body of the Dialog
2965      * @param {String} str new Title
2966      */
2967     setBody: function(str) {
2968         this.bodyEl.dom.innerHTML = str;
2969     },
2970     /**
2971      * Set the body of the Dialog using the template
2972      * @param {Obj} data - apply this data to the template and replace the body contents.
2973      */
2974     applyBody: function(obj)
2975     {
2976         if (!this.tmpl) {
2977             Roo.log("Error - using apply Body without a template");
2978             //code
2979         }
2980         this.tmpl.overwrite(this.bodyEl, obj);
2981     }
2982
2983 });
2984
2985
2986 Roo.apply(Roo.bootstrap.Modal,  {
2987     /**
2988          * Button config that displays a single OK button
2989          * @type Object
2990          */
2991         OK :  [{
2992             name : 'ok',
2993             weight : 'primary',
2994             html : 'OK'
2995         }],
2996         /**
2997          * Button config that displays Yes and No buttons
2998          * @type Object
2999          */
3000         YESNO : [
3001             {
3002                 name  : 'no',
3003                 html : 'No'
3004             },
3005             {
3006                 name  :'yes',
3007                 weight : 'primary',
3008                 html : 'Yes'
3009             }
3010         ],
3011
3012         /**
3013          * Button config that displays OK and Cancel buttons
3014          * @type Object
3015          */
3016         OKCANCEL : [
3017             {
3018                name : 'cancel',
3019                 html : 'Cancel'
3020             },
3021             {
3022                 name : 'ok',
3023                 weight : 'primary',
3024                 html : 'OK'
3025             }
3026         ],
3027         /**
3028          * Button config that displays Yes, No and Cancel buttons
3029          * @type Object
3030          */
3031         YESNOCANCEL : [
3032             {
3033                 name : 'yes',
3034                 weight : 'primary',
3035                 html : 'Yes'
3036             },
3037             {
3038                 name : 'no',
3039                 html : 'No'
3040             },
3041             {
3042                 name : 'cancel',
3043                 html : 'Cancel'
3044             }
3045         ],
3046         
3047         zIndex : 10001
3048 });
3049 /*
3050  * - LGPL
3051  *
3052  * messagebox - can be used as a replace
3053  * 
3054  */
3055 /**
3056  * @class Roo.MessageBox
3057  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
3058  * Example usage:
3059  *<pre><code>
3060 // Basic alert:
3061 Roo.Msg.alert('Status', 'Changes saved successfully.');
3062
3063 // Prompt for user data:
3064 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3065     if (btn == 'ok'){
3066         // process text value...
3067     }
3068 });
3069
3070 // Show a dialog using config options:
3071 Roo.Msg.show({
3072    title:'Save Changes?',
3073    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3074    buttons: Roo.Msg.YESNOCANCEL,
3075    fn: processResult,
3076    animEl: 'elId'
3077 });
3078 </code></pre>
3079  * @singleton
3080  */
3081 Roo.bootstrap.MessageBox = function(){
3082     var dlg, opt, mask, waitTimer;
3083     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3084     var buttons, activeTextEl, bwidth;
3085
3086     
3087     // private
3088     var handleButton = function(button){
3089         dlg.hide();
3090         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3091     };
3092
3093     // private
3094     var handleHide = function(){
3095         if(opt && opt.cls){
3096             dlg.el.removeClass(opt.cls);
3097         }
3098         //if(waitTimer){
3099         //    Roo.TaskMgr.stop(waitTimer);
3100         //    waitTimer = null;
3101         //}
3102     };
3103
3104     // private
3105     var updateButtons = function(b){
3106         var width = 0;
3107         if(!b){
3108             buttons["ok"].hide();
3109             buttons["cancel"].hide();
3110             buttons["yes"].hide();
3111             buttons["no"].hide();
3112             //dlg.footer.dom.style.display = 'none';
3113             return width;
3114         }
3115         dlg.footerEl.dom.style.display = '';
3116         for(var k in buttons){
3117             if(typeof buttons[k] != "function"){
3118                 if(b[k]){
3119                     buttons[k].show();
3120                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3121                     width += buttons[k].el.getWidth()+15;
3122                 }else{
3123                     buttons[k].hide();
3124                 }
3125             }
3126         }
3127         return width;
3128     };
3129
3130     // private
3131     var handleEsc = function(d, k, e){
3132         if(opt && opt.closable !== false){
3133             dlg.hide();
3134         }
3135         if(e){
3136             e.stopEvent();
3137         }
3138     };
3139
3140     return {
3141         /**
3142          * Returns a reference to the underlying {@link Roo.BasicDialog} element
3143          * @return {Roo.BasicDialog} The BasicDialog element
3144          */
3145         getDialog : function(){
3146            if(!dlg){
3147                 dlg = new Roo.bootstrap.Modal( {
3148                     //draggable: true,
3149                     //resizable:false,
3150                     //constraintoviewport:false,
3151                     //fixedcenter:true,
3152                     //collapsible : false,
3153                     //shim:true,
3154                     //modal: true,
3155                 //    width: 'auto',
3156                   //  height:100,
3157                     //buttonAlign:"center",
3158                     closeClick : function(){
3159                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3160                             handleButton("no");
3161                         }else{
3162                             handleButton("cancel");
3163                         }
3164                     }
3165                 });
3166                 dlg.render();
3167                 dlg.on("hide", handleHide);
3168                 mask = dlg.mask;
3169                 //dlg.addKeyListener(27, handleEsc);
3170                 buttons = {};
3171                 this.buttons = buttons;
3172                 var bt = this.buttonText;
3173                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3174                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3175                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3176                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3177                 //Roo.log(buttons);
3178                 bodyEl = dlg.bodyEl.createChild({
3179
3180                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3181                         '<textarea class="roo-mb-textarea"></textarea>' +
3182                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
3183                 });
3184                 msgEl = bodyEl.dom.firstChild;
3185                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3186                 textboxEl.enableDisplayMode();
3187                 textboxEl.addKeyListener([10,13], function(){
3188                     if(dlg.isVisible() && opt && opt.buttons){
3189                         if(opt.buttons.ok){
3190                             handleButton("ok");
3191                         }else if(opt.buttons.yes){
3192                             handleButton("yes");
3193                         }
3194                     }
3195                 });
3196                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3197                 textareaEl.enableDisplayMode();
3198                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3199                 progressEl.enableDisplayMode();
3200                 
3201                 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3202                 var pf = progressEl.dom.firstChild;
3203                 if (pf) {
3204                     pp = Roo.get(pf.firstChild);
3205                     pp.setHeight(pf.offsetHeight);
3206                 }
3207                 
3208             }
3209             return dlg;
3210         },
3211
3212         /**
3213          * Updates the message box body text
3214          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3215          * the XHTML-compliant non-breaking space character '&amp;#160;')
3216          * @return {Roo.MessageBox} This message box
3217          */
3218         updateText : function(text)
3219         {
3220             if(!dlg.isVisible() && !opt.width){
3221                 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3222                 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3223             }
3224             msgEl.innerHTML = text || '&#160;';
3225       
3226             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3227             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3228             var w = Math.max(
3229                     Math.min(opt.width || cw , this.maxWidth), 
3230                     Math.max(opt.minWidth || this.minWidth, bwidth)
3231             );
3232             if(opt.prompt){
3233                 activeTextEl.setWidth(w);
3234             }
3235             if(dlg.isVisible()){
3236                 dlg.fixedcenter = false;
3237             }
3238             // to big, make it scroll. = But as usual stupid IE does not support
3239             // !important..
3240             
3241             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3242                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3243                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3244             } else {
3245                 bodyEl.dom.style.height = '';
3246                 bodyEl.dom.style.overflowY = '';
3247             }
3248             if (cw > w) {
3249                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3250             } else {
3251                 bodyEl.dom.style.overflowX = '';
3252             }
3253             
3254             dlg.setContentSize(w, bodyEl.getHeight());
3255             if(dlg.isVisible()){
3256                 dlg.fixedcenter = true;
3257             }
3258             return this;
3259         },
3260
3261         /**
3262          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
3263          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3264          * @param {Number} value Any number between 0 and 1 (e.g., .5)
3265          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3266          * @return {Roo.MessageBox} This message box
3267          */
3268         updateProgress : function(value, text){
3269             if(text){
3270                 this.updateText(text);
3271             }
3272             
3273             if (pp) { // weird bug on my firefox - for some reason this is not defined
3274                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3275                 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3276             }
3277             return this;
3278         },        
3279
3280         /**
3281          * Returns true if the message box is currently displayed
3282          * @return {Boolean} True if the message box is visible, else false
3283          */
3284         isVisible : function(){
3285             return dlg && dlg.isVisible();  
3286         },
3287
3288         /**
3289          * Hides the message box if it is displayed
3290          */
3291         hide : function(){
3292             if(this.isVisible()){
3293                 dlg.hide();
3294             }  
3295         },
3296
3297         /**
3298          * Displays a new message box, or reinitializes an existing message box, based on the config options
3299          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3300          * The following config object properties are supported:
3301          * <pre>
3302 Property    Type             Description
3303 ----------  ---------------  ------------------------------------------------------------------------------------
3304 animEl            String/Element   An id or Element from which the message box should animate as it opens and
3305                                    closes (defaults to undefined)
3306 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3307                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
3308 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
3309                                    progress and wait dialogs will ignore this property and always hide the
3310                                    close button as they can only be closed programmatically.
3311 cls               String           A custom CSS class to apply to the message box element
3312 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
3313                                    displayed (defaults to 75)
3314 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
3315                                    function will be btn (the name of the button that was clicked, if applicable,
3316                                    e.g. "ok"), and text (the value of the active text field, if applicable).
3317                                    Progress and wait dialogs will ignore this option since they do not respond to
3318                                    user actions and can only be closed programmatically, so any required function
3319                                    should be called by the same code after it closes the dialog.
3320 icon              String           A CSS class that provides a background image to be used as an icon for
3321                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3322 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
3323 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
3324 modal             Boolean          False to allow user interaction with the page while the message box is
3325                                    displayed (defaults to true)
3326 msg               String           A string that will replace the existing message box body text (defaults
3327                                    to the XHTML-compliant non-breaking space character '&#160;')
3328 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
3329 progress          Boolean          True to display a progress bar (defaults to false)
3330 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
3331 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
3332 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
3333 title             String           The title text
3334 value             String           The string value to set into the active textbox element if displayed
3335 wait              Boolean          True to display a progress bar (defaults to false)
3336 width             Number           The width of the dialog in pixels
3337 </pre>
3338          *
3339          * Example usage:
3340          * <pre><code>
3341 Roo.Msg.show({
3342    title: 'Address',
3343    msg: 'Please enter your address:',
3344    width: 300,
3345    buttons: Roo.MessageBox.OKCANCEL,
3346    multiline: true,
3347    fn: saveAddress,
3348    animEl: 'addAddressBtn'
3349 });
3350 </code></pre>
3351          * @param {Object} config Configuration options
3352          * @return {Roo.MessageBox} This message box
3353          */
3354         show : function(options)
3355         {
3356             
3357             // this causes nightmares if you show one dialog after another
3358             // especially on callbacks..
3359              
3360             if(this.isVisible()){
3361                 
3362                 this.hide();
3363                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3364                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
3365                 Roo.log("New Dialog Message:" +  options.msg )
3366                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3367                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3368                 
3369             }
3370             var d = this.getDialog();
3371             opt = options;
3372             d.setTitle(opt.title || "&#160;");
3373             d.closeEl.setDisplayed(opt.closable !== false);
3374             activeTextEl = textboxEl;
3375             opt.prompt = opt.prompt || (opt.multiline ? true : false);
3376             if(opt.prompt){
3377                 if(opt.multiline){
3378                     textboxEl.hide();
3379                     textareaEl.show();
3380                     textareaEl.setHeight(typeof opt.multiline == "number" ?
3381                         opt.multiline : this.defaultTextHeight);
3382                     activeTextEl = textareaEl;
3383                 }else{
3384                     textboxEl.show();
3385                     textareaEl.hide();
3386                 }
3387             }else{
3388                 textboxEl.hide();
3389                 textareaEl.hide();
3390             }
3391             progressEl.setDisplayed(opt.progress === true);
3392             this.updateProgress(0);
3393             activeTextEl.dom.value = opt.value || "";
3394             if(opt.prompt){
3395                 dlg.setDefaultButton(activeTextEl);
3396             }else{
3397                 var bs = opt.buttons;
3398                 var db = null;
3399                 if(bs && bs.ok){
3400                     db = buttons["ok"];
3401                 }else if(bs && bs.yes){
3402                     db = buttons["yes"];
3403                 }
3404                 dlg.setDefaultButton(db);
3405             }
3406             bwidth = updateButtons(opt.buttons);
3407             this.updateText(opt.msg);
3408             if(opt.cls){
3409                 d.el.addClass(opt.cls);
3410             }
3411             d.proxyDrag = opt.proxyDrag === true;
3412             d.modal = opt.modal !== false;
3413             d.mask = opt.modal !== false ? mask : false;
3414             if(!d.isVisible()){
3415                 // force it to the end of the z-index stack so it gets a cursor in FF
3416                 document.body.appendChild(dlg.el.dom);
3417                 d.animateTarget = null;
3418                 d.show(options.animEl);
3419             }
3420             return this;
3421         },
3422
3423         /**
3424          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
3425          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3426          * and closing the message box when the process is complete.
3427          * @param {String} title The title bar text
3428          * @param {String} msg The message box body text
3429          * @return {Roo.MessageBox} This message box
3430          */
3431         progress : function(title, msg){
3432             this.show({
3433                 title : title,
3434                 msg : msg,
3435                 buttons: false,
3436                 progress:true,
3437                 closable:false,
3438                 minWidth: this.minProgressWidth,
3439                 modal : true
3440             });
3441             return this;
3442         },
3443
3444         /**
3445          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3446          * If a callback function is passed it will be called after the user clicks the button, and the
3447          * id of the button that was clicked will be passed as the only parameter to the callback
3448          * (could also be the top-right close button).
3449          * @param {String} title The title bar text
3450          * @param {String} msg The message box body text
3451          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3452          * @param {Object} scope (optional) The scope of the callback function
3453          * @return {Roo.MessageBox} This message box
3454          */
3455         alert : function(title, msg, fn, scope)
3456         {
3457             this.show({
3458                 title : title,
3459                 msg : msg,
3460                 buttons: this.OK,
3461                 fn: fn,
3462                 closable : false,
3463                 scope : scope,
3464                 modal : true
3465             });
3466             return this;
3467         },
3468
3469         /**
3470          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
3471          * interaction while waiting for a long-running process to complete that does not have defined intervals.
3472          * You are responsible for closing the message box when the process is complete.
3473          * @param {String} msg The message box body text
3474          * @param {String} title (optional) The title bar text
3475          * @return {Roo.MessageBox} This message box
3476          */
3477         wait : function(msg, title){
3478             this.show({
3479                 title : title,
3480                 msg : msg,
3481                 buttons: false,
3482                 closable:false,
3483                 progress:true,
3484                 modal:true,
3485                 width:300,
3486                 wait:true
3487             });
3488             waitTimer = Roo.TaskMgr.start({
3489                 run: function(i){
3490                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3491                 },
3492                 interval: 1000
3493             });
3494             return this;
3495         },
3496
3497         /**
3498          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3499          * If a callback function is passed it will be called after the user clicks either button, and the id of the
3500          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3501          * @param {String} title The title bar text
3502          * @param {String} msg The message box body text
3503          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3504          * @param {Object} scope (optional) The scope of the callback function
3505          * @return {Roo.MessageBox} This message box
3506          */
3507         confirm : function(title, msg, fn, scope){
3508             this.show({
3509                 title : title,
3510                 msg : msg,
3511                 buttons: this.YESNO,
3512                 fn: fn,
3513                 scope : scope,
3514                 modal : true
3515             });
3516             return this;
3517         },
3518
3519         /**
3520          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3521          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
3522          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3523          * (could also be the top-right close button) and the text that was entered will be passed as the two
3524          * parameters to the callback.
3525          * @param {String} title The title bar text
3526          * @param {String} msg The message box body text
3527          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3528          * @param {Object} scope (optional) The scope of the callback function
3529          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3530          * property, or the height in pixels to create the textbox (defaults to false / single-line)
3531          * @return {Roo.MessageBox} This message box
3532          */
3533         prompt : function(title, msg, fn, scope, multiline){
3534             this.show({
3535                 title : title,
3536                 msg : msg,
3537                 buttons: this.OKCANCEL,
3538                 fn: fn,
3539                 minWidth:250,
3540                 scope : scope,
3541                 prompt:true,
3542                 multiline: multiline,
3543                 modal : true
3544             });
3545             return this;
3546         },
3547
3548         /**
3549          * Button config that displays a single OK button
3550          * @type Object
3551          */
3552         OK : {ok:true},
3553         /**
3554          * Button config that displays Yes and No buttons
3555          * @type Object
3556          */
3557         YESNO : {yes:true, no:true},
3558         /**
3559          * Button config that displays OK and Cancel buttons
3560          * @type Object
3561          */
3562         OKCANCEL : {ok:true, cancel:true},
3563         /**
3564          * Button config that displays Yes, No and Cancel buttons
3565          * @type Object
3566          */
3567         YESNOCANCEL : {yes:true, no:true, cancel:true},
3568
3569         /**
3570          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3571          * @type Number
3572          */
3573         defaultTextHeight : 75,
3574         /**
3575          * The maximum width in pixels of the message box (defaults to 600)
3576          * @type Number
3577          */
3578         maxWidth : 600,
3579         /**
3580          * The minimum width in pixels of the message box (defaults to 100)
3581          * @type Number
3582          */
3583         minWidth : 100,
3584         /**
3585          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
3586          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3587          * @type Number
3588          */
3589         minProgressWidth : 250,
3590         /**
3591          * An object containing the default button text strings that can be overriden for localized language support.
3592          * Supported properties are: ok, cancel, yes and no.
3593          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3594          * @type Object
3595          */
3596         buttonText : {
3597             ok : "OK",
3598             cancel : "Cancel",
3599             yes : "Yes",
3600             no : "No"
3601         }
3602     };
3603 }();
3604
3605 /**
3606  * Shorthand for {@link Roo.MessageBox}
3607  */
3608 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3609 Roo.Msg = Roo.Msg || Roo.MessageBox;
3610 /*
3611  * - LGPL
3612  *
3613  * navbar
3614  * 
3615  */
3616
3617 /**
3618  * @class Roo.bootstrap.Navbar
3619  * @extends Roo.bootstrap.Component
3620  * Bootstrap Navbar class
3621
3622  * @constructor
3623  * Create a new Navbar
3624  * @param {Object} config The config object
3625  */
3626
3627
3628 Roo.bootstrap.Navbar = function(config){
3629     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3630     this.addEvents({
3631         // raw events
3632         /**
3633          * @event beforetoggle
3634          * Fire before toggle the menu
3635          * @param {Roo.EventObject} e
3636          */
3637         "beforetoggle" : true
3638     });
3639 };
3640
3641 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3642     
3643     
3644    
3645     // private
3646     navItems : false,
3647     loadMask : false,
3648     
3649     
3650     getAutoCreate : function(){
3651         
3652         
3653         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3654         
3655     },
3656     
3657     initEvents :function ()
3658     {
3659         //Roo.log(this.el.select('.navbar-toggle',true));
3660         this.el.select('.navbar-toggle',true).on('click', function() {
3661             if(this.fireEvent('beforetoggle', this) !== false){
3662                this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3663             }
3664             
3665         }, this);
3666         
3667         var mark = {
3668             tag: "div",
3669             cls:"x-dlg-mask"
3670         };
3671         
3672         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3673         
3674         var size = this.el.getSize();
3675         this.maskEl.setSize(size.width, size.height);
3676         this.maskEl.enableDisplayMode("block");
3677         this.maskEl.hide();
3678         
3679         if(this.loadMask){
3680             this.maskEl.show();
3681         }
3682     },
3683     
3684     
3685     getChildContainer : function()
3686     {
3687         if (this.el.select('.collapse').getCount()) {
3688             return this.el.select('.collapse',true).first();
3689         }
3690         
3691         return this.el;
3692     },
3693     
3694     mask : function()
3695     {
3696         this.maskEl.show();
3697     },
3698     
3699     unmask : function()
3700     {
3701         this.maskEl.hide();
3702     } 
3703     
3704     
3705     
3706     
3707 });
3708
3709
3710
3711  
3712
3713  /*
3714  * - LGPL
3715  *
3716  * navbar
3717  * 
3718  */
3719
3720 /**
3721  * @class Roo.bootstrap.NavSimplebar
3722  * @extends Roo.bootstrap.Navbar
3723  * Bootstrap Sidebar class
3724  *
3725  * @cfg {Boolean} inverse is inverted color
3726  * 
3727  * @cfg {String} type (nav | pills | tabs)
3728  * @cfg {Boolean} arrangement stacked | justified
3729  * @cfg {String} align (left | right) alignment
3730  * 
3731  * @cfg {Boolean} main (true|false) main nav bar? default false
3732  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3733  * 
3734  * @cfg {String} tag (header|footer|nav|div) default is nav 
3735
3736  * 
3737  * 
3738  * 
3739  * @constructor
3740  * Create a new Sidebar
3741  * @param {Object} config The config object
3742  */
3743
3744
3745 Roo.bootstrap.NavSimplebar = function(config){
3746     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3747 };
3748
3749 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3750     
3751     inverse: false,
3752     
3753     type: false,
3754     arrangement: '',
3755     align : false,
3756     
3757     
3758     
3759     main : false,
3760     
3761     
3762     tag : false,
3763     
3764     
3765     getAutoCreate : function(){
3766         
3767         
3768         var cfg = {
3769             tag : this.tag || 'div',
3770             cls : 'navbar'
3771         };
3772           
3773         
3774         cfg.cn = [
3775             {
3776                 cls: 'nav',
3777                 tag : 'ul'
3778             }
3779         ];
3780         
3781          
3782         this.type = this.type || 'nav';
3783         if (['tabs','pills'].indexOf(this.type)!==-1) {
3784             cfg.cn[0].cls += ' nav-' + this.type
3785         
3786         
3787         } else {
3788             if (this.type!=='nav') {
3789                 Roo.log('nav type must be nav/tabs/pills')
3790             }
3791             cfg.cn[0].cls += ' navbar-nav'
3792         }
3793         
3794         
3795         
3796         
3797         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3798             cfg.cn[0].cls += ' nav-' + this.arrangement;
3799         }
3800         
3801         
3802         if (this.align === 'right') {
3803             cfg.cn[0].cls += ' navbar-right';
3804         }
3805         
3806         if (this.inverse) {
3807             cfg.cls += ' navbar-inverse';
3808             
3809         }
3810         
3811         
3812         return cfg;
3813     
3814         
3815     }
3816     
3817     
3818     
3819 });
3820
3821
3822
3823  
3824
3825  
3826        /*
3827  * - LGPL
3828  *
3829  * navbar
3830  * 
3831  */
3832
3833 /**
3834  * @class Roo.bootstrap.NavHeaderbar
3835  * @extends Roo.bootstrap.NavSimplebar
3836  * Bootstrap Sidebar class
3837  *
3838  * @cfg {String} brand what is brand
3839  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3840  * @cfg {String} brand_href href of the brand
3841  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3842  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3843  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3844  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3845  * 
3846  * @constructor
3847  * Create a new Sidebar
3848  * @param {Object} config The config object
3849  */
3850
3851
3852 Roo.bootstrap.NavHeaderbar = function(config){
3853     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3854       
3855 };
3856
3857 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3858     
3859     position: '',
3860     brand: '',
3861     brand_href: false,
3862     srButton : true,
3863     autohide : false,
3864     desktopCenter : false,
3865    
3866     
3867     getAutoCreate : function(){
3868         
3869         var   cfg = {
3870             tag: this.nav || 'nav',
3871             cls: 'navbar',
3872             role: 'navigation',
3873             cn: []
3874         };
3875         
3876         var cn = cfg.cn;
3877         if (this.desktopCenter) {
3878             cn.push({cls : 'container', cn : []});
3879             cn = cn[0].cn;
3880         }
3881         
3882         if(this.srButton){
3883             cn.push({
3884                 tag: 'div',
3885                 cls: 'navbar-header',
3886                 cn: [
3887                     {
3888                         tag: 'button',
3889                         type: 'button',
3890                         cls: 'navbar-toggle',
3891                         'data-toggle': 'collapse',
3892                         cn: [
3893                             {
3894                                 tag: 'span',
3895                                 cls: 'sr-only',
3896                                 html: 'Toggle navigation'
3897                             },
3898                             {
3899                                 tag: 'span',
3900                                 cls: 'icon-bar'
3901                             },
3902                             {
3903                                 tag: 'span',
3904                                 cls: 'icon-bar'
3905                             },
3906                             {
3907                                 tag: 'span',
3908                                 cls: 'icon-bar'
3909                             }
3910                         ]
3911                     }
3912                 ]
3913             });
3914         }
3915         
3916         cn.push({
3917             tag: 'div',
3918             cls: 'collapse navbar-collapse',
3919             cn : []
3920         });
3921         
3922         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3923         
3924         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3925             cfg.cls += ' navbar-' + this.position;
3926             
3927             // tag can override this..
3928             
3929             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3930         }
3931         
3932         if (this.brand !== '') {
3933             cn[0].cn.push({
3934                 tag: 'a',
3935                 href: this.brand_href ? this.brand_href : '#',
3936                 cls: 'navbar-brand',
3937                 cn: [
3938                 this.brand
3939                 ]
3940             });
3941         }
3942         
3943         if(this.main){
3944             cfg.cls += ' main-nav';
3945         }
3946         
3947         
3948         return cfg;
3949
3950         
3951     },
3952     getHeaderChildContainer : function()
3953     {
3954         if (this.srButton && this.el.select('.navbar-header').getCount()) {
3955             return this.el.select('.navbar-header',true).first();
3956         }
3957         
3958         return this.getChildContainer();
3959     },
3960     
3961     
3962     initEvents : function()
3963     {
3964         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3965         
3966         if (this.autohide) {
3967             
3968             var prevScroll = 0;
3969             var ft = this.el;
3970             
3971             Roo.get(document).on('scroll',function(e) {
3972                 var ns = Roo.get(document).getScroll().top;
3973                 var os = prevScroll;
3974                 prevScroll = ns;
3975                 
3976                 if(ns > os){
3977                     ft.removeClass('slideDown');
3978                     ft.addClass('slideUp');
3979                     return;
3980                 }
3981                 ft.removeClass('slideUp');
3982                 ft.addClass('slideDown');
3983                  
3984               
3985           },this);
3986         }
3987     }    
3988     
3989 });
3990
3991
3992
3993  
3994
3995  /*
3996  * - LGPL
3997  *
3998  * navbar
3999  * 
4000  */
4001
4002 /**
4003  * @class Roo.bootstrap.NavSidebar
4004  * @extends Roo.bootstrap.Navbar
4005  * Bootstrap Sidebar class
4006  * 
4007  * @constructor
4008  * Create a new Sidebar
4009  * @param {Object} config The config object
4010  */
4011
4012
4013 Roo.bootstrap.NavSidebar = function(config){
4014     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4015 };
4016
4017 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
4018     
4019     sidebar : true, // used by Navbar Item and NavbarGroup at present...
4020     
4021     getAutoCreate : function(){
4022         
4023         
4024         return  {
4025             tag: 'div',
4026             cls: 'sidebar sidebar-nav'
4027         };
4028     
4029         
4030     }
4031     
4032     
4033     
4034 });
4035
4036
4037
4038  
4039
4040  /*
4041  * - LGPL
4042  *
4043  * nav group
4044  * 
4045  */
4046
4047 /**
4048  * @class Roo.bootstrap.NavGroup
4049  * @extends Roo.bootstrap.Component
4050  * Bootstrap NavGroup class
4051  * @cfg {String} align (left|right)
4052  * @cfg {Boolean} inverse
4053  * @cfg {String} type (nav|pills|tab) default nav
4054  * @cfg {String} navId - reference Id for navbar.
4055
4056  * 
4057  * @constructor
4058  * Create a new nav group
4059  * @param {Object} config The config object
4060  */
4061
4062 Roo.bootstrap.NavGroup = function(config){
4063     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4064     this.navItems = [];
4065    
4066     Roo.bootstrap.NavGroup.register(this);
4067      this.addEvents({
4068         /**
4069              * @event changed
4070              * Fires when the active item changes
4071              * @param {Roo.bootstrap.NavGroup} this
4072              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4073              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
4074          */
4075         'changed': true
4076      });
4077     
4078 };
4079
4080 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
4081     
4082     align: '',
4083     inverse: false,
4084     form: false,
4085     type: 'nav',
4086     navId : '',
4087     // private
4088     
4089     navItems : false, 
4090     
4091     getAutoCreate : function()
4092     {
4093         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4094         
4095         cfg = {
4096             tag : 'ul',
4097             cls: 'nav' 
4098         };
4099         
4100         if (['tabs','pills'].indexOf(this.type)!==-1) {
4101             cfg.cls += ' nav-' + this.type
4102         } else {
4103             if (this.type!=='nav') {
4104                 Roo.log('nav type must be nav/tabs/pills')
4105             }
4106             cfg.cls += ' navbar-nav'
4107         }
4108         
4109         if (this.parent() && this.parent().sidebar) {
4110             cfg = {
4111                 tag: 'ul',
4112                 cls: 'dashboard-menu sidebar-menu'
4113             };
4114             
4115             return cfg;
4116         }
4117         
4118         if (this.form === true) {
4119             cfg = {
4120                 tag: 'form',
4121                 cls: 'navbar-form'
4122             };
4123             
4124             if (this.align === 'right') {
4125                 cfg.cls += ' navbar-right';
4126             } else {
4127                 cfg.cls += ' navbar-left';
4128             }
4129         }
4130         
4131         if (this.align === 'right') {
4132             cfg.cls += ' navbar-right';
4133         }
4134         
4135         if (this.inverse) {
4136             cfg.cls += ' navbar-inverse';
4137             
4138         }
4139         
4140         
4141         return cfg;
4142     },
4143     /**
4144     * sets the active Navigation item
4145     * @param {Roo.bootstrap.NavItem} the new current navitem
4146     */
4147     setActiveItem : function(item)
4148     {
4149         var prev = false;
4150         Roo.each(this.navItems, function(v){
4151             if (v == item) {
4152                 return ;
4153             }
4154             if (v.isActive()) {
4155                 v.setActive(false, true);
4156                 prev = v;
4157                 
4158             }
4159             
4160         });
4161
4162         item.setActive(true, true);
4163         this.fireEvent('changed', this, item, prev);
4164         
4165         
4166     },
4167     /**
4168     * gets the active Navigation item
4169     * @return {Roo.bootstrap.NavItem} the current navitem
4170     */
4171     getActive : function()
4172     {
4173         
4174         var prev = false;
4175         Roo.each(this.navItems, function(v){
4176             
4177             if (v.isActive()) {
4178                 prev = v;
4179                 
4180             }
4181             
4182         });
4183         return prev;
4184     },
4185     
4186     indexOfNav : function()
4187     {
4188         
4189         var prev = false;
4190         Roo.each(this.navItems, function(v,i){
4191             
4192             if (v.isActive()) {
4193                 prev = i;
4194                 
4195             }
4196             
4197         });
4198         return prev;
4199     },
4200     /**
4201     * adds a Navigation item
4202     * @param {Roo.bootstrap.NavItem} the navitem to add
4203     */
4204     addItem : function(cfg)
4205     {
4206         var cn = new Roo.bootstrap.NavItem(cfg);
4207         this.register(cn);
4208         cn.parentId = this.id;
4209         cn.onRender(this.el, null);
4210         return cn;
4211     },
4212     /**
4213     * register a Navigation item
4214     * @param {Roo.bootstrap.NavItem} the navitem to add
4215     */
4216     register : function(item)
4217     {
4218         this.navItems.push( item);
4219         item.navId = this.navId;
4220     
4221     },
4222     
4223     /**
4224     * clear all the Navigation item
4225     */
4226    
4227     clearAll : function()
4228     {
4229         this.navItems = [];
4230         this.el.dom.innerHTML = '';
4231     },
4232     
4233     getNavItem: function(tabId)
4234     {
4235         var ret = false;
4236         Roo.each(this.navItems, function(e) {
4237             if (e.tabId == tabId) {
4238                ret =  e;
4239                return false;
4240             }
4241             return true;
4242             
4243         });
4244         return ret;
4245     },
4246     
4247     setActiveNext : function()
4248     {
4249         var i = this.indexOfNav(this.getActive());
4250         if (i > this.navItems.length) {
4251             return;
4252         }
4253         this.setActiveItem(this.navItems[i+1]);
4254     },
4255     setActivePrev : function()
4256     {
4257         var i = this.indexOfNav(this.getActive());
4258         if (i  < 1) {
4259             return;
4260         }
4261         this.setActiveItem(this.navItems[i-1]);
4262     },
4263     clearWasActive : function(except) {
4264         Roo.each(this.navItems, function(e) {
4265             if (e.tabId != except.tabId && e.was_active) {
4266                e.was_active = false;
4267                return false;
4268             }
4269             return true;
4270             
4271         });
4272     },
4273     getWasActive : function ()
4274     {
4275         var r = false;
4276         Roo.each(this.navItems, function(e) {
4277             if (e.was_active) {
4278                r = e;
4279                return false;
4280             }
4281             return true;
4282             
4283         });
4284         return r;
4285     }
4286     
4287     
4288 });
4289
4290  
4291 Roo.apply(Roo.bootstrap.NavGroup, {
4292     
4293     groups: {},
4294      /**
4295     * register a Navigation Group
4296     * @param {Roo.bootstrap.NavGroup} the navgroup to add
4297     */
4298     register : function(navgrp)
4299     {
4300         this.groups[navgrp.navId] = navgrp;
4301         
4302     },
4303     /**
4304     * fetch a Navigation Group based on the navigation ID
4305     * @param {string} the navgroup to add
4306     * @returns {Roo.bootstrap.NavGroup} the navgroup 
4307     */
4308     get: function(navId) {
4309         if (typeof(this.groups[navId]) == 'undefined') {
4310             return false;
4311             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4312         }
4313         return this.groups[navId] ;
4314     }
4315     
4316     
4317     
4318 });
4319
4320  /*
4321  * - LGPL
4322  *
4323  * row
4324  * 
4325  */
4326
4327 /**
4328  * @class Roo.bootstrap.NavItem
4329  * @extends Roo.bootstrap.Component
4330  * Bootstrap Navbar.NavItem class
4331  * @cfg {String} href  link to
4332  * @cfg {String} html content of button
4333  * @cfg {String} badge text inside badge
4334  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4335  * @cfg {String} glyphicon name of glyphicon
4336  * @cfg {String} icon name of font awesome icon
4337  * @cfg {Boolean} active Is item active
4338  * @cfg {Boolean} disabled Is item disabled
4339  
4340  * @cfg {Boolean} preventDefault (true | false) default false
4341  * @cfg {String} tabId the tab that this item activates.
4342  * @cfg {String} tagtype (a|span) render as a href or span?
4343  * @cfg {Boolean} animateRef (true|false) link to element default false  
4344   
4345  * @constructor
4346  * Create a new Navbar Item
4347  * @param {Object} config The config object
4348  */
4349 Roo.bootstrap.NavItem = function(config){
4350     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4351     this.addEvents({
4352         // raw events
4353         /**
4354          * @event click
4355          * The raw click event for the entire grid.
4356          * @param {Roo.EventObject} e
4357          */
4358         "click" : true,
4359          /**
4360             * @event changed
4361             * Fires when the active item active state changes
4362             * @param {Roo.bootstrap.NavItem} this
4363             * @param {boolean} state the new state
4364              
4365          */
4366         'changed': true,
4367         /**
4368             * @event scrollto
4369             * Fires when scroll to element
4370             * @param {Roo.bootstrap.NavItem} this
4371             * @param {Object} options
4372             * @param {Roo.EventObject} e
4373              
4374          */
4375         'scrollto': true
4376     });
4377    
4378 };
4379
4380 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
4381     
4382     href: false,
4383     html: '',
4384     badge: '',
4385     icon: false,
4386     glyphicon: false,
4387     active: false,
4388     preventDefault : false,
4389     tabId : false,
4390     tagtype : 'a',
4391     disabled : false,
4392     animateRef : false,
4393     was_active : false,
4394     
4395     getAutoCreate : function(){
4396          
4397         var cfg = {
4398             tag: 'li',
4399             cls: 'nav-item'
4400             
4401         };
4402         
4403         if (this.active) {
4404             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4405         }
4406         if (this.disabled) {
4407             cfg.cls += ' disabled';
4408         }
4409         
4410         if (this.href || this.html || this.glyphicon || this.icon) {
4411             cfg.cn = [
4412                 {
4413                     tag: this.tagtype,
4414                     href : this.href || "#",
4415                     html: this.html || ''
4416                 }
4417             ];
4418             
4419             if (this.icon) {
4420                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4421             }
4422
4423             if(this.glyphicon) {
4424                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
4425             }
4426             
4427             if (this.menu) {
4428                 
4429                 cfg.cn[0].html += " <span class='caret'></span>";
4430              
4431             }
4432             
4433             if (this.badge !== '') {
4434                  
4435                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4436             }
4437         }
4438         
4439         
4440         
4441         return cfg;
4442     },
4443     initEvents: function() 
4444     {
4445         if (typeof (this.menu) != 'undefined') {
4446             this.menu.parentType = this.xtype;
4447             this.menu.triggerEl = this.el;
4448             this.menu = this.addxtype(Roo.apply({}, this.menu));
4449         }
4450         
4451         this.el.select('a',true).on('click', this.onClick, this);
4452         
4453         if(this.tagtype == 'span'){
4454             this.el.select('span',true).on('click', this.onClick, this);
4455         }
4456        
4457         // at this point parent should be available..
4458         this.parent().register(this);
4459     },
4460     
4461     onClick : function(e)
4462     {
4463         if (e.getTarget('.dropdown-menu-item')) {
4464             // did you click on a menu itemm.... - then don't trigger onclick..
4465             return;
4466         }
4467         
4468         if(
4469                 this.preventDefault || 
4470                 this.href == '#' 
4471         ){
4472             Roo.log("NavItem - prevent Default?");
4473             e.preventDefault();
4474         }
4475         
4476         if (this.disabled) {
4477             return;
4478         }
4479         
4480         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4481         if (tg && tg.transition) {
4482             Roo.log("waiting for the transitionend");
4483             return;
4484         }
4485         
4486         
4487         
4488         //Roo.log("fire event clicked");
4489         if(this.fireEvent('click', this, e) === false){
4490             return;
4491         };
4492         
4493         if(this.tagtype == 'span'){
4494             return;
4495         }
4496         
4497         //Roo.log(this.href);
4498         var ael = this.el.select('a',true).first();
4499         //Roo.log(ael);
4500         
4501         if(ael && this.animateRef && this.href.indexOf('#') > -1){
4502             //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4503             if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4504                 return; // ignore... - it's a 'hash' to another page.
4505             }
4506             Roo.log("NavItem - prevent Default?");
4507             e.preventDefault();
4508             this.scrollToElement(e);
4509         }
4510         
4511         
4512         var p =  this.parent();
4513    
4514         if (['tabs','pills'].indexOf(p.type)!==-1) {
4515             if (typeof(p.setActiveItem) !== 'undefined') {
4516                 p.setActiveItem(this);
4517             }
4518         }
4519         
4520         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4521         if (p.parentType == 'NavHeaderbar' && !this.menu) {
4522             // remove the collapsed menu expand...
4523             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
4524         }
4525     },
4526     
4527     isActive: function () {
4528         return this.active
4529     },
4530     setActive : function(state, fire, is_was_active)
4531     {
4532         if (this.active && !state && this.navId) {
4533             this.was_active = true;
4534             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4535             if (nv) {
4536                 nv.clearWasActive(this);
4537             }
4538             
4539         }
4540         this.active = state;
4541         
4542         if (!state ) {
4543             this.el.removeClass('active');
4544         } else if (!this.el.hasClass('active')) {
4545             this.el.addClass('active');
4546         }
4547         if (fire) {
4548             this.fireEvent('changed', this, state);
4549         }
4550         
4551         // show a panel if it's registered and related..
4552         
4553         if (!this.navId || !this.tabId || !state || is_was_active) {
4554             return;
4555         }
4556         
4557         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4558         if (!tg) {
4559             return;
4560         }
4561         var pan = tg.getPanelByName(this.tabId);
4562         if (!pan) {
4563             return;
4564         }
4565         // if we can not flip to new panel - go back to old nav highlight..
4566         if (false == tg.showPanel(pan)) {
4567             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4568             if (nv) {
4569                 var onav = nv.getWasActive();
4570                 if (onav) {
4571                     onav.setActive(true, false, true);
4572                 }
4573             }
4574             
4575         }
4576         
4577         
4578         
4579     },
4580      // this should not be here...
4581     setDisabled : function(state)
4582     {
4583         this.disabled = state;
4584         if (!state ) {
4585             this.el.removeClass('disabled');
4586         } else if (!this.el.hasClass('disabled')) {
4587             this.el.addClass('disabled');
4588         }
4589         
4590     },
4591     
4592     /**
4593      * Fetch the element to display the tooltip on.
4594      * @return {Roo.Element} defaults to this.el
4595      */
4596     tooltipEl : function()
4597     {
4598         return this.el.select('' + this.tagtype + '', true).first();
4599     },
4600     
4601     scrollToElement : function(e)
4602     {
4603         var c = document.body;
4604         
4605         /*
4606          * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4607          */
4608         if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4609             c = document.documentElement;
4610         }
4611         
4612         var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4613         
4614         if(!target){
4615             return;
4616         }
4617
4618         var o = target.calcOffsetsTo(c);
4619         
4620         var options = {
4621             target : target,
4622             value : o[1]
4623         };
4624         
4625         this.fireEvent('scrollto', this, options, e);
4626         
4627         Roo.get(c).scrollTo('top', options.value, true);
4628         
4629         return;
4630     }
4631 });
4632  
4633
4634  /*
4635  * - LGPL
4636  *
4637  * sidebar item
4638  *
4639  *  li
4640  *    <span> icon </span>
4641  *    <span> text </span>
4642  *    <span>badge </span>
4643  */
4644
4645 /**
4646  * @class Roo.bootstrap.NavSidebarItem
4647  * @extends Roo.bootstrap.NavItem
4648  * Bootstrap Navbar.NavSidebarItem class
4649  * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4650  * {Boolean} open is the menu open
4651  * {Boolean} buttonView use button as the tigger el rather that a (default false)
4652  * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4653  * {String} buttonSize (sm|md|lg)the extra classes for the button
4654  * {Boolean} showArrow show arrow next to the text (default true)
4655  * @constructor
4656  * Create a new Navbar Button
4657  * @param {Object} config The config object
4658  */
4659 Roo.bootstrap.NavSidebarItem = function(config){
4660     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4661     this.addEvents({
4662         // raw events
4663         /**
4664          * @event click
4665          * The raw click event for the entire grid.
4666          * @param {Roo.EventObject} e
4667          */
4668         "click" : true,
4669          /**
4670             * @event changed
4671             * Fires when the active item active state changes
4672             * @param {Roo.bootstrap.NavSidebarItem} this
4673             * @param {boolean} state the new state
4674              
4675          */
4676         'changed': true
4677     });
4678    
4679 };
4680
4681 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4682     
4683     badgeWeight : 'default',
4684     
4685     open: false,
4686     
4687     buttonView : false,
4688     
4689     buttonWeight : 'default',
4690     
4691     buttonSize : 'md',
4692     
4693     showArrow : true,
4694     
4695     getAutoCreate : function(){
4696         
4697         
4698         var a = {
4699                 tag: 'a',
4700                 href : this.href || '#',
4701                 cls: '',
4702                 html : '',
4703                 cn : []
4704         };
4705         
4706         if(this.buttonView){
4707             a = {
4708                 tag: 'button',
4709                 href : this.href || '#',
4710                 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4711                 html : this.html,
4712                 cn : []
4713             };
4714         }
4715         
4716         var cfg = {
4717             tag: 'li',
4718             cls: '',
4719             cn: [ a ]
4720         };
4721         
4722         if (this.active) {
4723             cfg.cls += ' active';
4724         }
4725         
4726         if (this.disabled) {
4727             cfg.cls += ' disabled';
4728         }
4729         if (this.open) {
4730             cfg.cls += ' open x-open';
4731         }
4732         // left icon..
4733         if (this.glyphicon || this.icon) {
4734             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4735             a.cn.push({ tag : 'i', cls : c }) ;
4736         }
4737         
4738         if(!this.buttonView){
4739             var span = {
4740                 tag: 'span',
4741                 html : this.html || ''
4742             };
4743
4744             a.cn.push(span);
4745             
4746         }
4747         
4748         if (this.badge !== '') {
4749             a.cn.push({ tag: 'span',  cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge }); 
4750         }
4751         
4752         if (this.menu) {
4753             
4754             if(this.showArrow){
4755                 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4756             }
4757             
4758             a.cls += ' dropdown-toggle treeview' ;
4759         }
4760         
4761         return cfg;
4762     },
4763     
4764     initEvents : function()
4765     { 
4766         if (typeof (this.menu) != 'undefined') {
4767             this.menu.parentType = this.xtype;
4768             this.menu.triggerEl = this.el;
4769             this.menu = this.addxtype(Roo.apply({}, this.menu));
4770         }
4771         
4772         this.el.on('click', this.onClick, this);
4773         
4774         if(this.badge !== ''){
4775             this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4776         }
4777         
4778     },
4779     
4780     onClick : function(e)
4781     {
4782         if(this.disabled){
4783             e.preventDefault();
4784             return;
4785         }
4786         
4787         if(this.preventDefault){
4788             e.preventDefault();
4789         }
4790         
4791         this.fireEvent('click', this);
4792     },
4793     
4794     disable : function()
4795     {
4796         this.setDisabled(true);
4797     },
4798     
4799     enable : function()
4800     {
4801         this.setDisabled(false);
4802     },
4803     
4804     setDisabled : function(state)
4805     {
4806         if(this.disabled == state){
4807             return;
4808         }
4809         
4810         this.disabled = state;
4811         
4812         if (state) {
4813             this.el.addClass('disabled');
4814             return;
4815         }
4816         
4817         this.el.removeClass('disabled');
4818         
4819         return;
4820     },
4821     
4822     setActive : function(state)
4823     {
4824         if(this.active == state){
4825             return;
4826         }
4827         
4828         this.active = state;
4829         
4830         if (state) {
4831             this.el.addClass('active');
4832             return;
4833         }
4834         
4835         this.el.removeClass('active');
4836         
4837         return;
4838     },
4839     
4840     isActive: function () 
4841     {
4842         return this.active;
4843     },
4844     
4845     setBadge : function(str)
4846     {
4847         if(!this.badgeEl){
4848             return;
4849         }
4850         
4851         this.badgeEl.dom.innerHTML = str;
4852     }
4853     
4854    
4855      
4856  
4857 });
4858  
4859
4860  /*
4861  * - LGPL
4862  *
4863  * row
4864  * 
4865  */
4866
4867 /**
4868  * @class Roo.bootstrap.Row
4869  * @extends Roo.bootstrap.Component
4870  * Bootstrap Row class (contains columns...)
4871  * 
4872  * @constructor
4873  * Create a new Row
4874  * @param {Object} config The config object
4875  */
4876
4877 Roo.bootstrap.Row = function(config){
4878     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4879 };
4880
4881 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4882     
4883     getAutoCreate : function(){
4884        return {
4885             cls: 'row clearfix'
4886        };
4887     }
4888     
4889     
4890 });
4891
4892  
4893
4894  /*
4895  * - LGPL
4896  *
4897  * element
4898  * 
4899  */
4900
4901 /**
4902  * @class Roo.bootstrap.Element
4903  * @extends Roo.bootstrap.Component
4904  * Bootstrap Element class
4905  * @cfg {String} html contents of the element
4906  * @cfg {String} tag tag of the element
4907  * @cfg {String} cls class of the element
4908  * @cfg {Boolean} preventDefault (true|false) default false
4909  * @cfg {Boolean} clickable (true|false) default false
4910  * 
4911  * @constructor
4912  * Create a new Element
4913  * @param {Object} config The config object
4914  */
4915
4916 Roo.bootstrap.Element = function(config){
4917     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4918     
4919     this.addEvents({
4920         // raw events
4921         /**
4922          * @event click
4923          * When a element is chick
4924          * @param {Roo.bootstrap.Element} this
4925          * @param {Roo.EventObject} e
4926          */
4927         "click" : true
4928     });
4929 };
4930
4931 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4932     
4933     tag: 'div',
4934     cls: '',
4935     html: '',
4936     preventDefault: false, 
4937     clickable: false,
4938     
4939     getAutoCreate : function(){
4940         
4941         var cfg = {
4942             tag: this.tag,
4943             // cls: this.cls, double assign in parent class Component.js :: onRender
4944             html: this.html
4945         };
4946         
4947         return cfg;
4948     },
4949     
4950     initEvents: function() 
4951     {
4952         Roo.bootstrap.Element.superclass.initEvents.call(this);
4953         
4954         if(this.clickable){
4955             this.el.on('click', this.onClick, this);
4956         }
4957         
4958     },
4959     
4960     onClick : function(e)
4961     {
4962         if(this.preventDefault){
4963             e.preventDefault();
4964         }
4965         
4966         this.fireEvent('click', this, e);
4967     },
4968     
4969     getValue : function()
4970     {
4971         return this.el.dom.innerHTML;
4972     },
4973     
4974     setValue : function(value)
4975     {
4976         this.el.dom.innerHTML = value;
4977     }
4978    
4979 });
4980
4981  
4982
4983  /*
4984  * - LGPL
4985  *
4986  * pagination
4987  * 
4988  */
4989
4990 /**
4991  * @class Roo.bootstrap.Pagination
4992  * @extends Roo.bootstrap.Component
4993  * Bootstrap Pagination class
4994  * @cfg {String} size xs | sm | md | lg
4995  * @cfg {Boolean} inverse false | true
4996  * 
4997  * @constructor
4998  * Create a new Pagination
4999  * @param {Object} config The config object
5000  */
5001
5002 Roo.bootstrap.Pagination = function(config){
5003     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5004 };
5005
5006 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
5007     
5008     cls: false,
5009     size: false,
5010     inverse: false,
5011     
5012     getAutoCreate : function(){
5013         var cfg = {
5014             tag: 'ul',
5015                 cls: 'pagination'
5016         };
5017         if (this.inverse) {
5018             cfg.cls += ' inverse';
5019         }
5020         if (this.html) {
5021             cfg.html=this.html;
5022         }
5023         if (this.cls) {
5024             cfg.cls += " " + this.cls;
5025         }
5026         return cfg;
5027     }
5028    
5029 });
5030
5031  
5032
5033  /*
5034  * - LGPL
5035  *
5036  * Pagination item
5037  * 
5038  */
5039
5040
5041 /**
5042  * @class Roo.bootstrap.PaginationItem
5043  * @extends Roo.bootstrap.Component
5044  * Bootstrap PaginationItem class
5045  * @cfg {String} html text
5046  * @cfg {String} href the link
5047  * @cfg {Boolean} preventDefault (true | false) default true
5048  * @cfg {Boolean} active (true | false) default false
5049  * @cfg {Boolean} disabled default false
5050  * 
5051  * 
5052  * @constructor
5053  * Create a new PaginationItem
5054  * @param {Object} config The config object
5055  */
5056
5057
5058 Roo.bootstrap.PaginationItem = function(config){
5059     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5060     this.addEvents({
5061         // raw events
5062         /**
5063          * @event click
5064          * The raw click event for the entire grid.
5065          * @param {Roo.EventObject} e
5066          */
5067         "click" : true
5068     });
5069 };
5070
5071 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
5072     
5073     href : false,
5074     html : false,
5075     preventDefault: true,
5076     active : false,
5077     cls : false,
5078     disabled: false,
5079     
5080     getAutoCreate : function(){
5081         var cfg= {
5082             tag: 'li',
5083             cn: [
5084                 {
5085                     tag : 'a',
5086                     href : this.href ? this.href : '#',
5087                     html : this.html ? this.html : ''
5088                 }
5089             ]
5090         };
5091         
5092         if(this.cls){
5093             cfg.cls = this.cls;
5094         }
5095         
5096         if(this.disabled){
5097             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5098         }
5099         
5100         if(this.active){
5101             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5102         }
5103         
5104         return cfg;
5105     },
5106     
5107     initEvents: function() {
5108         
5109         this.el.on('click', this.onClick, this);
5110         
5111     },
5112     onClick : function(e)
5113     {
5114         Roo.log('PaginationItem on click ');
5115         if(this.preventDefault){
5116             e.preventDefault();
5117         }
5118         
5119         if(this.disabled){
5120             return;
5121         }
5122         
5123         this.fireEvent('click', this, e);
5124     }
5125    
5126 });
5127
5128  
5129
5130  /*
5131  * - LGPL
5132  *
5133  * slider
5134  * 
5135  */
5136
5137
5138 /**
5139  * @class Roo.bootstrap.Slider
5140  * @extends Roo.bootstrap.Component
5141  * Bootstrap Slider class
5142  *    
5143  * @constructor
5144  * Create a new Slider
5145  * @param {Object} config The config object
5146  */
5147
5148 Roo.bootstrap.Slider = function(config){
5149     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5150 };
5151
5152 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
5153     
5154     getAutoCreate : function(){
5155         
5156         var cfg = {
5157             tag: 'div',
5158             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5159             cn: [
5160                 {
5161                     tag: 'a',
5162                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
5163                 }
5164             ]
5165         };
5166         
5167         return cfg;
5168     }
5169    
5170 });
5171
5172  /*
5173  * Based on:
5174  * Ext JS Library 1.1.1
5175  * Copyright(c) 2006-2007, Ext JS, LLC.
5176  *
5177  * Originally Released Under LGPL - original licence link has changed is not relivant.
5178  *
5179  * Fork - LGPL
5180  * <script type="text/javascript">
5181  */
5182  
5183
5184 /**
5185  * @class Roo.grid.ColumnModel
5186  * @extends Roo.util.Observable
5187  * This is the default implementation of a ColumnModel used by the Grid. It defines
5188  * the columns in the grid.
5189  * <br>Usage:<br>
5190  <pre><code>
5191  var colModel = new Roo.grid.ColumnModel([
5192         {header: "Ticker", width: 60, sortable: true, locked: true},
5193         {header: "Company Name", width: 150, sortable: true},
5194         {header: "Market Cap.", width: 100, sortable: true},
5195         {header: "$ Sales", width: 100, sortable: true, renderer: money},
5196         {header: "Employees", width: 100, sortable: true, resizable: false}
5197  ]);
5198  </code></pre>
5199  * <p>
5200  
5201  * The config options listed for this class are options which may appear in each
5202  * individual column definition.
5203  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5204  * @constructor
5205  * @param {Object} config An Array of column config objects. See this class's
5206  * config objects for details.
5207 */
5208 Roo.grid.ColumnModel = function(config){
5209         /**
5210      * The config passed into the constructor
5211      */
5212     this.config = config;
5213     this.lookup = {};
5214
5215     // if no id, create one
5216     // if the column does not have a dataIndex mapping,
5217     // map it to the order it is in the config
5218     for(var i = 0, len = config.length; i < len; i++){
5219         var c = config[i];
5220         if(typeof c.dataIndex == "undefined"){
5221             c.dataIndex = i;
5222         }
5223         if(typeof c.renderer == "string"){
5224             c.renderer = Roo.util.Format[c.renderer];
5225         }
5226         if(typeof c.id == "undefined"){
5227             c.id = Roo.id();
5228         }
5229         if(c.editor && c.editor.xtype){
5230             c.editor  = Roo.factory(c.editor, Roo.grid);
5231         }
5232         if(c.editor && c.editor.isFormField){
5233             c.editor = new Roo.grid.GridEditor(c.editor);
5234         }
5235         this.lookup[c.id] = c;
5236     }
5237
5238     /**
5239      * The width of columns which have no width specified (defaults to 100)
5240      * @type Number
5241      */
5242     this.defaultWidth = 100;
5243
5244     /**
5245      * Default sortable of columns which have no sortable specified (defaults to false)
5246      * @type Boolean
5247      */
5248     this.defaultSortable = false;
5249
5250     this.addEvents({
5251         /**
5252              * @event widthchange
5253              * Fires when the width of a column changes.
5254              * @param {ColumnModel} this
5255              * @param {Number} columnIndex The column index
5256              * @param {Number} newWidth The new width
5257              */
5258             "widthchange": true,
5259         /**
5260              * @event headerchange
5261              * Fires when the text of a header changes.
5262              * @param {ColumnModel} this
5263              * @param {Number} columnIndex The column index
5264              * @param {Number} newText The new header text
5265              */
5266             "headerchange": true,
5267         /**
5268              * @event hiddenchange
5269              * Fires when a column is hidden or "unhidden".
5270              * @param {ColumnModel} this
5271              * @param {Number} columnIndex The column index
5272              * @param {Boolean} hidden true if hidden, false otherwise
5273              */
5274             "hiddenchange": true,
5275             /**
5276          * @event columnmoved
5277          * Fires when a column is moved.
5278          * @param {ColumnModel} this
5279          * @param {Number} oldIndex
5280          * @param {Number} newIndex
5281          */
5282         "columnmoved" : true,
5283         /**
5284          * @event columlockchange
5285          * Fires when a column's locked state is changed
5286          * @param {ColumnModel} this
5287          * @param {Number} colIndex
5288          * @param {Boolean} locked true if locked
5289          */
5290         "columnlockchange" : true
5291     });
5292     Roo.grid.ColumnModel.superclass.constructor.call(this);
5293 };
5294 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5295     /**
5296      * @cfg {String} header The header text to display in the Grid view.
5297      */
5298     /**
5299      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5300      * {@link Roo.data.Record} definition from which to draw the column's value. If not
5301      * specified, the column's index is used as an index into the Record's data Array.
5302      */
5303     /**
5304      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5305      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5306      */
5307     /**
5308      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5309      * Defaults to the value of the {@link #defaultSortable} property.
5310      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5311      */
5312     /**
5313      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
5314      */
5315     /**
5316      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
5317      */
5318     /**
5319      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5320      */
5321     /**
5322      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5323      */
5324     /**
5325      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5326      * given the cell's data value. See {@link #setRenderer}. If not specified, the
5327      * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5328      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5329      */
5330        /**
5331      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
5332      */
5333     /**
5334      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
5335      */
5336     /**
5337      * @cfg {String} cursor (Optional)
5338      */
5339     /**
5340      * @cfg {String} tooltip (Optional)
5341      */
5342     /**
5343      * @cfg {Number} xs (Optional)
5344      */
5345     /**
5346      * @cfg {Number} sm (Optional)
5347      */
5348     /**
5349      * @cfg {Number} md (Optional)
5350      */
5351     /**
5352      * @cfg {Number} lg (Optional)
5353      */
5354     /**
5355      * Returns the id of the column at the specified index.
5356      * @param {Number} index The column index
5357      * @return {String} the id
5358      */
5359     getColumnId : function(index){
5360         return this.config[index].id;
5361     },
5362
5363     /**
5364      * Returns the column for a specified id.
5365      * @param {String} id The column id
5366      * @return {Object} the column
5367      */
5368     getColumnById : function(id){
5369         return this.lookup[id];
5370     },
5371
5372     
5373     /**
5374      * Returns the column for a specified dataIndex.
5375      * @param {String} dataIndex The column dataIndex
5376      * @return {Object|Boolean} the column or false if not found
5377      */
5378     getColumnByDataIndex: function(dataIndex){
5379         var index = this.findColumnIndex(dataIndex);
5380         return index > -1 ? this.config[index] : false;
5381     },
5382     
5383     /**
5384      * Returns the index for a specified column id.
5385      * @param {String} id The column id
5386      * @return {Number} the index, or -1 if not found
5387      */
5388     getIndexById : function(id){
5389         for(var i = 0, len = this.config.length; i < len; i++){
5390             if(this.config[i].id == id){
5391                 return i;
5392             }
5393         }
5394         return -1;
5395     },
5396     
5397     /**
5398      * Returns the index for a specified column dataIndex.
5399      * @param {String} dataIndex The column dataIndex
5400      * @return {Number} the index, or -1 if not found
5401      */
5402     
5403     findColumnIndex : function(dataIndex){
5404         for(var i = 0, len = this.config.length; i < len; i++){
5405             if(this.config[i].dataIndex == dataIndex){
5406                 return i;
5407             }
5408         }
5409         return -1;
5410     },
5411     
5412     
5413     moveColumn : function(oldIndex, newIndex){
5414         var c = this.config[oldIndex];
5415         this.config.splice(oldIndex, 1);
5416         this.config.splice(newIndex, 0, c);
5417         this.dataMap = null;
5418         this.fireEvent("columnmoved", this, oldIndex, newIndex);
5419     },
5420
5421     isLocked : function(colIndex){
5422         return this.config[colIndex].locked === true;
5423     },
5424
5425     setLocked : function(colIndex, value, suppressEvent){
5426         if(this.isLocked(colIndex) == value){
5427             return;
5428         }
5429         this.config[colIndex].locked = value;
5430         if(!suppressEvent){
5431             this.fireEvent("columnlockchange", this, colIndex, value);
5432         }
5433     },
5434
5435     getTotalLockedWidth : function(){
5436         var totalWidth = 0;
5437         for(var i = 0; i < this.config.length; i++){
5438             if(this.isLocked(i) && !this.isHidden(i)){
5439                 this.totalWidth += this.getColumnWidth(i);
5440             }
5441         }
5442         return totalWidth;
5443     },
5444
5445     getLockedCount : function(){
5446         for(var i = 0, len = this.config.length; i < len; i++){
5447             if(!this.isLocked(i)){
5448                 return i;
5449             }
5450         }
5451         
5452         return this.config.length;
5453     },
5454
5455     /**
5456      * Returns the number of columns.
5457      * @return {Number}
5458      */
5459     getColumnCount : function(visibleOnly){
5460         if(visibleOnly === true){
5461             var c = 0;
5462             for(var i = 0, len = this.config.length; i < len; i++){
5463                 if(!this.isHidden(i)){
5464                     c++;
5465                 }
5466             }
5467             return c;
5468         }
5469         return this.config.length;
5470     },
5471
5472     /**
5473      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5474      * @param {Function} fn
5475      * @param {Object} scope (optional)
5476      * @return {Array} result
5477      */
5478     getColumnsBy : function(fn, scope){
5479         var r = [];
5480         for(var i = 0, len = this.config.length; i < len; i++){
5481             var c = this.config[i];
5482             if(fn.call(scope||this, c, i) === true){
5483                 r[r.length] = c;
5484             }
5485         }
5486         return r;
5487     },
5488
5489     /**
5490      * Returns true if the specified column is sortable.
5491      * @param {Number} col The column index
5492      * @return {Boolean}
5493      */
5494     isSortable : function(col){
5495         if(typeof this.config[col].sortable == "undefined"){
5496             return this.defaultSortable;
5497         }
5498         return this.config[col].sortable;
5499     },
5500
5501     /**
5502      * Returns the rendering (formatting) function defined for the column.
5503      * @param {Number} col The column index.
5504      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5505      */
5506     getRenderer : function(col){
5507         if(!this.config[col].renderer){
5508             return Roo.grid.ColumnModel.defaultRenderer;
5509         }
5510         return this.config[col].renderer;
5511     },
5512
5513     /**
5514      * Sets the rendering (formatting) function for a column.
5515      * @param {Number} col The column index
5516      * @param {Function} fn The function to use to process the cell's raw data
5517      * to return HTML markup for the grid view. The render function is called with
5518      * the following parameters:<ul>
5519      * <li>Data value.</li>
5520      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5521      * <li>css A CSS style string to apply to the table cell.</li>
5522      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5523      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5524      * <li>Row index</li>
5525      * <li>Column index</li>
5526      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5527      */
5528     setRenderer : function(col, fn){
5529         this.config[col].renderer = fn;
5530     },
5531
5532     /**
5533      * Returns the width for the specified column.
5534      * @param {Number} col The column index
5535      * @return {Number}
5536      */
5537     getColumnWidth : function(col){
5538         return this.config[col].width * 1 || this.defaultWidth;
5539     },
5540
5541     /**
5542      * Sets the width for a column.
5543      * @param {Number} col The column index
5544      * @param {Number} width The new width
5545      */
5546     setColumnWidth : function(col, width, suppressEvent){
5547         this.config[col].width = width;
5548         this.totalWidth = null;
5549         if(!suppressEvent){
5550              this.fireEvent("widthchange", this, col, width);
5551         }
5552     },
5553
5554     /**
5555      * Returns the total width of all columns.
5556      * @param {Boolean} includeHidden True to include hidden column widths
5557      * @return {Number}
5558      */
5559     getTotalWidth : function(includeHidden){
5560         if(!this.totalWidth){
5561             this.totalWidth = 0;
5562             for(var i = 0, len = this.config.length; i < len; i++){
5563                 if(includeHidden || !this.isHidden(i)){
5564                     this.totalWidth += this.getColumnWidth(i);
5565                 }
5566             }
5567         }
5568         return this.totalWidth;
5569     },
5570
5571     /**
5572      * Returns the header for the specified column.
5573      * @param {Number} col The column index
5574      * @return {String}
5575      */
5576     getColumnHeader : function(col){
5577         return this.config[col].header;
5578     },
5579
5580     /**
5581      * Sets the header for a column.
5582      * @param {Number} col The column index
5583      * @param {String} header The new header
5584      */
5585     setColumnHeader : function(col, header){
5586         this.config[col].header = header;
5587         this.fireEvent("headerchange", this, col, header);
5588     },
5589
5590     /**
5591      * Returns the tooltip for the specified column.
5592      * @param {Number} col The column index
5593      * @return {String}
5594      */
5595     getColumnTooltip : function(col){
5596             return this.config[col].tooltip;
5597     },
5598     /**
5599      * Sets the tooltip for a column.
5600      * @param {Number} col The column index
5601      * @param {String} tooltip The new tooltip
5602      */
5603     setColumnTooltip : function(col, tooltip){
5604             this.config[col].tooltip = tooltip;
5605     },
5606
5607     /**
5608      * Returns the dataIndex for the specified column.
5609      * @param {Number} col The column index
5610      * @return {Number}
5611      */
5612     getDataIndex : function(col){
5613         return this.config[col].dataIndex;
5614     },
5615
5616     /**
5617      * Sets the dataIndex for a column.
5618      * @param {Number} col The column index
5619      * @param {Number} dataIndex The new dataIndex
5620      */
5621     setDataIndex : function(col, dataIndex){
5622         this.config[col].dataIndex = dataIndex;
5623     },
5624
5625     
5626     
5627     /**
5628      * Returns true if the cell is editable.
5629      * @param {Number} colIndex The column index
5630      * @param {Number} rowIndex The row index - this is nto actually used..?
5631      * @return {Boolean}
5632      */
5633     isCellEditable : function(colIndex, rowIndex){
5634         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5635     },
5636
5637     /**
5638      * Returns the editor defined for the cell/column.
5639      * return false or null to disable editing.
5640      * @param {Number} colIndex The column index
5641      * @param {Number} rowIndex The row index
5642      * @return {Object}
5643      */
5644     getCellEditor : function(colIndex, rowIndex){
5645         return this.config[colIndex].editor;
5646     },
5647
5648     /**
5649      * Sets if a column is editable.
5650      * @param {Number} col The column index
5651      * @param {Boolean} editable True if the column is editable
5652      */
5653     setEditable : function(col, editable){
5654         this.config[col].editable = editable;
5655     },
5656
5657
5658     /**
5659      * Returns true if the column is hidden.
5660      * @param {Number} colIndex The column index
5661      * @return {Boolean}
5662      */
5663     isHidden : function(colIndex){
5664         return this.config[colIndex].hidden;
5665     },
5666
5667
5668     /**
5669      * Returns true if the column width cannot be changed
5670      */
5671     isFixed : function(colIndex){
5672         return this.config[colIndex].fixed;
5673     },
5674
5675     /**
5676      * Returns true if the column can be resized
5677      * @return {Boolean}
5678      */
5679     isResizable : function(colIndex){
5680         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5681     },
5682     /**
5683      * Sets if a column is hidden.
5684      * @param {Number} colIndex The column index
5685      * @param {Boolean} hidden True if the column is hidden
5686      */
5687     setHidden : function(colIndex, hidden){
5688         this.config[colIndex].hidden = hidden;
5689         this.totalWidth = null;
5690         this.fireEvent("hiddenchange", this, colIndex, hidden);
5691     },
5692
5693     /**
5694      * Sets the editor for a column.
5695      * @param {Number} col The column index
5696      * @param {Object} editor The editor object
5697      */
5698     setEditor : function(col, editor){
5699         this.config[col].editor = editor;
5700     }
5701 });
5702
5703 Roo.grid.ColumnModel.defaultRenderer = function(value)
5704 {
5705     if(typeof value == "object") {
5706         return value;
5707     }
5708         if(typeof value == "string" && value.length < 1){
5709             return "&#160;";
5710         }
5711     
5712         return String.format("{0}", value);
5713 };
5714
5715 // Alias for backwards compatibility
5716 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5717 /*
5718  * Based on:
5719  * Ext JS Library 1.1.1
5720  * Copyright(c) 2006-2007, Ext JS, LLC.
5721  *
5722  * Originally Released Under LGPL - original licence link has changed is not relivant.
5723  *
5724  * Fork - LGPL
5725  * <script type="text/javascript">
5726  */
5727  
5728 /**
5729  * @class Roo.LoadMask
5730  * A simple utility class for generically masking elements while loading data.  If the element being masked has
5731  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5732  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
5733  * element's UpdateManager load indicator and will be destroyed after the initial load.
5734  * @constructor
5735  * Create a new LoadMask
5736  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5737  * @param {Object} config The config object
5738  */
5739 Roo.LoadMask = function(el, config){
5740     this.el = Roo.get(el);
5741     Roo.apply(this, config);
5742     if(this.store){
5743         this.store.on('beforeload', this.onBeforeLoad, this);
5744         this.store.on('load', this.onLoad, this);
5745         this.store.on('loadexception', this.onLoadException, this);
5746         this.removeMask = false;
5747     }else{
5748         var um = this.el.getUpdateManager();
5749         um.showLoadIndicator = false; // disable the default indicator
5750         um.on('beforeupdate', this.onBeforeLoad, this);
5751         um.on('update', this.onLoad, this);
5752         um.on('failure', this.onLoad, this);
5753         this.removeMask = true;
5754     }
5755 };
5756
5757 Roo.LoadMask.prototype = {
5758     /**
5759      * @cfg {Boolean} removeMask
5760      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5761      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
5762      */
5763     /**
5764      * @cfg {String} msg
5765      * The text to display in a centered loading message box (defaults to 'Loading...')
5766      */
5767     msg : 'Loading...',
5768     /**
5769      * @cfg {String} msgCls
5770      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5771      */
5772     msgCls : 'x-mask-loading',
5773
5774     /**
5775      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5776      * @type Boolean
5777      */
5778     disabled: false,
5779
5780     /**
5781      * Disables the mask to prevent it from being displayed
5782      */
5783     disable : function(){
5784        this.disabled = true;
5785     },
5786
5787     /**
5788      * Enables the mask so that it can be displayed
5789      */
5790     enable : function(){
5791         this.disabled = false;
5792     },
5793     
5794     onLoadException : function()
5795     {
5796         Roo.log(arguments);
5797         
5798         if (typeof(arguments[3]) != 'undefined') {
5799             Roo.MessageBox.alert("Error loading",arguments[3]);
5800         } 
5801         /*
5802         try {
5803             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5804                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5805             }   
5806         } catch(e) {
5807             
5808         }
5809         */
5810     
5811         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5812     },
5813     // private
5814     onLoad : function()
5815     {
5816         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5817     },
5818
5819     // private
5820     onBeforeLoad : function(){
5821         if(!this.disabled){
5822             (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5823         }
5824     },
5825
5826     // private
5827     destroy : function(){
5828         if(this.store){
5829             this.store.un('beforeload', this.onBeforeLoad, this);
5830             this.store.un('load', this.onLoad, this);
5831             this.store.un('loadexception', this.onLoadException, this);
5832         }else{
5833             var um = this.el.getUpdateManager();
5834             um.un('beforeupdate', this.onBeforeLoad, this);
5835             um.un('update', this.onLoad, this);
5836             um.un('failure', this.onLoad, this);
5837         }
5838     }
5839 };/*
5840  * - LGPL
5841  *
5842  * table
5843  * 
5844  */
5845
5846 /**
5847  * @class Roo.bootstrap.Table
5848  * @extends Roo.bootstrap.Component
5849  * Bootstrap Table class
5850  * @cfg {String} cls table class
5851  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5852  * @cfg {String} bgcolor Specifies the background color for a table
5853  * @cfg {Number} border Specifies whether the table cells should have borders or not
5854  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5855  * @cfg {Number} cellspacing Specifies the space between cells
5856  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5857  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5858  * @cfg {String} sortable Specifies that the table should be sortable
5859  * @cfg {String} summary Specifies a summary of the content of a table
5860  * @cfg {Number} width Specifies the width of a table
5861  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5862  * 
5863  * @cfg {boolean} striped Should the rows be alternative striped
5864  * @cfg {boolean} bordered Add borders to the table
5865  * @cfg {boolean} hover Add hover highlighting
5866  * @cfg {boolean} condensed Format condensed
5867  * @cfg {boolean} responsive Format condensed
5868  * @cfg {Boolean} loadMask (true|false) default false
5869  * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5870  * @cfg {Boolean} headerShow (true|false) generate thead, default true
5871  * @cfg {Boolean} rowSelection (true|false) default false
5872  * @cfg {Boolean} cellSelection (true|false) default false
5873  * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5874  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5875  * @cfg {Boolean} lazyLoad  auto load data while scrolling to the end (default false)
5876  
5877  * 
5878  * @constructor
5879  * Create a new Table
5880  * @param {Object} config The config object
5881  */
5882
5883 Roo.bootstrap.Table = function(config){
5884     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5885     
5886   
5887     
5888     // BC...
5889     this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5890     this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5891     this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5892     this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5893     
5894     this.sm = this.sm || {xtype: 'RowSelectionModel'};
5895     if (this.sm) {
5896         this.sm.grid = this;
5897         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5898         this.sm = this.selModel;
5899         this.sm.xmodule = this.xmodule || false;
5900     }
5901     
5902     if (this.cm && typeof(this.cm.config) == 'undefined') {
5903         this.colModel = new Roo.grid.ColumnModel(this.cm);
5904         this.cm = this.colModel;
5905         this.cm.xmodule = this.xmodule || false;
5906     }
5907     if (this.store) {
5908         this.store= Roo.factory(this.store, Roo.data);
5909         this.ds = this.store;
5910         this.ds.xmodule = this.xmodule || false;
5911          
5912     }
5913     if (this.footer && this.store) {
5914         this.footer.dataSource = this.ds;
5915         this.footer = Roo.factory(this.footer);
5916     }
5917     
5918     /** @private */
5919     this.addEvents({
5920         /**
5921          * @event cellclick
5922          * Fires when a cell is clicked
5923          * @param {Roo.bootstrap.Table} this
5924          * @param {Roo.Element} el
5925          * @param {Number} rowIndex
5926          * @param {Number} columnIndex
5927          * @param {Roo.EventObject} e
5928          */
5929         "cellclick" : true,
5930         /**
5931          * @event celldblclick
5932          * Fires when a cell is double clicked
5933          * @param {Roo.bootstrap.Table} this
5934          * @param {Roo.Element} el
5935          * @param {Number} rowIndex
5936          * @param {Number} columnIndex
5937          * @param {Roo.EventObject} e
5938          */
5939         "celldblclick" : true,
5940         /**
5941          * @event rowclick
5942          * Fires when a row is clicked
5943          * @param {Roo.bootstrap.Table} this
5944          * @param {Roo.Element} el
5945          * @param {Number} rowIndex
5946          * @param {Roo.EventObject} e
5947          */
5948         "rowclick" : true,
5949         /**
5950          * @event rowdblclick
5951          * Fires when a row is double clicked
5952          * @param {Roo.bootstrap.Table} this
5953          * @param {Roo.Element} el
5954          * @param {Number} rowIndex
5955          * @param {Roo.EventObject} e
5956          */
5957         "rowdblclick" : true,
5958         /**
5959          * @event mouseover
5960          * Fires when a mouseover occur
5961          * @param {Roo.bootstrap.Table} this
5962          * @param {Roo.Element} el
5963          * @param {Number} rowIndex
5964          * @param {Number} columnIndex
5965          * @param {Roo.EventObject} e
5966          */
5967         "mouseover" : true,
5968         /**
5969          * @event mouseout
5970          * Fires when a mouseout occur
5971          * @param {Roo.bootstrap.Table} this
5972          * @param {Roo.Element} el
5973          * @param {Number} rowIndex
5974          * @param {Number} columnIndex
5975          * @param {Roo.EventObject} e
5976          */
5977         "mouseout" : true,
5978         /**
5979          * @event rowclass
5980          * Fires when a row is rendered, so you can change add a style to it.
5981          * @param {Roo.bootstrap.Table} this
5982          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5983          */
5984         'rowclass' : true,
5985           /**
5986          * @event rowsrendered
5987          * Fires when all the  rows have been rendered
5988          * @param {Roo.bootstrap.Table} this
5989          */
5990         'rowsrendered' : true,
5991         /**
5992          * @event contextmenu
5993          * The raw contextmenu event for the entire grid.
5994          * @param {Roo.EventObject} e
5995          */
5996         "contextmenu" : true,
5997         /**
5998          * @event rowcontextmenu
5999          * Fires when a row is right clicked
6000          * @param {Roo.bootstrap.Table} this
6001          * @param {Number} rowIndex
6002          * @param {Roo.EventObject} e
6003          */
6004         "rowcontextmenu" : true,
6005         /**
6006          * @event cellcontextmenu
6007          * Fires when a cell is right clicked
6008          * @param {Roo.bootstrap.Table} this
6009          * @param {Number} rowIndex
6010          * @param {Number} cellIndex
6011          * @param {Roo.EventObject} e
6012          */
6013          "cellcontextmenu" : true,
6014          /**
6015          * @event headercontextmenu
6016          * Fires when a header is right clicked
6017          * @param {Roo.bootstrap.Table} this
6018          * @param {Number} columnIndex
6019          * @param {Roo.EventObject} e
6020          */
6021         "headercontextmenu" : true
6022     });
6023 };
6024
6025 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
6026     
6027     cls: false,
6028     align: false,
6029     bgcolor: false,
6030     border: false,
6031     cellpadding: false,
6032     cellspacing: false,
6033     frame: false,
6034     rules: false,
6035     sortable: false,
6036     summary: false,
6037     width: false,
6038     striped : false,
6039     scrollBody : false,
6040     bordered: false,
6041     hover:  false,
6042     condensed : false,
6043     responsive : false,
6044     sm : false,
6045     cm : false,
6046     store : false,
6047     loadMask : false,
6048     footerShow : true,
6049     headerShow : true,
6050   
6051     rowSelection : false,
6052     cellSelection : false,
6053     layout : false,
6054     
6055     // Roo.Element - the tbody
6056     mainBody: false,
6057     // Roo.Element - thead element
6058     mainHead: false,
6059     
6060     container: false, // used by gridpanel...
6061     
6062     lazyLoad : false,
6063     
6064     CSS : Roo.util.CSS,
6065     
6066     getAutoCreate : function()
6067     {
6068         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6069         
6070         cfg = {
6071             tag: 'table',
6072             cls : 'table',
6073             cn : []
6074         };
6075         if (this.scrollBody) {
6076             cfg.cls += ' table-body-fixed';
6077         }    
6078         if (this.striped) {
6079             cfg.cls += ' table-striped';
6080         }
6081         
6082         if (this.hover) {
6083             cfg.cls += ' table-hover';
6084         }
6085         if (this.bordered) {
6086             cfg.cls += ' table-bordered';
6087         }
6088         if (this.condensed) {
6089             cfg.cls += ' table-condensed';
6090         }
6091         if (this.responsive) {
6092             cfg.cls += ' table-responsive';
6093         }
6094         
6095         if (this.cls) {
6096             cfg.cls+=  ' ' +this.cls;
6097         }
6098         
6099         // this lot should be simplifed...
6100         
6101         if (this.align) {
6102             cfg.align=this.align;
6103         }
6104         if (this.bgcolor) {
6105             cfg.bgcolor=this.bgcolor;
6106         }
6107         if (this.border) {
6108             cfg.border=this.border;
6109         }
6110         if (this.cellpadding) {
6111             cfg.cellpadding=this.cellpadding;
6112         }
6113         if (this.cellspacing) {
6114             cfg.cellspacing=this.cellspacing;
6115         }
6116         if (this.frame) {
6117             cfg.frame=this.frame;
6118         }
6119         if (this.rules) {
6120             cfg.rules=this.rules;
6121         }
6122         if (this.sortable) {
6123             cfg.sortable=this.sortable;
6124         }
6125         if (this.summary) {
6126             cfg.summary=this.summary;
6127         }
6128         if (this.width) {
6129             cfg.width=this.width;
6130         }
6131         if (this.layout) {
6132             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6133         }
6134         
6135         if(this.store || this.cm){
6136             if(this.headerShow){
6137                 cfg.cn.push(this.renderHeader());
6138             }
6139             
6140             cfg.cn.push(this.renderBody());
6141             
6142             if(this.footerShow){
6143                 cfg.cn.push(this.renderFooter());
6144             }
6145             // where does this come from?
6146             //cfg.cls+=  ' TableGrid';
6147         }
6148         
6149         return { cn : [ cfg ] };
6150     },
6151     
6152     initEvents : function()
6153     {   
6154         if(!this.store || !this.cm){
6155             return;
6156         }
6157         if (this.selModel) {
6158             this.selModel.initEvents();
6159         }
6160         
6161         
6162         //Roo.log('initEvents with ds!!!!');
6163         
6164         this.mainBody = this.el.select('tbody', true).first();
6165         this.mainHead = this.el.select('thead', true).first();
6166         
6167         
6168         
6169         
6170         var _this = this;
6171         
6172         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6173             e.on('click', _this.sort, _this);
6174         });
6175         
6176         this.mainBody.on("click", this.onClick, this);
6177         this.mainBody.on("dblclick", this.onDblClick, this);
6178         
6179         // why is this done????? = it breaks dialogs??
6180         //this.parent().el.setStyle('position', 'relative');
6181         
6182         
6183         if (this.footer) {
6184             this.footer.parentId = this.id;
6185             this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6186             
6187             if(this.lazyLoad){
6188                 this.el.select('tfoot tr td').first().addClass('hide');
6189             }
6190         } 
6191         
6192         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6193         
6194         this.store.on('load', this.onLoad, this);
6195         this.store.on('beforeload', this.onBeforeLoad, this);
6196         this.store.on('update', this.onUpdate, this);
6197         this.store.on('add', this.onAdd, this);
6198         this.store.on("clear", this.clear, this);
6199         
6200         this.el.on("contextmenu", this.onContextMenu, this);
6201         
6202         this.mainBody.on('scroll', this.onBodyScroll, this);
6203         
6204         this.cm.on("headerchange", this.onHeaderChange, this);
6205         
6206         this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6207         
6208     },
6209     
6210     onContextMenu : function(e, t)
6211     {
6212         this.processEvent("contextmenu", e);
6213     },
6214     
6215     processEvent : function(name, e)
6216     {
6217         if (name != 'touchstart' ) {
6218             this.fireEvent(name, e);    
6219         }
6220         
6221         var t = e.getTarget();
6222         
6223         var cell = Roo.get(t);
6224         
6225         if(!cell){
6226             return;
6227         }
6228         
6229         if(cell.findParent('tfoot', false, true)){
6230             return;
6231         }
6232         
6233         if(cell.findParent('thead', false, true)){
6234             
6235             if(e.getTarget().nodeName.toLowerCase() != 'th'){
6236                 cell = Roo.get(t).findParent('th', false, true);
6237                 if (!cell) {
6238                     Roo.log("failed to find th in thead?");
6239                     Roo.log(e.getTarget());
6240                     return;
6241                 }
6242             }
6243             
6244             var cellIndex = cell.dom.cellIndex;
6245             
6246             var ename = name == 'touchstart' ? 'click' : name;
6247             this.fireEvent("header" + ename, this, cellIndex, e);
6248             
6249             return;
6250         }
6251         
6252         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6253             cell = Roo.get(t).findParent('td', false, true);
6254             if (!cell) {
6255                 Roo.log("failed to find th in tbody?");
6256                 Roo.log(e.getTarget());
6257                 return;
6258             }
6259         }
6260         
6261         var row = cell.findParent('tr', false, true);
6262         var cellIndex = cell.dom.cellIndex;
6263         var rowIndex = row.dom.rowIndex - 1;
6264         
6265         if(row !== false){
6266             
6267             this.fireEvent("row" + name, this, rowIndex, e);
6268             
6269             if(cell !== false){
6270             
6271                 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6272             }
6273         }
6274         
6275     },
6276     
6277     onMouseover : function(e, el)
6278     {
6279         var cell = Roo.get(el);
6280         
6281         if(!cell){
6282             return;
6283         }
6284         
6285         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6286             cell = cell.findParent('td', false, true);
6287         }
6288         
6289         var row = cell.findParent('tr', false, true);
6290         var cellIndex = cell.dom.cellIndex;
6291         var rowIndex = row.dom.rowIndex - 1; // start from 0
6292         
6293         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6294         
6295     },
6296     
6297     onMouseout : function(e, el)
6298     {
6299         var cell = Roo.get(el);
6300         
6301         if(!cell){
6302             return;
6303         }
6304         
6305         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6306             cell = cell.findParent('td', false, true);
6307         }
6308         
6309         var row = cell.findParent('tr', false, true);
6310         var cellIndex = cell.dom.cellIndex;
6311         var rowIndex = row.dom.rowIndex - 1; // start from 0
6312         
6313         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6314         
6315     },
6316     
6317     onClick : function(e, el)
6318     {
6319         var cell = Roo.get(el);
6320         
6321         if(!cell || (!this.cellSelection && !this.rowSelection)){
6322             return;
6323         }
6324         
6325         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6326             cell = cell.findParent('td', false, true);
6327         }
6328         
6329         if(!cell || typeof(cell) == 'undefined'){
6330             return;
6331         }
6332         
6333         var row = cell.findParent('tr', false, true);
6334         
6335         if(!row || typeof(row) == 'undefined'){
6336             return;
6337         }
6338         
6339         var cellIndex = cell.dom.cellIndex;
6340         var rowIndex = this.getRowIndex(row);
6341         
6342         // why??? - should these not be based on SelectionModel?
6343         if(this.cellSelection){
6344             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6345         }
6346         
6347         if(this.rowSelection){
6348             this.fireEvent('rowclick', this, row, rowIndex, e);
6349         }
6350         
6351         
6352     },
6353         
6354     onDblClick : function(e,el)
6355     {
6356         var cell = Roo.get(el);
6357         
6358         if(!cell || (!this.cellSelection && !this.rowSelection)){
6359             return;
6360         }
6361         
6362         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6363             cell = cell.findParent('td', false, true);
6364         }
6365         
6366         if(!cell || typeof(cell) == 'undefined'){
6367             return;
6368         }
6369         
6370         var row = cell.findParent('tr', false, true);
6371         
6372         if(!row || typeof(row) == 'undefined'){
6373             return;
6374         }
6375         
6376         var cellIndex = cell.dom.cellIndex;
6377         var rowIndex = this.getRowIndex(row);
6378         
6379         if(this.cellSelection){
6380             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6381         }
6382         
6383         if(this.rowSelection){
6384             this.fireEvent('rowdblclick', this, row, rowIndex, e);
6385         }
6386     },
6387     
6388     sort : function(e,el)
6389     {
6390         var col = Roo.get(el);
6391         
6392         if(!col.hasClass('sortable')){
6393             return;
6394         }
6395         
6396         var sort = col.attr('sort');
6397         var dir = 'ASC';
6398         
6399         if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6400             dir = 'DESC';
6401         }
6402         
6403         this.store.sortInfo = {field : sort, direction : dir};
6404         
6405         if (this.footer) {
6406             Roo.log("calling footer first");
6407             this.footer.onClick('first');
6408         } else {
6409         
6410             this.store.load({ params : { start : 0 } });
6411         }
6412     },
6413     
6414     renderHeader : function()
6415     {
6416         var header = {
6417             tag: 'thead',
6418             cn : []
6419         };
6420         
6421         var cm = this.cm;
6422         this.totalWidth = 0;
6423         
6424         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6425             
6426             var config = cm.config[i];
6427             
6428             var c = {
6429                 tag: 'th',
6430                 cls : 'x-hcol-' + i,
6431                 style : '',
6432                 html: cm.getColumnHeader(i)
6433             };
6434             
6435             var hh = '';
6436             
6437             if(typeof(config.sortable) != 'undefined' && config.sortable){
6438                 c.cls = 'sortable';
6439                 c.html = '<i class="glyphicon"></i>' + c.html;
6440             }
6441             
6442             if(typeof(config.lgHeader) != 'undefined'){
6443                 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6444             }
6445             
6446             if(typeof(config.mdHeader) != 'undefined'){
6447                 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6448             }
6449             
6450             if(typeof(config.smHeader) != 'undefined'){
6451                 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6452             }
6453             
6454             if(typeof(config.xsHeader) != 'undefined'){
6455                 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6456             }
6457             
6458             if(hh.length){
6459                 c.html = hh;
6460             }
6461             
6462             if(typeof(config.tooltip) != 'undefined'){
6463                 c.tooltip = config.tooltip;
6464             }
6465             
6466             if(typeof(config.colspan) != 'undefined'){
6467                 c.colspan = config.colspan;
6468             }
6469             
6470             if(typeof(config.hidden) != 'undefined' && config.hidden){
6471                 c.style += ' display:none;';
6472             }
6473             
6474             if(typeof(config.dataIndex) != 'undefined'){
6475                 c.sort = config.dataIndex;
6476             }
6477             
6478            
6479             
6480             if(typeof(config.align) != 'undefined' && config.align.length){
6481                 c.style += ' text-align:' + config.align + ';';
6482             }
6483             
6484             if(typeof(config.width) != 'undefined'){
6485                 c.style += ' width:' + config.width + 'px;';
6486                 this.totalWidth += config.width;
6487             } else {
6488                 this.totalWidth += 100; // assume minimum of 100 per column?
6489             }
6490             
6491             if(typeof(config.cls) != 'undefined'){
6492                 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6493             }
6494             
6495             ['xs','sm','md','lg'].map(function(size){
6496                 
6497                 if(typeof(config[size]) == 'undefined'){
6498                     return;
6499                 }
6500                 
6501                 if (!config[size]) { // 0 = hidden
6502                     c.cls += ' hidden-' + size;
6503                     return;
6504                 }
6505                 
6506                 c.cls += ' col-' + size + '-' + config[size];
6507
6508             });
6509             
6510             header.cn.push(c)
6511         }
6512         
6513         return header;
6514     },
6515     
6516     renderBody : function()
6517     {
6518         var body = {
6519             tag: 'tbody',
6520             cn : [
6521                 {
6522                     tag: 'tr',
6523                     cn : [
6524                         {
6525                             tag : 'td',
6526                             colspan :  this.cm.getColumnCount()
6527                         }
6528                     ]
6529                 }
6530             ]
6531         };
6532         
6533         return body;
6534     },
6535     
6536     renderFooter : function()
6537     {
6538         var footer = {
6539             tag: 'tfoot',
6540             cn : [
6541                 {
6542                     tag: 'tr',
6543                     cn : [
6544                         {
6545                             tag : 'td',
6546                             colspan :  this.cm.getColumnCount()
6547                         }
6548                     ]
6549                 }
6550             ]
6551         };
6552         
6553         return footer;
6554     },
6555     
6556     
6557     
6558     onLoad : function()
6559     {
6560 //        Roo.log('ds onload');
6561         this.clear();
6562         
6563         var _this = this;
6564         var cm = this.cm;
6565         var ds = this.store;
6566         
6567         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6568             e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6569             if (_this.store.sortInfo) {
6570                     
6571                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6572                     e.select('i', true).addClass(['glyphicon-arrow-up']);
6573                 }
6574                 
6575                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6576                     e.select('i', true).addClass(['glyphicon-arrow-down']);
6577                 }
6578             }
6579         });
6580         
6581         var tbody =  this.mainBody;
6582               
6583         if(ds.getCount() > 0){
6584             ds.data.each(function(d,rowIndex){
6585                 var row =  this.renderRow(cm, ds, rowIndex);
6586                 
6587                 tbody.createChild(row);
6588                 
6589                 var _this = this;
6590                 
6591                 if(row.cellObjects.length){
6592                     Roo.each(row.cellObjects, function(r){
6593                         _this.renderCellObject(r);
6594                     })
6595                 }
6596                 
6597             }, this);
6598         }
6599         
6600         Roo.each(this.el.select('tbody td', true).elements, function(e){
6601             e.on('mouseover', _this.onMouseover, _this);
6602         });
6603         
6604         Roo.each(this.el.select('tbody td', true).elements, function(e){
6605             e.on('mouseout', _this.onMouseout, _this);
6606         });
6607         this.fireEvent('rowsrendered', this);
6608         //if(this.loadMask){
6609         //    this.maskEl.hide();
6610         //}
6611         
6612         this.autoSize();
6613     },
6614     
6615     
6616     onUpdate : function(ds,record)
6617     {
6618         this.refreshRow(record);
6619         this.autoSize();
6620     },
6621     
6622     onRemove : function(ds, record, index, isUpdate){
6623         if(isUpdate !== true){
6624             this.fireEvent("beforerowremoved", this, index, record);
6625         }
6626         var bt = this.mainBody.dom;
6627         
6628         var rows = this.el.select('tbody > tr', true).elements;
6629         
6630         if(typeof(rows[index]) != 'undefined'){
6631             bt.removeChild(rows[index].dom);
6632         }
6633         
6634 //        if(bt.rows[index]){
6635 //            bt.removeChild(bt.rows[index]);
6636 //        }
6637         
6638         if(isUpdate !== true){
6639             //this.stripeRows(index);
6640             //this.syncRowHeights(index, index);
6641             //this.layout();
6642             this.fireEvent("rowremoved", this, index, record);
6643         }
6644     },
6645     
6646     onAdd : function(ds, records, rowIndex)
6647     {
6648         //Roo.log('on Add called');
6649         // - note this does not handle multiple adding very well..
6650         var bt = this.mainBody.dom;
6651         for (var i =0 ; i < records.length;i++) {
6652             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6653             //Roo.log(records[i]);
6654             //Roo.log(this.store.getAt(rowIndex+i));
6655             this.insertRow(this.store, rowIndex + i, false);
6656             return;
6657         }
6658         
6659     },
6660     
6661     
6662     refreshRow : function(record){
6663         var ds = this.store, index;
6664         if(typeof record == 'number'){
6665             index = record;
6666             record = ds.getAt(index);
6667         }else{
6668             index = ds.indexOf(record);
6669         }
6670         this.insertRow(ds, index, true);
6671         this.autoSize();
6672         this.onRemove(ds, record, index+1, true);
6673         this.autoSize();
6674         //this.syncRowHeights(index, index);
6675         //this.layout();
6676         this.fireEvent("rowupdated", this, index, record);
6677     },
6678     
6679     insertRow : function(dm, rowIndex, isUpdate){
6680         
6681         if(!isUpdate){
6682             this.fireEvent("beforerowsinserted", this, rowIndex);
6683         }
6684             //var s = this.getScrollState();
6685         var row = this.renderRow(this.cm, this.store, rowIndex);
6686         // insert before rowIndex..
6687         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6688         
6689         var _this = this;
6690                 
6691         if(row.cellObjects.length){
6692             Roo.each(row.cellObjects, function(r){
6693                 _this.renderCellObject(r);
6694             })
6695         }
6696             
6697         if(!isUpdate){
6698             this.fireEvent("rowsinserted", this, rowIndex);
6699             //this.syncRowHeights(firstRow, lastRow);
6700             //this.stripeRows(firstRow);
6701             //this.layout();
6702         }
6703         
6704     },
6705     
6706     
6707     getRowDom : function(rowIndex)
6708     {
6709         var rows = this.el.select('tbody > tr', true).elements;
6710         
6711         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6712         
6713     },
6714     // returns the object tree for a tr..
6715   
6716     
6717     renderRow : function(cm, ds, rowIndex) 
6718     {
6719         var d = ds.getAt(rowIndex);
6720         
6721         var row = {
6722             tag : 'tr',
6723             cls : 'x-row-' + rowIndex,
6724             cn : []
6725         };
6726             
6727         var cellObjects = [];
6728         
6729         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6730             var config = cm.config[i];
6731             
6732             var renderer = cm.getRenderer(i);
6733             var value = '';
6734             var id = false;
6735             
6736             if(typeof(renderer) !== 'undefined'){
6737                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6738             }
6739             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6740             // and are rendered into the cells after the row is rendered - using the id for the element.
6741             
6742             if(typeof(value) === 'object'){
6743                 id = Roo.id();
6744                 cellObjects.push({
6745                     container : id,
6746                     cfg : value 
6747                 })
6748             }
6749             
6750             var rowcfg = {
6751                 record: d,
6752                 rowIndex : rowIndex,
6753                 colIndex : i,
6754                 rowClass : ''
6755             };
6756
6757             this.fireEvent('rowclass', this, rowcfg);
6758             
6759             var td = {
6760                 tag: 'td',
6761                 cls : rowcfg.rowClass + ' x-col-' + i,
6762                 style: '',
6763                 html: (typeof(value) === 'object') ? '' : value
6764             };
6765             
6766             if (id) {
6767                 td.id = id;
6768             }
6769             
6770             if(typeof(config.colspan) != 'undefined'){
6771                 td.colspan = config.colspan;
6772             }
6773             
6774             if(typeof(config.hidden) != 'undefined' && config.hidden){
6775                 td.style += ' display:none;';
6776             }
6777             
6778             if(typeof(config.align) != 'undefined' && config.align.length){
6779                 td.style += ' text-align:' + config.align + ';';
6780             }
6781             
6782             if(typeof(config.width) != 'undefined'){
6783                 td.style += ' width:' +  config.width + 'px;';
6784             }
6785             
6786             if(typeof(config.cursor) != 'undefined'){
6787                 td.style += ' cursor:' +  config.cursor + ';';
6788             }
6789             
6790             if(typeof(config.cls) != 'undefined'){
6791                 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6792             }
6793             
6794             ['xs','sm','md','lg'].map(function(size){
6795                 
6796                 if(typeof(config[size]) == 'undefined'){
6797                     return;
6798                 }
6799                 
6800                 if (!config[size]) { // 0 = hidden
6801                     td.cls += ' hidden-' + size;
6802                     return;
6803                 }
6804                 
6805                 td.cls += ' col-' + size + '-' + config[size];
6806
6807             });
6808             
6809             row.cn.push(td);
6810            
6811         }
6812         
6813         row.cellObjects = cellObjects;
6814         
6815         return row;
6816           
6817     },
6818     
6819     
6820     
6821     onBeforeLoad : function()
6822     {
6823         //Roo.log('ds onBeforeLoad');
6824         
6825         //this.clear();
6826         
6827         //if(this.loadMask){
6828         //    this.maskEl.show();
6829         //}
6830     },
6831      /**
6832      * Remove all rows
6833      */
6834     clear : function()
6835     {
6836         this.el.select('tbody', true).first().dom.innerHTML = '';
6837     },
6838     /**
6839      * Show or hide a row.
6840      * @param {Number} rowIndex to show or hide
6841      * @param {Boolean} state hide
6842      */
6843     setRowVisibility : function(rowIndex, state)
6844     {
6845         var bt = this.mainBody.dom;
6846         
6847         var rows = this.el.select('tbody > tr', true).elements;
6848         
6849         if(typeof(rows[rowIndex]) == 'undefined'){
6850             return;
6851         }
6852         rows[rowIndex].dom.style.display = state ? '' : 'none';
6853     },
6854     
6855     
6856     getSelectionModel : function(){
6857         if(!this.selModel){
6858             this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6859         }
6860         return this.selModel;
6861     },
6862     /*
6863      * Render the Roo.bootstrap object from renderder
6864      */
6865     renderCellObject : function(r)
6866     {
6867         var _this = this;
6868         
6869         r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6870         
6871         var t = r.cfg.render(r.container);
6872         
6873         if(r.cfg.cn){
6874             Roo.each(r.cfg.cn, function(c){
6875                 var child = {
6876                     container: t.getChildContainer(),
6877                     cfg: c
6878                 };
6879                 _this.renderCellObject(child);
6880             })
6881         }
6882     },
6883     
6884     getRowIndex : function(row)
6885     {
6886         var rowIndex = -1;
6887         
6888         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6889             if(el != row){
6890                 return;
6891             }
6892             
6893             rowIndex = index;
6894         });
6895         
6896         return rowIndex;
6897     },
6898      /**
6899      * Returns the grid's underlying element = used by panel.Grid
6900      * @return {Element} The element
6901      */
6902     getGridEl : function(){
6903         return this.el;
6904     },
6905      /**
6906      * Forces a resize - used by panel.Grid
6907      * @return {Element} The element
6908      */
6909     autoSize : function()
6910     {
6911         //var ctr = Roo.get(this.container.dom.parentElement);
6912         var ctr = Roo.get(this.el.dom);
6913         
6914         var thd = this.getGridEl().select('thead',true).first();
6915         var tbd = this.getGridEl().select('tbody', true).first();
6916         var tfd = this.getGridEl().select('tfoot', true).first();
6917         
6918         var cw = ctr.getWidth();
6919         
6920         if (tbd) {
6921             
6922             tbd.setSize(ctr.getWidth(),
6923                         ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6924             );
6925             var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6926             cw -= barsize;
6927         }
6928         cw = Math.max(cw, this.totalWidth);
6929         this.getGridEl().select('tr',true).setWidth(cw);
6930         // resize 'expandable coloumn?
6931         
6932         return; // we doe not have a view in this design..
6933         
6934     },
6935     onBodyScroll: function()
6936     {
6937         //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6938         if(this.mainHead){
6939             this.mainHead.setStyle({
6940                 'position' : 'relative',
6941                 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6942             });
6943         }
6944         
6945         if(this.lazyLoad){
6946             
6947             var scrollHeight = this.mainBody.dom.scrollHeight;
6948             
6949             var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6950             
6951             var height = this.mainBody.getHeight();
6952             
6953             if(scrollHeight - height == scrollTop) {
6954                 
6955                 var total = this.ds.getTotalCount();
6956                 
6957                 if(this.footer.cursor + this.footer.pageSize < total){
6958                     
6959                     this.footer.ds.load({
6960                         params : {
6961                             start : this.footer.cursor + this.footer.pageSize,
6962                             limit : this.footer.pageSize
6963                         },
6964                         add : true
6965                     });
6966                 }
6967             }
6968             
6969         }
6970     },
6971     
6972     onHeaderChange : function()
6973     {
6974         var header = this.renderHeader();
6975         var table = this.el.select('table', true).first();
6976         
6977         this.mainHead.remove();
6978         this.mainHead = table.createChild(header, this.mainBody, false);
6979     },
6980     
6981     onHiddenChange : function(colModel, colIndex, hidden)
6982     {
6983         var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
6984         var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
6985         
6986         this.CSS.updateRule(thSelector, "display", "");
6987         this.CSS.updateRule(tdSelector, "display", "");
6988         
6989         if(hidden){
6990             this.CSS.updateRule(thSelector, "display", "none");
6991             this.CSS.updateRule(tdSelector, "display", "none");
6992         }
6993         
6994         this.onHeaderChange();
6995         this.onLoad();
6996         
6997     }
6998     
6999 });
7000
7001  
7002
7003  /*
7004  * - LGPL
7005  *
7006  * table cell
7007  * 
7008  */
7009
7010 /**
7011  * @class Roo.bootstrap.TableCell
7012  * @extends Roo.bootstrap.Component
7013  * Bootstrap TableCell class
7014  * @cfg {String} html cell contain text
7015  * @cfg {String} cls cell class
7016  * @cfg {String} tag cell tag (td|th) default td
7017  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7018  * @cfg {String} align Aligns the content in a cell
7019  * @cfg {String} axis Categorizes cells
7020  * @cfg {String} bgcolor Specifies the background color of a cell
7021  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7022  * @cfg {Number} colspan Specifies the number of columns a cell should span
7023  * @cfg {String} headers Specifies one or more header cells a cell is related to
7024  * @cfg {Number} height Sets the height of a cell
7025  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7026  * @cfg {Number} rowspan Sets the number of rows a cell should span
7027  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7028  * @cfg {String} valign Vertical aligns the content in a cell
7029  * @cfg {Number} width Specifies the width of a cell
7030  * 
7031  * @constructor
7032  * Create a new TableCell
7033  * @param {Object} config The config object
7034  */
7035
7036 Roo.bootstrap.TableCell = function(config){
7037     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7038 };
7039
7040 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
7041     
7042     html: false,
7043     cls: false,
7044     tag: false,
7045     abbr: false,
7046     align: false,
7047     axis: false,
7048     bgcolor: false,
7049     charoff: false,
7050     colspan: false,
7051     headers: false,
7052     height: false,
7053     nowrap: false,
7054     rowspan: false,
7055     scope: false,
7056     valign: false,
7057     width: false,
7058     
7059     
7060     getAutoCreate : function(){
7061         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7062         
7063         cfg = {
7064             tag: 'td'
7065         };
7066         
7067         if(this.tag){
7068             cfg.tag = this.tag;
7069         }
7070         
7071         if (this.html) {
7072             cfg.html=this.html
7073         }
7074         if (this.cls) {
7075             cfg.cls=this.cls
7076         }
7077         if (this.abbr) {
7078             cfg.abbr=this.abbr
7079         }
7080         if (this.align) {
7081             cfg.align=this.align
7082         }
7083         if (this.axis) {
7084             cfg.axis=this.axis
7085         }
7086         if (this.bgcolor) {
7087             cfg.bgcolor=this.bgcolor
7088         }
7089         if (this.charoff) {
7090             cfg.charoff=this.charoff
7091         }
7092         if (this.colspan) {
7093             cfg.colspan=this.colspan
7094         }
7095         if (this.headers) {
7096             cfg.headers=this.headers
7097         }
7098         if (this.height) {
7099             cfg.height=this.height
7100         }
7101         if (this.nowrap) {
7102             cfg.nowrap=this.nowrap
7103         }
7104         if (this.rowspan) {
7105             cfg.rowspan=this.rowspan
7106         }
7107         if (this.scope) {
7108             cfg.scope=this.scope
7109         }
7110         if (this.valign) {
7111             cfg.valign=this.valign
7112         }
7113         if (this.width) {
7114             cfg.width=this.width
7115         }
7116         
7117         
7118         return cfg;
7119     }
7120    
7121 });
7122
7123  
7124
7125  /*
7126  * - LGPL
7127  *
7128  * table row
7129  * 
7130  */
7131
7132 /**
7133  * @class Roo.bootstrap.TableRow
7134  * @extends Roo.bootstrap.Component
7135  * Bootstrap TableRow class
7136  * @cfg {String} cls row class
7137  * @cfg {String} align Aligns the content in a table row
7138  * @cfg {String} bgcolor Specifies a background color for a table row
7139  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7140  * @cfg {String} valign Vertical aligns the content in a table row
7141  * 
7142  * @constructor
7143  * Create a new TableRow
7144  * @param {Object} config The config object
7145  */
7146
7147 Roo.bootstrap.TableRow = function(config){
7148     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7149 };
7150
7151 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
7152     
7153     cls: false,
7154     align: false,
7155     bgcolor: false,
7156     charoff: false,
7157     valign: false,
7158     
7159     getAutoCreate : function(){
7160         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7161         
7162         cfg = {
7163             tag: 'tr'
7164         };
7165             
7166         if(this.cls){
7167             cfg.cls = this.cls;
7168         }
7169         if(this.align){
7170             cfg.align = this.align;
7171         }
7172         if(this.bgcolor){
7173             cfg.bgcolor = this.bgcolor;
7174         }
7175         if(this.charoff){
7176             cfg.charoff = this.charoff;
7177         }
7178         if(this.valign){
7179             cfg.valign = this.valign;
7180         }
7181         
7182         return cfg;
7183     }
7184    
7185 });
7186
7187  
7188
7189  /*
7190  * - LGPL
7191  *
7192  * table body
7193  * 
7194  */
7195
7196 /**
7197  * @class Roo.bootstrap.TableBody
7198  * @extends Roo.bootstrap.Component
7199  * Bootstrap TableBody class
7200  * @cfg {String} cls element class
7201  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7202  * @cfg {String} align Aligns the content inside the element
7203  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7204  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7205  * 
7206  * @constructor
7207  * Create a new TableBody
7208  * @param {Object} config The config object
7209  */
7210
7211 Roo.bootstrap.TableBody = function(config){
7212     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7213 };
7214
7215 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
7216     
7217     cls: false,
7218     tag: false,
7219     align: false,
7220     charoff: false,
7221     valign: false,
7222     
7223     getAutoCreate : function(){
7224         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7225         
7226         cfg = {
7227             tag: 'tbody'
7228         };
7229             
7230         if (this.cls) {
7231             cfg.cls=this.cls
7232         }
7233         if(this.tag){
7234             cfg.tag = this.tag;
7235         }
7236         
7237         if(this.align){
7238             cfg.align = this.align;
7239         }
7240         if(this.charoff){
7241             cfg.charoff = this.charoff;
7242         }
7243         if(this.valign){
7244             cfg.valign = this.valign;
7245         }
7246         
7247         return cfg;
7248     }
7249     
7250     
7251 //    initEvents : function()
7252 //    {
7253 //        
7254 //        if(!this.store){
7255 //            return;
7256 //        }
7257 //        
7258 //        this.store = Roo.factory(this.store, Roo.data);
7259 //        this.store.on('load', this.onLoad, this);
7260 //        
7261 //        this.store.load();
7262 //        
7263 //    },
7264 //    
7265 //    onLoad: function () 
7266 //    {   
7267 //        this.fireEvent('load', this);
7268 //    }
7269 //    
7270 //   
7271 });
7272
7273  
7274
7275  /*
7276  * Based on:
7277  * Ext JS Library 1.1.1
7278  * Copyright(c) 2006-2007, Ext JS, LLC.
7279  *
7280  * Originally Released Under LGPL - original licence link has changed is not relivant.
7281  *
7282  * Fork - LGPL
7283  * <script type="text/javascript">
7284  */
7285
7286 // as we use this in bootstrap.
7287 Roo.namespace('Roo.form');
7288  /**
7289  * @class Roo.form.Action
7290  * Internal Class used to handle form actions
7291  * @constructor
7292  * @param {Roo.form.BasicForm} el The form element or its id
7293  * @param {Object} config Configuration options
7294  */
7295
7296  
7297  
7298 // define the action interface
7299 Roo.form.Action = function(form, options){
7300     this.form = form;
7301     this.options = options || {};
7302 };
7303 /**
7304  * Client Validation Failed
7305  * @const 
7306  */
7307 Roo.form.Action.CLIENT_INVALID = 'client';
7308 /**
7309  * Server Validation Failed
7310  * @const 
7311  */
7312 Roo.form.Action.SERVER_INVALID = 'server';
7313  /**
7314  * Connect to Server Failed
7315  * @const 
7316  */
7317 Roo.form.Action.CONNECT_FAILURE = 'connect';
7318 /**
7319  * Reading Data from Server Failed
7320  * @const 
7321  */
7322 Roo.form.Action.LOAD_FAILURE = 'load';
7323
7324 Roo.form.Action.prototype = {
7325     type : 'default',
7326     failureType : undefined,
7327     response : undefined,
7328     result : undefined,
7329
7330     // interface method
7331     run : function(options){
7332
7333     },
7334
7335     // interface method
7336     success : function(response){
7337
7338     },
7339
7340     // interface method
7341     handleResponse : function(response){
7342
7343     },
7344
7345     // default connection failure
7346     failure : function(response){
7347         
7348         this.response = response;
7349         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7350         this.form.afterAction(this, false);
7351     },
7352
7353     processResponse : function(response){
7354         this.response = response;
7355         if(!response.responseText){
7356             return true;
7357         }
7358         this.result = this.handleResponse(response);
7359         return this.result;
7360     },
7361
7362     // utility functions used internally
7363     getUrl : function(appendParams){
7364         var url = this.options.url || this.form.url || this.form.el.dom.action;
7365         if(appendParams){
7366             var p = this.getParams();
7367             if(p){
7368                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7369             }
7370         }
7371         return url;
7372     },
7373
7374     getMethod : function(){
7375         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7376     },
7377
7378     getParams : function(){
7379         var bp = this.form.baseParams;
7380         var p = this.options.params;
7381         if(p){
7382             if(typeof p == "object"){
7383                 p = Roo.urlEncode(Roo.applyIf(p, bp));
7384             }else if(typeof p == 'string' && bp){
7385                 p += '&' + Roo.urlEncode(bp);
7386             }
7387         }else if(bp){
7388             p = Roo.urlEncode(bp);
7389         }
7390         return p;
7391     },
7392
7393     createCallback : function(){
7394         return {
7395             success: this.success,
7396             failure: this.failure,
7397             scope: this,
7398             timeout: (this.form.timeout*1000),
7399             upload: this.form.fileUpload ? this.success : undefined
7400         };
7401     }
7402 };
7403
7404 Roo.form.Action.Submit = function(form, options){
7405     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7406 };
7407
7408 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7409     type : 'submit',
7410
7411     haveProgress : false,
7412     uploadComplete : false,
7413     
7414     // uploadProgress indicator.
7415     uploadProgress : function()
7416     {
7417         if (!this.form.progressUrl) {
7418             return;
7419         }
7420         
7421         if (!this.haveProgress) {
7422             Roo.MessageBox.progress("Uploading", "Uploading");
7423         }
7424         if (this.uploadComplete) {
7425            Roo.MessageBox.hide();
7426            return;
7427         }
7428         
7429         this.haveProgress = true;
7430    
7431         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7432         
7433         var c = new Roo.data.Connection();
7434         c.request({
7435             url : this.form.progressUrl,
7436             params: {
7437                 id : uid
7438             },
7439             method: 'GET',
7440             success : function(req){
7441                //console.log(data);
7442                 var rdata = false;
7443                 var edata;
7444                 try  {
7445                    rdata = Roo.decode(req.responseText)
7446                 } catch (e) {
7447                     Roo.log("Invalid data from server..");
7448                     Roo.log(edata);
7449                     return;
7450                 }
7451                 if (!rdata || !rdata.success) {
7452                     Roo.log(rdata);
7453                     Roo.MessageBox.alert(Roo.encode(rdata));
7454                     return;
7455                 }
7456                 var data = rdata.data;
7457                 
7458                 if (this.uploadComplete) {
7459                    Roo.MessageBox.hide();
7460                    return;
7461                 }
7462                    
7463                 if (data){
7464                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7465                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7466                     );
7467                 }
7468                 this.uploadProgress.defer(2000,this);
7469             },
7470        
7471             failure: function(data) {
7472                 Roo.log('progress url failed ');
7473                 Roo.log(data);
7474             },
7475             scope : this
7476         });
7477            
7478     },
7479     
7480     
7481     run : function()
7482     {
7483         // run get Values on the form, so it syncs any secondary forms.
7484         this.form.getValues();
7485         
7486         var o = this.options;
7487         var method = this.getMethod();
7488         var isPost = method == 'POST';
7489         if(o.clientValidation === false || this.form.isValid()){
7490             
7491             if (this.form.progressUrl) {
7492                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7493                     (new Date() * 1) + '' + Math.random());
7494                     
7495             } 
7496             
7497             
7498             Roo.Ajax.request(Roo.apply(this.createCallback(), {
7499                 form:this.form.el.dom,
7500                 url:this.getUrl(!isPost),
7501                 method: method,
7502                 params:isPost ? this.getParams() : null,
7503                 isUpload: this.form.fileUpload
7504             }));
7505             
7506             this.uploadProgress();
7507
7508         }else if (o.clientValidation !== false){ // client validation failed
7509             this.failureType = Roo.form.Action.CLIENT_INVALID;
7510             this.form.afterAction(this, false);
7511         }
7512     },
7513
7514     success : function(response)
7515     {
7516         this.uploadComplete= true;
7517         if (this.haveProgress) {
7518             Roo.MessageBox.hide();
7519         }
7520         
7521         
7522         var result = this.processResponse(response);
7523         if(result === true || result.success){
7524             this.form.afterAction(this, true);
7525             return;
7526         }
7527         if(result.errors){
7528             this.form.markInvalid(result.errors);
7529             this.failureType = Roo.form.Action.SERVER_INVALID;
7530         }
7531         this.form.afterAction(this, false);
7532     },
7533     failure : function(response)
7534     {
7535         this.uploadComplete= true;
7536         if (this.haveProgress) {
7537             Roo.MessageBox.hide();
7538         }
7539         
7540         this.response = response;
7541         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7542         this.form.afterAction(this, false);
7543     },
7544     
7545     handleResponse : function(response){
7546         if(this.form.errorReader){
7547             var rs = this.form.errorReader.read(response);
7548             var errors = [];
7549             if(rs.records){
7550                 for(var i = 0, len = rs.records.length; i < len; i++) {
7551                     var r = rs.records[i];
7552                     errors[i] = r.data;
7553                 }
7554             }
7555             if(errors.length < 1){
7556                 errors = null;
7557             }
7558             return {
7559                 success : rs.success,
7560                 errors : errors
7561             };
7562         }
7563         var ret = false;
7564         try {
7565             ret = Roo.decode(response.responseText);
7566         } catch (e) {
7567             ret = {
7568                 success: false,
7569                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7570                 errors : []
7571             };
7572         }
7573         return ret;
7574         
7575     }
7576 });
7577
7578
7579 Roo.form.Action.Load = function(form, options){
7580     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7581     this.reader = this.form.reader;
7582 };
7583
7584 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7585     type : 'load',
7586
7587     run : function(){
7588         
7589         Roo.Ajax.request(Roo.apply(
7590                 this.createCallback(), {
7591                     method:this.getMethod(),
7592                     url:this.getUrl(false),
7593                     params:this.getParams()
7594         }));
7595     },
7596
7597     success : function(response){
7598         
7599         var result = this.processResponse(response);
7600         if(result === true || !result.success || !result.data){
7601             this.failureType = Roo.form.Action.LOAD_FAILURE;
7602             this.form.afterAction(this, false);
7603             return;
7604         }
7605         this.form.clearInvalid();
7606         this.form.setValues(result.data);
7607         this.form.afterAction(this, true);
7608     },
7609
7610     handleResponse : function(response){
7611         if(this.form.reader){
7612             var rs = this.form.reader.read(response);
7613             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7614             return {
7615                 success : rs.success,
7616                 data : data
7617             };
7618         }
7619         return Roo.decode(response.responseText);
7620     }
7621 });
7622
7623 Roo.form.Action.ACTION_TYPES = {
7624     'load' : Roo.form.Action.Load,
7625     'submit' : Roo.form.Action.Submit
7626 };/*
7627  * - LGPL
7628  *
7629  * form
7630  *
7631  */
7632
7633 /**
7634  * @class Roo.bootstrap.Form
7635  * @extends Roo.bootstrap.Component
7636  * Bootstrap Form class
7637  * @cfg {String} method  GET | POST (default POST)
7638  * @cfg {String} labelAlign top | left (default top)
7639  * @cfg {String} align left  | right - for navbars
7640  * @cfg {Boolean} loadMask load mask when submit (default true)
7641
7642  *
7643  * @constructor
7644  * Create a new Form
7645  * @param {Object} config The config object
7646  */
7647
7648
7649 Roo.bootstrap.Form = function(config){
7650     
7651     Roo.bootstrap.Form.superclass.constructor.call(this, config);
7652     
7653     Roo.bootstrap.Form.popover.apply();
7654     
7655     this.addEvents({
7656         /**
7657          * @event clientvalidation
7658          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7659          * @param {Form} this
7660          * @param {Boolean} valid true if the form has passed client-side validation
7661          */
7662         clientvalidation: true,
7663         /**
7664          * @event beforeaction
7665          * Fires before any action is performed. Return false to cancel the action.
7666          * @param {Form} this
7667          * @param {Action} action The action to be performed
7668          */
7669         beforeaction: true,
7670         /**
7671          * @event actionfailed
7672          * Fires when an action fails.
7673          * @param {Form} this
7674          * @param {Action} action The action that failed
7675          */
7676         actionfailed : true,
7677         /**
7678          * @event actioncomplete
7679          * Fires when an action is completed.
7680          * @param {Form} this
7681          * @param {Action} action The action that completed
7682          */
7683         actioncomplete : true
7684     });
7685 };
7686
7687 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
7688
7689      /**
7690      * @cfg {String} method
7691      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7692      */
7693     method : 'POST',
7694     /**
7695      * @cfg {String} url
7696      * The URL to use for form actions if one isn't supplied in the action options.
7697      */
7698     /**
7699      * @cfg {Boolean} fileUpload
7700      * Set to true if this form is a file upload.
7701      */
7702
7703     /**
7704      * @cfg {Object} baseParams
7705      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7706      */
7707
7708     /**
7709      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7710      */
7711     timeout: 30,
7712     /**
7713      * @cfg {Sting} align (left|right) for navbar forms
7714      */
7715     align : 'left',
7716
7717     // private
7718     activeAction : null,
7719
7720     /**
7721      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7722      * element by passing it or its id or mask the form itself by passing in true.
7723      * @type Mixed
7724      */
7725     waitMsgTarget : false,
7726
7727     loadMask : true,
7728     
7729     /**
7730      * @cfg {Boolean} errorMask (true|false) default false
7731      */
7732     errorMask : false,
7733     
7734     /**
7735      * @cfg {Number} maskOffset Default 100
7736      */
7737     maskOffset : 100,
7738     
7739     /**
7740      * @cfg {Boolean} maskBody
7741      */
7742     maskBody : false,
7743
7744     getAutoCreate : function(){
7745
7746         var cfg = {
7747             tag: 'form',
7748             method : this.method || 'POST',
7749             id : this.id || Roo.id(),
7750             cls : ''
7751         };
7752         if (this.parent().xtype.match(/^Nav/)) {
7753             cfg.cls = 'navbar-form navbar-' + this.align;
7754
7755         }
7756
7757         if (this.labelAlign == 'left' ) {
7758             cfg.cls += ' form-horizontal';
7759         }
7760
7761
7762         return cfg;
7763     },
7764     initEvents : function()
7765     {
7766         this.el.on('submit', this.onSubmit, this);
7767         // this was added as random key presses on the form where triggering form submit.
7768         this.el.on('keypress', function(e) {
7769             if (e.getCharCode() != 13) {
7770                 return true;
7771             }
7772             // we might need to allow it for textareas.. and some other items.
7773             // check e.getTarget().
7774
7775             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7776                 return true;
7777             }
7778
7779             Roo.log("keypress blocked");
7780
7781             e.preventDefault();
7782             return false;
7783         });
7784         
7785     },
7786     // private
7787     onSubmit : function(e){
7788         e.stopEvent();
7789     },
7790
7791      /**
7792      * Returns true if client-side validation on the form is successful.
7793      * @return Boolean
7794      */
7795     isValid : function(){
7796         var items = this.getItems();
7797         var valid = true;
7798         var target = false;
7799         
7800         items.each(function(f){
7801             
7802             if(f.validate()){
7803                 return;
7804             }
7805             valid = false;
7806
7807             if(!target && f.el.isVisible(true)){
7808                 target = f;
7809             }
7810            
7811         });
7812         
7813         if(this.errorMask && !valid){
7814             Roo.bootstrap.Form.popover.mask(this, target);
7815         }
7816         
7817         return valid;
7818     },
7819     
7820     /**
7821      * Returns true if any fields in this form have changed since their original load.
7822      * @return Boolean
7823      */
7824     isDirty : function(){
7825         var dirty = false;
7826         var items = this.getItems();
7827         items.each(function(f){
7828            if(f.isDirty()){
7829                dirty = true;
7830                return false;
7831            }
7832            return true;
7833         });
7834         return dirty;
7835     },
7836      /**
7837      * Performs a predefined action (submit or load) or custom actions you define on this form.
7838      * @param {String} actionName The name of the action type
7839      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
7840      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7841      * accept other config options):
7842      * <pre>
7843 Property          Type             Description
7844 ----------------  ---------------  ----------------------------------------------------------------------------------
7845 url               String           The url for the action (defaults to the form's url)
7846 method            String           The form method to use (defaults to the form's method, or POST if not defined)
7847 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
7848 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
7849                                    validate the form on the client (defaults to false)
7850      * </pre>
7851      * @return {BasicForm} this
7852      */
7853     doAction : function(action, options){
7854         if(typeof action == 'string'){
7855             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7856         }
7857         if(this.fireEvent('beforeaction', this, action) !== false){
7858             this.beforeAction(action);
7859             action.run.defer(100, action);
7860         }
7861         return this;
7862     },
7863
7864     // private
7865     beforeAction : function(action){
7866         var o = action.options;
7867         
7868         if(this.loadMask){
7869             
7870             if(this.maskBody){
7871                 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7872             } else {
7873                 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7874             }
7875         }
7876         // not really supported yet.. ??
7877
7878         //if(this.waitMsgTarget === true){
7879         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7880         //}else if(this.waitMsgTarget){
7881         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7882         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7883         //}else {
7884         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7885        // }
7886
7887     },
7888
7889     // private
7890     afterAction : function(action, success){
7891         this.activeAction = null;
7892         var o = action.options;
7893
7894         if(this.loadMask){
7895             
7896             if(this.maskBody){
7897                 Roo.get(document.body).unmask();
7898             } else {
7899                 this.el.unmask();
7900             }
7901         }
7902         
7903         //if(this.waitMsgTarget === true){
7904 //            this.el.unmask();
7905         //}else if(this.waitMsgTarget){
7906         //    this.waitMsgTarget.unmask();
7907         //}else{
7908         //    Roo.MessageBox.updateProgress(1);
7909         //    Roo.MessageBox.hide();
7910        // }
7911         //
7912         if(success){
7913             if(o.reset){
7914                 this.reset();
7915             }
7916             Roo.callback(o.success, o.scope, [this, action]);
7917             this.fireEvent('actioncomplete', this, action);
7918
7919         }else{
7920
7921             // failure condition..
7922             // we have a scenario where updates need confirming.
7923             // eg. if a locking scenario exists..
7924             // we look for { errors : { needs_confirm : true }} in the response.
7925             if (
7926                 (typeof(action.result) != 'undefined')  &&
7927                 (typeof(action.result.errors) != 'undefined')  &&
7928                 (typeof(action.result.errors.needs_confirm) != 'undefined')
7929            ){
7930                 var _t = this;
7931                 Roo.log("not supported yet");
7932                  /*
7933
7934                 Roo.MessageBox.confirm(
7935                     "Change requires confirmation",
7936                     action.result.errorMsg,
7937                     function(r) {
7938                         if (r != 'yes') {
7939                             return;
7940                         }
7941                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
7942                     }
7943
7944                 );
7945                 */
7946
7947
7948                 return;
7949             }
7950
7951             Roo.callback(o.failure, o.scope, [this, action]);
7952             // show an error message if no failed handler is set..
7953             if (!this.hasListener('actionfailed')) {
7954                 Roo.log("need to add dialog support");
7955                 /*
7956                 Roo.MessageBox.alert("Error",
7957                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7958                         action.result.errorMsg :
7959                         "Saving Failed, please check your entries or try again"
7960                 );
7961                 */
7962             }
7963
7964             this.fireEvent('actionfailed', this, action);
7965         }
7966
7967     },
7968     /**
7969      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7970      * @param {String} id The value to search for
7971      * @return Field
7972      */
7973     findField : function(id){
7974         var items = this.getItems();
7975         var field = items.get(id);
7976         if(!field){
7977              items.each(function(f){
7978                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7979                     field = f;
7980                     return false;
7981                 }
7982                 return true;
7983             });
7984         }
7985         return field || null;
7986     },
7987      /**
7988      * Mark fields in this form invalid in bulk.
7989      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7990      * @return {BasicForm} this
7991      */
7992     markInvalid : function(errors){
7993         if(errors instanceof Array){
7994             for(var i = 0, len = errors.length; i < len; i++){
7995                 var fieldError = errors[i];
7996                 var f = this.findField(fieldError.id);
7997                 if(f){
7998                     f.markInvalid(fieldError.msg);
7999                 }
8000             }
8001         }else{
8002             var field, id;
8003             for(id in errors){
8004                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8005                     field.markInvalid(errors[id]);
8006                 }
8007             }
8008         }
8009         //Roo.each(this.childForms || [], function (f) {
8010         //    f.markInvalid(errors);
8011         //});
8012
8013         return this;
8014     },
8015
8016     /**
8017      * Set values for fields in this form in bulk.
8018      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8019      * @return {BasicForm} this
8020      */
8021     setValues : function(values){
8022         if(values instanceof Array){ // array of objects
8023             for(var i = 0, len = values.length; i < len; i++){
8024                 var v = values[i];
8025                 var f = this.findField(v.id);
8026                 if(f){
8027                     f.setValue(v.value);
8028                     if(this.trackResetOnLoad){
8029                         f.originalValue = f.getValue();
8030                     }
8031                 }
8032             }
8033         }else{ // object hash
8034             var field, id;
8035             for(id in values){
8036                 if(typeof values[id] != 'function' && (field = this.findField(id))){
8037
8038                     if (field.setFromData &&
8039                         field.valueField &&
8040                         field.displayField &&
8041                         // combos' with local stores can
8042                         // be queried via setValue()
8043                         // to set their value..
8044                         (field.store && !field.store.isLocal)
8045                         ) {
8046                         // it's a combo
8047                         var sd = { };
8048                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8049                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8050                         field.setFromData(sd);
8051
8052                     } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8053                         
8054                         field.setFromData(values);
8055                         
8056                     } else {
8057                         field.setValue(values[id]);
8058                     }
8059
8060
8061                     if(this.trackResetOnLoad){
8062                         field.originalValue = field.getValue();
8063                     }
8064                 }
8065             }
8066         }
8067
8068         //Roo.each(this.childForms || [], function (f) {
8069         //    f.setValues(values);
8070         //});
8071
8072         return this;
8073     },
8074
8075     /**
8076      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8077      * they are returned as an array.
8078      * @param {Boolean} asString
8079      * @return {Object}
8080      */
8081     getValues : function(asString){
8082         //if (this.childForms) {
8083             // copy values from the child forms
8084         //    Roo.each(this.childForms, function (f) {
8085         //        this.setValues(f.getValues());
8086         //    }, this);
8087         //}
8088
8089
8090
8091         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8092         if(asString === true){
8093             return fs;
8094         }
8095         return Roo.urlDecode(fs);
8096     },
8097
8098     /**
8099      * Returns the fields in this form as an object with key/value pairs.
8100      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8101      * @return {Object}
8102      */
8103     getFieldValues : function(with_hidden)
8104     {
8105         var items = this.getItems();
8106         var ret = {};
8107         items.each(function(f){
8108             
8109             if (!f.getName()) {
8110                 return;
8111             }
8112             
8113             var v = f.getValue();
8114             
8115             if (f.inputType =='radio') {
8116                 if (typeof(ret[f.getName()]) == 'undefined') {
8117                     ret[f.getName()] = ''; // empty..
8118                 }
8119
8120                 if (!f.el.dom.checked) {
8121                     return;
8122
8123                 }
8124                 v = f.el.dom.value;
8125
8126             }
8127             
8128             if(f.xtype == 'MoneyField'){
8129                 ret[f.currencyName] = f.getCurrency();
8130             }
8131
8132             // not sure if this supported any more..
8133             if ((typeof(v) == 'object') && f.getRawValue) {
8134                 v = f.getRawValue() ; // dates..
8135             }
8136             // combo boxes where name != hiddenName...
8137             if (f.name !== false && f.name != '' && f.name != f.getName()) {
8138                 ret[f.name] = f.getRawValue();
8139             }
8140             ret[f.getName()] = v;
8141         });
8142
8143         return ret;
8144     },
8145
8146     /**
8147      * Clears all invalid messages in this form.
8148      * @return {BasicForm} this
8149      */
8150     clearInvalid : function(){
8151         var items = this.getItems();
8152
8153         items.each(function(f){
8154            f.clearInvalid();
8155         });
8156
8157         return this;
8158     },
8159
8160     /**
8161      * Resets this form.
8162      * @return {BasicForm} this
8163      */
8164     reset : function(){
8165         var items = this.getItems();
8166         items.each(function(f){
8167             f.reset();
8168         });
8169
8170         Roo.each(this.childForms || [], function (f) {
8171             f.reset();
8172         });
8173
8174
8175         return this;
8176     },
8177     
8178     getItems : function()
8179     {
8180         var r=new Roo.util.MixedCollection(false, function(o){
8181             return o.id || (o.id = Roo.id());
8182         });
8183         var iter = function(el) {
8184             if (el.inputEl) {
8185                 r.add(el);
8186             }
8187             if (!el.items) {
8188                 return;
8189             }
8190             Roo.each(el.items,function(e) {
8191                 iter(e);
8192             });
8193         };
8194
8195         iter(this);
8196         return r;
8197     },
8198     
8199     hideFields : function(items)
8200     {
8201         Roo.each(items, function(i){
8202             
8203             var f = this.findField(i);
8204             
8205             if(!f){
8206                 return;
8207             }
8208             
8209             if(f.xtype == 'DateField'){
8210                 f.setVisible(false);
8211                 return;
8212             }
8213             
8214             f.hide();
8215             
8216         }, this);
8217     },
8218     
8219     showFields : function(items)
8220     {
8221         Roo.each(items, function(i){
8222             
8223             var f = this.findField(i);
8224             
8225             if(!f){
8226                 return;
8227             }
8228             
8229             if(f.xtype == 'DateField'){
8230                 f.setVisible(true);
8231                 return;
8232             }
8233             
8234             f.show();
8235             
8236         }, this);
8237     }
8238
8239 });
8240
8241 Roo.apply(Roo.bootstrap.Form, {
8242     
8243     popover : {
8244         
8245         padding : 5,
8246         
8247         isApplied : false,
8248         
8249         isMasked : false,
8250         
8251         form : false,
8252         
8253         target : false,
8254         
8255         toolTip : false,
8256         
8257         intervalID : false,
8258         
8259         maskEl : false,
8260         
8261         apply : function()
8262         {
8263             if(this.isApplied){
8264                 return;
8265             }
8266             
8267             this.maskEl = {
8268                 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8269                 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8270                 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8271                 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8272             };
8273             
8274             this.maskEl.top.enableDisplayMode("block");
8275             this.maskEl.left.enableDisplayMode("block");
8276             this.maskEl.bottom.enableDisplayMode("block");
8277             this.maskEl.right.enableDisplayMode("block");
8278             
8279             this.toolTip = new Roo.bootstrap.Tooltip({
8280                 cls : 'roo-form-error-popover',
8281                 alignment : {
8282                     'left' : ['r-l', [-2,0], 'right'],
8283                     'right' : ['l-r', [2,0], 'left'],
8284                     'bottom' : ['tl-bl', [0,2], 'top'],
8285                     'top' : [ 'bl-tl', [0,-2], 'bottom']
8286                 }
8287             });
8288             
8289             this.toolTip.render(Roo.get(document.body));
8290
8291             this.toolTip.el.enableDisplayMode("block");
8292             
8293             Roo.get(document.body).on('click', function(){
8294                 this.unmask();
8295             }, this);
8296             
8297             Roo.get(document.body).on('touchstart', function(){
8298                 this.unmask();
8299             }, this);
8300             
8301             this.isApplied = true
8302         },
8303         
8304         mask : function(form, target)
8305         {
8306             this.form = form;
8307             
8308             this.target = target;
8309             
8310             if(!this.form.errorMask || !target.el){
8311                 return;
8312             }
8313             
8314             var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8315             
8316             Roo.log(scrollable);
8317             
8318             var ot = this.target.el.calcOffsetsTo(scrollable);
8319             
8320             var scrollTo = ot[1] - this.form.maskOffset;
8321             
8322             scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8323             
8324             scrollable.scrollTo('top', scrollTo);
8325             
8326             var box = this.target.el.getBox();
8327             Roo.log(box);
8328             var zIndex = Roo.bootstrap.Modal.zIndex++;
8329
8330             
8331             this.maskEl.top.setStyle('position', 'absolute');
8332             this.maskEl.top.setStyle('z-index', zIndex);
8333             this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8334             this.maskEl.top.setLeft(0);
8335             this.maskEl.top.setTop(0);
8336             this.maskEl.top.show();
8337             
8338             this.maskEl.left.setStyle('position', 'absolute');
8339             this.maskEl.left.setStyle('z-index', zIndex);
8340             this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8341             this.maskEl.left.setLeft(0);
8342             this.maskEl.left.setTop(box.y - this.padding);
8343             this.maskEl.left.show();
8344
8345             this.maskEl.bottom.setStyle('position', 'absolute');
8346             this.maskEl.bottom.setStyle('z-index', zIndex);
8347             this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8348             this.maskEl.bottom.setLeft(0);
8349             this.maskEl.bottom.setTop(box.bottom + this.padding);
8350             this.maskEl.bottom.show();
8351
8352             this.maskEl.right.setStyle('position', 'absolute');
8353             this.maskEl.right.setStyle('z-index', zIndex);
8354             this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8355             this.maskEl.right.setLeft(box.right + this.padding);
8356             this.maskEl.right.setTop(box.y - this.padding);
8357             this.maskEl.right.show();
8358
8359             this.toolTip.bindEl = this.target.el;
8360
8361             this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8362
8363             var tip = this.target.blankText;
8364
8365             if(this.target.getValue() !== '' ) {
8366                 
8367                 if (this.target.invalidText.length) {
8368                     tip = this.target.invalidText;
8369                 } else if (this.target.regexText.length){
8370                     tip = this.target.regexText;
8371                 }
8372             }
8373
8374             this.toolTip.show(tip);
8375
8376             this.intervalID = window.setInterval(function() {
8377                 Roo.bootstrap.Form.popover.unmask();
8378             }, 10000);
8379
8380             window.onwheel = function(){ return false;};
8381             
8382             (function(){ this.isMasked = true; }).defer(500, this);
8383             
8384         },
8385         
8386         unmask : function()
8387         {
8388             if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8389                 return;
8390             }
8391             
8392             this.maskEl.top.setStyle('position', 'absolute');
8393             this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8394             this.maskEl.top.hide();
8395
8396             this.maskEl.left.setStyle('position', 'absolute');
8397             this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8398             this.maskEl.left.hide();
8399
8400             this.maskEl.bottom.setStyle('position', 'absolute');
8401             this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8402             this.maskEl.bottom.hide();
8403
8404             this.maskEl.right.setStyle('position', 'absolute');
8405             this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8406             this.maskEl.right.hide();
8407             
8408             this.toolTip.hide();
8409             
8410             this.toolTip.el.hide();
8411             
8412             window.onwheel = function(){ return true;};
8413             
8414             if(this.intervalID){
8415                 window.clearInterval(this.intervalID);
8416                 this.intervalID = false;
8417             }
8418             
8419             this.isMasked = false;
8420             
8421         }
8422         
8423     }
8424     
8425 });
8426
8427 /*
8428  * Based on:
8429  * Ext JS Library 1.1.1
8430  * Copyright(c) 2006-2007, Ext JS, LLC.
8431  *
8432  * Originally Released Under LGPL - original licence link has changed is not relivant.
8433  *
8434  * Fork - LGPL
8435  * <script type="text/javascript">
8436  */
8437 /**
8438  * @class Roo.form.VTypes
8439  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8440  * @singleton
8441  */
8442 Roo.form.VTypes = function(){
8443     // closure these in so they are only created once.
8444     var alpha = /^[a-zA-Z_]+$/;
8445     var alphanum = /^[a-zA-Z0-9_]+$/;
8446     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8447     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8448
8449     // All these messages and functions are configurable
8450     return {
8451         /**
8452          * The function used to validate email addresses
8453          * @param {String} value The email address
8454          */
8455         'email' : function(v){
8456             return email.test(v);
8457         },
8458         /**
8459          * The error text to display when the email validation function returns false
8460          * @type String
8461          */
8462         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8463         /**
8464          * The keystroke filter mask to be applied on email input
8465          * @type RegExp
8466          */
8467         'emailMask' : /[a-z0-9_\.\-@]/i,
8468
8469         /**
8470          * The function used to validate URLs
8471          * @param {String} value The URL
8472          */
8473         'url' : function(v){
8474             return url.test(v);
8475         },
8476         /**
8477          * The error text to display when the url validation function returns false
8478          * @type String
8479          */
8480         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8481         
8482         /**
8483          * The function used to validate alpha values
8484          * @param {String} value The value
8485          */
8486         'alpha' : function(v){
8487             return alpha.test(v);
8488         },
8489         /**
8490          * The error text to display when the alpha validation function returns false
8491          * @type String
8492          */
8493         'alphaText' : 'This field should only contain letters and _',
8494         /**
8495          * The keystroke filter mask to be applied on alpha input
8496          * @type RegExp
8497          */
8498         'alphaMask' : /[a-z_]/i,
8499
8500         /**
8501          * The function used to validate alphanumeric values
8502          * @param {String} value The value
8503          */
8504         'alphanum' : function(v){
8505             return alphanum.test(v);
8506         },
8507         /**
8508          * The error text to display when the alphanumeric validation function returns false
8509          * @type String
8510          */
8511         'alphanumText' : 'This field should only contain letters, numbers and _',
8512         /**
8513          * The keystroke filter mask to be applied on alphanumeric input
8514          * @type RegExp
8515          */
8516         'alphanumMask' : /[a-z0-9_]/i
8517     };
8518 }();/*
8519  * - LGPL
8520  *
8521  * Input
8522  * 
8523  */
8524
8525 /**
8526  * @class Roo.bootstrap.Input
8527  * @extends Roo.bootstrap.Component
8528  * Bootstrap Input class
8529  * @cfg {Boolean} disabled is it disabled
8530  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8531  * @cfg {String} name name of the input
8532  * @cfg {string} fieldLabel - the label associated
8533  * @cfg {string} placeholder - placeholder to put in text.
8534  * @cfg {string}  before - input group add on before
8535  * @cfg {string} after - input group add on after
8536  * @cfg {string} size - (lg|sm) or leave empty..
8537  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8538  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8539  * @cfg {Number} md colspan out of 12 for computer-sized screens
8540  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8541  * @cfg {string} value default value of the input
8542  * @cfg {Number} labelWidth set the width of label 
8543  * @cfg {Number} labellg set the width of label (1-12)
8544  * @cfg {Number} labelmd set the width of label (1-12)
8545  * @cfg {Number} labelsm set the width of label (1-12)
8546  * @cfg {Number} labelxs set the width of label (1-12)
8547  * @cfg {String} labelAlign (top|left)
8548  * @cfg {Boolean} readOnly Specifies that the field should be read-only
8549  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8550  * @cfg {String} indicatorpos (left|right) default left
8551  * @cfg {String} capture (user|camera) use for file input only. (default empty)
8552  * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8553
8554  * @cfg {String} align (left|center|right) Default left
8555  * @cfg {Boolean} forceFeedback (true|false) Default false
8556  * 
8557  * @constructor
8558  * Create a new Input
8559  * @param {Object} config The config object
8560  */
8561
8562 Roo.bootstrap.Input = function(config){
8563     
8564     Roo.bootstrap.Input.superclass.constructor.call(this, config);
8565     
8566     this.addEvents({
8567         /**
8568          * @event focus
8569          * Fires when this field receives input focus.
8570          * @param {Roo.form.Field} this
8571          */
8572         focus : true,
8573         /**
8574          * @event blur
8575          * Fires when this field loses input focus.
8576          * @param {Roo.form.Field} this
8577          */
8578         blur : true,
8579         /**
8580          * @event specialkey
8581          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
8582          * {@link Roo.EventObject#getKey} to determine which key was pressed.
8583          * @param {Roo.form.Field} this
8584          * @param {Roo.EventObject} e The event object
8585          */
8586         specialkey : true,
8587         /**
8588          * @event change
8589          * Fires just before the field blurs if the field value has changed.
8590          * @param {Roo.form.Field} this
8591          * @param {Mixed} newValue The new value
8592          * @param {Mixed} oldValue The original value
8593          */
8594         change : true,
8595         /**
8596          * @event invalid
8597          * Fires after the field has been marked as invalid.
8598          * @param {Roo.form.Field} this
8599          * @param {String} msg The validation message
8600          */
8601         invalid : true,
8602         /**
8603          * @event valid
8604          * Fires after the field has been validated with no errors.
8605          * @param {Roo.form.Field} this
8606          */
8607         valid : true,
8608          /**
8609          * @event keyup
8610          * Fires after the key up
8611          * @param {Roo.form.Field} this
8612          * @param {Roo.EventObject}  e The event Object
8613          */
8614         keyup : true
8615     });
8616 };
8617
8618 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
8619      /**
8620      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8621       automatic validation (defaults to "keyup").
8622      */
8623     validationEvent : "keyup",
8624      /**
8625      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8626      */
8627     validateOnBlur : true,
8628     /**
8629      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8630      */
8631     validationDelay : 250,
8632      /**
8633      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8634      */
8635     focusClass : "x-form-focus",  // not needed???
8636     
8637        
8638     /**
8639      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8640      */
8641     invalidClass : "has-warning",
8642     
8643     /**
8644      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8645      */
8646     validClass : "has-success",
8647     
8648     /**
8649      * @cfg {Boolean} hasFeedback (true|false) default true
8650      */
8651     hasFeedback : true,
8652     
8653     /**
8654      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8655      */
8656     invalidFeedbackClass : "glyphicon-warning-sign",
8657     
8658     /**
8659      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8660      */
8661     validFeedbackClass : "glyphicon-ok",
8662     
8663     /**
8664      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8665      */
8666     selectOnFocus : false,
8667     
8668      /**
8669      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8670      */
8671     maskRe : null,
8672        /**
8673      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8674      */
8675     vtype : null,
8676     
8677       /**
8678      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8679      */
8680     disableKeyFilter : false,
8681     
8682        /**
8683      * @cfg {Boolean} disabled True to disable the field (defaults to false).
8684      */
8685     disabled : false,
8686      /**
8687      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8688      */
8689     allowBlank : true,
8690     /**
8691      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8692      */
8693     blankText : "Please complete this mandatory field",
8694     
8695      /**
8696      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8697      */
8698     minLength : 0,
8699     /**
8700      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8701      */
8702     maxLength : Number.MAX_VALUE,
8703     /**
8704      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8705      */
8706     minLengthText : "The minimum length for this field is {0}",
8707     /**
8708      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8709      */
8710     maxLengthText : "The maximum length for this field is {0}",
8711   
8712     
8713     /**
8714      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8715      * If available, this function will be called only after the basic validators all return true, and will be passed the
8716      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8717      */
8718     validator : null,
8719     /**
8720      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8721      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8722      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
8723      */
8724     regex : null,
8725     /**
8726      * @cfg {String} regexText -- Depricated - use Invalid Text
8727      */
8728     regexText : "",
8729     
8730     /**
8731      * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8732      */
8733     invalidText : "",
8734     
8735     
8736     
8737     autocomplete: false,
8738     
8739     
8740     fieldLabel : '',
8741     inputType : 'text',
8742     
8743     name : false,
8744     placeholder: false,
8745     before : false,
8746     after : false,
8747     size : false,
8748     hasFocus : false,
8749     preventMark: false,
8750     isFormField : true,
8751     value : '',
8752     labelWidth : 2,
8753     labelAlign : false,
8754     readOnly : false,
8755     align : false,
8756     formatedValue : false,
8757     forceFeedback : false,
8758     
8759     indicatorpos : 'left',
8760     
8761     labellg : 0,
8762     labelmd : 0,
8763     labelsm : 0,
8764     labelxs : 0,
8765     
8766     capture : '',
8767     accept : '',
8768     
8769     parentLabelAlign : function()
8770     {
8771         var parent = this;
8772         while (parent.parent()) {
8773             parent = parent.parent();
8774             if (typeof(parent.labelAlign) !='undefined') {
8775                 return parent.labelAlign;
8776             }
8777         }
8778         return 'left';
8779         
8780     },
8781     
8782     getAutoCreate : function()
8783     {
8784         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8785         
8786         var id = Roo.id();
8787         
8788         var cfg = {};
8789         
8790         if(this.inputType != 'hidden'){
8791             cfg.cls = 'form-group' //input-group
8792         }
8793         
8794         var input =  {
8795             tag: 'input',
8796             id : id,
8797             type : this.inputType,
8798             value : this.value,
8799             cls : 'form-control',
8800             placeholder : this.placeholder || '',
8801             autocomplete : this.autocomplete || 'new-password'
8802         };
8803         
8804         if(this.capture.length){
8805             input.capture = this.capture;
8806         }
8807         
8808         if(this.accept.length){
8809             input.accept = this.accept + "/*";
8810         }
8811         
8812         if(this.align){
8813             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8814         }
8815         
8816         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8817             input.maxLength = this.maxLength;
8818         }
8819         
8820         if (this.disabled) {
8821             input.disabled=true;
8822         }
8823         
8824         if (this.readOnly) {
8825             input.readonly=true;
8826         }
8827         
8828         if (this.name) {
8829             input.name = this.name;
8830         }
8831         
8832         if (this.size) {
8833             input.cls += ' input-' + this.size;
8834         }
8835         
8836         var settings=this;
8837         ['xs','sm','md','lg'].map(function(size){
8838             if (settings[size]) {
8839                 cfg.cls += ' col-' + size + '-' + settings[size];
8840             }
8841         });
8842         
8843         var inputblock = input;
8844         
8845         var feedback = {
8846             tag: 'span',
8847             cls: 'glyphicon form-control-feedback'
8848         };
8849             
8850         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8851             
8852             inputblock = {
8853                 cls : 'has-feedback',
8854                 cn :  [
8855                     input,
8856                     feedback
8857                 ] 
8858             };  
8859         }
8860         
8861         if (this.before || this.after) {
8862             
8863             inputblock = {
8864                 cls : 'input-group',
8865                 cn :  [] 
8866             };
8867             
8868             if (this.before && typeof(this.before) == 'string') {
8869                 
8870                 inputblock.cn.push({
8871                     tag :'span',
8872                     cls : 'roo-input-before input-group-addon',
8873                     html : this.before
8874                 });
8875             }
8876             if (this.before && typeof(this.before) == 'object') {
8877                 this.before = Roo.factory(this.before);
8878                 
8879                 inputblock.cn.push({
8880                     tag :'span',
8881                     cls : 'roo-input-before input-group-' +
8882                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8883                 });
8884             }
8885             
8886             inputblock.cn.push(input);
8887             
8888             if (this.after && typeof(this.after) == 'string') {
8889                 inputblock.cn.push({
8890                     tag :'span',
8891                     cls : 'roo-input-after input-group-addon',
8892                     html : this.after
8893                 });
8894             }
8895             if (this.after && typeof(this.after) == 'object') {
8896                 this.after = Roo.factory(this.after);
8897                 
8898                 inputblock.cn.push({
8899                     tag :'span',
8900                     cls : 'roo-input-after input-group-' +
8901                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8902                 });
8903             }
8904             
8905             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8906                 inputblock.cls += ' has-feedback';
8907                 inputblock.cn.push(feedback);
8908             }
8909         };
8910         
8911         if (align ==='left' && this.fieldLabel.length) {
8912             
8913             cfg.cls += ' roo-form-group-label-left';
8914             
8915             cfg.cn = [
8916                 {
8917                     tag : 'i',
8918                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8919                     tooltip : 'This field is required'
8920                 },
8921                 {
8922                     tag: 'label',
8923                     'for' :  id,
8924                     cls : 'control-label',
8925                     html : this.fieldLabel
8926
8927                 },
8928                 {
8929                     cls : "", 
8930                     cn: [
8931                         inputblock
8932                     ]
8933                 }
8934             ];
8935             
8936             var labelCfg = cfg.cn[1];
8937             var contentCfg = cfg.cn[2];
8938             
8939             if(this.indicatorpos == 'right'){
8940                 cfg.cn = [
8941                     {
8942                         tag: 'label',
8943                         'for' :  id,
8944                         cls : 'control-label',
8945                         cn : [
8946                             {
8947                                 tag : 'span',
8948                                 html : this.fieldLabel
8949                             },
8950                             {
8951                                 tag : 'i',
8952                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8953                                 tooltip : 'This field is required'
8954                             }
8955                         ]
8956                     },
8957                     {
8958                         cls : "",
8959                         cn: [
8960                             inputblock
8961                         ]
8962                     }
8963
8964                 ];
8965                 
8966                 labelCfg = cfg.cn[0];
8967                 contentCfg = cfg.cn[1];
8968             
8969             }
8970             
8971             if(this.labelWidth > 12){
8972                 labelCfg.style = "width: " + this.labelWidth + 'px';
8973             }
8974             
8975             if(this.labelWidth < 13 && this.labelmd == 0){
8976                 this.labelmd = this.labelWidth;
8977             }
8978             
8979             if(this.labellg > 0){
8980                 labelCfg.cls += ' col-lg-' + this.labellg;
8981                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8982             }
8983             
8984             if(this.labelmd > 0){
8985                 labelCfg.cls += ' col-md-' + this.labelmd;
8986                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8987             }
8988             
8989             if(this.labelsm > 0){
8990                 labelCfg.cls += ' col-sm-' + this.labelsm;
8991                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8992             }
8993             
8994             if(this.labelxs > 0){
8995                 labelCfg.cls += ' col-xs-' + this.labelxs;
8996                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8997             }
8998             
8999             
9000         } else if ( this.fieldLabel.length) {
9001                 
9002             cfg.cn = [
9003                 {
9004                     tag : 'i',
9005                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9006                     tooltip : 'This field is required'
9007                 },
9008                 {
9009                     tag: 'label',
9010                    //cls : 'input-group-addon',
9011                     html : this.fieldLabel
9012
9013                 },
9014
9015                inputblock
9016
9017            ];
9018            
9019            if(this.indicatorpos == 'right'){
9020                 
9021                 cfg.cn = [
9022                     {
9023                         tag: 'label',
9024                        //cls : 'input-group-addon',
9025                         html : this.fieldLabel
9026
9027                     },
9028                     {
9029                         tag : 'i',
9030                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9031                         tooltip : 'This field is required'
9032                     },
9033
9034                    inputblock
9035
9036                ];
9037
9038             }
9039
9040         } else {
9041             
9042             cfg.cn = [
9043
9044                     inputblock
9045
9046             ];
9047                 
9048                 
9049         };
9050         
9051         if (this.parentType === 'Navbar' &&  this.parent().bar) {
9052            cfg.cls += ' navbar-form';
9053         }
9054         
9055         if (this.parentType === 'NavGroup') {
9056            cfg.cls += ' navbar-form';
9057            cfg.tag = 'li';
9058         }
9059         
9060         return cfg;
9061         
9062     },
9063     /**
9064      * return the real input element.
9065      */
9066     inputEl: function ()
9067     {
9068         return this.el.select('input.form-control',true).first();
9069     },
9070     
9071     tooltipEl : function()
9072     {
9073         return this.inputEl();
9074     },
9075     
9076     indicatorEl : function()
9077     {
9078         var indicator = this.el.select('i.roo-required-indicator',true).first();
9079         
9080         if(!indicator){
9081             return false;
9082         }
9083         
9084         return indicator;
9085         
9086     },
9087     
9088     setDisabled : function(v)
9089     {
9090         var i  = this.inputEl().dom;
9091         if (!v) {
9092             i.removeAttribute('disabled');
9093             return;
9094             
9095         }
9096         i.setAttribute('disabled','true');
9097     },
9098     initEvents : function()
9099     {
9100           
9101         this.inputEl().on("keydown" , this.fireKey,  this);
9102         this.inputEl().on("focus", this.onFocus,  this);
9103         this.inputEl().on("blur", this.onBlur,  this);
9104         
9105         this.inputEl().relayEvent('keyup', this);
9106         
9107         this.indicator = this.indicatorEl();
9108         
9109         if(this.indicator){
9110             this.indicator.addClass('invisible');
9111         }
9112  
9113         // reference to original value for reset
9114         this.originalValue = this.getValue();
9115         //Roo.form.TextField.superclass.initEvents.call(this);
9116         if(this.validationEvent == 'keyup'){
9117             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9118             this.inputEl().on('keyup', this.filterValidation, this);
9119         }
9120         else if(this.validationEvent !== false){
9121             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9122         }
9123         
9124         if(this.selectOnFocus){
9125             this.on("focus", this.preFocus, this);
9126             
9127         }
9128         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9129             this.inputEl().on("keypress", this.filterKeys, this);
9130         } else {
9131             this.inputEl().relayEvent('keypress', this);
9132         }
9133        /* if(this.grow){
9134             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
9135             this.el.on("click", this.autoSize,  this);
9136         }
9137         */
9138         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9139             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9140         }
9141         
9142         if (typeof(this.before) == 'object') {
9143             this.before.render(this.el.select('.roo-input-before',true).first());
9144         }
9145         if (typeof(this.after) == 'object') {
9146             this.after.render(this.el.select('.roo-input-after',true).first());
9147         }
9148         
9149         this.inputEl().on('change', this.onChange, this);
9150         
9151     },
9152     filterValidation : function(e){
9153         if(!e.isNavKeyPress()){
9154             this.validationTask.delay(this.validationDelay);
9155         }
9156     },
9157      /**
9158      * Validates the field value
9159      * @return {Boolean} True if the value is valid, else false
9160      */
9161     validate : function(){
9162         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9163         if(this.disabled || this.validateValue(this.getRawValue())){
9164             this.markValid();
9165             return true;
9166         }
9167         
9168         this.markInvalid();
9169         return false;
9170     },
9171     
9172     
9173     /**
9174      * Validates a value according to the field's validation rules and marks the field as invalid
9175      * if the validation fails
9176      * @param {Mixed} value The value to validate
9177      * @return {Boolean} True if the value is valid, else false
9178      */
9179     validateValue : function(value)
9180     {
9181         if(this.getVisibilityEl().hasClass('hidden')){
9182             return true;
9183         }
9184         
9185         if(value.length < 1)  { // if it's blank
9186             if(this.allowBlank){
9187                 return true;
9188             }
9189             return false;
9190         }
9191         
9192         if(value.length < this.minLength){
9193             return false;
9194         }
9195         if(value.length > this.maxLength){
9196             return false;
9197         }
9198         if(this.vtype){
9199             var vt = Roo.form.VTypes;
9200             if(!vt[this.vtype](value, this)){
9201                 return false;
9202             }
9203         }
9204         if(typeof this.validator == "function"){
9205             var msg = this.validator(value);
9206             if(msg !== true){
9207                 return false;
9208             }
9209             if (typeof(msg) == 'string') {
9210                 this.invalidText = msg;
9211             }
9212         }
9213         
9214         if(this.regex && !this.regex.test(value)){
9215             return false;
9216         }
9217         
9218         return true;
9219     },
9220     
9221      // private
9222     fireKey : function(e){
9223         //Roo.log('field ' + e.getKey());
9224         if(e.isNavKeyPress()){
9225             this.fireEvent("specialkey", this, e);
9226         }
9227     },
9228     focus : function (selectText){
9229         if(this.rendered){
9230             this.inputEl().focus();
9231             if(selectText === true){
9232                 this.inputEl().dom.select();
9233             }
9234         }
9235         return this;
9236     } ,
9237     
9238     onFocus : function(){
9239         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9240            // this.el.addClass(this.focusClass);
9241         }
9242         if(!this.hasFocus){
9243             this.hasFocus = true;
9244             this.startValue = this.getValue();
9245             this.fireEvent("focus", this);
9246         }
9247     },
9248     
9249     beforeBlur : Roo.emptyFn,
9250
9251     
9252     // private
9253     onBlur : function(){
9254         this.beforeBlur();
9255         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9256             //this.el.removeClass(this.focusClass);
9257         }
9258         this.hasFocus = false;
9259         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9260             this.validate();
9261         }
9262         var v = this.getValue();
9263         if(String(v) !== String(this.startValue)){
9264             this.fireEvent('change', this, v, this.startValue);
9265         }
9266         this.fireEvent("blur", this);
9267     },
9268     
9269     onChange : function(e)
9270     {
9271         var v = this.getValue();
9272         if(String(v) !== String(this.startValue)){
9273             this.fireEvent('change', this, v, this.startValue);
9274         }
9275         
9276     },
9277     
9278     /**
9279      * Resets the current field value to the originally loaded value and clears any validation messages
9280      */
9281     reset : function(){
9282         this.setValue(this.originalValue);
9283         this.validate();
9284     },
9285      /**
9286      * Returns the name of the field
9287      * @return {Mixed} name The name field
9288      */
9289     getName: function(){
9290         return this.name;
9291     },
9292      /**
9293      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
9294      * @return {Mixed} value The field value
9295      */
9296     getValue : function(){
9297         
9298         var v = this.inputEl().getValue();
9299         
9300         return v;
9301     },
9302     /**
9303      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
9304      * @return {Mixed} value The field value
9305      */
9306     getRawValue : function(){
9307         var v = this.inputEl().getValue();
9308         
9309         return v;
9310     },
9311     
9312     /**
9313      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
9314      * @param {Mixed} value The value to set
9315      */
9316     setRawValue : function(v){
9317         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9318     },
9319     
9320     selectText : function(start, end){
9321         var v = this.getRawValue();
9322         if(v.length > 0){
9323             start = start === undefined ? 0 : start;
9324             end = end === undefined ? v.length : end;
9325             var d = this.inputEl().dom;
9326             if(d.setSelectionRange){
9327                 d.setSelectionRange(start, end);
9328             }else if(d.createTextRange){
9329                 var range = d.createTextRange();
9330                 range.moveStart("character", start);
9331                 range.moveEnd("character", v.length-end);
9332                 range.select();
9333             }
9334         }
9335     },
9336     
9337     /**
9338      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
9339      * @param {Mixed} value The value to set
9340      */
9341     setValue : function(v){
9342         this.value = v;
9343         if(this.rendered){
9344             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9345             this.validate();
9346         }
9347     },
9348     
9349     /*
9350     processValue : function(value){
9351         if(this.stripCharsRe){
9352             var newValue = value.replace(this.stripCharsRe, '');
9353             if(newValue !== value){
9354                 this.setRawValue(newValue);
9355                 return newValue;
9356             }
9357         }
9358         return value;
9359     },
9360   */
9361     preFocus : function(){
9362         
9363         if(this.selectOnFocus){
9364             this.inputEl().dom.select();
9365         }
9366     },
9367     filterKeys : function(e){
9368         var k = e.getKey();
9369         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9370             return;
9371         }
9372         var c = e.getCharCode(), cc = String.fromCharCode(c);
9373         if(Roo.isIE && (e.isSpecialKey() || !cc)){
9374             return;
9375         }
9376         if(!this.maskRe.test(cc)){
9377             e.stopEvent();
9378         }
9379     },
9380      /**
9381      * Clear any invalid styles/messages for this field
9382      */
9383     clearInvalid : function(){
9384         
9385         if(!this.el || this.preventMark){ // not rendered
9386             return;
9387         }
9388         
9389      
9390         this.el.removeClass(this.invalidClass);
9391         
9392         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9393             
9394             var feedback = this.el.select('.form-control-feedback', true).first();
9395             
9396             if(feedback){
9397                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9398             }
9399             
9400         }
9401         
9402         this.fireEvent('valid', this);
9403     },
9404     
9405      /**
9406      * Mark this field as valid
9407      */
9408     markValid : function()
9409     {
9410         if(!this.el  || this.preventMark){ // not rendered...
9411             return;
9412         }
9413         
9414         this.el.removeClass([this.invalidClass, this.validClass]);
9415         
9416         var feedback = this.el.select('.form-control-feedback', true).first();
9417             
9418         if(feedback){
9419             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9420         }
9421         
9422         if(this.indicator){
9423             this.indicator.removeClass('visible');
9424             this.indicator.addClass('invisible');
9425         }
9426         
9427         if(this.disabled){
9428             return;
9429         }
9430         
9431         if(this.allowBlank && !this.getRawValue().length){
9432             return;
9433         }
9434         
9435         this.el.addClass(this.validClass);
9436         
9437         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9438             
9439             var feedback = this.el.select('.form-control-feedback', true).first();
9440             
9441             if(feedback){
9442                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9443                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9444             }
9445             
9446         }
9447         
9448         this.fireEvent('valid', this);
9449     },
9450     
9451      /**
9452      * Mark this field as invalid
9453      * @param {String} msg The validation message
9454      */
9455     markInvalid : function(msg)
9456     {
9457         if(!this.el  || this.preventMark){ // not rendered
9458             return;
9459         }
9460         
9461         this.el.removeClass([this.invalidClass, this.validClass]);
9462         
9463         var feedback = this.el.select('.form-control-feedback', true).first();
9464             
9465         if(feedback){
9466             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9467         }
9468
9469         if(this.disabled){
9470             return;
9471         }
9472         
9473         if(this.allowBlank && !this.getRawValue().length){
9474             return;
9475         }
9476         
9477         if(this.indicator){
9478             this.indicator.removeClass('invisible');
9479             this.indicator.addClass('visible');
9480         }
9481         
9482         this.el.addClass(this.invalidClass);
9483         
9484         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9485             
9486             var feedback = this.el.select('.form-control-feedback', true).first();
9487             
9488             if(feedback){
9489                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9490                 
9491                 if(this.getValue().length || this.forceFeedback){
9492                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9493                 }
9494                 
9495             }
9496             
9497         }
9498         
9499         this.fireEvent('invalid', this, msg);
9500     },
9501     // private
9502     SafariOnKeyDown : function(event)
9503     {
9504         // this is a workaround for a password hang bug on chrome/ webkit.
9505         if (this.inputEl().dom.type != 'password') {
9506             return;
9507         }
9508         
9509         var isSelectAll = false;
9510         
9511         if(this.inputEl().dom.selectionEnd > 0){
9512             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9513         }
9514         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9515             event.preventDefault();
9516             this.setValue('');
9517             return;
9518         }
9519         
9520         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9521             
9522             event.preventDefault();
9523             // this is very hacky as keydown always get's upper case.
9524             //
9525             var cc = String.fromCharCode(event.getCharCode());
9526             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
9527             
9528         }
9529     },
9530     adjustWidth : function(tag, w){
9531         tag = tag.toLowerCase();
9532         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9533             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9534                 if(tag == 'input'){
9535                     return w + 2;
9536                 }
9537                 if(tag == 'textarea'){
9538                     return w-2;
9539                 }
9540             }else if(Roo.isOpera){
9541                 if(tag == 'input'){
9542                     return w + 2;
9543                 }
9544                 if(tag == 'textarea'){
9545                     return w-2;
9546                 }
9547             }
9548         }
9549         return w;
9550     },
9551     
9552     setFieldLabel : function(v)
9553     {
9554         if(!this.rendered){
9555             return;
9556         }
9557         
9558         if(this.indicator){
9559             var ar = this.el.select('label > span',true);
9560             
9561             if (ar.elements.length) {
9562                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9563                 this.fieldLabel = v;
9564                 return;
9565             }
9566             
9567             var br = this.el.select('label',true);
9568             
9569             if(br.elements.length) {
9570                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9571                 this.fieldLabel = v;
9572                 return;
9573             }
9574             
9575             Roo.log('Cannot Found any of label > span || label in input');
9576             return;
9577         }
9578         
9579         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9580         this.fieldLabel = v;
9581         
9582         
9583     }
9584 });
9585
9586  
9587 /*
9588  * - LGPL
9589  *
9590  * Input
9591  * 
9592  */
9593
9594 /**
9595  * @class Roo.bootstrap.TextArea
9596  * @extends Roo.bootstrap.Input
9597  * Bootstrap TextArea class
9598  * @cfg {Number} cols Specifies the visible width of a text area
9599  * @cfg {Number} rows Specifies the visible number of lines in a text area
9600  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9601  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9602  * @cfg {string} html text
9603  * 
9604  * @constructor
9605  * Create a new TextArea
9606  * @param {Object} config The config object
9607  */
9608
9609 Roo.bootstrap.TextArea = function(config){
9610     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9611    
9612 };
9613
9614 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
9615      
9616     cols : false,
9617     rows : 5,
9618     readOnly : false,
9619     warp : 'soft',
9620     resize : false,
9621     value: false,
9622     html: false,
9623     
9624     getAutoCreate : function(){
9625         
9626         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9627         
9628         var id = Roo.id();
9629         
9630         var cfg = {};
9631         
9632         if(this.inputType != 'hidden'){
9633             cfg.cls = 'form-group' //input-group
9634         }
9635         
9636         var input =  {
9637             tag: 'textarea',
9638             id : id,
9639             warp : this.warp,
9640             rows : this.rows,
9641             value : this.value || '',
9642             html: this.html || '',
9643             cls : 'form-control',
9644             placeholder : this.placeholder || '' 
9645             
9646         };
9647         
9648         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9649             input.maxLength = this.maxLength;
9650         }
9651         
9652         if(this.resize){
9653             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9654         }
9655         
9656         if(this.cols){
9657             input.cols = this.cols;
9658         }
9659         
9660         if (this.readOnly) {
9661             input.readonly = true;
9662         }
9663         
9664         if (this.name) {
9665             input.name = this.name;
9666         }
9667         
9668         if (this.size) {
9669             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9670         }
9671         
9672         var settings=this;
9673         ['xs','sm','md','lg'].map(function(size){
9674             if (settings[size]) {
9675                 cfg.cls += ' col-' + size + '-' + settings[size];
9676             }
9677         });
9678         
9679         var inputblock = input;
9680         
9681         if(this.hasFeedback && !this.allowBlank){
9682             
9683             var feedback = {
9684                 tag: 'span',
9685                 cls: 'glyphicon form-control-feedback'
9686             };
9687
9688             inputblock = {
9689                 cls : 'has-feedback',
9690                 cn :  [
9691                     input,
9692                     feedback
9693                 ] 
9694             };  
9695         }
9696         
9697         
9698         if (this.before || this.after) {
9699             
9700             inputblock = {
9701                 cls : 'input-group',
9702                 cn :  [] 
9703             };
9704             if (this.before) {
9705                 inputblock.cn.push({
9706                     tag :'span',
9707                     cls : 'input-group-addon',
9708                     html : this.before
9709                 });
9710             }
9711             
9712             inputblock.cn.push(input);
9713             
9714             if(this.hasFeedback && !this.allowBlank){
9715                 inputblock.cls += ' has-feedback';
9716                 inputblock.cn.push(feedback);
9717             }
9718             
9719             if (this.after) {
9720                 inputblock.cn.push({
9721                     tag :'span',
9722                     cls : 'input-group-addon',
9723                     html : this.after
9724                 });
9725             }
9726             
9727         }
9728         
9729         if (align ==='left' && this.fieldLabel.length) {
9730             cfg.cn = [
9731                 {
9732                     tag: 'label',
9733                     'for' :  id,
9734                     cls : 'control-label',
9735                     html : this.fieldLabel
9736                 },
9737                 {
9738                     cls : "",
9739                     cn: [
9740                         inputblock
9741                     ]
9742                 }
9743
9744             ];
9745             
9746             if(this.labelWidth > 12){
9747                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9748             }
9749
9750             if(this.labelWidth < 13 && this.labelmd == 0){
9751                 this.labelmd = this.labelWidth;
9752             }
9753
9754             if(this.labellg > 0){
9755                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9756                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9757             }
9758
9759             if(this.labelmd > 0){
9760                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9761                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9762             }
9763
9764             if(this.labelsm > 0){
9765                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9766                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9767             }
9768
9769             if(this.labelxs > 0){
9770                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9771                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9772             }
9773             
9774         } else if ( this.fieldLabel.length) {
9775             cfg.cn = [
9776
9777                {
9778                    tag: 'label',
9779                    //cls : 'input-group-addon',
9780                    html : this.fieldLabel
9781
9782                },
9783
9784                inputblock
9785
9786            ];
9787
9788         } else {
9789
9790             cfg.cn = [
9791
9792                 inputblock
9793
9794             ];
9795                 
9796         }
9797         
9798         if (this.disabled) {
9799             input.disabled=true;
9800         }
9801         
9802         return cfg;
9803         
9804     },
9805     /**
9806      * return the real textarea element.
9807      */
9808     inputEl: function ()
9809     {
9810         return this.el.select('textarea.form-control',true).first();
9811     },
9812     
9813     /**
9814      * Clear any invalid styles/messages for this field
9815      */
9816     clearInvalid : function()
9817     {
9818         
9819         if(!this.el || this.preventMark){ // not rendered
9820             return;
9821         }
9822         
9823         var label = this.el.select('label', true).first();
9824         var icon = this.el.select('i.fa-star', true).first();
9825         
9826         if(label && icon){
9827             icon.remove();
9828         }
9829         
9830         this.el.removeClass(this.invalidClass);
9831         
9832         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9833             
9834             var feedback = this.el.select('.form-control-feedback', true).first();
9835             
9836             if(feedback){
9837                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9838             }
9839             
9840         }
9841         
9842         this.fireEvent('valid', this);
9843     },
9844     
9845      /**
9846      * Mark this field as valid
9847      */
9848     markValid : function()
9849     {
9850         if(!this.el  || this.preventMark){ // not rendered
9851             return;
9852         }
9853         
9854         this.el.removeClass([this.invalidClass, this.validClass]);
9855         
9856         var feedback = this.el.select('.form-control-feedback', true).first();
9857             
9858         if(feedback){
9859             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9860         }
9861
9862         if(this.disabled || this.allowBlank){
9863             return;
9864         }
9865         
9866         var label = this.el.select('label', true).first();
9867         var icon = this.el.select('i.fa-star', true).first();
9868         
9869         if(label && icon){
9870             icon.remove();
9871         }
9872         
9873         this.el.addClass(this.validClass);
9874         
9875         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9876             
9877             var feedback = this.el.select('.form-control-feedback', true).first();
9878             
9879             if(feedback){
9880                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9881                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9882             }
9883             
9884         }
9885         
9886         this.fireEvent('valid', this);
9887     },
9888     
9889      /**
9890      * Mark this field as invalid
9891      * @param {String} msg The validation message
9892      */
9893     markInvalid : function(msg)
9894     {
9895         if(!this.el  || this.preventMark){ // not rendered
9896             return;
9897         }
9898         
9899         this.el.removeClass([this.invalidClass, this.validClass]);
9900         
9901         var feedback = this.el.select('.form-control-feedback', true).first();
9902             
9903         if(feedback){
9904             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9905         }
9906
9907         if(this.disabled || this.allowBlank){
9908             return;
9909         }
9910         
9911         var label = this.el.select('label', true).first();
9912         var icon = this.el.select('i.fa-star', true).first();
9913         
9914         if(!this.getValue().length && label && !icon){
9915             this.el.createChild({
9916                 tag : 'i',
9917                 cls : 'text-danger fa fa-lg fa-star',
9918                 tooltip : 'This field is required',
9919                 style : 'margin-right:5px;'
9920             }, label, true);
9921         }
9922
9923         this.el.addClass(this.invalidClass);
9924         
9925         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9926             
9927             var feedback = this.el.select('.form-control-feedback', true).first();
9928             
9929             if(feedback){
9930                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9931                 
9932                 if(this.getValue().length || this.forceFeedback){
9933                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9934                 }
9935                 
9936             }
9937             
9938         }
9939         
9940         this.fireEvent('invalid', this, msg);
9941     }
9942 });
9943
9944  
9945 /*
9946  * - LGPL
9947  *
9948  * trigger field - base class for combo..
9949  * 
9950  */
9951  
9952 /**
9953  * @class Roo.bootstrap.TriggerField
9954  * @extends Roo.bootstrap.Input
9955  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9956  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9957  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9958  * for which you can provide a custom implementation.  For example:
9959  * <pre><code>
9960 var trigger = new Roo.bootstrap.TriggerField();
9961 trigger.onTriggerClick = myTriggerFn;
9962 trigger.applyTo('my-field');
9963 </code></pre>
9964  *
9965  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9966  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9967  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
9968  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9969  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9970
9971  * @constructor
9972  * Create a new TriggerField.
9973  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9974  * to the base TextField)
9975  */
9976 Roo.bootstrap.TriggerField = function(config){
9977     this.mimicing = false;
9978     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9979 };
9980
9981 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
9982     /**
9983      * @cfg {String} triggerClass A CSS class to apply to the trigger
9984      */
9985      /**
9986      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9987      */
9988     hideTrigger:false,
9989
9990     /**
9991      * @cfg {Boolean} removable (true|false) special filter default false
9992      */
9993     removable : false,
9994     
9995     /** @cfg {Boolean} grow @hide */
9996     /** @cfg {Number} growMin @hide */
9997     /** @cfg {Number} growMax @hide */
9998
9999     /**
10000      * @hide 
10001      * @method
10002      */
10003     autoSize: Roo.emptyFn,
10004     // private
10005     monitorTab : true,
10006     // private
10007     deferHeight : true,
10008
10009     
10010     actionMode : 'wrap',
10011     
10012     caret : false,
10013     
10014     
10015     getAutoCreate : function(){
10016        
10017         var align = this.labelAlign || this.parentLabelAlign();
10018         
10019         var id = Roo.id();
10020         
10021         var cfg = {
10022             cls: 'form-group' //input-group
10023         };
10024         
10025         
10026         var input =  {
10027             tag: 'input',
10028             id : id,
10029             type : this.inputType,
10030             cls : 'form-control',
10031             autocomplete: 'new-password',
10032             placeholder : this.placeholder || '' 
10033             
10034         };
10035         if (this.name) {
10036             input.name = this.name;
10037         }
10038         if (this.size) {
10039             input.cls += ' input-' + this.size;
10040         }
10041         
10042         if (this.disabled) {
10043             input.disabled=true;
10044         }
10045         
10046         var inputblock = input;
10047         
10048         if(this.hasFeedback && !this.allowBlank){
10049             
10050             var feedback = {
10051                 tag: 'span',
10052                 cls: 'glyphicon form-control-feedback'
10053             };
10054             
10055             if(this.removable && !this.editable && !this.tickable){
10056                 inputblock = {
10057                     cls : 'has-feedback',
10058                     cn :  [
10059                         inputblock,
10060                         {
10061                             tag: 'button',
10062                             html : 'x',
10063                             cls : 'roo-combo-removable-btn close'
10064                         },
10065                         feedback
10066                     ] 
10067                 };
10068             } else {
10069                 inputblock = {
10070                     cls : 'has-feedback',
10071                     cn :  [
10072                         inputblock,
10073                         feedback
10074                     ] 
10075                 };
10076             }
10077
10078         } else {
10079             if(this.removable && !this.editable && !this.tickable){
10080                 inputblock = {
10081                     cls : 'roo-removable',
10082                     cn :  [
10083                         inputblock,
10084                         {
10085                             tag: 'button',
10086                             html : 'x',
10087                             cls : 'roo-combo-removable-btn close'
10088                         }
10089                     ] 
10090                 };
10091             }
10092         }
10093         
10094         if (this.before || this.after) {
10095             
10096             inputblock = {
10097                 cls : 'input-group',
10098                 cn :  [] 
10099             };
10100             if (this.before) {
10101                 inputblock.cn.push({
10102                     tag :'span',
10103                     cls : 'input-group-addon',
10104                     html : this.before
10105                 });
10106             }
10107             
10108             inputblock.cn.push(input);
10109             
10110             if(this.hasFeedback && !this.allowBlank){
10111                 inputblock.cls += ' has-feedback';
10112                 inputblock.cn.push(feedback);
10113             }
10114             
10115             if (this.after) {
10116                 inputblock.cn.push({
10117                     tag :'span',
10118                     cls : 'input-group-addon',
10119                     html : this.after
10120                 });
10121             }
10122             
10123         };
10124         
10125         var box = {
10126             tag: 'div',
10127             cn: [
10128                 {
10129                     tag: 'input',
10130                     type : 'hidden',
10131                     cls: 'form-hidden-field'
10132                 },
10133                 inputblock
10134             ]
10135             
10136         };
10137         
10138         if(this.multiple){
10139             box = {
10140                 tag: 'div',
10141                 cn: [
10142                     {
10143                         tag: 'input',
10144                         type : 'hidden',
10145                         cls: 'form-hidden-field'
10146                     },
10147                     {
10148                         tag: 'ul',
10149                         cls: 'roo-select2-choices',
10150                         cn:[
10151                             {
10152                                 tag: 'li',
10153                                 cls: 'roo-select2-search-field',
10154                                 cn: [
10155
10156                                     inputblock
10157                                 ]
10158                             }
10159                         ]
10160                     }
10161                 ]
10162             }
10163         };
10164         
10165         var combobox = {
10166             cls: 'roo-select2-container input-group',
10167             cn: [
10168                 box
10169 //                {
10170 //                    tag: 'ul',
10171 //                    cls: 'typeahead typeahead-long dropdown-menu',
10172 //                    style: 'display:none'
10173 //                }
10174             ]
10175         };
10176         
10177         if(!this.multiple && this.showToggleBtn){
10178             
10179             var caret = {
10180                         tag: 'span',
10181                         cls: 'caret'
10182              };
10183             if (this.caret != false) {
10184                 caret = {
10185                      tag: 'i',
10186                      cls: 'fa fa-' + this.caret
10187                 };
10188                 
10189             }
10190             
10191             combobox.cn.push({
10192                 tag :'span',
10193                 cls : 'input-group-addon btn dropdown-toggle',
10194                 cn : [
10195                     caret,
10196                     {
10197                         tag: 'span',
10198                         cls: 'combobox-clear',
10199                         cn  : [
10200                             {
10201                                 tag : 'i',
10202                                 cls: 'icon-remove'
10203                             }
10204                         ]
10205                     }
10206                 ]
10207
10208             })
10209         }
10210         
10211         if(this.multiple){
10212             combobox.cls += ' roo-select2-container-multi';
10213         }
10214         
10215         if (align ==='left' && this.fieldLabel.length) {
10216             
10217             cfg.cls += ' roo-form-group-label-left';
10218
10219             cfg.cn = [
10220                 {
10221                     tag : 'i',
10222                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10223                     tooltip : 'This field is required'
10224                 },
10225                 {
10226                     tag: 'label',
10227                     'for' :  id,
10228                     cls : 'control-label',
10229                     html : this.fieldLabel
10230
10231                 },
10232                 {
10233                     cls : "", 
10234                     cn: [
10235                         combobox
10236                     ]
10237                 }
10238
10239             ];
10240             
10241             var labelCfg = cfg.cn[1];
10242             var contentCfg = cfg.cn[2];
10243             
10244             if(this.indicatorpos == 'right'){
10245                 cfg.cn = [
10246                     {
10247                         tag: 'label',
10248                         'for' :  id,
10249                         cls : 'control-label',
10250                         cn : [
10251                             {
10252                                 tag : 'span',
10253                                 html : this.fieldLabel
10254                             },
10255                             {
10256                                 tag : 'i',
10257                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10258                                 tooltip : 'This field is required'
10259                             }
10260                         ]
10261                     },
10262                     {
10263                         cls : "", 
10264                         cn: [
10265                             combobox
10266                         ]
10267                     }
10268
10269                 ];
10270                 
10271                 labelCfg = cfg.cn[0];
10272                 contentCfg = cfg.cn[1];
10273             }
10274             
10275             if(this.labelWidth > 12){
10276                 labelCfg.style = "width: " + this.labelWidth + 'px';
10277             }
10278             
10279             if(this.labelWidth < 13 && this.labelmd == 0){
10280                 this.labelmd = this.labelWidth;
10281             }
10282             
10283             if(this.labellg > 0){
10284                 labelCfg.cls += ' col-lg-' + this.labellg;
10285                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10286             }
10287             
10288             if(this.labelmd > 0){
10289                 labelCfg.cls += ' col-md-' + this.labelmd;
10290                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10291             }
10292             
10293             if(this.labelsm > 0){
10294                 labelCfg.cls += ' col-sm-' + this.labelsm;
10295                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10296             }
10297             
10298             if(this.labelxs > 0){
10299                 labelCfg.cls += ' col-xs-' + this.labelxs;
10300                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10301             }
10302             
10303         } else if ( this.fieldLabel.length) {
10304 //                Roo.log(" label");
10305             cfg.cn = [
10306                 {
10307                    tag : 'i',
10308                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10309                    tooltip : 'This field is required'
10310                },
10311                {
10312                    tag: 'label',
10313                    //cls : 'input-group-addon',
10314                    html : this.fieldLabel
10315
10316                },
10317
10318                combobox
10319
10320             ];
10321             
10322             if(this.indicatorpos == 'right'){
10323                 
10324                 cfg.cn = [
10325                     {
10326                        tag: 'label',
10327                        cn : [
10328                            {
10329                                tag : 'span',
10330                                html : this.fieldLabel
10331                            },
10332                            {
10333                               tag : 'i',
10334                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10335                               tooltip : 'This field is required'
10336                            }
10337                        ]
10338
10339                     },
10340                     combobox
10341
10342                 ];
10343
10344             }
10345
10346         } else {
10347             
10348 //                Roo.log(" no label && no align");
10349                 cfg = combobox
10350                      
10351                 
10352         }
10353         
10354         var settings=this;
10355         ['xs','sm','md','lg'].map(function(size){
10356             if (settings[size]) {
10357                 cfg.cls += ' col-' + size + '-' + settings[size];
10358             }
10359         });
10360         
10361         return cfg;
10362         
10363     },
10364     
10365     
10366     
10367     // private
10368     onResize : function(w, h){
10369 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10370 //        if(typeof w == 'number'){
10371 //            var x = w - this.trigger.getWidth();
10372 //            this.inputEl().setWidth(this.adjustWidth('input', x));
10373 //            this.trigger.setStyle('left', x+'px');
10374 //        }
10375     },
10376
10377     // private
10378     adjustSize : Roo.BoxComponent.prototype.adjustSize,
10379
10380     // private
10381     getResizeEl : function(){
10382         return this.inputEl();
10383     },
10384
10385     // private
10386     getPositionEl : function(){
10387         return this.inputEl();
10388     },
10389
10390     // private
10391     alignErrorIcon : function(){
10392         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10393     },
10394
10395     // private
10396     initEvents : function(){
10397         
10398         this.createList();
10399         
10400         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10401         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10402         if(!this.multiple && this.showToggleBtn){
10403             this.trigger = this.el.select('span.dropdown-toggle',true).first();
10404             if(this.hideTrigger){
10405                 this.trigger.setDisplayed(false);
10406             }
10407             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10408         }
10409         
10410         if(this.multiple){
10411             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10412         }
10413         
10414         if(this.removable && !this.editable && !this.tickable){
10415             var close = this.closeTriggerEl();
10416             
10417             if(close){
10418                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10419                 close.on('click', this.removeBtnClick, this, close);
10420             }
10421         }
10422         
10423         //this.trigger.addClassOnOver('x-form-trigger-over');
10424         //this.trigger.addClassOnClick('x-form-trigger-click');
10425         
10426         //if(!this.width){
10427         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10428         //}
10429     },
10430     
10431     closeTriggerEl : function()
10432     {
10433         var close = this.el.select('.roo-combo-removable-btn', true).first();
10434         return close ? close : false;
10435     },
10436     
10437     removeBtnClick : function(e, h, el)
10438     {
10439         e.preventDefault();
10440         
10441         if(this.fireEvent("remove", this) !== false){
10442             this.reset();
10443             this.fireEvent("afterremove", this)
10444         }
10445     },
10446     
10447     createList : function()
10448     {
10449         this.list = Roo.get(document.body).createChild({
10450             tag: 'ul',
10451             cls: 'typeahead typeahead-long dropdown-menu',
10452             style: 'display:none'
10453         });
10454         
10455         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10456         
10457     },
10458
10459     // private
10460     initTrigger : function(){
10461        
10462     },
10463
10464     // private
10465     onDestroy : function(){
10466         if(this.trigger){
10467             this.trigger.removeAllListeners();
10468           //  this.trigger.remove();
10469         }
10470         //if(this.wrap){
10471         //    this.wrap.remove();
10472         //}
10473         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10474     },
10475
10476     // private
10477     onFocus : function(){
10478         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10479         /*
10480         if(!this.mimicing){
10481             this.wrap.addClass('x-trigger-wrap-focus');
10482             this.mimicing = true;
10483             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10484             if(this.monitorTab){
10485                 this.el.on("keydown", this.checkTab, this);
10486             }
10487         }
10488         */
10489     },
10490
10491     // private
10492     checkTab : function(e){
10493         if(e.getKey() == e.TAB){
10494             this.triggerBlur();
10495         }
10496     },
10497
10498     // private
10499     onBlur : function(){
10500         // do nothing
10501     },
10502
10503     // private
10504     mimicBlur : function(e, t){
10505         /*
10506         if(!this.wrap.contains(t) && this.validateBlur()){
10507             this.triggerBlur();
10508         }
10509         */
10510     },
10511
10512     // private
10513     triggerBlur : function(){
10514         this.mimicing = false;
10515         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10516         if(this.monitorTab){
10517             this.el.un("keydown", this.checkTab, this);
10518         }
10519         //this.wrap.removeClass('x-trigger-wrap-focus');
10520         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10521     },
10522
10523     // private
10524     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10525     validateBlur : function(e, t){
10526         return true;
10527     },
10528
10529     // private
10530     onDisable : function(){
10531         this.inputEl().dom.disabled = true;
10532         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10533         //if(this.wrap){
10534         //    this.wrap.addClass('x-item-disabled');
10535         //}
10536     },
10537
10538     // private
10539     onEnable : function(){
10540         this.inputEl().dom.disabled = false;
10541         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10542         //if(this.wrap){
10543         //    this.el.removeClass('x-item-disabled');
10544         //}
10545     },
10546
10547     // private
10548     onShow : function(){
10549         var ae = this.getActionEl();
10550         
10551         if(ae){
10552             ae.dom.style.display = '';
10553             ae.dom.style.visibility = 'visible';
10554         }
10555     },
10556
10557     // private
10558     
10559     onHide : function(){
10560         var ae = this.getActionEl();
10561         ae.dom.style.display = 'none';
10562     },
10563
10564     /**
10565      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
10566      * by an implementing function.
10567      * @method
10568      * @param {EventObject} e
10569      */
10570     onTriggerClick : Roo.emptyFn
10571 });
10572  /*
10573  * Based on:
10574  * Ext JS Library 1.1.1
10575  * Copyright(c) 2006-2007, Ext JS, LLC.
10576  *
10577  * Originally Released Under LGPL - original licence link has changed is not relivant.
10578  *
10579  * Fork - LGPL
10580  * <script type="text/javascript">
10581  */
10582
10583
10584 /**
10585  * @class Roo.data.SortTypes
10586  * @singleton
10587  * Defines the default sorting (casting?) comparison functions used when sorting data.
10588  */
10589 Roo.data.SortTypes = {
10590     /**
10591      * Default sort that does nothing
10592      * @param {Mixed} s The value being converted
10593      * @return {Mixed} The comparison value
10594      */
10595     none : function(s){
10596         return s;
10597     },
10598     
10599     /**
10600      * The regular expression used to strip tags
10601      * @type {RegExp}
10602      * @property
10603      */
10604     stripTagsRE : /<\/?[^>]+>/gi,
10605     
10606     /**
10607      * Strips all HTML tags to sort on text only
10608      * @param {Mixed} s The value being converted
10609      * @return {String} The comparison value
10610      */
10611     asText : function(s){
10612         return String(s).replace(this.stripTagsRE, "");
10613     },
10614     
10615     /**
10616      * Strips all HTML tags to sort on text only - Case insensitive
10617      * @param {Mixed} s The value being converted
10618      * @return {String} The comparison value
10619      */
10620     asUCText : function(s){
10621         return String(s).toUpperCase().replace(this.stripTagsRE, "");
10622     },
10623     
10624     /**
10625      * Case insensitive string
10626      * @param {Mixed} s The value being converted
10627      * @return {String} The comparison value
10628      */
10629     asUCString : function(s) {
10630         return String(s).toUpperCase();
10631     },
10632     
10633     /**
10634      * Date sorting
10635      * @param {Mixed} s The value being converted
10636      * @return {Number} The comparison value
10637      */
10638     asDate : function(s) {
10639         if(!s){
10640             return 0;
10641         }
10642         if(s instanceof Date){
10643             return s.getTime();
10644         }
10645         return Date.parse(String(s));
10646     },
10647     
10648     /**
10649      * Float sorting
10650      * @param {Mixed} s The value being converted
10651      * @return {Float} The comparison value
10652      */
10653     asFloat : function(s) {
10654         var val = parseFloat(String(s).replace(/,/g, ""));
10655         if(isNaN(val)) {
10656             val = 0;
10657         }
10658         return val;
10659     },
10660     
10661     /**
10662      * Integer sorting
10663      * @param {Mixed} s The value being converted
10664      * @return {Number} The comparison value
10665      */
10666     asInt : function(s) {
10667         var val = parseInt(String(s).replace(/,/g, ""));
10668         if(isNaN(val)) {
10669             val = 0;
10670         }
10671         return val;
10672     }
10673 };/*
10674  * Based on:
10675  * Ext JS Library 1.1.1
10676  * Copyright(c) 2006-2007, Ext JS, LLC.
10677  *
10678  * Originally Released Under LGPL - original licence link has changed is not relivant.
10679  *
10680  * Fork - LGPL
10681  * <script type="text/javascript">
10682  */
10683
10684 /**
10685 * @class Roo.data.Record
10686  * Instances of this class encapsulate both record <em>definition</em> information, and record
10687  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10688  * to access Records cached in an {@link Roo.data.Store} object.<br>
10689  * <p>
10690  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10691  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10692  * objects.<br>
10693  * <p>
10694  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10695  * @constructor
10696  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10697  * {@link #create}. The parameters are the same.
10698  * @param {Array} data An associative Array of data values keyed by the field name.
10699  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10700  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10701  * not specified an integer id is generated.
10702  */
10703 Roo.data.Record = function(data, id){
10704     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10705     this.data = data;
10706 };
10707
10708 /**
10709  * Generate a constructor for a specific record layout.
10710  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10711  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10712  * Each field definition object may contain the following properties: <ul>
10713  * <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,
10714  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10715  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10716  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10717  * is being used, then this is a string containing the javascript expression to reference the data relative to 
10718  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10719  * to the data item relative to the record element. If the mapping expression is the same as the field name,
10720  * this may be omitted.</p></li>
10721  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10722  * <ul><li>auto (Default, implies no conversion)</li>
10723  * <li>string</li>
10724  * <li>int</li>
10725  * <li>float</li>
10726  * <li>boolean</li>
10727  * <li>date</li></ul></p></li>
10728  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10729  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10730  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10731  * by the Reader into an object that will be stored in the Record. It is passed the
10732  * following parameters:<ul>
10733  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10734  * </ul></p></li>
10735  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10736  * </ul>
10737  * <br>usage:<br><pre><code>
10738 var TopicRecord = Roo.data.Record.create(
10739     {name: 'title', mapping: 'topic_title'},
10740     {name: 'author', mapping: 'username'},
10741     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10742     {name: 'lastPost', mapping: 'post_time', type: 'date'},
10743     {name: 'lastPoster', mapping: 'user2'},
10744     {name: 'excerpt', mapping: 'post_text'}
10745 );
10746
10747 var myNewRecord = new TopicRecord({
10748     title: 'Do my job please',
10749     author: 'noobie',
10750     totalPosts: 1,
10751     lastPost: new Date(),
10752     lastPoster: 'Animal',
10753     excerpt: 'No way dude!'
10754 });
10755 myStore.add(myNewRecord);
10756 </code></pre>
10757  * @method create
10758  * @static
10759  */
10760 Roo.data.Record.create = function(o){
10761     var f = function(){
10762         f.superclass.constructor.apply(this, arguments);
10763     };
10764     Roo.extend(f, Roo.data.Record);
10765     var p = f.prototype;
10766     p.fields = new Roo.util.MixedCollection(false, function(field){
10767         return field.name;
10768     });
10769     for(var i = 0, len = o.length; i < len; i++){
10770         p.fields.add(new Roo.data.Field(o[i]));
10771     }
10772     f.getField = function(name){
10773         return p.fields.get(name);  
10774     };
10775     return f;
10776 };
10777
10778 Roo.data.Record.AUTO_ID = 1000;
10779 Roo.data.Record.EDIT = 'edit';
10780 Roo.data.Record.REJECT = 'reject';
10781 Roo.data.Record.COMMIT = 'commit';
10782
10783 Roo.data.Record.prototype = {
10784     /**
10785      * Readonly flag - true if this record has been modified.
10786      * @type Boolean
10787      */
10788     dirty : false,
10789     editing : false,
10790     error: null,
10791     modified: null,
10792
10793     // private
10794     join : function(store){
10795         this.store = store;
10796     },
10797
10798     /**
10799      * Set the named field to the specified value.
10800      * @param {String} name The name of the field to set.
10801      * @param {Object} value The value to set the field to.
10802      */
10803     set : function(name, value){
10804         if(this.data[name] == value){
10805             return;
10806         }
10807         this.dirty = true;
10808         if(!this.modified){
10809             this.modified = {};
10810         }
10811         if(typeof this.modified[name] == 'undefined'){
10812             this.modified[name] = this.data[name];
10813         }
10814         this.data[name] = value;
10815         if(!this.editing && this.store){
10816             this.store.afterEdit(this);
10817         }       
10818     },
10819
10820     /**
10821      * Get the value of the named field.
10822      * @param {String} name The name of the field to get the value of.
10823      * @return {Object} The value of the field.
10824      */
10825     get : function(name){
10826         return this.data[name]; 
10827     },
10828
10829     // private
10830     beginEdit : function(){
10831         this.editing = true;
10832         this.modified = {}; 
10833     },
10834
10835     // private
10836     cancelEdit : function(){
10837         this.editing = false;
10838         delete this.modified;
10839     },
10840
10841     // private
10842     endEdit : function(){
10843         this.editing = false;
10844         if(this.dirty && this.store){
10845             this.store.afterEdit(this);
10846         }
10847     },
10848
10849     /**
10850      * Usually called by the {@link Roo.data.Store} which owns the Record.
10851      * Rejects all changes made to the Record since either creation, or the last commit operation.
10852      * Modified fields are reverted to their original values.
10853      * <p>
10854      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10855      * of reject operations.
10856      */
10857     reject : function(){
10858         var m = this.modified;
10859         for(var n in m){
10860             if(typeof m[n] != "function"){
10861                 this.data[n] = m[n];
10862             }
10863         }
10864         this.dirty = false;
10865         delete this.modified;
10866         this.editing = false;
10867         if(this.store){
10868             this.store.afterReject(this);
10869         }
10870     },
10871
10872     /**
10873      * Usually called by the {@link Roo.data.Store} which owns the Record.
10874      * Commits all changes made to the Record since either creation, or the last commit operation.
10875      * <p>
10876      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10877      * of commit operations.
10878      */
10879     commit : function(){
10880         this.dirty = false;
10881         delete this.modified;
10882         this.editing = false;
10883         if(this.store){
10884             this.store.afterCommit(this);
10885         }
10886     },
10887
10888     // private
10889     hasError : function(){
10890         return this.error != null;
10891     },
10892
10893     // private
10894     clearError : function(){
10895         this.error = null;
10896     },
10897
10898     /**
10899      * Creates a copy of this record.
10900      * @param {String} id (optional) A new record id if you don't want to use this record's id
10901      * @return {Record}
10902      */
10903     copy : function(newId) {
10904         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10905     }
10906 };/*
10907  * Based on:
10908  * Ext JS Library 1.1.1
10909  * Copyright(c) 2006-2007, Ext JS, LLC.
10910  *
10911  * Originally Released Under LGPL - original licence link has changed is not relivant.
10912  *
10913  * Fork - LGPL
10914  * <script type="text/javascript">
10915  */
10916
10917
10918
10919 /**
10920  * @class Roo.data.Store
10921  * @extends Roo.util.Observable
10922  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10923  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10924  * <p>
10925  * 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
10926  * has no knowledge of the format of the data returned by the Proxy.<br>
10927  * <p>
10928  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10929  * instances from the data object. These records are cached and made available through accessor functions.
10930  * @constructor
10931  * Creates a new Store.
10932  * @param {Object} config A config object containing the objects needed for the Store to access data,
10933  * and read the data into Records.
10934  */
10935 Roo.data.Store = function(config){
10936     this.data = new Roo.util.MixedCollection(false);
10937     this.data.getKey = function(o){
10938         return o.id;
10939     };
10940     this.baseParams = {};
10941     // private
10942     this.paramNames = {
10943         "start" : "start",
10944         "limit" : "limit",
10945         "sort" : "sort",
10946         "dir" : "dir",
10947         "multisort" : "_multisort"
10948     };
10949
10950     if(config && config.data){
10951         this.inlineData = config.data;
10952         delete config.data;
10953     }
10954
10955     Roo.apply(this, config);
10956     
10957     if(this.reader){ // reader passed
10958         this.reader = Roo.factory(this.reader, Roo.data);
10959         this.reader.xmodule = this.xmodule || false;
10960         if(!this.recordType){
10961             this.recordType = this.reader.recordType;
10962         }
10963         if(this.reader.onMetaChange){
10964             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10965         }
10966     }
10967
10968     if(this.recordType){
10969         this.fields = this.recordType.prototype.fields;
10970     }
10971     this.modified = [];
10972
10973     this.addEvents({
10974         /**
10975          * @event datachanged
10976          * Fires when the data cache has changed, and a widget which is using this Store
10977          * as a Record cache should refresh its view.
10978          * @param {Store} this
10979          */
10980         datachanged : true,
10981         /**
10982          * @event metachange
10983          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10984          * @param {Store} this
10985          * @param {Object} meta The JSON metadata
10986          */
10987         metachange : true,
10988         /**
10989          * @event add
10990          * Fires when Records have been added to the Store
10991          * @param {Store} this
10992          * @param {Roo.data.Record[]} records The array of Records added
10993          * @param {Number} index The index at which the record(s) were added
10994          */
10995         add : true,
10996         /**
10997          * @event remove
10998          * Fires when a Record has been removed from the Store
10999          * @param {Store} this
11000          * @param {Roo.data.Record} record The Record that was removed
11001          * @param {Number} index The index at which the record was removed
11002          */
11003         remove : true,
11004         /**
11005          * @event update
11006          * Fires when a Record has been updated
11007          * @param {Store} this
11008          * @param {Roo.data.Record} record The Record that was updated
11009          * @param {String} operation The update operation being performed.  Value may be one of:
11010          * <pre><code>
11011  Roo.data.Record.EDIT
11012  Roo.data.Record.REJECT
11013  Roo.data.Record.COMMIT
11014          * </code></pre>
11015          */
11016         update : true,
11017         /**
11018          * @event clear
11019          * Fires when the data cache has been cleared.
11020          * @param {Store} this
11021          */
11022         clear : true,
11023         /**
11024          * @event beforeload
11025          * Fires before a request is made for a new data object.  If the beforeload handler returns false
11026          * the load action will be canceled.
11027          * @param {Store} this
11028          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11029          */
11030         beforeload : true,
11031         /**
11032          * @event beforeloadadd
11033          * Fires after a new set of Records has been loaded.
11034          * @param {Store} this
11035          * @param {Roo.data.Record[]} records The Records that were loaded
11036          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11037          */
11038         beforeloadadd : true,
11039         /**
11040          * @event load
11041          * Fires after a new set of Records has been loaded, before they are added to the store.
11042          * @param {Store} this
11043          * @param {Roo.data.Record[]} records The Records that were loaded
11044          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11045          * @params {Object} return from reader
11046          */
11047         load : true,
11048         /**
11049          * @event loadexception
11050          * Fires if an exception occurs in the Proxy during loading.
11051          * Called with the signature of the Proxy's "loadexception" event.
11052          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11053          * 
11054          * @param {Proxy} 
11055          * @param {Object} return from JsonData.reader() - success, totalRecords, records
11056          * @param {Object} load options 
11057          * @param {Object} jsonData from your request (normally this contains the Exception)
11058          */
11059         loadexception : true
11060     });
11061     
11062     if(this.proxy){
11063         this.proxy = Roo.factory(this.proxy, Roo.data);
11064         this.proxy.xmodule = this.xmodule || false;
11065         this.relayEvents(this.proxy,  ["loadexception"]);
11066     }
11067     this.sortToggle = {};
11068     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11069
11070     Roo.data.Store.superclass.constructor.call(this);
11071
11072     if(this.inlineData){
11073         this.loadData(this.inlineData);
11074         delete this.inlineData;
11075     }
11076 };
11077
11078 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11079      /**
11080     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
11081     * without a remote query - used by combo/forms at present.
11082     */
11083     
11084     /**
11085     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11086     */
11087     /**
11088     * @cfg {Array} data Inline data to be loaded when the store is initialized.
11089     */
11090     /**
11091     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11092     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11093     */
11094     /**
11095     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11096     * on any HTTP request
11097     */
11098     /**
11099     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11100     */
11101     /**
11102     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11103     */
11104     multiSort: false,
11105     /**
11106     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11107     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11108     */
11109     remoteSort : false,
11110
11111     /**
11112     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11113      * loaded or when a record is removed. (defaults to false).
11114     */
11115     pruneModifiedRecords : false,
11116
11117     // private
11118     lastOptions : null,
11119
11120     /**
11121      * Add Records to the Store and fires the add event.
11122      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11123      */
11124     add : function(records){
11125         records = [].concat(records);
11126         for(var i = 0, len = records.length; i < len; i++){
11127             records[i].join(this);
11128         }
11129         var index = this.data.length;
11130         this.data.addAll(records);
11131         this.fireEvent("add", this, records, index);
11132     },
11133
11134     /**
11135      * Remove a Record from the Store and fires the remove event.
11136      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11137      */
11138     remove : function(record){
11139         var index = this.data.indexOf(record);
11140         this.data.removeAt(index);
11141  
11142         if(this.pruneModifiedRecords){
11143             this.modified.remove(record);
11144         }
11145         this.fireEvent("remove", this, record, index);
11146     },
11147
11148     /**
11149      * Remove all Records from the Store and fires the clear event.
11150      */
11151     removeAll : function(){
11152         this.data.clear();
11153         if(this.pruneModifiedRecords){
11154             this.modified = [];
11155         }
11156         this.fireEvent("clear", this);
11157     },
11158
11159     /**
11160      * Inserts Records to the Store at the given index and fires the add event.
11161      * @param {Number} index The start index at which to insert the passed Records.
11162      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11163      */
11164     insert : function(index, records){
11165         records = [].concat(records);
11166         for(var i = 0, len = records.length; i < len; i++){
11167             this.data.insert(index, records[i]);
11168             records[i].join(this);
11169         }
11170         this.fireEvent("add", this, records, index);
11171     },
11172
11173     /**
11174      * Get the index within the cache of the passed Record.
11175      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11176      * @return {Number} The index of the passed Record. Returns -1 if not found.
11177      */
11178     indexOf : function(record){
11179         return this.data.indexOf(record);
11180     },
11181
11182     /**
11183      * Get the index within the cache of the Record with the passed id.
11184      * @param {String} id The id of the Record to find.
11185      * @return {Number} The index of the Record. Returns -1 if not found.
11186      */
11187     indexOfId : function(id){
11188         return this.data.indexOfKey(id);
11189     },
11190
11191     /**
11192      * Get the Record with the specified id.
11193      * @param {String} id The id of the Record to find.
11194      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11195      */
11196     getById : function(id){
11197         return this.data.key(id);
11198     },
11199
11200     /**
11201      * Get the Record at the specified index.
11202      * @param {Number} index The index of the Record to find.
11203      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11204      */
11205     getAt : function(index){
11206         return this.data.itemAt(index);
11207     },
11208
11209     /**
11210      * Returns a range of Records between specified indices.
11211      * @param {Number} startIndex (optional) The starting index (defaults to 0)
11212      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11213      * @return {Roo.data.Record[]} An array of Records
11214      */
11215     getRange : function(start, end){
11216         return this.data.getRange(start, end);
11217     },
11218
11219     // private
11220     storeOptions : function(o){
11221         o = Roo.apply({}, o);
11222         delete o.callback;
11223         delete o.scope;
11224         this.lastOptions = o;
11225     },
11226
11227     /**
11228      * Loads the Record cache from the configured Proxy using the configured Reader.
11229      * <p>
11230      * If using remote paging, then the first load call must specify the <em>start</em>
11231      * and <em>limit</em> properties in the options.params property to establish the initial
11232      * position within the dataset, and the number of Records to cache on each read from the Proxy.
11233      * <p>
11234      * <strong>It is important to note that for remote data sources, loading is asynchronous,
11235      * and this call will return before the new data has been loaded. Perform any post-processing
11236      * in a callback function, or in a "load" event handler.</strong>
11237      * <p>
11238      * @param {Object} options An object containing properties which control loading options:<ul>
11239      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11240      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11241      * passed the following arguments:<ul>
11242      * <li>r : Roo.data.Record[]</li>
11243      * <li>options: Options object from the load call</li>
11244      * <li>success: Boolean success indicator</li></ul></li>
11245      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11246      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11247      * </ul>
11248      */
11249     load : function(options){
11250         options = options || {};
11251         if(this.fireEvent("beforeload", this, options) !== false){
11252             this.storeOptions(options);
11253             var p = Roo.apply(options.params || {}, this.baseParams);
11254             // if meta was not loaded from remote source.. try requesting it.
11255             if (!this.reader.metaFromRemote) {
11256                 p._requestMeta = 1;
11257             }
11258             if(this.sortInfo && this.remoteSort){
11259                 var pn = this.paramNames;
11260                 p[pn["sort"]] = this.sortInfo.field;
11261                 p[pn["dir"]] = this.sortInfo.direction;
11262             }
11263             if (this.multiSort) {
11264                 var pn = this.paramNames;
11265                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11266             }
11267             
11268             this.proxy.load(p, this.reader, this.loadRecords, this, options);
11269         }
11270     },
11271
11272     /**
11273      * Reloads the Record cache from the configured Proxy using the configured Reader and
11274      * the options from the last load operation performed.
11275      * @param {Object} options (optional) An object containing properties which may override the options
11276      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11277      * the most recently used options are reused).
11278      */
11279     reload : function(options){
11280         this.load(Roo.applyIf(options||{}, this.lastOptions));
11281     },
11282
11283     // private
11284     // Called as a callback by the Reader during a load operation.
11285     loadRecords : function(o, options, success){
11286         if(!o || success === false){
11287             if(success !== false){
11288                 this.fireEvent("load", this, [], options, o);
11289             }
11290             if(options.callback){
11291                 options.callback.call(options.scope || this, [], options, false);
11292             }
11293             return;
11294         }
11295         // if data returned failure - throw an exception.
11296         if (o.success === false) {
11297             // show a message if no listener is registered.
11298             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11299                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11300             }
11301             // loadmask wil be hooked into this..
11302             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11303             return;
11304         }
11305         var r = o.records, t = o.totalRecords || r.length;
11306         
11307         this.fireEvent("beforeloadadd", this, r, options, o);
11308         
11309         if(!options || options.add !== true){
11310             if(this.pruneModifiedRecords){
11311                 this.modified = [];
11312             }
11313             for(var i = 0, len = r.length; i < len; i++){
11314                 r[i].join(this);
11315             }
11316             if(this.snapshot){
11317                 this.data = this.snapshot;
11318                 delete this.snapshot;
11319             }
11320             this.data.clear();
11321             this.data.addAll(r);
11322             this.totalLength = t;
11323             this.applySort();
11324             this.fireEvent("datachanged", this);
11325         }else{
11326             this.totalLength = Math.max(t, this.data.length+r.length);
11327             this.add(r);
11328         }
11329         
11330         if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11331                 
11332             var e = new Roo.data.Record({});
11333
11334             e.set(this.parent.displayField, this.parent.emptyTitle);
11335             e.set(this.parent.valueField, '');
11336
11337             this.insert(0, e);
11338         }
11339             
11340         this.fireEvent("load", this, r, options, o);
11341         if(options.callback){
11342             options.callback.call(options.scope || this, r, options, true);
11343         }
11344     },
11345
11346
11347     /**
11348      * Loads data from a passed data block. A Reader which understands the format of the data
11349      * must have been configured in the constructor.
11350      * @param {Object} data The data block from which to read the Records.  The format of the data expected
11351      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11352      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11353      */
11354     loadData : function(o, append){
11355         var r = this.reader.readRecords(o);
11356         this.loadRecords(r, {add: append}, true);
11357     },
11358
11359     /**
11360      * Gets the number of cached records.
11361      * <p>
11362      * <em>If using paging, this may not be the total size of the dataset. If the data object
11363      * used by the Reader contains the dataset size, then the getTotalCount() function returns
11364      * the data set size</em>
11365      */
11366     getCount : function(){
11367         return this.data.length || 0;
11368     },
11369
11370     /**
11371      * Gets the total number of records in the dataset as returned by the server.
11372      * <p>
11373      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11374      * the dataset size</em>
11375      */
11376     getTotalCount : function(){
11377         return this.totalLength || 0;
11378     },
11379
11380     /**
11381      * Returns the sort state of the Store as an object with two properties:
11382      * <pre><code>
11383  field {String} The name of the field by which the Records are sorted
11384  direction {String} The sort order, "ASC" or "DESC"
11385      * </code></pre>
11386      */
11387     getSortState : function(){
11388         return this.sortInfo;
11389     },
11390
11391     // private
11392     applySort : function(){
11393         if(this.sortInfo && !this.remoteSort){
11394             var s = this.sortInfo, f = s.field;
11395             var st = this.fields.get(f).sortType;
11396             var fn = function(r1, r2){
11397                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11398                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11399             };
11400             this.data.sort(s.direction, fn);
11401             if(this.snapshot && this.snapshot != this.data){
11402                 this.snapshot.sort(s.direction, fn);
11403             }
11404         }
11405     },
11406
11407     /**
11408      * Sets the default sort column and order to be used by the next load operation.
11409      * @param {String} fieldName The name of the field to sort by.
11410      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11411      */
11412     setDefaultSort : function(field, dir){
11413         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11414     },
11415
11416     /**
11417      * Sort the Records.
11418      * If remote sorting is used, the sort is performed on the server, and the cache is
11419      * reloaded. If local sorting is used, the cache is sorted internally.
11420      * @param {String} fieldName The name of the field to sort by.
11421      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11422      */
11423     sort : function(fieldName, dir){
11424         var f = this.fields.get(fieldName);
11425         if(!dir){
11426             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11427             
11428             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11429                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11430             }else{
11431                 dir = f.sortDir;
11432             }
11433         }
11434         this.sortToggle[f.name] = dir;
11435         this.sortInfo = {field: f.name, direction: dir};
11436         if(!this.remoteSort){
11437             this.applySort();
11438             this.fireEvent("datachanged", this);
11439         }else{
11440             this.load(this.lastOptions);
11441         }
11442     },
11443
11444     /**
11445      * Calls the specified function for each of the Records in the cache.
11446      * @param {Function} fn The function to call. The Record is passed as the first parameter.
11447      * Returning <em>false</em> aborts and exits the iteration.
11448      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11449      */
11450     each : function(fn, scope){
11451         this.data.each(fn, scope);
11452     },
11453
11454     /**
11455      * Gets all records modified since the last commit.  Modified records are persisted across load operations
11456      * (e.g., during paging).
11457      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11458      */
11459     getModifiedRecords : function(){
11460         return this.modified;
11461     },
11462
11463     // private
11464     createFilterFn : function(property, value, anyMatch){
11465         if(!value.exec){ // not a regex
11466             value = String(value);
11467             if(value.length == 0){
11468                 return false;
11469             }
11470             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11471         }
11472         return function(r){
11473             return value.test(r.data[property]);
11474         };
11475     },
11476
11477     /**
11478      * Sums the value of <i>property</i> for each record between start and end and returns the result.
11479      * @param {String} property A field on your records
11480      * @param {Number} start The record index to start at (defaults to 0)
11481      * @param {Number} end The last record index to include (defaults to length - 1)
11482      * @return {Number} The sum
11483      */
11484     sum : function(property, start, end){
11485         var rs = this.data.items, v = 0;
11486         start = start || 0;
11487         end = (end || end === 0) ? end : rs.length-1;
11488
11489         for(var i = start; i <= end; i++){
11490             v += (rs[i].data[property] || 0);
11491         }
11492         return v;
11493     },
11494
11495     /**
11496      * Filter the records by a specified property.
11497      * @param {String} field A field on your records
11498      * @param {String/RegExp} value Either a string that the field
11499      * should start with or a RegExp to test against the field
11500      * @param {Boolean} anyMatch True to match any part not just the beginning
11501      */
11502     filter : function(property, value, anyMatch){
11503         var fn = this.createFilterFn(property, value, anyMatch);
11504         return fn ? this.filterBy(fn) : this.clearFilter();
11505     },
11506
11507     /**
11508      * Filter by a function. The specified function will be called with each
11509      * record in this data source. If the function returns true the record is included,
11510      * otherwise it is filtered.
11511      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11512      * @param {Object} scope (optional) The scope of the function (defaults to this)
11513      */
11514     filterBy : function(fn, scope){
11515         this.snapshot = this.snapshot || this.data;
11516         this.data = this.queryBy(fn, scope||this);
11517         this.fireEvent("datachanged", this);
11518     },
11519
11520     /**
11521      * Query the records by a specified property.
11522      * @param {String} field A field on your records
11523      * @param {String/RegExp} value Either a string that the field
11524      * should start with or a RegExp to test against the field
11525      * @param {Boolean} anyMatch True to match any part not just the beginning
11526      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11527      */
11528     query : function(property, value, anyMatch){
11529         var fn = this.createFilterFn(property, value, anyMatch);
11530         return fn ? this.queryBy(fn) : this.data.clone();
11531     },
11532
11533     /**
11534      * Query by a function. The specified function will be called with each
11535      * record in this data source. If the function returns true the record is included
11536      * in the results.
11537      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11538      * @param {Object} scope (optional) The scope of the function (defaults to this)
11539       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11540      **/
11541     queryBy : function(fn, scope){
11542         var data = this.snapshot || this.data;
11543         return data.filterBy(fn, scope||this);
11544     },
11545
11546     /**
11547      * Collects unique values for a particular dataIndex from this store.
11548      * @param {String} dataIndex The property to collect
11549      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11550      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11551      * @return {Array} An array of the unique values
11552      **/
11553     collect : function(dataIndex, allowNull, bypassFilter){
11554         var d = (bypassFilter === true && this.snapshot) ?
11555                 this.snapshot.items : this.data.items;
11556         var v, sv, r = [], l = {};
11557         for(var i = 0, len = d.length; i < len; i++){
11558             v = d[i].data[dataIndex];
11559             sv = String(v);
11560             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11561                 l[sv] = true;
11562                 r[r.length] = v;
11563             }
11564         }
11565         return r;
11566     },
11567
11568     /**
11569      * Revert to a view of the Record cache with no filtering applied.
11570      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11571      */
11572     clearFilter : function(suppressEvent){
11573         if(this.snapshot && this.snapshot != this.data){
11574             this.data = this.snapshot;
11575             delete this.snapshot;
11576             if(suppressEvent !== true){
11577                 this.fireEvent("datachanged", this);
11578             }
11579         }
11580     },
11581
11582     // private
11583     afterEdit : function(record){
11584         if(this.modified.indexOf(record) == -1){
11585             this.modified.push(record);
11586         }
11587         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11588     },
11589     
11590     // private
11591     afterReject : function(record){
11592         this.modified.remove(record);
11593         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11594     },
11595
11596     // private
11597     afterCommit : function(record){
11598         this.modified.remove(record);
11599         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11600     },
11601
11602     /**
11603      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11604      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11605      */
11606     commitChanges : function(){
11607         var m = this.modified.slice(0);
11608         this.modified = [];
11609         for(var i = 0, len = m.length; i < len; i++){
11610             m[i].commit();
11611         }
11612     },
11613
11614     /**
11615      * Cancel outstanding changes on all changed records.
11616      */
11617     rejectChanges : function(){
11618         var m = this.modified.slice(0);
11619         this.modified = [];
11620         for(var i = 0, len = m.length; i < len; i++){
11621             m[i].reject();
11622         }
11623     },
11624
11625     onMetaChange : function(meta, rtype, o){
11626         this.recordType = rtype;
11627         this.fields = rtype.prototype.fields;
11628         delete this.snapshot;
11629         this.sortInfo = meta.sortInfo || this.sortInfo;
11630         this.modified = [];
11631         this.fireEvent('metachange', this, this.reader.meta);
11632     },
11633     
11634     moveIndex : function(data, type)
11635     {
11636         var index = this.indexOf(data);
11637         
11638         var newIndex = index + type;
11639         
11640         this.remove(data);
11641         
11642         this.insert(newIndex, data);
11643         
11644     }
11645 });/*
11646  * Based on:
11647  * Ext JS Library 1.1.1
11648  * Copyright(c) 2006-2007, Ext JS, LLC.
11649  *
11650  * Originally Released Under LGPL - original licence link has changed is not relivant.
11651  *
11652  * Fork - LGPL
11653  * <script type="text/javascript">
11654  */
11655
11656 /**
11657  * @class Roo.data.SimpleStore
11658  * @extends Roo.data.Store
11659  * Small helper class to make creating Stores from Array data easier.
11660  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11661  * @cfg {Array} fields An array of field definition objects, or field name strings.
11662  * @cfg {Array} data The multi-dimensional array of data
11663  * @constructor
11664  * @param {Object} config
11665  */
11666 Roo.data.SimpleStore = function(config){
11667     Roo.data.SimpleStore.superclass.constructor.call(this, {
11668         isLocal : true,
11669         reader: new Roo.data.ArrayReader({
11670                 id: config.id
11671             },
11672             Roo.data.Record.create(config.fields)
11673         ),
11674         proxy : new Roo.data.MemoryProxy(config.data)
11675     });
11676     this.load();
11677 };
11678 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11679  * Based on:
11680  * Ext JS Library 1.1.1
11681  * Copyright(c) 2006-2007, Ext JS, LLC.
11682  *
11683  * Originally Released Under LGPL - original licence link has changed is not relivant.
11684  *
11685  * Fork - LGPL
11686  * <script type="text/javascript">
11687  */
11688
11689 /**
11690 /**
11691  * @extends Roo.data.Store
11692  * @class Roo.data.JsonStore
11693  * Small helper class to make creating Stores for JSON data easier. <br/>
11694 <pre><code>
11695 var store = new Roo.data.JsonStore({
11696     url: 'get-images.php',
11697     root: 'images',
11698     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11699 });
11700 </code></pre>
11701  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11702  * JsonReader and HttpProxy (unless inline data is provided).</b>
11703  * @cfg {Array} fields An array of field definition objects, or field name strings.
11704  * @constructor
11705  * @param {Object} config
11706  */
11707 Roo.data.JsonStore = function(c){
11708     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11709         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11710         reader: new Roo.data.JsonReader(c, c.fields)
11711     }));
11712 };
11713 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11714  * Based on:
11715  * Ext JS Library 1.1.1
11716  * Copyright(c) 2006-2007, Ext JS, LLC.
11717  *
11718  * Originally Released Under LGPL - original licence link has changed is not relivant.
11719  *
11720  * Fork - LGPL
11721  * <script type="text/javascript">
11722  */
11723
11724  
11725 Roo.data.Field = function(config){
11726     if(typeof config == "string"){
11727         config = {name: config};
11728     }
11729     Roo.apply(this, config);
11730     
11731     if(!this.type){
11732         this.type = "auto";
11733     }
11734     
11735     var st = Roo.data.SortTypes;
11736     // named sortTypes are supported, here we look them up
11737     if(typeof this.sortType == "string"){
11738         this.sortType = st[this.sortType];
11739     }
11740     
11741     // set default sortType for strings and dates
11742     if(!this.sortType){
11743         switch(this.type){
11744             case "string":
11745                 this.sortType = st.asUCString;
11746                 break;
11747             case "date":
11748                 this.sortType = st.asDate;
11749                 break;
11750             default:
11751                 this.sortType = st.none;
11752         }
11753     }
11754
11755     // define once
11756     var stripRe = /[\$,%]/g;
11757
11758     // prebuilt conversion function for this field, instead of
11759     // switching every time we're reading a value
11760     if(!this.convert){
11761         var cv, dateFormat = this.dateFormat;
11762         switch(this.type){
11763             case "":
11764             case "auto":
11765             case undefined:
11766                 cv = function(v){ return v; };
11767                 break;
11768             case "string":
11769                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11770                 break;
11771             case "int":
11772                 cv = function(v){
11773                     return v !== undefined && v !== null && v !== '' ?
11774                            parseInt(String(v).replace(stripRe, ""), 10) : '';
11775                     };
11776                 break;
11777             case "float":
11778                 cv = function(v){
11779                     return v !== undefined && v !== null && v !== '' ?
11780                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
11781                     };
11782                 break;
11783             case "bool":
11784             case "boolean":
11785                 cv = function(v){ return v === true || v === "true" || v == 1; };
11786                 break;
11787             case "date":
11788                 cv = function(v){
11789                     if(!v){
11790                         return '';
11791                     }
11792                     if(v instanceof Date){
11793                         return v;
11794                     }
11795                     if(dateFormat){
11796                         if(dateFormat == "timestamp"){
11797                             return new Date(v*1000);
11798                         }
11799                         return Date.parseDate(v, dateFormat);
11800                     }
11801                     var parsed = Date.parse(v);
11802                     return parsed ? new Date(parsed) : null;
11803                 };
11804              break;
11805             
11806         }
11807         this.convert = cv;
11808     }
11809 };
11810
11811 Roo.data.Field.prototype = {
11812     dateFormat: null,
11813     defaultValue: "",
11814     mapping: null,
11815     sortType : null,
11816     sortDir : "ASC"
11817 };/*
11818  * Based on:
11819  * Ext JS Library 1.1.1
11820  * Copyright(c) 2006-2007, Ext JS, LLC.
11821  *
11822  * Originally Released Under LGPL - original licence link has changed is not relivant.
11823  *
11824  * Fork - LGPL
11825  * <script type="text/javascript">
11826  */
11827  
11828 // Base class for reading structured data from a data source.  This class is intended to be
11829 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11830
11831 /**
11832  * @class Roo.data.DataReader
11833  * Base class for reading structured data from a data source.  This class is intended to be
11834  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11835  */
11836
11837 Roo.data.DataReader = function(meta, recordType){
11838     
11839     this.meta = meta;
11840     
11841     this.recordType = recordType instanceof Array ? 
11842         Roo.data.Record.create(recordType) : recordType;
11843 };
11844
11845 Roo.data.DataReader.prototype = {
11846      /**
11847      * Create an empty record
11848      * @param {Object} data (optional) - overlay some values
11849      * @return {Roo.data.Record} record created.
11850      */
11851     newRow :  function(d) {
11852         var da =  {};
11853         this.recordType.prototype.fields.each(function(c) {
11854             switch( c.type) {
11855                 case 'int' : da[c.name] = 0; break;
11856                 case 'date' : da[c.name] = new Date(); break;
11857                 case 'float' : da[c.name] = 0.0; break;
11858                 case 'boolean' : da[c.name] = false; break;
11859                 default : da[c.name] = ""; break;
11860             }
11861             
11862         });
11863         return new this.recordType(Roo.apply(da, d));
11864     }
11865     
11866 };/*
11867  * Based on:
11868  * Ext JS Library 1.1.1
11869  * Copyright(c) 2006-2007, Ext JS, LLC.
11870  *
11871  * Originally Released Under LGPL - original licence link has changed is not relivant.
11872  *
11873  * Fork - LGPL
11874  * <script type="text/javascript">
11875  */
11876
11877 /**
11878  * @class Roo.data.DataProxy
11879  * @extends Roo.data.Observable
11880  * This class is an abstract base class for implementations which provide retrieval of
11881  * unformatted data objects.<br>
11882  * <p>
11883  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11884  * (of the appropriate type which knows how to parse the data object) to provide a block of
11885  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11886  * <p>
11887  * Custom implementations must implement the load method as described in
11888  * {@link Roo.data.HttpProxy#load}.
11889  */
11890 Roo.data.DataProxy = function(){
11891     this.addEvents({
11892         /**
11893          * @event beforeload
11894          * Fires before a network request is made to retrieve a data object.
11895          * @param {Object} This DataProxy object.
11896          * @param {Object} params The params parameter to the load function.
11897          */
11898         beforeload : true,
11899         /**
11900          * @event load
11901          * Fires before the load method's callback is called.
11902          * @param {Object} This DataProxy object.
11903          * @param {Object} o The data object.
11904          * @param {Object} arg The callback argument object passed to the load function.
11905          */
11906         load : true,
11907         /**
11908          * @event loadexception
11909          * Fires if an Exception occurs during data retrieval.
11910          * @param {Object} This DataProxy object.
11911          * @param {Object} o The data object.
11912          * @param {Object} arg The callback argument object passed to the load function.
11913          * @param {Object} e The Exception.
11914          */
11915         loadexception : true
11916     });
11917     Roo.data.DataProxy.superclass.constructor.call(this);
11918 };
11919
11920 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11921
11922     /**
11923      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11924      */
11925 /*
11926  * Based on:
11927  * Ext JS Library 1.1.1
11928  * Copyright(c) 2006-2007, Ext JS, LLC.
11929  *
11930  * Originally Released Under LGPL - original licence link has changed is not relivant.
11931  *
11932  * Fork - LGPL
11933  * <script type="text/javascript">
11934  */
11935 /**
11936  * @class Roo.data.MemoryProxy
11937  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11938  * to the Reader when its load method is called.
11939  * @constructor
11940  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11941  */
11942 Roo.data.MemoryProxy = function(data){
11943     if (data.data) {
11944         data = data.data;
11945     }
11946     Roo.data.MemoryProxy.superclass.constructor.call(this);
11947     this.data = data;
11948 };
11949
11950 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11951     
11952     /**
11953      * Load data from the requested source (in this case an in-memory
11954      * data object passed to the constructor), read the data object into
11955      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11956      * process that block using the passed callback.
11957      * @param {Object} params This parameter is not used by the MemoryProxy class.
11958      * @param {Roo.data.DataReader} reader The Reader object which converts the data
11959      * object into a block of Roo.data.Records.
11960      * @param {Function} callback The function into which to pass the block of Roo.data.records.
11961      * The function must be passed <ul>
11962      * <li>The Record block object</li>
11963      * <li>The "arg" argument from the load function</li>
11964      * <li>A boolean success indicator</li>
11965      * </ul>
11966      * @param {Object} scope The scope in which to call the callback
11967      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11968      */
11969     load : function(params, reader, callback, scope, arg){
11970         params = params || {};
11971         var result;
11972         try {
11973             result = reader.readRecords(this.data);
11974         }catch(e){
11975             this.fireEvent("loadexception", this, arg, null, e);
11976             callback.call(scope, null, arg, false);
11977             return;
11978         }
11979         callback.call(scope, result, arg, true);
11980     },
11981     
11982     // private
11983     update : function(params, records){
11984         
11985     }
11986 });/*
11987  * Based on:
11988  * Ext JS Library 1.1.1
11989  * Copyright(c) 2006-2007, Ext JS, LLC.
11990  *
11991  * Originally Released Under LGPL - original licence link has changed is not relivant.
11992  *
11993  * Fork - LGPL
11994  * <script type="text/javascript">
11995  */
11996 /**
11997  * @class Roo.data.HttpProxy
11998  * @extends Roo.data.DataProxy
11999  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12000  * configured to reference a certain URL.<br><br>
12001  * <p>
12002  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12003  * from which the running page was served.<br><br>
12004  * <p>
12005  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12006  * <p>
12007  * Be aware that to enable the browser to parse an XML document, the server must set
12008  * the Content-Type header in the HTTP response to "text/xml".
12009  * @constructor
12010  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12011  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
12012  * will be used to make the request.
12013  */
12014 Roo.data.HttpProxy = function(conn){
12015     Roo.data.HttpProxy.superclass.constructor.call(this);
12016     // is conn a conn config or a real conn?
12017     this.conn = conn;
12018     this.useAjax = !conn || !conn.events;
12019   
12020 };
12021
12022 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12023     // thse are take from connection...
12024     
12025     /**
12026      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12027      */
12028     /**
12029      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12030      * extra parameters to each request made by this object. (defaults to undefined)
12031      */
12032     /**
12033      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12034      *  to each request made by this object. (defaults to undefined)
12035      */
12036     /**
12037      * @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)
12038      */
12039     /**
12040      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12041      */
12042      /**
12043      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12044      * @type Boolean
12045      */
12046   
12047
12048     /**
12049      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12050      * @type Boolean
12051      */
12052     /**
12053      * Return the {@link Roo.data.Connection} object being used by this Proxy.
12054      * @return {Connection} The Connection object. This object may be used to subscribe to events on
12055      * a finer-grained basis than the DataProxy events.
12056      */
12057     getConnection : function(){
12058         return this.useAjax ? Roo.Ajax : this.conn;
12059     },
12060
12061     /**
12062      * Load data from the configured {@link Roo.data.Connection}, read the data object into
12063      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12064      * process that block using the passed callback.
12065      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12066      * for the request to the remote server.
12067      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12068      * object into a block of Roo.data.Records.
12069      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12070      * The function must be passed <ul>
12071      * <li>The Record block object</li>
12072      * <li>The "arg" argument from the load function</li>
12073      * <li>A boolean success indicator</li>
12074      * </ul>
12075      * @param {Object} scope The scope in which to call the callback
12076      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12077      */
12078     load : function(params, reader, callback, scope, arg){
12079         if(this.fireEvent("beforeload", this, params) !== false){
12080             var  o = {
12081                 params : params || {},
12082                 request: {
12083                     callback : callback,
12084                     scope : scope,
12085                     arg : arg
12086                 },
12087                 reader: reader,
12088                 callback : this.loadResponse,
12089                 scope: this
12090             };
12091             if(this.useAjax){
12092                 Roo.applyIf(o, this.conn);
12093                 if(this.activeRequest){
12094                     Roo.Ajax.abort(this.activeRequest);
12095                 }
12096                 this.activeRequest = Roo.Ajax.request(o);
12097             }else{
12098                 this.conn.request(o);
12099             }
12100         }else{
12101             callback.call(scope||this, null, arg, false);
12102         }
12103     },
12104
12105     // private
12106     loadResponse : function(o, success, response){
12107         delete this.activeRequest;
12108         if(!success){
12109             this.fireEvent("loadexception", this, o, response);
12110             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12111             return;
12112         }
12113         var result;
12114         try {
12115             result = o.reader.read(response);
12116         }catch(e){
12117             this.fireEvent("loadexception", this, o, response, e);
12118             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12119             return;
12120         }
12121         
12122         this.fireEvent("load", this, o, o.request.arg);
12123         o.request.callback.call(o.request.scope, result, o.request.arg, true);
12124     },
12125
12126     // private
12127     update : function(dataSet){
12128
12129     },
12130
12131     // private
12132     updateResponse : function(dataSet){
12133
12134     }
12135 });/*
12136  * Based on:
12137  * Ext JS Library 1.1.1
12138  * Copyright(c) 2006-2007, Ext JS, LLC.
12139  *
12140  * Originally Released Under LGPL - original licence link has changed is not relivant.
12141  *
12142  * Fork - LGPL
12143  * <script type="text/javascript">
12144  */
12145
12146 /**
12147  * @class Roo.data.ScriptTagProxy
12148  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12149  * other than the originating domain of the running page.<br><br>
12150  * <p>
12151  * <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
12152  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12153  * <p>
12154  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12155  * source code that is used as the source inside a &lt;script> tag.<br><br>
12156  * <p>
12157  * In order for the browser to process the returned data, the server must wrap the data object
12158  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12159  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12160  * depending on whether the callback name was passed:
12161  * <p>
12162  * <pre><code>
12163 boolean scriptTag = false;
12164 String cb = request.getParameter("callback");
12165 if (cb != null) {
12166     scriptTag = true;
12167     response.setContentType("text/javascript");
12168 } else {
12169     response.setContentType("application/x-json");
12170 }
12171 Writer out = response.getWriter();
12172 if (scriptTag) {
12173     out.write(cb + "(");
12174 }
12175 out.print(dataBlock.toJsonString());
12176 if (scriptTag) {
12177     out.write(");");
12178 }
12179 </pre></code>
12180  *
12181  * @constructor
12182  * @param {Object} config A configuration object.
12183  */
12184 Roo.data.ScriptTagProxy = function(config){
12185     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12186     Roo.apply(this, config);
12187     this.head = document.getElementsByTagName("head")[0];
12188 };
12189
12190 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12191
12192 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12193     /**
12194      * @cfg {String} url The URL from which to request the data object.
12195      */
12196     /**
12197      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12198      */
12199     timeout : 30000,
12200     /**
12201      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12202      * the server the name of the callback function set up by the load call to process the returned data object.
12203      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12204      * javascript output which calls this named function passing the data object as its only parameter.
12205      */
12206     callbackParam : "callback",
12207     /**
12208      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12209      * name to the request.
12210      */
12211     nocache : true,
12212
12213     /**
12214      * Load data from the configured URL, read the data object into
12215      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12216      * process that block using the passed callback.
12217      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12218      * for the request to the remote server.
12219      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12220      * object into a block of Roo.data.Records.
12221      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12222      * The function must be passed <ul>
12223      * <li>The Record block object</li>
12224      * <li>The "arg" argument from the load function</li>
12225      * <li>A boolean success indicator</li>
12226      * </ul>
12227      * @param {Object} scope The scope in which to call the callback
12228      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12229      */
12230     load : function(params, reader, callback, scope, arg){
12231         if(this.fireEvent("beforeload", this, params) !== false){
12232
12233             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12234
12235             var url = this.url;
12236             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12237             if(this.nocache){
12238                 url += "&_dc=" + (new Date().getTime());
12239             }
12240             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12241             var trans = {
12242                 id : transId,
12243                 cb : "stcCallback"+transId,
12244                 scriptId : "stcScript"+transId,
12245                 params : params,
12246                 arg : arg,
12247                 url : url,
12248                 callback : callback,
12249                 scope : scope,
12250                 reader : reader
12251             };
12252             var conn = this;
12253
12254             window[trans.cb] = function(o){
12255                 conn.handleResponse(o, trans);
12256             };
12257
12258             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12259
12260             if(this.autoAbort !== false){
12261                 this.abort();
12262             }
12263
12264             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12265
12266             var script = document.createElement("script");
12267             script.setAttribute("src", url);
12268             script.setAttribute("type", "text/javascript");
12269             script.setAttribute("id", trans.scriptId);
12270             this.head.appendChild(script);
12271
12272             this.trans = trans;
12273         }else{
12274             callback.call(scope||this, null, arg, false);
12275         }
12276     },
12277
12278     // private
12279     isLoading : function(){
12280         return this.trans ? true : false;
12281     },
12282
12283     /**
12284      * Abort the current server request.
12285      */
12286     abort : function(){
12287         if(this.isLoading()){
12288             this.destroyTrans(this.trans);
12289         }
12290     },
12291
12292     // private
12293     destroyTrans : function(trans, isLoaded){
12294         this.head.removeChild(document.getElementById(trans.scriptId));
12295         clearTimeout(trans.timeoutId);
12296         if(isLoaded){
12297             window[trans.cb] = undefined;
12298             try{
12299                 delete window[trans.cb];
12300             }catch(e){}
12301         }else{
12302             // if hasn't been loaded, wait for load to remove it to prevent script error
12303             window[trans.cb] = function(){
12304                 window[trans.cb] = undefined;
12305                 try{
12306                     delete window[trans.cb];
12307                 }catch(e){}
12308             };
12309         }
12310     },
12311
12312     // private
12313     handleResponse : function(o, trans){
12314         this.trans = false;
12315         this.destroyTrans(trans, true);
12316         var result;
12317         try {
12318             result = trans.reader.readRecords(o);
12319         }catch(e){
12320             this.fireEvent("loadexception", this, o, trans.arg, e);
12321             trans.callback.call(trans.scope||window, null, trans.arg, false);
12322             return;
12323         }
12324         this.fireEvent("load", this, o, trans.arg);
12325         trans.callback.call(trans.scope||window, result, trans.arg, true);
12326     },
12327
12328     // private
12329     handleFailure : function(trans){
12330         this.trans = false;
12331         this.destroyTrans(trans, false);
12332         this.fireEvent("loadexception", this, null, trans.arg);
12333         trans.callback.call(trans.scope||window, null, trans.arg, false);
12334     }
12335 });/*
12336  * Based on:
12337  * Ext JS Library 1.1.1
12338  * Copyright(c) 2006-2007, Ext JS, LLC.
12339  *
12340  * Originally Released Under LGPL - original licence link has changed is not relivant.
12341  *
12342  * Fork - LGPL
12343  * <script type="text/javascript">
12344  */
12345
12346 /**
12347  * @class Roo.data.JsonReader
12348  * @extends Roo.data.DataReader
12349  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12350  * based on mappings in a provided Roo.data.Record constructor.
12351  * 
12352  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12353  * in the reply previously. 
12354  * 
12355  * <p>
12356  * Example code:
12357  * <pre><code>
12358 var RecordDef = Roo.data.Record.create([
12359     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
12360     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
12361 ]);
12362 var myReader = new Roo.data.JsonReader({
12363     totalProperty: "results",    // The property which contains the total dataset size (optional)
12364     root: "rows",                // The property which contains an Array of row objects
12365     id: "id"                     // The property within each row object that provides an ID for the record (optional)
12366 }, RecordDef);
12367 </code></pre>
12368  * <p>
12369  * This would consume a JSON file like this:
12370  * <pre><code>
12371 { 'results': 2, 'rows': [
12372     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12373     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12374 }
12375 </code></pre>
12376  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12377  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12378  * paged from the remote server.
12379  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12380  * @cfg {String} root name of the property which contains the Array of row objects.
12381  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12382  * @cfg {Array} fields Array of field definition objects
12383  * @constructor
12384  * Create a new JsonReader
12385  * @param {Object} meta Metadata configuration options
12386  * @param {Object} recordType Either an Array of field definition objects,
12387  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12388  */
12389 Roo.data.JsonReader = function(meta, recordType){
12390     
12391     meta = meta || {};
12392     // set some defaults:
12393     Roo.applyIf(meta, {
12394         totalProperty: 'total',
12395         successProperty : 'success',
12396         root : 'data',
12397         id : 'id'
12398     });
12399     
12400     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12401 };
12402 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12403     
12404     /**
12405      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
12406      * Used by Store query builder to append _requestMeta to params.
12407      * 
12408      */
12409     metaFromRemote : false,
12410     /**
12411      * This method is only used by a DataProxy which has retrieved data from a remote server.
12412      * @param {Object} response The XHR object which contains the JSON data in its responseText.
12413      * @return {Object} data A data block which is used by an Roo.data.Store object as
12414      * a cache of Roo.data.Records.
12415      */
12416     read : function(response){
12417         var json = response.responseText;
12418        
12419         var o = /* eval:var:o */ eval("("+json+")");
12420         if(!o) {
12421             throw {message: "JsonReader.read: Json object not found"};
12422         }
12423         
12424         if(o.metaData){
12425             
12426             delete this.ef;
12427             this.metaFromRemote = true;
12428             this.meta = o.metaData;
12429             this.recordType = Roo.data.Record.create(o.metaData.fields);
12430             this.onMetaChange(this.meta, this.recordType, o);
12431         }
12432         return this.readRecords(o);
12433     },
12434
12435     // private function a store will implement
12436     onMetaChange : function(meta, recordType, o){
12437
12438     },
12439
12440     /**
12441          * @ignore
12442          */
12443     simpleAccess: function(obj, subsc) {
12444         return obj[subsc];
12445     },
12446
12447         /**
12448          * @ignore
12449          */
12450     getJsonAccessor: function(){
12451         var re = /[\[\.]/;
12452         return function(expr) {
12453             try {
12454                 return(re.test(expr))
12455                     ? new Function("obj", "return obj." + expr)
12456                     : function(obj){
12457                         return obj[expr];
12458                     };
12459             } catch(e){}
12460             return Roo.emptyFn;
12461         };
12462     }(),
12463
12464     /**
12465      * Create a data block containing Roo.data.Records from an XML document.
12466      * @param {Object} o An object which contains an Array of row objects in the property specified
12467      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12468      * which contains the total size of the dataset.
12469      * @return {Object} data A data block which is used by an Roo.data.Store object as
12470      * a cache of Roo.data.Records.
12471      */
12472     readRecords : function(o){
12473         /**
12474          * After any data loads, the raw JSON data is available for further custom processing.
12475          * @type Object
12476          */
12477         this.o = o;
12478         var s = this.meta, Record = this.recordType,
12479             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12480
12481 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
12482         if (!this.ef) {
12483             if(s.totalProperty) {
12484                     this.getTotal = this.getJsonAccessor(s.totalProperty);
12485                 }
12486                 if(s.successProperty) {
12487                     this.getSuccess = this.getJsonAccessor(s.successProperty);
12488                 }
12489                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12490                 if (s.id) {
12491                         var g = this.getJsonAccessor(s.id);
12492                         this.getId = function(rec) {
12493                                 var r = g(rec);  
12494                                 return (r === undefined || r === "") ? null : r;
12495                         };
12496                 } else {
12497                         this.getId = function(){return null;};
12498                 }
12499             this.ef = [];
12500             for(var jj = 0; jj < fl; jj++){
12501                 f = fi[jj];
12502                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12503                 this.ef[jj] = this.getJsonAccessor(map);
12504             }
12505         }
12506
12507         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12508         if(s.totalProperty){
12509             var vt = parseInt(this.getTotal(o), 10);
12510             if(!isNaN(vt)){
12511                 totalRecords = vt;
12512             }
12513         }
12514         if(s.successProperty){
12515             var vs = this.getSuccess(o);
12516             if(vs === false || vs === 'false'){
12517                 success = false;
12518             }
12519         }
12520         var records = [];
12521         for(var i = 0; i < c; i++){
12522                 var n = root[i];
12523             var values = {};
12524             var id = this.getId(n);
12525             for(var j = 0; j < fl; j++){
12526                 f = fi[j];
12527             var v = this.ef[j](n);
12528             if (!f.convert) {
12529                 Roo.log('missing convert for ' + f.name);
12530                 Roo.log(f);
12531                 continue;
12532             }
12533             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12534             }
12535             var record = new Record(values, id);
12536             record.json = n;
12537             records[i] = record;
12538         }
12539         return {
12540             raw : o,
12541             success : success,
12542             records : records,
12543             totalRecords : totalRecords
12544         };
12545     }
12546 });/*
12547  * Based on:
12548  * Ext JS Library 1.1.1
12549  * Copyright(c) 2006-2007, Ext JS, LLC.
12550  *
12551  * Originally Released Under LGPL - original licence link has changed is not relivant.
12552  *
12553  * Fork - LGPL
12554  * <script type="text/javascript">
12555  */
12556
12557 /**
12558  * @class Roo.data.ArrayReader
12559  * @extends Roo.data.DataReader
12560  * Data reader class to create an Array of Roo.data.Record objects from an Array.
12561  * Each element of that Array represents a row of data fields. The
12562  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12563  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12564  * <p>
12565  * Example code:.
12566  * <pre><code>
12567 var RecordDef = Roo.data.Record.create([
12568     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
12569     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
12570 ]);
12571 var myReader = new Roo.data.ArrayReader({
12572     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
12573 }, RecordDef);
12574 </code></pre>
12575  * <p>
12576  * This would consume an Array like this:
12577  * <pre><code>
12578 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12579   </code></pre>
12580  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12581  * @constructor
12582  * Create a new JsonReader
12583  * @param {Object} meta Metadata configuration options.
12584  * @param {Object} recordType Either an Array of field definition objects
12585  * as specified to {@link Roo.data.Record#create},
12586  * or an {@link Roo.data.Record} object
12587  * created using {@link Roo.data.Record#create}.
12588  */
12589 Roo.data.ArrayReader = function(meta, recordType){
12590     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12591 };
12592
12593 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12594     /**
12595      * Create a data block containing Roo.data.Records from an XML document.
12596      * @param {Object} o An Array of row objects which represents the dataset.
12597      * @return {Object} data A data block which is used by an Roo.data.Store object as
12598      * a cache of Roo.data.Records.
12599      */
12600     readRecords : function(o){
12601         var sid = this.meta ? this.meta.id : null;
12602         var recordType = this.recordType, fields = recordType.prototype.fields;
12603         var records = [];
12604         var root = o;
12605             for(var i = 0; i < root.length; i++){
12606                     var n = root[i];
12607                 var values = {};
12608                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12609                 for(var j = 0, jlen = fields.length; j < jlen; j++){
12610                 var f = fields.items[j];
12611                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12612                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12613                 v = f.convert(v);
12614                 values[f.name] = v;
12615             }
12616                 var record = new recordType(values, id);
12617                 record.json = n;
12618                 records[records.length] = record;
12619             }
12620             return {
12621                 records : records,
12622                 totalRecords : records.length
12623             };
12624     }
12625 });/*
12626  * - LGPL
12627  * * 
12628  */
12629
12630 /**
12631  * @class Roo.bootstrap.ComboBox
12632  * @extends Roo.bootstrap.TriggerField
12633  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12634  * @cfg {Boolean} append (true|false) default false
12635  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12636  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12637  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12638  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12639  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12640  * @cfg {Boolean} animate default true
12641  * @cfg {Boolean} emptyResultText only for touch device
12642  * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12643  * @cfg {String} emptyTitle default ''
12644  * @constructor
12645  * Create a new ComboBox.
12646  * @param {Object} config Configuration options
12647  */
12648 Roo.bootstrap.ComboBox = function(config){
12649     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12650     this.addEvents({
12651         /**
12652          * @event expand
12653          * Fires when the dropdown list is expanded
12654         * @param {Roo.bootstrap.ComboBox} combo This combo box
12655         */
12656         'expand' : true,
12657         /**
12658          * @event collapse
12659          * Fires when the dropdown list is collapsed
12660         * @param {Roo.bootstrap.ComboBox} combo This combo box
12661         */
12662         'collapse' : true,
12663         /**
12664          * @event beforeselect
12665          * Fires before a list item is selected. Return false to cancel the selection.
12666         * @param {Roo.bootstrap.ComboBox} combo This combo box
12667         * @param {Roo.data.Record} record The data record returned from the underlying store
12668         * @param {Number} index The index of the selected item in the dropdown list
12669         */
12670         'beforeselect' : true,
12671         /**
12672          * @event select
12673          * Fires when a list item is selected
12674         * @param {Roo.bootstrap.ComboBox} combo This combo box
12675         * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12676         * @param {Number} index The index of the selected item in the dropdown list
12677         */
12678         'select' : true,
12679         /**
12680          * @event beforequery
12681          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12682          * The event object passed has these properties:
12683         * @param {Roo.bootstrap.ComboBox} combo This combo box
12684         * @param {String} query The query
12685         * @param {Boolean} forceAll true to force "all" query
12686         * @param {Boolean} cancel true to cancel the query
12687         * @param {Object} e The query event object
12688         */
12689         'beforequery': true,
12690          /**
12691          * @event add
12692          * Fires when the 'add' icon is pressed (add a listener to enable add button)
12693         * @param {Roo.bootstrap.ComboBox} combo This combo box
12694         */
12695         'add' : true,
12696         /**
12697          * @event edit
12698          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12699         * @param {Roo.bootstrap.ComboBox} combo This combo box
12700         * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12701         */
12702         'edit' : true,
12703         /**
12704          * @event remove
12705          * Fires when the remove value from the combobox array
12706         * @param {Roo.bootstrap.ComboBox} combo This combo box
12707         */
12708         'remove' : true,
12709         /**
12710          * @event afterremove
12711          * Fires when the remove value from the combobox array
12712         * @param {Roo.bootstrap.ComboBox} combo This combo box
12713         */
12714         'afterremove' : true,
12715         /**
12716          * @event specialfilter
12717          * Fires when specialfilter
12718             * @param {Roo.bootstrap.ComboBox} combo This combo box
12719             */
12720         'specialfilter' : true,
12721         /**
12722          * @event tick
12723          * Fires when tick the element
12724             * @param {Roo.bootstrap.ComboBox} combo This combo box
12725             */
12726         'tick' : true,
12727         /**
12728          * @event touchviewdisplay
12729          * Fires when touch view require special display (default is using displayField)
12730             * @param {Roo.bootstrap.ComboBox} combo This combo box
12731             * @param {Object} cfg set html .
12732             */
12733         'touchviewdisplay' : true
12734         
12735     });
12736     
12737     this.item = [];
12738     this.tickItems = [];
12739     
12740     this.selectedIndex = -1;
12741     if(this.mode == 'local'){
12742         if(config.queryDelay === undefined){
12743             this.queryDelay = 10;
12744         }
12745         if(config.minChars === undefined){
12746             this.minChars = 0;
12747         }
12748     }
12749 };
12750
12751 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12752      
12753     /**
12754      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12755      * rendering into an Roo.Editor, defaults to false)
12756      */
12757     /**
12758      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12759      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12760      */
12761     /**
12762      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12763      */
12764     /**
12765      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12766      * the dropdown list (defaults to undefined, with no header element)
12767      */
12768
12769      /**
12770      * @cfg {String/Roo.Template} tpl The template to use to render the output
12771      */
12772      
12773      /**
12774      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12775      */
12776     listWidth: undefined,
12777     /**
12778      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12779      * mode = 'remote' or 'text' if mode = 'local')
12780      */
12781     displayField: undefined,
12782     
12783     /**
12784      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12785      * mode = 'remote' or 'value' if mode = 'local'). 
12786      * Note: use of a valueField requires the user make a selection
12787      * in order for a value to be mapped.
12788      */
12789     valueField: undefined,
12790     /**
12791      * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12792      */
12793     modalTitle : '',
12794     
12795     /**
12796      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12797      * field's data value (defaults to the underlying DOM element's name)
12798      */
12799     hiddenName: undefined,
12800     /**
12801      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12802      */
12803     listClass: '',
12804     /**
12805      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12806      */
12807     selectedClass: 'active',
12808     
12809     /**
12810      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12811      */
12812     shadow:'sides',
12813     /**
12814      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12815      * anchor positions (defaults to 'tl-bl')
12816      */
12817     listAlign: 'tl-bl?',
12818     /**
12819      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12820      */
12821     maxHeight: 300,
12822     /**
12823      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
12824      * query specified by the allQuery config option (defaults to 'query')
12825      */
12826     triggerAction: 'query',
12827     /**
12828      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12829      * (defaults to 4, does not apply if editable = false)
12830      */
12831     minChars : 4,
12832     /**
12833      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12834      * delay (typeAheadDelay) if it matches a known value (defaults to false)
12835      */
12836     typeAhead: false,
12837     /**
12838      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12839      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12840      */
12841     queryDelay: 500,
12842     /**
12843      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12844      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
12845      */
12846     pageSize: 0,
12847     /**
12848      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
12849      * when editable = true (defaults to false)
12850      */
12851     selectOnFocus:false,
12852     /**
12853      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12854      */
12855     queryParam: 'query',
12856     /**
12857      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
12858      * when mode = 'remote' (defaults to 'Loading...')
12859      */
12860     loadingText: 'Loading...',
12861     /**
12862      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12863      */
12864     resizable: false,
12865     /**
12866      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12867      */
12868     handleHeight : 8,
12869     /**
12870      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12871      * traditional select (defaults to true)
12872      */
12873     editable: true,
12874     /**
12875      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12876      */
12877     allQuery: '',
12878     /**
12879      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12880      */
12881     mode: 'remote',
12882     /**
12883      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12884      * listWidth has a higher value)
12885      */
12886     minListWidth : 70,
12887     /**
12888      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12889      * allow the user to set arbitrary text into the field (defaults to false)
12890      */
12891     forceSelection:false,
12892     /**
12893      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12894      * if typeAhead = true (defaults to 250)
12895      */
12896     typeAheadDelay : 250,
12897     /**
12898      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12899      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12900      */
12901     valueNotFoundText : undefined,
12902     /**
12903      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12904      */
12905     blockFocus : false,
12906     
12907     /**
12908      * @cfg {Boolean} disableClear Disable showing of clear button.
12909      */
12910     disableClear : false,
12911     /**
12912      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
12913      */
12914     alwaysQuery : false,
12915     
12916     /**
12917      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
12918      */
12919     multiple : false,
12920     
12921     /**
12922      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12923      */
12924     invalidClass : "has-warning",
12925     
12926     /**
12927      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12928      */
12929     validClass : "has-success",
12930     
12931     /**
12932      * @cfg {Boolean} specialFilter (true|false) special filter default false
12933      */
12934     specialFilter : false,
12935     
12936     /**
12937      * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12938      */
12939     mobileTouchView : true,
12940     
12941     /**
12942      * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12943      */
12944     useNativeIOS : false,
12945     
12946     ios_options : false,
12947     
12948     //private
12949     addicon : false,
12950     editicon: false,
12951     
12952     page: 0,
12953     hasQuery: false,
12954     append: false,
12955     loadNext: false,
12956     autoFocus : true,
12957     tickable : false,
12958     btnPosition : 'right',
12959     triggerList : true,
12960     showToggleBtn : true,
12961     animate : true,
12962     emptyResultText: 'Empty',
12963     triggerText : 'Select',
12964     emptyTitle : '',
12965     
12966     // element that contains real text value.. (when hidden is used..)
12967     
12968     getAutoCreate : function()
12969     {   
12970         var cfg = false;
12971         //render
12972         /*
12973          * Render classic select for iso
12974          */
12975         
12976         if(Roo.isIOS && this.useNativeIOS){
12977             cfg = this.getAutoCreateNativeIOS();
12978             return cfg;
12979         }
12980         
12981         /*
12982          * Touch Devices
12983          */
12984         
12985         if(Roo.isTouch && this.mobileTouchView){
12986             cfg = this.getAutoCreateTouchView();
12987             return cfg;;
12988         }
12989         
12990         /*
12991          *  Normal ComboBox
12992          */
12993         if(!this.tickable){
12994             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12995             return cfg;
12996         }
12997         
12998         /*
12999          *  ComboBox with tickable selections
13000          */
13001              
13002         var align = this.labelAlign || this.parentLabelAlign();
13003         
13004         cfg = {
13005             cls : 'form-group roo-combobox-tickable' //input-group
13006         };
13007         
13008         var btn_text_select = '';
13009         var btn_text_done = '';
13010         var btn_text_cancel = '';
13011         
13012         if (this.btn_text_show) {
13013             btn_text_select = 'Select';
13014             btn_text_done = 'Done';
13015             btn_text_cancel = 'Cancel'; 
13016         }
13017         
13018         var buttons = {
13019             tag : 'div',
13020             cls : 'tickable-buttons',
13021             cn : [
13022                 {
13023                     tag : 'button',
13024                     type : 'button',
13025                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13026                     //html : this.triggerText
13027                     html: btn_text_select
13028                 },
13029                 {
13030                     tag : 'button',
13031                     type : 'button',
13032                     name : 'ok',
13033                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13034                     //html : 'Done'
13035                     html: btn_text_done
13036                 },
13037                 {
13038                     tag : 'button',
13039                     type : 'button',
13040                     name : 'cancel',
13041                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13042                     //html : 'Cancel'
13043                     html: btn_text_cancel
13044                 }
13045             ]
13046         };
13047         
13048         if(this.editable){
13049             buttons.cn.unshift({
13050                 tag: 'input',
13051                 cls: 'roo-select2-search-field-input'
13052             });
13053         }
13054         
13055         var _this = this;
13056         
13057         Roo.each(buttons.cn, function(c){
13058             if (_this.size) {
13059                 c.cls += ' btn-' + _this.size;
13060             }
13061
13062             if (_this.disabled) {
13063                 c.disabled = true;
13064             }
13065         });
13066         
13067         var box = {
13068             tag: 'div',
13069             cn: [
13070                 {
13071                     tag: 'input',
13072                     type : 'hidden',
13073                     cls: 'form-hidden-field'
13074                 },
13075                 {
13076                     tag: 'ul',
13077                     cls: 'roo-select2-choices',
13078                     cn:[
13079                         {
13080                             tag: 'li',
13081                             cls: 'roo-select2-search-field',
13082                             cn: [
13083                                 buttons
13084                             ]
13085                         }
13086                     ]
13087                 }
13088             ]
13089         };
13090         
13091         var combobox = {
13092             cls: 'roo-select2-container input-group roo-select2-container-multi',
13093             cn: [
13094                 box
13095 //                {
13096 //                    tag: 'ul',
13097 //                    cls: 'typeahead typeahead-long dropdown-menu',
13098 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
13099 //                }
13100             ]
13101         };
13102         
13103         if(this.hasFeedback && !this.allowBlank){
13104             
13105             var feedback = {
13106                 tag: 'span',
13107                 cls: 'glyphicon form-control-feedback'
13108             };
13109
13110             combobox.cn.push(feedback);
13111         }
13112         
13113         
13114         if (align ==='left' && this.fieldLabel.length) {
13115             
13116             cfg.cls += ' roo-form-group-label-left';
13117             
13118             cfg.cn = [
13119                 {
13120                     tag : 'i',
13121                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13122                     tooltip : 'This field is required'
13123                 },
13124                 {
13125                     tag: 'label',
13126                     'for' :  id,
13127                     cls : 'control-label',
13128                     html : this.fieldLabel
13129
13130                 },
13131                 {
13132                     cls : "", 
13133                     cn: [
13134                         combobox
13135                     ]
13136                 }
13137
13138             ];
13139             
13140             var labelCfg = cfg.cn[1];
13141             var contentCfg = cfg.cn[2];
13142             
13143
13144             if(this.indicatorpos == 'right'){
13145                 
13146                 cfg.cn = [
13147                     {
13148                         tag: 'label',
13149                         'for' :  id,
13150                         cls : 'control-label',
13151                         cn : [
13152                             {
13153                                 tag : 'span',
13154                                 html : this.fieldLabel
13155                             },
13156                             {
13157                                 tag : 'i',
13158                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13159                                 tooltip : 'This field is required'
13160                             }
13161                         ]
13162                     },
13163                     {
13164                         cls : "",
13165                         cn: [
13166                             combobox
13167                         ]
13168                     }
13169
13170                 ];
13171                 
13172                 
13173                 
13174                 labelCfg = cfg.cn[0];
13175                 contentCfg = cfg.cn[1];
13176             
13177             }
13178             
13179             if(this.labelWidth > 12){
13180                 labelCfg.style = "width: " + this.labelWidth + 'px';
13181             }
13182             
13183             if(this.labelWidth < 13 && this.labelmd == 0){
13184                 this.labelmd = this.labelWidth;
13185             }
13186             
13187             if(this.labellg > 0){
13188                 labelCfg.cls += ' col-lg-' + this.labellg;
13189                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13190             }
13191             
13192             if(this.labelmd > 0){
13193                 labelCfg.cls += ' col-md-' + this.labelmd;
13194                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13195             }
13196             
13197             if(this.labelsm > 0){
13198                 labelCfg.cls += ' col-sm-' + this.labelsm;
13199                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13200             }
13201             
13202             if(this.labelxs > 0){
13203                 labelCfg.cls += ' col-xs-' + this.labelxs;
13204                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13205             }
13206                 
13207                 
13208         } else if ( this.fieldLabel.length) {
13209 //                Roo.log(" label");
13210                  cfg.cn = [
13211                     {
13212                         tag : 'i',
13213                         cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13214                         tooltip : 'This field is required'
13215                     },
13216                     {
13217                         tag: 'label',
13218                         //cls : 'input-group-addon',
13219                         html : this.fieldLabel
13220                     },
13221                     combobox
13222                 ];
13223                 
13224                 if(this.indicatorpos == 'right'){
13225                     cfg.cn = [
13226                         {
13227                             tag: 'label',
13228                             //cls : 'input-group-addon',
13229                             html : this.fieldLabel
13230                         },
13231                         {
13232                             tag : 'i',
13233                             cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13234                             tooltip : 'This field is required'
13235                         },
13236                         combobox
13237                     ];
13238                     
13239                 }
13240
13241         } else {
13242             
13243 //                Roo.log(" no label && no align");
13244                 cfg = combobox
13245                      
13246                 
13247         }
13248          
13249         var settings=this;
13250         ['xs','sm','md','lg'].map(function(size){
13251             if (settings[size]) {
13252                 cfg.cls += ' col-' + size + '-' + settings[size];
13253             }
13254         });
13255         
13256         return cfg;
13257         
13258     },
13259     
13260     _initEventsCalled : false,
13261     
13262     // private
13263     initEvents: function()
13264     {   
13265         if (this._initEventsCalled) { // as we call render... prevent looping...
13266             return;
13267         }
13268         this._initEventsCalled = true;
13269         
13270         if (!this.store) {
13271             throw "can not find store for combo";
13272         }
13273         
13274         this.indicator = this.indicatorEl();
13275         
13276         this.store = Roo.factory(this.store, Roo.data);
13277         this.store.parent = this;
13278         
13279         // if we are building from html. then this element is so complex, that we can not really
13280         // use the rendered HTML.
13281         // so we have to trash and replace the previous code.
13282         if (Roo.XComponent.build_from_html) {
13283             // remove this element....
13284             var e = this.el.dom, k=0;
13285             while (e ) { e = e.previousSibling;  ++k;}
13286
13287             this.el.remove();
13288             
13289             this.el=false;
13290             this.rendered = false;
13291             
13292             this.render(this.parent().getChildContainer(true), k);
13293         }
13294         
13295         if(Roo.isIOS && this.useNativeIOS){
13296             this.initIOSView();
13297             return;
13298         }
13299         
13300         /*
13301          * Touch Devices
13302          */
13303         
13304         if(Roo.isTouch && this.mobileTouchView){
13305             this.initTouchView();
13306             return;
13307         }
13308         
13309         if(this.tickable){
13310             this.initTickableEvents();
13311             return;
13312         }
13313         
13314         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13315         
13316         if(this.hiddenName){
13317             
13318             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13319             
13320             this.hiddenField.dom.value =
13321                 this.hiddenValue !== undefined ? this.hiddenValue :
13322                 this.value !== undefined ? this.value : '';
13323
13324             // prevent input submission
13325             this.el.dom.removeAttribute('name');
13326             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13327              
13328              
13329         }
13330         //if(Roo.isGecko){
13331         //    this.el.dom.setAttribute('autocomplete', 'off');
13332         //}
13333         
13334         var cls = 'x-combo-list';
13335         
13336         //this.list = new Roo.Layer({
13337         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13338         //});
13339         
13340         var _this = this;
13341         
13342         (function(){
13343             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13344             _this.list.setWidth(lw);
13345         }).defer(100);
13346         
13347         this.list.on('mouseover', this.onViewOver, this);
13348         this.list.on('mousemove', this.onViewMove, this);
13349         this.list.on('scroll', this.onViewScroll, this);
13350         
13351         /*
13352         this.list.swallowEvent('mousewheel');
13353         this.assetHeight = 0;
13354
13355         if(this.title){
13356             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13357             this.assetHeight += this.header.getHeight();
13358         }
13359
13360         this.innerList = this.list.createChild({cls:cls+'-inner'});
13361         this.innerList.on('mouseover', this.onViewOver, this);
13362         this.innerList.on('mousemove', this.onViewMove, this);
13363         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13364         
13365         if(this.allowBlank && !this.pageSize && !this.disableClear){
13366             this.footer = this.list.createChild({cls:cls+'-ft'});
13367             this.pageTb = new Roo.Toolbar(this.footer);
13368            
13369         }
13370         if(this.pageSize){
13371             this.footer = this.list.createChild({cls:cls+'-ft'});
13372             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13373                     {pageSize: this.pageSize});
13374             
13375         }
13376         
13377         if (this.pageTb && this.allowBlank && !this.disableClear) {
13378             var _this = this;
13379             this.pageTb.add(new Roo.Toolbar.Fill(), {
13380                 cls: 'x-btn-icon x-btn-clear',
13381                 text: '&#160;',
13382                 handler: function()
13383                 {
13384                     _this.collapse();
13385                     _this.clearValue();
13386                     _this.onSelect(false, -1);
13387                 }
13388             });
13389         }
13390         if (this.footer) {
13391             this.assetHeight += this.footer.getHeight();
13392         }
13393         */
13394             
13395         if(!this.tpl){
13396             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13397         }
13398
13399         this.view = new Roo.View(this.list, this.tpl, {
13400             singleSelect:true, store: this.store, selectedClass: this.selectedClass
13401         });
13402         //this.view.wrapEl.setDisplayed(false);
13403         this.view.on('click', this.onViewClick, this);
13404         
13405         
13406         this.store.on('beforeload', this.onBeforeLoad, this);
13407         this.store.on('load', this.onLoad, this);
13408         this.store.on('loadexception', this.onLoadException, this);
13409         /*
13410         if(this.resizable){
13411             this.resizer = new Roo.Resizable(this.list,  {
13412                pinned:true, handles:'se'
13413             });
13414             this.resizer.on('resize', function(r, w, h){
13415                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13416                 this.listWidth = w;
13417                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13418                 this.restrictHeight();
13419             }, this);
13420             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13421         }
13422         */
13423         if(!this.editable){
13424             this.editable = true;
13425             this.setEditable(false);
13426         }
13427         
13428         /*
13429         
13430         if (typeof(this.events.add.listeners) != 'undefined') {
13431             
13432             this.addicon = this.wrap.createChild(
13433                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
13434        
13435             this.addicon.on('click', function(e) {
13436                 this.fireEvent('add', this);
13437             }, this);
13438         }
13439         if (typeof(this.events.edit.listeners) != 'undefined') {
13440             
13441             this.editicon = this.wrap.createChild(
13442                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
13443             if (this.addicon) {
13444                 this.editicon.setStyle('margin-left', '40px');
13445             }
13446             this.editicon.on('click', function(e) {
13447                 
13448                 // we fire even  if inothing is selected..
13449                 this.fireEvent('edit', this, this.lastData );
13450                 
13451             }, this);
13452         }
13453         */
13454         
13455         this.keyNav = new Roo.KeyNav(this.inputEl(), {
13456             "up" : function(e){
13457                 this.inKeyMode = true;
13458                 this.selectPrev();
13459             },
13460
13461             "down" : function(e){
13462                 if(!this.isExpanded()){
13463                     this.onTriggerClick();
13464                 }else{
13465                     this.inKeyMode = true;
13466                     this.selectNext();
13467                 }
13468             },
13469
13470             "enter" : function(e){
13471 //                this.onViewClick();
13472                 //return true;
13473                 this.collapse();
13474                 
13475                 if(this.fireEvent("specialkey", this, e)){
13476                     this.onViewClick(false);
13477                 }
13478                 
13479                 return true;
13480             },
13481
13482             "esc" : function(e){
13483                 this.collapse();
13484             },
13485
13486             "tab" : function(e){
13487                 this.collapse();
13488                 
13489                 if(this.fireEvent("specialkey", this, e)){
13490                     this.onViewClick(false);
13491                 }
13492                 
13493                 return true;
13494             },
13495
13496             scope : this,
13497
13498             doRelay : function(foo, bar, hname){
13499                 if(hname == 'down' || this.scope.isExpanded()){
13500                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13501                 }
13502                 return true;
13503             },
13504
13505             forceKeyDown: true
13506         });
13507         
13508         
13509         this.queryDelay = Math.max(this.queryDelay || 10,
13510                 this.mode == 'local' ? 10 : 250);
13511         
13512         
13513         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13514         
13515         if(this.typeAhead){
13516             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13517         }
13518         if(this.editable !== false){
13519             this.inputEl().on("keyup", this.onKeyUp, this);
13520         }
13521         if(this.forceSelection){
13522             this.inputEl().on('blur', this.doForce, this);
13523         }
13524         
13525         if(this.multiple){
13526             this.choices = this.el.select('ul.roo-select2-choices', true).first();
13527             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13528         }
13529     },
13530     
13531     initTickableEvents: function()
13532     {   
13533         this.createList();
13534         
13535         if(this.hiddenName){
13536             
13537             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13538             
13539             this.hiddenField.dom.value =
13540                 this.hiddenValue !== undefined ? this.hiddenValue :
13541                 this.value !== undefined ? this.value : '';
13542
13543             // prevent input submission
13544             this.el.dom.removeAttribute('name');
13545             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13546              
13547              
13548         }
13549         
13550 //        this.list = this.el.select('ul.dropdown-menu',true).first();
13551         
13552         this.choices = this.el.select('ul.roo-select2-choices', true).first();
13553         this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13554         if(this.triggerList){
13555             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13556         }
13557          
13558         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13559         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13560         
13561         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13562         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13563         
13564         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13565         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13566         
13567         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13568         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13569         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13570         
13571         this.okBtn.hide();
13572         this.cancelBtn.hide();
13573         
13574         var _this = this;
13575         
13576         (function(){
13577             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13578             _this.list.setWidth(lw);
13579         }).defer(100);
13580         
13581         this.list.on('mouseover', this.onViewOver, this);
13582         this.list.on('mousemove', this.onViewMove, this);
13583         
13584         this.list.on('scroll', this.onViewScroll, this);
13585         
13586         if(!this.tpl){
13587             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>';
13588         }
13589
13590         this.view = new Roo.View(this.list, this.tpl, {
13591             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13592         });
13593         
13594         //this.view.wrapEl.setDisplayed(false);
13595         this.view.on('click', this.onViewClick, this);
13596         
13597         
13598         
13599         this.store.on('beforeload', this.onBeforeLoad, this);
13600         this.store.on('load', this.onLoad, this);
13601         this.store.on('loadexception', this.onLoadException, this);
13602         
13603         if(this.editable){
13604             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13605                 "up" : function(e){
13606                     this.inKeyMode = true;
13607                     this.selectPrev();
13608                 },
13609
13610                 "down" : function(e){
13611                     this.inKeyMode = true;
13612                     this.selectNext();
13613                 },
13614
13615                 "enter" : function(e){
13616                     if(this.fireEvent("specialkey", this, e)){
13617                         this.onViewClick(false);
13618                     }
13619                     
13620                     return true;
13621                 },
13622
13623                 "esc" : function(e){
13624                     this.onTickableFooterButtonClick(e, false, false);
13625                 },
13626
13627                 "tab" : function(e){
13628                     this.fireEvent("specialkey", this, e);
13629                     
13630                     this.onTickableFooterButtonClick(e, false, false);
13631                     
13632                     return true;
13633                 },
13634
13635                 scope : this,
13636
13637                 doRelay : function(e, fn, key){
13638                     if(this.scope.isExpanded()){
13639                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13640                     }
13641                     return true;
13642                 },
13643
13644                 forceKeyDown: true
13645             });
13646         }
13647         
13648         this.queryDelay = Math.max(this.queryDelay || 10,
13649                 this.mode == 'local' ? 10 : 250);
13650         
13651         
13652         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13653         
13654         if(this.typeAhead){
13655             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13656         }
13657         
13658         if(this.editable !== false){
13659             this.tickableInputEl().on("keyup", this.onKeyUp, this);
13660         }
13661         
13662         this.indicator = this.indicatorEl();
13663         
13664         if(this.indicator){
13665             this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13666             this.indicator.hide();
13667         }
13668         
13669     },
13670
13671     onDestroy : function(){
13672         if(this.view){
13673             this.view.setStore(null);
13674             this.view.el.removeAllListeners();
13675             this.view.el.remove();
13676             this.view.purgeListeners();
13677         }
13678         if(this.list){
13679             this.list.dom.innerHTML  = '';
13680         }
13681         
13682         if(this.store){
13683             this.store.un('beforeload', this.onBeforeLoad, this);
13684             this.store.un('load', this.onLoad, this);
13685             this.store.un('loadexception', this.onLoadException, this);
13686         }
13687         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13688     },
13689
13690     // private
13691     fireKey : function(e){
13692         if(e.isNavKeyPress() && !this.list.isVisible()){
13693             this.fireEvent("specialkey", this, e);
13694         }
13695     },
13696
13697     // private
13698     onResize: function(w, h){
13699 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13700 //        
13701 //        if(typeof w != 'number'){
13702 //            // we do not handle it!?!?
13703 //            return;
13704 //        }
13705 //        var tw = this.trigger.getWidth();
13706 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
13707 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
13708 //        var x = w - tw;
13709 //        this.inputEl().setWidth( this.adjustWidth('input', x));
13710 //            
13711 //        //this.trigger.setStyle('left', x+'px');
13712 //        
13713 //        if(this.list && this.listWidth === undefined){
13714 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13715 //            this.list.setWidth(lw);
13716 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13717 //        }
13718         
13719     
13720         
13721     },
13722
13723     /**
13724      * Allow or prevent the user from directly editing the field text.  If false is passed,
13725      * the user will only be able to select from the items defined in the dropdown list.  This method
13726      * is the runtime equivalent of setting the 'editable' config option at config time.
13727      * @param {Boolean} value True to allow the user to directly edit the field text
13728      */
13729     setEditable : function(value){
13730         if(value == this.editable){
13731             return;
13732         }
13733         this.editable = value;
13734         if(!value){
13735             this.inputEl().dom.setAttribute('readOnly', true);
13736             this.inputEl().on('mousedown', this.onTriggerClick,  this);
13737             this.inputEl().addClass('x-combo-noedit');
13738         }else{
13739             this.inputEl().dom.setAttribute('readOnly', false);
13740             this.inputEl().un('mousedown', this.onTriggerClick,  this);
13741             this.inputEl().removeClass('x-combo-noedit');
13742         }
13743     },
13744
13745     // private
13746     
13747     onBeforeLoad : function(combo,opts){
13748         if(!this.hasFocus){
13749             return;
13750         }
13751          if (!opts.add) {
13752             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13753          }
13754         this.restrictHeight();
13755         this.selectedIndex = -1;
13756     },
13757
13758     // private
13759     onLoad : function(){
13760         
13761         this.hasQuery = false;
13762         
13763         if(!this.hasFocus){
13764             return;
13765         }
13766         
13767         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13768             this.loading.hide();
13769         }
13770         
13771         if(this.store.getCount() > 0){
13772             
13773             this.expand();
13774             this.restrictHeight();
13775             if(this.lastQuery == this.allQuery){
13776                 if(this.editable && !this.tickable){
13777                     this.inputEl().dom.select();
13778                 }
13779                 
13780                 if(
13781                     !this.selectByValue(this.value, true) &&
13782                     this.autoFocus && 
13783                     (
13784                         !this.store.lastOptions ||
13785                         typeof(this.store.lastOptions.add) == 'undefined' || 
13786                         this.store.lastOptions.add != true
13787                     )
13788                 ){
13789                     this.select(0, true);
13790                 }
13791             }else{
13792                 if(this.autoFocus){
13793                     this.selectNext();
13794                 }
13795                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13796                     this.taTask.delay(this.typeAheadDelay);
13797                 }
13798             }
13799         }else{
13800             this.onEmptyResults();
13801         }
13802         
13803         //this.el.focus();
13804     },
13805     // private
13806     onLoadException : function()
13807     {
13808         this.hasQuery = false;
13809         
13810         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13811             this.loading.hide();
13812         }
13813         
13814         if(this.tickable && this.editable){
13815             return;
13816         }
13817         
13818         this.collapse();
13819         // only causes errors at present
13820         //Roo.log(this.store.reader.jsonData);
13821         //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13822             // fixme
13823             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13824         //}
13825         
13826         
13827     },
13828     // private
13829     onTypeAhead : function(){
13830         if(this.store.getCount() > 0){
13831             var r = this.store.getAt(0);
13832             var newValue = r.data[this.displayField];
13833             var len = newValue.length;
13834             var selStart = this.getRawValue().length;
13835             
13836             if(selStart != len){
13837                 this.setRawValue(newValue);
13838                 this.selectText(selStart, newValue.length);
13839             }
13840         }
13841     },
13842
13843     // private
13844     onSelect : function(record, index){
13845         
13846         if(this.fireEvent('beforeselect', this, record, index) !== false){
13847         
13848             this.setFromData(index > -1 ? record.data : false);
13849             
13850             this.collapse();
13851             this.fireEvent('select', this, record, index);
13852         }
13853     },
13854
13855     /**
13856      * Returns the currently selected field value or empty string if no value is set.
13857      * @return {String} value The selected value
13858      */
13859     getValue : function()
13860     {
13861         if(Roo.isIOS && this.useNativeIOS){
13862             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13863         }
13864         
13865         if(this.multiple){
13866             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13867         }
13868         
13869         if(this.valueField){
13870             return typeof this.value != 'undefined' ? this.value : '';
13871         }else{
13872             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13873         }
13874     },
13875     
13876     getRawValue : function()
13877     {
13878         if(Roo.isIOS && this.useNativeIOS){
13879             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13880         }
13881         
13882         var v = this.inputEl().getValue();
13883         
13884         return v;
13885     },
13886
13887     /**
13888      * Clears any text/value currently set in the field
13889      */
13890     clearValue : function(){
13891         
13892         if(this.hiddenField){
13893             this.hiddenField.dom.value = '';
13894         }
13895         this.value = '';
13896         this.setRawValue('');
13897         this.lastSelectionText = '';
13898         this.lastData = false;
13899         
13900         var close = this.closeTriggerEl();
13901         
13902         if(close){
13903             close.hide();
13904         }
13905         
13906         this.validate();
13907         
13908     },
13909
13910     /**
13911      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
13912      * will be displayed in the field.  If the value does not match the data value of an existing item,
13913      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13914      * Otherwise the field will be blank (although the value will still be set).
13915      * @param {String} value The value to match
13916      */
13917     setValue : function(v)
13918     {
13919         if(Roo.isIOS && this.useNativeIOS){
13920             this.setIOSValue(v);
13921             return;
13922         }
13923         
13924         if(this.multiple){
13925             this.syncValue();
13926             return;
13927         }
13928         
13929         var text = v;
13930         if(this.valueField){
13931             var r = this.findRecord(this.valueField, v);
13932             if(r){
13933                 text = r.data[this.displayField];
13934             }else if(this.valueNotFoundText !== undefined){
13935                 text = this.valueNotFoundText;
13936             }
13937         }
13938         this.lastSelectionText = text;
13939         if(this.hiddenField){
13940             this.hiddenField.dom.value = v;
13941         }
13942         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13943         this.value = v;
13944         
13945         var close = this.closeTriggerEl();
13946         
13947         if(close){
13948             (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13949         }
13950         
13951         this.validate();
13952     },
13953     /**
13954      * @property {Object} the last set data for the element
13955      */
13956     
13957     lastData : false,
13958     /**
13959      * Sets the value of the field based on a object which is related to the record format for the store.
13960      * @param {Object} value the value to set as. or false on reset?
13961      */
13962     setFromData : function(o){
13963         
13964         if(this.multiple){
13965             this.addItem(o);
13966             return;
13967         }
13968             
13969         var dv = ''; // display value
13970         var vv = ''; // value value..
13971         this.lastData = o;
13972         if (this.displayField) {
13973             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13974         } else {
13975             // this is an error condition!!!
13976             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
13977         }
13978         
13979         if(this.valueField){
13980             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13981         }
13982         
13983         var close = this.closeTriggerEl();
13984         
13985         if(close){
13986             if(dv.length || vv * 1 > 0){
13987                 close.show() ;
13988                 this.blockFocus=true;
13989             } else {
13990                 close.hide();
13991             }             
13992         }
13993         
13994         if(this.hiddenField){
13995             this.hiddenField.dom.value = vv;
13996             
13997             this.lastSelectionText = dv;
13998             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13999             this.value = vv;
14000             return;
14001         }
14002         // no hidden field.. - we store the value in 'value', but still display
14003         // display field!!!!
14004         this.lastSelectionText = dv;
14005         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14006         this.value = vv;
14007         
14008         
14009         
14010     },
14011     // private
14012     reset : function(){
14013         // overridden so that last data is reset..
14014         
14015         if(this.multiple){
14016             this.clearItem();
14017             return;
14018         }
14019         
14020         this.setValue(this.originalValue);
14021         //this.clearInvalid();
14022         this.lastData = false;
14023         if (this.view) {
14024             this.view.clearSelections();
14025         }
14026         
14027         this.validate();
14028     },
14029     // private
14030     findRecord : function(prop, value){
14031         var record;
14032         if(this.store.getCount() > 0){
14033             this.store.each(function(r){
14034                 if(r.data[prop] == value){
14035                     record = r;
14036                     return false;
14037                 }
14038                 return true;
14039             });
14040         }
14041         return record;
14042     },
14043     
14044     getName: function()
14045     {
14046         // returns hidden if it's set..
14047         if (!this.rendered) {return ''};
14048         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
14049         
14050     },
14051     // private
14052     onViewMove : function(e, t){
14053         this.inKeyMode = false;
14054     },
14055
14056     // private
14057     onViewOver : function(e, t){
14058         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14059             return;
14060         }
14061         var item = this.view.findItemFromChild(t);
14062         
14063         if(item){
14064             var index = this.view.indexOf(item);
14065             this.select(index, false);
14066         }
14067     },
14068
14069     // private
14070     onViewClick : function(view, doFocus, el, e)
14071     {
14072         var index = this.view.getSelectedIndexes()[0];
14073         
14074         var r = this.store.getAt(index);
14075         
14076         if(this.tickable){
14077             
14078             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14079                 return;
14080             }
14081             
14082             var rm = false;
14083             var _this = this;
14084             
14085             Roo.each(this.tickItems, function(v,k){
14086                 
14087                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14088                     Roo.log(v);
14089                     _this.tickItems.splice(k, 1);
14090                     
14091                     if(typeof(e) == 'undefined' && view == false){
14092                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14093                     }
14094                     
14095                     rm = true;
14096                     return;
14097                 }
14098             });
14099             
14100             if(rm){
14101                 return;
14102             }
14103             
14104             if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14105                 this.tickItems.push(r.data);
14106             }
14107             
14108             if(typeof(e) == 'undefined' && view == false){
14109                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14110             }
14111                     
14112             return;
14113         }
14114         
14115         if(r){
14116             this.onSelect(r, index);
14117         }
14118         if(doFocus !== false && !this.blockFocus){
14119             this.inputEl().focus();
14120         }
14121     },
14122
14123     // private
14124     restrictHeight : function(){
14125         //this.innerList.dom.style.height = '';
14126         //var inner = this.innerList.dom;
14127         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14128         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14129         //this.list.beginUpdate();
14130         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14131         this.list.alignTo(this.inputEl(), this.listAlign);
14132         this.list.alignTo(this.inputEl(), this.listAlign);
14133         //this.list.endUpdate();
14134     },
14135
14136     // private
14137     onEmptyResults : function(){
14138         
14139         if(this.tickable && this.editable){
14140             this.hasFocus = false;
14141             this.restrictHeight();
14142             return;
14143         }
14144         
14145         this.collapse();
14146     },
14147
14148     /**
14149      * Returns true if the dropdown list is expanded, else false.
14150      */
14151     isExpanded : function(){
14152         return this.list.isVisible();
14153     },
14154
14155     /**
14156      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14157      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14158      * @param {String} value The data value of the item to select
14159      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14160      * selected item if it is not currently in view (defaults to true)
14161      * @return {Boolean} True if the value matched an item in the list, else false
14162      */
14163     selectByValue : function(v, scrollIntoView){
14164         if(v !== undefined && v !== null){
14165             var r = this.findRecord(this.valueField || this.displayField, v);
14166             if(r){
14167                 this.select(this.store.indexOf(r), scrollIntoView);
14168                 return true;
14169             }
14170         }
14171         return false;
14172     },
14173
14174     /**
14175      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14176      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14177      * @param {Number} index The zero-based index of the list item to select
14178      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14179      * selected item if it is not currently in view (defaults to true)
14180      */
14181     select : function(index, scrollIntoView){
14182         this.selectedIndex = index;
14183         this.view.select(index);
14184         if(scrollIntoView !== false){
14185             var el = this.view.getNode(index);
14186             /*
14187              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14188              */
14189             if(el){
14190                 this.list.scrollChildIntoView(el, false);
14191             }
14192         }
14193     },
14194
14195     // private
14196     selectNext : function(){
14197         var ct = this.store.getCount();
14198         if(ct > 0){
14199             if(this.selectedIndex == -1){
14200                 this.select(0);
14201             }else if(this.selectedIndex < ct-1){
14202                 this.select(this.selectedIndex+1);
14203             }
14204         }
14205     },
14206
14207     // private
14208     selectPrev : function(){
14209         var ct = this.store.getCount();
14210         if(ct > 0){
14211             if(this.selectedIndex == -1){
14212                 this.select(0);
14213             }else if(this.selectedIndex != 0){
14214                 this.select(this.selectedIndex-1);
14215             }
14216         }
14217     },
14218
14219     // private
14220     onKeyUp : function(e){
14221         if(this.editable !== false && !e.isSpecialKey()){
14222             this.lastKey = e.getKey();
14223             this.dqTask.delay(this.queryDelay);
14224         }
14225     },
14226
14227     // private
14228     validateBlur : function(){
14229         return !this.list || !this.list.isVisible();   
14230     },
14231
14232     // private
14233     initQuery : function(){
14234         
14235         var v = this.getRawValue();
14236         
14237         if(this.tickable && this.editable){
14238             v = this.tickableInputEl().getValue();
14239         }
14240         
14241         this.doQuery(v);
14242     },
14243
14244     // private
14245     doForce : function(){
14246         if(this.inputEl().dom.value.length > 0){
14247             this.inputEl().dom.value =
14248                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14249              
14250         }
14251     },
14252
14253     /**
14254      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
14255      * query allowing the query action to be canceled if needed.
14256      * @param {String} query The SQL query to execute
14257      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14258      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
14259      * saved in the current store (defaults to false)
14260      */
14261     doQuery : function(q, forceAll){
14262         
14263         if(q === undefined || q === null){
14264             q = '';
14265         }
14266         var qe = {
14267             query: q,
14268             forceAll: forceAll,
14269             combo: this,
14270             cancel:false
14271         };
14272         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14273             return false;
14274         }
14275         q = qe.query;
14276         
14277         forceAll = qe.forceAll;
14278         if(forceAll === true || (q.length >= this.minChars)){
14279             
14280             this.hasQuery = true;
14281             
14282             if(this.lastQuery != q || this.alwaysQuery){
14283                 this.lastQuery = q;
14284                 if(this.mode == 'local'){
14285                     this.selectedIndex = -1;
14286                     if(forceAll){
14287                         this.store.clearFilter();
14288                     }else{
14289                         
14290                         if(this.specialFilter){
14291                             this.fireEvent('specialfilter', this);
14292                             this.onLoad();
14293                             return;
14294                         }
14295                         
14296                         this.store.filter(this.displayField, q);
14297                     }
14298                     
14299                     this.store.fireEvent("datachanged", this.store);
14300                     
14301                     this.onLoad();
14302                     
14303                     
14304                 }else{
14305                     
14306                     this.store.baseParams[this.queryParam] = q;
14307                     
14308                     var options = {params : this.getParams(q)};
14309                     
14310                     if(this.loadNext){
14311                         options.add = true;
14312                         options.params.start = this.page * this.pageSize;
14313                     }
14314                     
14315                     this.store.load(options);
14316                     
14317                     /*
14318                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
14319                      *  we should expand the list on onLoad
14320                      *  so command out it
14321                      */
14322 //                    this.expand();
14323                 }
14324             }else{
14325                 this.selectedIndex = -1;
14326                 this.onLoad();   
14327             }
14328         }
14329         
14330         this.loadNext = false;
14331     },
14332     
14333     // private
14334     getParams : function(q){
14335         var p = {};
14336         //p[this.queryParam] = q;
14337         
14338         if(this.pageSize){
14339             p.start = 0;
14340             p.limit = this.pageSize;
14341         }
14342         return p;
14343     },
14344
14345     /**
14346      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14347      */
14348     collapse : function(){
14349         if(!this.isExpanded()){
14350             return;
14351         }
14352         
14353         this.list.hide();
14354         
14355         this.hasFocus = false;
14356         
14357         if(this.tickable){
14358             this.okBtn.hide();
14359             this.cancelBtn.hide();
14360             this.trigger.show();
14361             
14362             if(this.editable){
14363                 this.tickableInputEl().dom.value = '';
14364                 this.tickableInputEl().blur();
14365             }
14366             
14367         }
14368         
14369         Roo.get(document).un('mousedown', this.collapseIf, this);
14370         Roo.get(document).un('mousewheel', this.collapseIf, this);
14371         if (!this.editable) {
14372             Roo.get(document).un('keydown', this.listKeyPress, this);
14373         }
14374         this.fireEvent('collapse', this);
14375         
14376         this.validate();
14377     },
14378
14379     // private
14380     collapseIf : function(e){
14381         var in_combo  = e.within(this.el);
14382         var in_list =  e.within(this.list);
14383         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14384         
14385         if (in_combo || in_list || is_list) {
14386             //e.stopPropagation();
14387             return;
14388         }
14389         
14390         if(this.tickable){
14391             this.onTickableFooterButtonClick(e, false, false);
14392         }
14393
14394         this.collapse();
14395         
14396     },
14397
14398     /**
14399      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14400      */
14401     expand : function(){
14402        
14403         if(this.isExpanded() || !this.hasFocus){
14404             return;
14405         }
14406         
14407         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14408         this.list.setWidth(lw);
14409         
14410         Roo.log('expand');
14411         
14412         this.list.show();
14413         
14414         this.restrictHeight();
14415         
14416         if(this.tickable){
14417             
14418             this.tickItems = Roo.apply([], this.item);
14419             
14420             this.okBtn.show();
14421             this.cancelBtn.show();
14422             this.trigger.hide();
14423             
14424             if(this.editable){
14425                 this.tickableInputEl().focus();
14426             }
14427             
14428         }
14429         
14430         Roo.get(document).on('mousedown', this.collapseIf, this);
14431         Roo.get(document).on('mousewheel', this.collapseIf, this);
14432         if (!this.editable) {
14433             Roo.get(document).on('keydown', this.listKeyPress, this);
14434         }
14435         
14436         this.fireEvent('expand', this);
14437     },
14438
14439     // private
14440     // Implements the default empty TriggerField.onTriggerClick function
14441     onTriggerClick : function(e)
14442     {
14443         Roo.log('trigger click');
14444         
14445         if(this.disabled || !this.triggerList){
14446             return;
14447         }
14448         
14449         this.page = 0;
14450         this.loadNext = false;
14451         
14452         if(this.isExpanded()){
14453             this.collapse();
14454             if (!this.blockFocus) {
14455                 this.inputEl().focus();
14456             }
14457             
14458         }else {
14459             this.hasFocus = true;
14460             if(this.triggerAction == 'all') {
14461                 this.doQuery(this.allQuery, true);
14462             } else {
14463                 this.doQuery(this.getRawValue());
14464             }
14465             if (!this.blockFocus) {
14466                 this.inputEl().focus();
14467             }
14468         }
14469     },
14470     
14471     onTickableTriggerClick : function(e)
14472     {
14473         if(this.disabled){
14474             return;
14475         }
14476         
14477         this.page = 0;
14478         this.loadNext = false;
14479         this.hasFocus = true;
14480         
14481         if(this.triggerAction == 'all') {
14482             this.doQuery(this.allQuery, true);
14483         } else {
14484             this.doQuery(this.getRawValue());
14485         }
14486     },
14487     
14488     onSearchFieldClick : function(e)
14489     {
14490         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14491             this.onTickableFooterButtonClick(e, false, false);
14492             return;
14493         }
14494         
14495         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14496             return;
14497         }
14498         
14499         this.page = 0;
14500         this.loadNext = false;
14501         this.hasFocus = true;
14502         
14503         if(this.triggerAction == 'all') {
14504             this.doQuery(this.allQuery, true);
14505         } else {
14506             this.doQuery(this.getRawValue());
14507         }
14508     },
14509     
14510     listKeyPress : function(e)
14511     {
14512         //Roo.log('listkeypress');
14513         // scroll to first matching element based on key pres..
14514         if (e.isSpecialKey()) {
14515             return false;
14516         }
14517         var k = String.fromCharCode(e.getKey()).toUpperCase();
14518         //Roo.log(k);
14519         var match  = false;
14520         var csel = this.view.getSelectedNodes();
14521         var cselitem = false;
14522         if (csel.length) {
14523             var ix = this.view.indexOf(csel[0]);
14524             cselitem  = this.store.getAt(ix);
14525             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14526                 cselitem = false;
14527             }
14528             
14529         }
14530         
14531         this.store.each(function(v) { 
14532             if (cselitem) {
14533                 // start at existing selection.
14534                 if (cselitem.id == v.id) {
14535                     cselitem = false;
14536                 }
14537                 return true;
14538             }
14539                 
14540             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14541                 match = this.store.indexOf(v);
14542                 return false;
14543             }
14544             return true;
14545         }, this);
14546         
14547         if (match === false) {
14548             return true; // no more action?
14549         }
14550         // scroll to?
14551         this.view.select(match);
14552         var sn = Roo.get(this.view.getSelectedNodes()[0]);
14553         sn.scrollIntoView(sn.dom.parentNode, false);
14554     },
14555     
14556     onViewScroll : function(e, t){
14557         
14558         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){
14559             return;
14560         }
14561         
14562         this.hasQuery = true;
14563         
14564         this.loading = this.list.select('.loading', true).first();
14565         
14566         if(this.loading === null){
14567             this.list.createChild({
14568                 tag: 'div',
14569                 cls: 'loading roo-select2-more-results roo-select2-active',
14570                 html: 'Loading more results...'
14571             });
14572             
14573             this.loading = this.list.select('.loading', true).first();
14574             
14575             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14576             
14577             this.loading.hide();
14578         }
14579         
14580         this.loading.show();
14581         
14582         var _combo = this;
14583         
14584         this.page++;
14585         this.loadNext = true;
14586         
14587         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14588         
14589         return;
14590     },
14591     
14592     addItem : function(o)
14593     {   
14594         var dv = ''; // display value
14595         
14596         if (this.displayField) {
14597             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14598         } else {
14599             // this is an error condition!!!
14600             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14601         }
14602         
14603         if(!dv.length){
14604             return;
14605         }
14606         
14607         var choice = this.choices.createChild({
14608             tag: 'li',
14609             cls: 'roo-select2-search-choice',
14610             cn: [
14611                 {
14612                     tag: 'div',
14613                     html: dv
14614                 },
14615                 {
14616                     tag: 'a',
14617                     href: '#',
14618                     cls: 'roo-select2-search-choice-close fa fa-times',
14619                     tabindex: '-1'
14620                 }
14621             ]
14622             
14623         }, this.searchField);
14624         
14625         var close = choice.select('a.roo-select2-search-choice-close', true).first();
14626         
14627         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14628         
14629         this.item.push(o);
14630         
14631         this.lastData = o;
14632         
14633         this.syncValue();
14634         
14635         this.inputEl().dom.value = '';
14636         
14637         this.validate();
14638     },
14639     
14640     onRemoveItem : function(e, _self, o)
14641     {
14642         e.preventDefault();
14643         
14644         this.lastItem = Roo.apply([], this.item);
14645         
14646         var index = this.item.indexOf(o.data) * 1;
14647         
14648         if( index < 0){
14649             Roo.log('not this item?!');
14650             return;
14651         }
14652         
14653         this.item.splice(index, 1);
14654         o.item.remove();
14655         
14656         this.syncValue();
14657         
14658         this.fireEvent('remove', this, e);
14659         
14660         this.validate();
14661         
14662     },
14663     
14664     syncValue : function()
14665     {
14666         if(!this.item.length){
14667             this.clearValue();
14668             return;
14669         }
14670             
14671         var value = [];
14672         var _this = this;
14673         Roo.each(this.item, function(i){
14674             if(_this.valueField){
14675                 value.push(i[_this.valueField]);
14676                 return;
14677             }
14678
14679             value.push(i);
14680         });
14681
14682         this.value = value.join(',');
14683
14684         if(this.hiddenField){
14685             this.hiddenField.dom.value = this.value;
14686         }
14687         
14688         this.store.fireEvent("datachanged", this.store);
14689         
14690         this.validate();
14691     },
14692     
14693     clearItem : function()
14694     {
14695         if(!this.multiple){
14696             return;
14697         }
14698         
14699         this.item = [];
14700         
14701         Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14702            c.remove();
14703         });
14704         
14705         this.syncValue();
14706         
14707         this.validate();
14708         
14709         if(this.tickable && !Roo.isTouch){
14710             this.view.refresh();
14711         }
14712     },
14713     
14714     inputEl: function ()
14715     {
14716         if(Roo.isIOS && this.useNativeIOS){
14717             return this.el.select('select.roo-ios-select', true).first();
14718         }
14719         
14720         if(Roo.isTouch && this.mobileTouchView){
14721             return this.el.select('input.form-control',true).first();
14722         }
14723         
14724         if(this.tickable){
14725             return this.searchField;
14726         }
14727         
14728         return this.el.select('input.form-control',true).first();
14729     },
14730     
14731     onTickableFooterButtonClick : function(e, btn, el)
14732     {
14733         e.preventDefault();
14734         
14735         this.lastItem = Roo.apply([], this.item);
14736         
14737         if(btn && btn.name == 'cancel'){
14738             this.tickItems = Roo.apply([], this.item);
14739             this.collapse();
14740             return;
14741         }
14742         
14743         this.clearItem();
14744         
14745         var _this = this;
14746         
14747         Roo.each(this.tickItems, function(o){
14748             _this.addItem(o);
14749         });
14750         
14751         this.collapse();
14752         
14753     },
14754     
14755     validate : function()
14756     {
14757         if(this.getVisibilityEl().hasClass('hidden')){
14758             return true;
14759         }
14760         
14761         var v = this.getRawValue();
14762         
14763         if(this.multiple){
14764             v = this.getValue();
14765         }
14766         
14767         if(this.disabled || this.allowBlank || v.length){
14768             this.markValid();
14769             return true;
14770         }
14771         
14772         this.markInvalid();
14773         return false;
14774     },
14775     
14776     tickableInputEl : function()
14777     {
14778         if(!this.tickable || !this.editable){
14779             return this.inputEl();
14780         }
14781         
14782         return this.inputEl().select('.roo-select2-search-field-input', true).first();
14783     },
14784     
14785     
14786     getAutoCreateTouchView : function()
14787     {
14788         var id = Roo.id();
14789         
14790         var cfg = {
14791             cls: 'form-group' //input-group
14792         };
14793         
14794         var input =  {
14795             tag: 'input',
14796             id : id,
14797             type : this.inputType,
14798             cls : 'form-control x-combo-noedit',
14799             autocomplete: 'new-password',
14800             placeholder : this.placeholder || '',
14801             readonly : true
14802         };
14803         
14804         if (this.name) {
14805             input.name = this.name;
14806         }
14807         
14808         if (this.size) {
14809             input.cls += ' input-' + this.size;
14810         }
14811         
14812         if (this.disabled) {
14813             input.disabled = true;
14814         }
14815         
14816         var inputblock = {
14817             cls : '',
14818             cn : [
14819                 input
14820             ]
14821         };
14822         
14823         if(this.before){
14824             inputblock.cls += ' input-group';
14825             
14826             inputblock.cn.unshift({
14827                 tag :'span',
14828                 cls : 'input-group-addon',
14829                 html : this.before
14830             });
14831         }
14832         
14833         if(this.removable && !this.multiple){
14834             inputblock.cls += ' roo-removable';
14835             
14836             inputblock.cn.push({
14837                 tag: 'button',
14838                 html : 'x',
14839                 cls : 'roo-combo-removable-btn close'
14840             });
14841         }
14842
14843         if(this.hasFeedback && !this.allowBlank){
14844             
14845             inputblock.cls += ' has-feedback';
14846             
14847             inputblock.cn.push({
14848                 tag: 'span',
14849                 cls: 'glyphicon form-control-feedback'
14850             });
14851             
14852         }
14853         
14854         if (this.after) {
14855             
14856             inputblock.cls += (this.before) ? '' : ' input-group';
14857             
14858             inputblock.cn.push({
14859                 tag :'span',
14860                 cls : 'input-group-addon',
14861                 html : this.after
14862             });
14863         }
14864
14865         var box = {
14866             tag: 'div',
14867             cn: [
14868                 {
14869                     tag: 'input',
14870                     type : 'hidden',
14871                     cls: 'form-hidden-field'
14872                 },
14873                 inputblock
14874             ]
14875             
14876         };
14877         
14878         if(this.multiple){
14879             box = {
14880                 tag: 'div',
14881                 cn: [
14882                     {
14883                         tag: 'input',
14884                         type : 'hidden',
14885                         cls: 'form-hidden-field'
14886                     },
14887                     {
14888                         tag: 'ul',
14889                         cls: 'roo-select2-choices',
14890                         cn:[
14891                             {
14892                                 tag: 'li',
14893                                 cls: 'roo-select2-search-field',
14894                                 cn: [
14895
14896                                     inputblock
14897                                 ]
14898                             }
14899                         ]
14900                     }
14901                 ]
14902             }
14903         };
14904         
14905         var combobox = {
14906             cls: 'roo-select2-container input-group roo-touchview-combobox ',
14907             cn: [
14908                 box
14909             ]
14910         };
14911         
14912         if(!this.multiple && this.showToggleBtn){
14913             
14914             var caret = {
14915                         tag: 'span',
14916                         cls: 'caret'
14917             };
14918             
14919             if (this.caret != false) {
14920                 caret = {
14921                      tag: 'i',
14922                      cls: 'fa fa-' + this.caret
14923                 };
14924                 
14925             }
14926             
14927             combobox.cn.push({
14928                 tag :'span',
14929                 cls : 'input-group-addon btn dropdown-toggle',
14930                 cn : [
14931                     caret,
14932                     {
14933                         tag: 'span',
14934                         cls: 'combobox-clear',
14935                         cn  : [
14936                             {
14937                                 tag : 'i',
14938                                 cls: 'icon-remove'
14939                             }
14940                         ]
14941                     }
14942                 ]
14943
14944             })
14945         }
14946         
14947         if(this.multiple){
14948             combobox.cls += ' roo-select2-container-multi';
14949         }
14950         
14951         var align = this.labelAlign || this.parentLabelAlign();
14952         
14953         if (align ==='left' && this.fieldLabel.length) {
14954
14955             cfg.cn = [
14956                 {
14957                    tag : 'i',
14958                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14959                    tooltip : 'This field is required'
14960                 },
14961                 {
14962                     tag: 'label',
14963                     cls : 'control-label',
14964                     html : this.fieldLabel
14965
14966                 },
14967                 {
14968                     cls : '', 
14969                     cn: [
14970                         combobox
14971                     ]
14972                 }
14973             ];
14974             
14975             var labelCfg = cfg.cn[1];
14976             var contentCfg = cfg.cn[2];
14977             
14978
14979             if(this.indicatorpos == 'right'){
14980                 cfg.cn = [
14981                     {
14982                         tag: 'label',
14983                         'for' :  id,
14984                         cls : 'control-label',
14985                         cn : [
14986                             {
14987                                 tag : 'span',
14988                                 html : this.fieldLabel
14989                             },
14990                             {
14991                                 tag : 'i',
14992                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14993                                 tooltip : 'This field is required'
14994                             }
14995                         ]
14996                     },
14997                     {
14998                         cls : "",
14999                         cn: [
15000                             combobox
15001                         ]
15002                     }
15003
15004                 ];
15005                 
15006                 labelCfg = cfg.cn[0];
15007                 contentCfg = cfg.cn[1];
15008             }
15009             
15010            
15011             
15012             if(this.labelWidth > 12){
15013                 labelCfg.style = "width: " + this.labelWidth + 'px';
15014             }
15015             
15016             if(this.labelWidth < 13 && this.labelmd == 0){
15017                 this.labelmd = this.labelWidth;
15018             }
15019             
15020             if(this.labellg > 0){
15021                 labelCfg.cls += ' col-lg-' + this.labellg;
15022                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15023             }
15024             
15025             if(this.labelmd > 0){
15026                 labelCfg.cls += ' col-md-' + this.labelmd;
15027                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15028             }
15029             
15030             if(this.labelsm > 0){
15031                 labelCfg.cls += ' col-sm-' + this.labelsm;
15032                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15033             }
15034             
15035             if(this.labelxs > 0){
15036                 labelCfg.cls += ' col-xs-' + this.labelxs;
15037                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15038             }
15039                 
15040                 
15041         } else if ( this.fieldLabel.length) {
15042             cfg.cn = [
15043                 {
15044                    tag : 'i',
15045                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15046                    tooltip : 'This field is required'
15047                 },
15048                 {
15049                     tag: 'label',
15050                     cls : 'control-label',
15051                     html : this.fieldLabel
15052
15053                 },
15054                 {
15055                     cls : '', 
15056                     cn: [
15057                         combobox
15058                     ]
15059                 }
15060             ];
15061             
15062             if(this.indicatorpos == 'right'){
15063                 cfg.cn = [
15064                     {
15065                         tag: 'label',
15066                         cls : 'control-label',
15067                         html : this.fieldLabel,
15068                         cn : [
15069                             {
15070                                tag : 'i',
15071                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15072                                tooltip : 'This field is required'
15073                             }
15074                         ]
15075                     },
15076                     {
15077                         cls : '', 
15078                         cn: [
15079                             combobox
15080                         ]
15081                     }
15082                 ];
15083             }
15084         } else {
15085             cfg.cn = combobox;    
15086         }
15087         
15088         
15089         var settings = this;
15090         
15091         ['xs','sm','md','lg'].map(function(size){
15092             if (settings[size]) {
15093                 cfg.cls += ' col-' + size + '-' + settings[size];
15094             }
15095         });
15096         
15097         return cfg;
15098     },
15099     
15100     initTouchView : function()
15101     {
15102         this.renderTouchView();
15103         
15104         this.touchViewEl.on('scroll', function(){
15105             this.el.dom.scrollTop = 0;
15106         }, this);
15107         
15108         this.originalValue = this.getValue();
15109         
15110         this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15111         
15112         this.inputEl().on("click", this.showTouchView, this);
15113         if (this.triggerEl) {
15114             this.triggerEl.on("click", this.showTouchView, this);
15115         }
15116         
15117         
15118         this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15119         this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15120         
15121         this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15122         
15123         this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15124         this.store.on('load', this.onTouchViewLoad, this);
15125         this.store.on('loadexception', this.onTouchViewLoadException, this);
15126         
15127         if(this.hiddenName){
15128             
15129             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15130             
15131             this.hiddenField.dom.value =
15132                 this.hiddenValue !== undefined ? this.hiddenValue :
15133                 this.value !== undefined ? this.value : '';
15134         
15135             this.el.dom.removeAttribute('name');
15136             this.hiddenField.dom.setAttribute('name', this.hiddenName);
15137         }
15138         
15139         if(this.multiple){
15140             this.choices = this.el.select('ul.roo-select2-choices', true).first();
15141             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15142         }
15143         
15144         if(this.removable && !this.multiple){
15145             var close = this.closeTriggerEl();
15146             if(close){
15147                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15148                 close.on('click', this.removeBtnClick, this, close);
15149             }
15150         }
15151         /*
15152          * fix the bug in Safari iOS8
15153          */
15154         this.inputEl().on("focus", function(e){
15155             document.activeElement.blur();
15156         }, this);
15157         
15158         return;
15159         
15160         
15161     },
15162     
15163     renderTouchView : function()
15164     {
15165         this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15166         this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15167         
15168         this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15169         this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15170         
15171         this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15172         this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15173         this.touchViewBodyEl.setStyle('overflow', 'auto');
15174         
15175         this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15176         this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15177         
15178         this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15179         this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15180         
15181     },
15182     
15183     showTouchView : function()
15184     {
15185         if(this.disabled){
15186             return;
15187         }
15188         
15189         this.touchViewHeaderEl.hide();
15190
15191         if(this.modalTitle.length){
15192             this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15193             this.touchViewHeaderEl.show();
15194         }
15195
15196         this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15197         this.touchViewEl.show();
15198
15199         this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15200         
15201         //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15202         //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15203
15204         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15205
15206         if(this.modalTitle.length){
15207             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15208         }
15209         
15210         this.touchViewBodyEl.setHeight(bodyHeight);
15211
15212         if(this.animate){
15213             var _this = this;
15214             (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15215         }else{
15216             this.touchViewEl.addClass('in');
15217         }
15218
15219         this.doTouchViewQuery();
15220         
15221     },
15222     
15223     hideTouchView : function()
15224     {
15225         this.touchViewEl.removeClass('in');
15226
15227         if(this.animate){
15228             var _this = this;
15229             (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15230         }else{
15231             this.touchViewEl.setStyle('display', 'none');
15232         }
15233         
15234     },
15235     
15236     setTouchViewValue : function()
15237     {
15238         if(this.multiple){
15239             this.clearItem();
15240         
15241             var _this = this;
15242
15243             Roo.each(this.tickItems, function(o){
15244                 this.addItem(o);
15245             }, this);
15246         }
15247         
15248         this.hideTouchView();
15249     },
15250     
15251     doTouchViewQuery : function()
15252     {
15253         var qe = {
15254             query: '',
15255             forceAll: true,
15256             combo: this,
15257             cancel:false
15258         };
15259         
15260         if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15261             return false;
15262         }
15263         
15264         if(!this.alwaysQuery || this.mode == 'local'){
15265             this.onTouchViewLoad();
15266             return;
15267         }
15268         
15269         this.store.load();
15270     },
15271     
15272     onTouchViewBeforeLoad : function(combo,opts)
15273     {
15274         return;
15275     },
15276
15277     // private
15278     onTouchViewLoad : function()
15279     {
15280         if(this.store.getCount() < 1){
15281             this.onTouchViewEmptyResults();
15282             return;
15283         }
15284         
15285         this.clearTouchView();
15286         
15287         var rawValue = this.getRawValue();
15288         
15289         var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15290         
15291         this.tickItems = [];
15292         
15293         this.store.data.each(function(d, rowIndex){
15294             var row = this.touchViewListGroup.createChild(template);
15295             
15296             if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15297                 row.addClass(d.data.cls);
15298             }
15299             
15300             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15301                 var cfg = {
15302                     data : d.data,
15303                     html : d.data[this.displayField]
15304                 };
15305                 
15306                 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15307                     row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15308                 }
15309             }
15310             row.removeClass('selected');
15311             if(!this.multiple && this.valueField &&
15312                     typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15313             {
15314                 // radio buttons..
15315                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15316                 row.addClass('selected');
15317             }
15318             
15319             if(this.multiple && this.valueField &&
15320                     typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15321             {
15322                 
15323                 // checkboxes...
15324                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15325                 this.tickItems.push(d.data);
15326             }
15327             
15328             row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15329             
15330         }, this);
15331         
15332         var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15333         
15334         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15335
15336         if(this.modalTitle.length){
15337             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15338         }
15339
15340         var listHeight = this.touchViewListGroup.getHeight();
15341         
15342         var _this = this;
15343         
15344         if(firstChecked && listHeight > bodyHeight){
15345             (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15346         }
15347         
15348     },
15349     
15350     onTouchViewLoadException : function()
15351     {
15352         this.hideTouchView();
15353     },
15354     
15355     onTouchViewEmptyResults : function()
15356     {
15357         this.clearTouchView();
15358         
15359         this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15360         
15361         this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15362         
15363     },
15364     
15365     clearTouchView : function()
15366     {
15367         this.touchViewListGroup.dom.innerHTML = '';
15368     },
15369     
15370     onTouchViewClick : function(e, el, o)
15371     {
15372         e.preventDefault();
15373         
15374         var row = o.row;
15375         var rowIndex = o.rowIndex;
15376         
15377         var r = this.store.getAt(rowIndex);
15378         
15379         if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15380             
15381             if(!this.multiple){
15382                 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15383                     c.dom.removeAttribute('checked');
15384                 }, this);
15385
15386                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15387
15388                 this.setFromData(r.data);
15389
15390                 var close = this.closeTriggerEl();
15391
15392                 if(close){
15393                     close.show();
15394                 }
15395
15396                 this.hideTouchView();
15397
15398                 this.fireEvent('select', this, r, rowIndex);
15399
15400                 return;
15401             }
15402
15403             if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15404                 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15405                 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15406                 return;
15407             }
15408
15409             row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15410             this.addItem(r.data);
15411             this.tickItems.push(r.data);
15412         }
15413     },
15414     
15415     getAutoCreateNativeIOS : function()
15416     {
15417         var cfg = {
15418             cls: 'form-group' //input-group,
15419         };
15420         
15421         var combobox =  {
15422             tag: 'select',
15423             cls : 'roo-ios-select'
15424         };
15425         
15426         if (this.name) {
15427             combobox.name = this.name;
15428         }
15429         
15430         if (this.disabled) {
15431             combobox.disabled = true;
15432         }
15433         
15434         var settings = this;
15435         
15436         ['xs','sm','md','lg'].map(function(size){
15437             if (settings[size]) {
15438                 cfg.cls += ' col-' + size + '-' + settings[size];
15439             }
15440         });
15441         
15442         cfg.cn = combobox;
15443         
15444         return cfg;
15445         
15446     },
15447     
15448     initIOSView : function()
15449     {
15450         this.store.on('load', this.onIOSViewLoad, this);
15451         
15452         return;
15453     },
15454     
15455     onIOSViewLoad : function()
15456     {
15457         if(this.store.getCount() < 1){
15458             return;
15459         }
15460         
15461         this.clearIOSView();
15462         
15463         if(this.allowBlank) {
15464             
15465             var default_text = '-- SELECT --';
15466             
15467             if(this.placeholder.length){
15468                 default_text = this.placeholder;
15469             }
15470             
15471             if(this.emptyTitle.length){
15472                 default_text += ' - ' + this.emptyTitle + ' -';
15473             }
15474             
15475             var opt = this.inputEl().createChild({
15476                 tag: 'option',
15477                 value : 0,
15478                 html : default_text
15479             });
15480             
15481             var o = {};
15482             o[this.valueField] = 0;
15483             o[this.displayField] = default_text;
15484             
15485             this.ios_options.push({
15486                 data : o,
15487                 el : opt
15488             });
15489             
15490         }
15491         
15492         this.store.data.each(function(d, rowIndex){
15493             
15494             var html = '';
15495             
15496             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15497                 html = d.data[this.displayField];
15498             }
15499             
15500             var value = '';
15501             
15502             if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15503                 value = d.data[this.valueField];
15504             }
15505             
15506             var option = {
15507                 tag: 'option',
15508                 value : value,
15509                 html : html
15510             };
15511             
15512             if(this.value == d.data[this.valueField]){
15513                 option['selected'] = true;
15514             }
15515             
15516             var opt = this.inputEl().createChild(option);
15517             
15518             this.ios_options.push({
15519                 data : d.data,
15520                 el : opt
15521             });
15522             
15523         }, this);
15524         
15525         this.inputEl().on('change', function(){
15526            this.fireEvent('select', this);
15527         }, this);
15528         
15529     },
15530     
15531     clearIOSView: function()
15532     {
15533         this.inputEl().dom.innerHTML = '';
15534         
15535         this.ios_options = [];
15536     },
15537     
15538     setIOSValue: function(v)
15539     {
15540         this.value = v;
15541         
15542         if(!this.ios_options){
15543             return;
15544         }
15545         
15546         Roo.each(this.ios_options, function(opts){
15547            
15548            opts.el.dom.removeAttribute('selected');
15549            
15550            if(opts.data[this.valueField] != v){
15551                return;
15552            }
15553            
15554            opts.el.dom.setAttribute('selected', true);
15555            
15556         }, this);
15557     }
15558
15559     /** 
15560     * @cfg {Boolean} grow 
15561     * @hide 
15562     */
15563     /** 
15564     * @cfg {Number} growMin 
15565     * @hide 
15566     */
15567     /** 
15568     * @cfg {Number} growMax 
15569     * @hide 
15570     */
15571     /**
15572      * @hide
15573      * @method autoSize
15574      */
15575 });
15576
15577 Roo.apply(Roo.bootstrap.ComboBox,  {
15578     
15579     header : {
15580         tag: 'div',
15581         cls: 'modal-header',
15582         cn: [
15583             {
15584                 tag: 'h4',
15585                 cls: 'modal-title'
15586             }
15587         ]
15588     },
15589     
15590     body : {
15591         tag: 'div',
15592         cls: 'modal-body',
15593         cn: [
15594             {
15595                 tag: 'ul',
15596                 cls: 'list-group'
15597             }
15598         ]
15599     },
15600     
15601     listItemRadio : {
15602         tag: 'li',
15603         cls: 'list-group-item',
15604         cn: [
15605             {
15606                 tag: 'span',
15607                 cls: 'roo-combobox-list-group-item-value'
15608             },
15609             {
15610                 tag: 'div',
15611                 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15612                 cn: [
15613                     {
15614                         tag: 'input',
15615                         type: 'radio'
15616                     },
15617                     {
15618                         tag: 'label'
15619                     }
15620                 ]
15621             }
15622         ]
15623     },
15624     
15625     listItemCheckbox : {
15626         tag: 'li',
15627         cls: 'list-group-item',
15628         cn: [
15629             {
15630                 tag: 'span',
15631                 cls: 'roo-combobox-list-group-item-value'
15632             },
15633             {
15634                 tag: 'div',
15635                 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15636                 cn: [
15637                     {
15638                         tag: 'input',
15639                         type: 'checkbox'
15640                     },
15641                     {
15642                         tag: 'label'
15643                     }
15644                 ]
15645             }
15646         ]
15647     },
15648     
15649     emptyResult : {
15650         tag: 'div',
15651         cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15652     },
15653     
15654     footer : {
15655         tag: 'div',
15656         cls: 'modal-footer',
15657         cn: [
15658             {
15659                 tag: 'div',
15660                 cls: 'row',
15661                 cn: [
15662                     {
15663                         tag: 'div',
15664                         cls: 'col-xs-6 text-left',
15665                         cn: {
15666                             tag: 'button',
15667                             cls: 'btn btn-danger roo-touch-view-cancel',
15668                             html: 'Cancel'
15669                         }
15670                     },
15671                     {
15672                         tag: 'div',
15673                         cls: 'col-xs-6 text-right',
15674                         cn: {
15675                             tag: 'button',
15676                             cls: 'btn btn-success roo-touch-view-ok',
15677                             html: 'OK'
15678                         }
15679                     }
15680                 ]
15681             }
15682         ]
15683         
15684     }
15685 });
15686
15687 Roo.apply(Roo.bootstrap.ComboBox,  {
15688     
15689     touchViewTemplate : {
15690         tag: 'div',
15691         cls: 'modal fade roo-combobox-touch-view',
15692         cn: [
15693             {
15694                 tag: 'div',
15695                 cls: 'modal-dialog',
15696                 style : 'position:fixed', // we have to fix position....
15697                 cn: [
15698                     {
15699                         tag: 'div',
15700                         cls: 'modal-content',
15701                         cn: [
15702                             Roo.bootstrap.ComboBox.header,
15703                             Roo.bootstrap.ComboBox.body,
15704                             Roo.bootstrap.ComboBox.footer
15705                         ]
15706                     }
15707                 ]
15708             }
15709         ]
15710     }
15711 });/*
15712  * Based on:
15713  * Ext JS Library 1.1.1
15714  * Copyright(c) 2006-2007, Ext JS, LLC.
15715  *
15716  * Originally Released Under LGPL - original licence link has changed is not relivant.
15717  *
15718  * Fork - LGPL
15719  * <script type="text/javascript">
15720  */
15721
15722 /**
15723  * @class Roo.View
15724  * @extends Roo.util.Observable
15725  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
15726  * This class also supports single and multi selection modes. <br>
15727  * Create a data model bound view:
15728  <pre><code>
15729  var store = new Roo.data.Store(...);
15730
15731  var view = new Roo.View({
15732     el : "my-element",
15733     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
15734  
15735     singleSelect: true,
15736     selectedClass: "ydataview-selected",
15737     store: store
15738  });
15739
15740  // listen for node click?
15741  view.on("click", function(vw, index, node, e){
15742  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15743  });
15744
15745  // load XML data
15746  dataModel.load("foobar.xml");
15747  </code></pre>
15748  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15749  * <br><br>
15750  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15751  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15752  * 
15753  * Note: old style constructor is still suported (container, template, config)
15754  * 
15755  * @constructor
15756  * Create a new View
15757  * @param {Object} config The config object
15758  * 
15759  */
15760 Roo.View = function(config, depreciated_tpl, depreciated_config){
15761     
15762     this.parent = false;
15763     
15764     if (typeof(depreciated_tpl) == 'undefined') {
15765         // new way.. - universal constructor.
15766         Roo.apply(this, config);
15767         this.el  = Roo.get(this.el);
15768     } else {
15769         // old format..
15770         this.el  = Roo.get(config);
15771         this.tpl = depreciated_tpl;
15772         Roo.apply(this, depreciated_config);
15773     }
15774     this.wrapEl  = this.el.wrap().wrap();
15775     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15776     
15777     
15778     if(typeof(this.tpl) == "string"){
15779         this.tpl = new Roo.Template(this.tpl);
15780     } else {
15781         // support xtype ctors..
15782         this.tpl = new Roo.factory(this.tpl, Roo);
15783     }
15784     
15785     
15786     this.tpl.compile();
15787     
15788     /** @private */
15789     this.addEvents({
15790         /**
15791          * @event beforeclick
15792          * Fires before a click is processed. Returns false to cancel the default action.
15793          * @param {Roo.View} this
15794          * @param {Number} index The index of the target node
15795          * @param {HTMLElement} node The target node
15796          * @param {Roo.EventObject} e The raw event object
15797          */
15798             "beforeclick" : true,
15799         /**
15800          * @event click
15801          * Fires when a template node is clicked.
15802          * @param {Roo.View} this
15803          * @param {Number} index The index of the target node
15804          * @param {HTMLElement} node The target node
15805          * @param {Roo.EventObject} e The raw event object
15806          */
15807             "click" : true,
15808         /**
15809          * @event dblclick
15810          * Fires when a template node is double clicked.
15811          * @param {Roo.View} this
15812          * @param {Number} index The index of the target node
15813          * @param {HTMLElement} node The target node
15814          * @param {Roo.EventObject} e The raw event object
15815          */
15816             "dblclick" : true,
15817         /**
15818          * @event contextmenu
15819          * Fires when a template node is right clicked.
15820          * @param {Roo.View} this
15821          * @param {Number} index The index of the target node
15822          * @param {HTMLElement} node The target node
15823          * @param {Roo.EventObject} e The raw event object
15824          */
15825             "contextmenu" : true,
15826         /**
15827          * @event selectionchange
15828          * Fires when the selected nodes change.
15829          * @param {Roo.View} this
15830          * @param {Array} selections Array of the selected nodes
15831          */
15832             "selectionchange" : true,
15833     
15834         /**
15835          * @event beforeselect
15836          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15837          * @param {Roo.View} this
15838          * @param {HTMLElement} node The node to be selected
15839          * @param {Array} selections Array of currently selected nodes
15840          */
15841             "beforeselect" : true,
15842         /**
15843          * @event preparedata
15844          * Fires on every row to render, to allow you to change the data.
15845          * @param {Roo.View} this
15846          * @param {Object} data to be rendered (change this)
15847          */
15848           "preparedata" : true
15849           
15850           
15851         });
15852
15853
15854
15855     this.el.on({
15856         "click": this.onClick,
15857         "dblclick": this.onDblClick,
15858         "contextmenu": this.onContextMenu,
15859         scope:this
15860     });
15861
15862     this.selections = [];
15863     this.nodes = [];
15864     this.cmp = new Roo.CompositeElementLite([]);
15865     if(this.store){
15866         this.store = Roo.factory(this.store, Roo.data);
15867         this.setStore(this.store, true);
15868     }
15869     
15870     if ( this.footer && this.footer.xtype) {
15871            
15872          var fctr = this.wrapEl.appendChild(document.createElement("div"));
15873         
15874         this.footer.dataSource = this.store;
15875         this.footer.container = fctr;
15876         this.footer = Roo.factory(this.footer, Roo);
15877         fctr.insertFirst(this.el);
15878         
15879         // this is a bit insane - as the paging toolbar seems to detach the el..
15880 //        dom.parentNode.parentNode.parentNode
15881          // they get detached?
15882     }
15883     
15884     
15885     Roo.View.superclass.constructor.call(this);
15886     
15887     
15888 };
15889
15890 Roo.extend(Roo.View, Roo.util.Observable, {
15891     
15892      /**
15893      * @cfg {Roo.data.Store} store Data store to load data from.
15894      */
15895     store : false,
15896     
15897     /**
15898      * @cfg {String|Roo.Element} el The container element.
15899      */
15900     el : '',
15901     
15902     /**
15903      * @cfg {String|Roo.Template} tpl The template used by this View 
15904      */
15905     tpl : false,
15906     /**
15907      * @cfg {String} dataName the named area of the template to use as the data area
15908      *                          Works with domtemplates roo-name="name"
15909      */
15910     dataName: false,
15911     /**
15912      * @cfg {String} selectedClass The css class to add to selected nodes
15913      */
15914     selectedClass : "x-view-selected",
15915      /**
15916      * @cfg {String} emptyText The empty text to show when nothing is loaded.
15917      */
15918     emptyText : "",
15919     
15920     /**
15921      * @cfg {String} text to display on mask (default Loading)
15922      */
15923     mask : false,
15924     /**
15925      * @cfg {Boolean} multiSelect Allow multiple selection
15926      */
15927     multiSelect : false,
15928     /**
15929      * @cfg {Boolean} singleSelect Allow single selection
15930      */
15931     singleSelect:  false,
15932     
15933     /**
15934      * @cfg {Boolean} toggleSelect - selecting 
15935      */
15936     toggleSelect : false,
15937     
15938     /**
15939      * @cfg {Boolean} tickable - selecting 
15940      */
15941     tickable : false,
15942     
15943     /**
15944      * Returns the element this view is bound to.
15945      * @return {Roo.Element}
15946      */
15947     getEl : function(){
15948         return this.wrapEl;
15949     },
15950     
15951     
15952
15953     /**
15954      * Refreshes the view. - called by datachanged on the store. - do not call directly.
15955      */
15956     refresh : function(){
15957         //Roo.log('refresh');
15958         var t = this.tpl;
15959         
15960         // if we are using something like 'domtemplate', then
15961         // the what gets used is:
15962         // t.applySubtemplate(NAME, data, wrapping data..)
15963         // the outer template then get' applied with
15964         //     the store 'extra data'
15965         // and the body get's added to the
15966         //      roo-name="data" node?
15967         //      <span class='roo-tpl-{name}'></span> ?????
15968         
15969         
15970         
15971         this.clearSelections();
15972         this.el.update("");
15973         var html = [];
15974         var records = this.store.getRange();
15975         if(records.length < 1) {
15976             
15977             // is this valid??  = should it render a template??
15978             
15979             this.el.update(this.emptyText);
15980             return;
15981         }
15982         var el = this.el;
15983         if (this.dataName) {
15984             this.el.update(t.apply(this.store.meta)); //????
15985             el = this.el.child('.roo-tpl-' + this.dataName);
15986         }
15987         
15988         for(var i = 0, len = records.length; i < len; i++){
15989             var data = this.prepareData(records[i].data, i, records[i]);
15990             this.fireEvent("preparedata", this, data, i, records[i]);
15991             
15992             var d = Roo.apply({}, data);
15993             
15994             if(this.tickable){
15995                 Roo.apply(d, {'roo-id' : Roo.id()});
15996                 
15997                 var _this = this;
15998             
15999                 Roo.each(this.parent.item, function(item){
16000                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16001                         return;
16002                     }
16003                     Roo.apply(d, {'roo-data-checked' : 'checked'});
16004                 });
16005             }
16006             
16007             html[html.length] = Roo.util.Format.trim(
16008                 this.dataName ?
16009                     t.applySubtemplate(this.dataName, d, this.store.meta) :
16010                     t.apply(d)
16011             );
16012         }
16013         
16014         
16015         
16016         el.update(html.join(""));
16017         this.nodes = el.dom.childNodes;
16018         this.updateIndexes(0);
16019     },
16020     
16021
16022     /**
16023      * Function to override to reformat the data that is sent to
16024      * the template for each node.
16025      * DEPRICATED - use the preparedata event handler.
16026      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16027      * a JSON object for an UpdateManager bound view).
16028      */
16029     prepareData : function(data, index, record)
16030     {
16031         this.fireEvent("preparedata", this, data, index, record);
16032         return data;
16033     },
16034
16035     onUpdate : function(ds, record){
16036         // Roo.log('on update');   
16037         this.clearSelections();
16038         var index = this.store.indexOf(record);
16039         var n = this.nodes[index];
16040         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16041         n.parentNode.removeChild(n);
16042         this.updateIndexes(index, index);
16043     },
16044
16045     
16046     
16047 // --------- FIXME     
16048     onAdd : function(ds, records, index)
16049     {
16050         //Roo.log(['on Add', ds, records, index] );        
16051         this.clearSelections();
16052         if(this.nodes.length == 0){
16053             this.refresh();
16054             return;
16055         }
16056         var n = this.nodes[index];
16057         for(var i = 0, len = records.length; i < len; i++){
16058             var d = this.prepareData(records[i].data, i, records[i]);
16059             if(n){
16060                 this.tpl.insertBefore(n, d);
16061             }else{
16062                 
16063                 this.tpl.append(this.el, d);
16064             }
16065         }
16066         this.updateIndexes(index);
16067     },
16068
16069     onRemove : function(ds, record, index){
16070        // Roo.log('onRemove');
16071         this.clearSelections();
16072         var el = this.dataName  ?
16073             this.el.child('.roo-tpl-' + this.dataName) :
16074             this.el; 
16075         
16076         el.dom.removeChild(this.nodes[index]);
16077         this.updateIndexes(index);
16078     },
16079
16080     /**
16081      * Refresh an individual node.
16082      * @param {Number} index
16083      */
16084     refreshNode : function(index){
16085         this.onUpdate(this.store, this.store.getAt(index));
16086     },
16087
16088     updateIndexes : function(startIndex, endIndex){
16089         var ns = this.nodes;
16090         startIndex = startIndex || 0;
16091         endIndex = endIndex || ns.length - 1;
16092         for(var i = startIndex; i <= endIndex; i++){
16093             ns[i].nodeIndex = i;
16094         }
16095     },
16096
16097     /**
16098      * Changes the data store this view uses and refresh the view.
16099      * @param {Store} store
16100      */
16101     setStore : function(store, initial){
16102         if(!initial && this.store){
16103             this.store.un("datachanged", this.refresh);
16104             this.store.un("add", this.onAdd);
16105             this.store.un("remove", this.onRemove);
16106             this.store.un("update", this.onUpdate);
16107             this.store.un("clear", this.refresh);
16108             this.store.un("beforeload", this.onBeforeLoad);
16109             this.store.un("load", this.onLoad);
16110             this.store.un("loadexception", this.onLoad);
16111         }
16112         if(store){
16113           
16114             store.on("datachanged", this.refresh, this);
16115             store.on("add", this.onAdd, this);
16116             store.on("remove", this.onRemove, this);
16117             store.on("update", this.onUpdate, this);
16118             store.on("clear", this.refresh, this);
16119             store.on("beforeload", this.onBeforeLoad, this);
16120             store.on("load", this.onLoad, this);
16121             store.on("loadexception", this.onLoad, this);
16122         }
16123         
16124         if(store){
16125             this.refresh();
16126         }
16127     },
16128     /**
16129      * onbeforeLoad - masks the loading area.
16130      *
16131      */
16132     onBeforeLoad : function(store,opts)
16133     {
16134          //Roo.log('onBeforeLoad');   
16135         if (!opts.add) {
16136             this.el.update("");
16137         }
16138         this.el.mask(this.mask ? this.mask : "Loading" ); 
16139     },
16140     onLoad : function ()
16141     {
16142         this.el.unmask();
16143     },
16144     
16145
16146     /**
16147      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16148      * @param {HTMLElement} node
16149      * @return {HTMLElement} The template node
16150      */
16151     findItemFromChild : function(node){
16152         var el = this.dataName  ?
16153             this.el.child('.roo-tpl-' + this.dataName,true) :
16154             this.el.dom; 
16155         
16156         if(!node || node.parentNode == el){
16157                     return node;
16158             }
16159             var p = node.parentNode;
16160             while(p && p != el){
16161             if(p.parentNode == el){
16162                 return p;
16163             }
16164             p = p.parentNode;
16165         }
16166             return null;
16167     },
16168
16169     /** @ignore */
16170     onClick : function(e){
16171         var item = this.findItemFromChild(e.getTarget());
16172         if(item){
16173             var index = this.indexOf(item);
16174             if(this.onItemClick(item, index, e) !== false){
16175                 this.fireEvent("click", this, index, item, e);
16176             }
16177         }else{
16178             this.clearSelections();
16179         }
16180     },
16181
16182     /** @ignore */
16183     onContextMenu : function(e){
16184         var item = this.findItemFromChild(e.getTarget());
16185         if(item){
16186             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16187         }
16188     },
16189
16190     /** @ignore */
16191     onDblClick : function(e){
16192         var item = this.findItemFromChild(e.getTarget());
16193         if(item){
16194             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16195         }
16196     },
16197
16198     onItemClick : function(item, index, e)
16199     {
16200         if(this.fireEvent("beforeclick", this, index, item, e) === false){
16201             return false;
16202         }
16203         if (this.toggleSelect) {
16204             var m = this.isSelected(item) ? 'unselect' : 'select';
16205             //Roo.log(m);
16206             var _t = this;
16207             _t[m](item, true, false);
16208             return true;
16209         }
16210         if(this.multiSelect || this.singleSelect){
16211             if(this.multiSelect && e.shiftKey && this.lastSelection){
16212                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16213             }else{
16214                 this.select(item, this.multiSelect && e.ctrlKey);
16215                 this.lastSelection = item;
16216             }
16217             
16218             if(!this.tickable){
16219                 e.preventDefault();
16220             }
16221             
16222         }
16223         return true;
16224     },
16225
16226     /**
16227      * Get the number of selected nodes.
16228      * @return {Number}
16229      */
16230     getSelectionCount : function(){
16231         return this.selections.length;
16232     },
16233
16234     /**
16235      * Get the currently selected nodes.
16236      * @return {Array} An array of HTMLElements
16237      */
16238     getSelectedNodes : function(){
16239         return this.selections;
16240     },
16241
16242     /**
16243      * Get the indexes of the selected nodes.
16244      * @return {Array}
16245      */
16246     getSelectedIndexes : function(){
16247         var indexes = [], s = this.selections;
16248         for(var i = 0, len = s.length; i < len; i++){
16249             indexes.push(s[i].nodeIndex);
16250         }
16251         return indexes;
16252     },
16253
16254     /**
16255      * Clear all selections
16256      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16257      */
16258     clearSelections : function(suppressEvent){
16259         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16260             this.cmp.elements = this.selections;
16261             this.cmp.removeClass(this.selectedClass);
16262             this.selections = [];
16263             if(!suppressEvent){
16264                 this.fireEvent("selectionchange", this, this.selections);
16265             }
16266         }
16267     },
16268
16269     /**
16270      * Returns true if the passed node is selected
16271      * @param {HTMLElement/Number} node The node or node index
16272      * @return {Boolean}
16273      */
16274     isSelected : function(node){
16275         var s = this.selections;
16276         if(s.length < 1){
16277             return false;
16278         }
16279         node = this.getNode(node);
16280         return s.indexOf(node) !== -1;
16281     },
16282
16283     /**
16284      * Selects nodes.
16285      * @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
16286      * @param {Boolean} keepExisting (optional) true to keep existing selections
16287      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16288      */
16289     select : function(nodeInfo, keepExisting, suppressEvent){
16290         if(nodeInfo instanceof Array){
16291             if(!keepExisting){
16292                 this.clearSelections(true);
16293             }
16294             for(var i = 0, len = nodeInfo.length; i < len; i++){
16295                 this.select(nodeInfo[i], true, true);
16296             }
16297             return;
16298         } 
16299         var node = this.getNode(nodeInfo);
16300         if(!node || this.isSelected(node)){
16301             return; // already selected.
16302         }
16303         if(!keepExisting){
16304             this.clearSelections(true);
16305         }
16306         
16307         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16308             Roo.fly(node).addClass(this.selectedClass);
16309             this.selections.push(node);
16310             if(!suppressEvent){
16311                 this.fireEvent("selectionchange", this, this.selections);
16312             }
16313         }
16314         
16315         
16316     },
16317       /**
16318      * Unselects nodes.
16319      * @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
16320      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16321      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16322      */
16323     unselect : function(nodeInfo, keepExisting, suppressEvent)
16324     {
16325         if(nodeInfo instanceof Array){
16326             Roo.each(this.selections, function(s) {
16327                 this.unselect(s, nodeInfo);
16328             }, this);
16329             return;
16330         }
16331         var node = this.getNode(nodeInfo);
16332         if(!node || !this.isSelected(node)){
16333             //Roo.log("not selected");
16334             return; // not selected.
16335         }
16336         // fireevent???
16337         var ns = [];
16338         Roo.each(this.selections, function(s) {
16339             if (s == node ) {
16340                 Roo.fly(node).removeClass(this.selectedClass);
16341
16342                 return;
16343             }
16344             ns.push(s);
16345         },this);
16346         
16347         this.selections= ns;
16348         this.fireEvent("selectionchange", this, this.selections);
16349     },
16350
16351     /**
16352      * Gets a template node.
16353      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16354      * @return {HTMLElement} The node or null if it wasn't found
16355      */
16356     getNode : function(nodeInfo){
16357         if(typeof nodeInfo == "string"){
16358             return document.getElementById(nodeInfo);
16359         }else if(typeof nodeInfo == "number"){
16360             return this.nodes[nodeInfo];
16361         }
16362         return nodeInfo;
16363     },
16364
16365     /**
16366      * Gets a range template nodes.
16367      * @param {Number} startIndex
16368      * @param {Number} endIndex
16369      * @return {Array} An array of nodes
16370      */
16371     getNodes : function(start, end){
16372         var ns = this.nodes;
16373         start = start || 0;
16374         end = typeof end == "undefined" ? ns.length - 1 : end;
16375         var nodes = [];
16376         if(start <= end){
16377             for(var i = start; i <= end; i++){
16378                 nodes.push(ns[i]);
16379             }
16380         } else{
16381             for(var i = start; i >= end; i--){
16382                 nodes.push(ns[i]);
16383             }
16384         }
16385         return nodes;
16386     },
16387
16388     /**
16389      * Finds the index of the passed node
16390      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16391      * @return {Number} The index of the node or -1
16392      */
16393     indexOf : function(node){
16394         node = this.getNode(node);
16395         if(typeof node.nodeIndex == "number"){
16396             return node.nodeIndex;
16397         }
16398         var ns = this.nodes;
16399         for(var i = 0, len = ns.length; i < len; i++){
16400             if(ns[i] == node){
16401                 return i;
16402             }
16403         }
16404         return -1;
16405     }
16406 });
16407 /*
16408  * - LGPL
16409  *
16410  * based on jquery fullcalendar
16411  * 
16412  */
16413
16414 Roo.bootstrap = Roo.bootstrap || {};
16415 /**
16416  * @class Roo.bootstrap.Calendar
16417  * @extends Roo.bootstrap.Component
16418  * Bootstrap Calendar class
16419  * @cfg {Boolean} loadMask (true|false) default false
16420  * @cfg {Object} header generate the user specific header of the calendar, default false
16421
16422  * @constructor
16423  * Create a new Container
16424  * @param {Object} config The config object
16425  */
16426
16427
16428
16429 Roo.bootstrap.Calendar = function(config){
16430     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16431      this.addEvents({
16432         /**
16433              * @event select
16434              * Fires when a date is selected
16435              * @param {DatePicker} this
16436              * @param {Date} date The selected date
16437              */
16438         'select': true,
16439         /**
16440              * @event monthchange
16441              * Fires when the displayed month changes 
16442              * @param {DatePicker} this
16443              * @param {Date} date The selected month
16444              */
16445         'monthchange': true,
16446         /**
16447              * @event evententer
16448              * Fires when mouse over an event
16449              * @param {Calendar} this
16450              * @param {event} Event
16451              */
16452         'evententer': true,
16453         /**
16454              * @event eventleave
16455              * Fires when the mouse leaves an
16456              * @param {Calendar} this
16457              * @param {event}
16458              */
16459         'eventleave': true,
16460         /**
16461              * @event eventclick
16462              * Fires when the mouse click an
16463              * @param {Calendar} this
16464              * @param {event}
16465              */
16466         'eventclick': true
16467         
16468     });
16469
16470 };
16471
16472 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
16473     
16474      /**
16475      * @cfg {Number} startDay
16476      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16477      */
16478     startDay : 0,
16479     
16480     loadMask : false,
16481     
16482     header : false,
16483       
16484     getAutoCreate : function(){
16485         
16486         
16487         var fc_button = function(name, corner, style, content ) {
16488             return Roo.apply({},{
16489                 tag : 'span',
16490                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
16491                          (corner.length ?
16492                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16493                             ''
16494                         ),
16495                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16496                 unselectable: 'on'
16497             });
16498         };
16499         
16500         var header = {};
16501         
16502         if(!this.header){
16503             header = {
16504                 tag : 'table',
16505                 cls : 'fc-header',
16506                 style : 'width:100%',
16507                 cn : [
16508                     {
16509                         tag: 'tr',
16510                         cn : [
16511                             {
16512                                 tag : 'td',
16513                                 cls : 'fc-header-left',
16514                                 cn : [
16515                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
16516                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
16517                                     { tag: 'span', cls: 'fc-header-space' },
16518                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
16519
16520
16521                                 ]
16522                             },
16523
16524                             {
16525                                 tag : 'td',
16526                                 cls : 'fc-header-center',
16527                                 cn : [
16528                                     {
16529                                         tag: 'span',
16530                                         cls: 'fc-header-title',
16531                                         cn : {
16532                                             tag: 'H2',
16533                                             html : 'month / year'
16534                                         }
16535                                     }
16536
16537                                 ]
16538                             },
16539                             {
16540                                 tag : 'td',
16541                                 cls : 'fc-header-right',
16542                                 cn : [
16543                               /*      fc_button('month', 'left', '', 'month' ),
16544                                     fc_button('week', '', '', 'week' ),
16545                                     fc_button('day', 'right', '', 'day' )
16546                                 */    
16547
16548                                 ]
16549                             }
16550
16551                         ]
16552                     }
16553                 ]
16554             };
16555         }
16556         
16557         header = this.header;
16558         
16559        
16560         var cal_heads = function() {
16561             var ret = [];
16562             // fixme - handle this.
16563             
16564             for (var i =0; i < Date.dayNames.length; i++) {
16565                 var d = Date.dayNames[i];
16566                 ret.push({
16567                     tag: 'th',
16568                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16569                     html : d.substring(0,3)
16570                 });
16571                 
16572             }
16573             ret[0].cls += ' fc-first';
16574             ret[6].cls += ' fc-last';
16575             return ret;
16576         };
16577         var cal_cell = function(n) {
16578             return  {
16579                 tag: 'td',
16580                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16581                 cn : [
16582                     {
16583                         cn : [
16584                             {
16585                                 cls: 'fc-day-number',
16586                                 html: 'D'
16587                             },
16588                             {
16589                                 cls: 'fc-day-content',
16590                              
16591                                 cn : [
16592                                      {
16593                                         style: 'position: relative;' // height: 17px;
16594                                     }
16595                                 ]
16596                             }
16597                             
16598                             
16599                         ]
16600                     }
16601                 ]
16602                 
16603             }
16604         };
16605         var cal_rows = function() {
16606             
16607             var ret = [];
16608             for (var r = 0; r < 6; r++) {
16609                 var row= {
16610                     tag : 'tr',
16611                     cls : 'fc-week',
16612                     cn : []
16613                 };
16614                 
16615                 for (var i =0; i < Date.dayNames.length; i++) {
16616                     var d = Date.dayNames[i];
16617                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16618
16619                 }
16620                 row.cn[0].cls+=' fc-first';
16621                 row.cn[0].cn[0].style = 'min-height:90px';
16622                 row.cn[6].cls+=' fc-last';
16623                 ret.push(row);
16624                 
16625             }
16626             ret[0].cls += ' fc-first';
16627             ret[4].cls += ' fc-prev-last';
16628             ret[5].cls += ' fc-last';
16629             return ret;
16630             
16631         };
16632         
16633         var cal_table = {
16634             tag: 'table',
16635             cls: 'fc-border-separate',
16636             style : 'width:100%',
16637             cellspacing  : 0,
16638             cn : [
16639                 { 
16640                     tag: 'thead',
16641                     cn : [
16642                         { 
16643                             tag: 'tr',
16644                             cls : 'fc-first fc-last',
16645                             cn : cal_heads()
16646                         }
16647                     ]
16648                 },
16649                 { 
16650                     tag: 'tbody',
16651                     cn : cal_rows()
16652                 }
16653                   
16654             ]
16655         };
16656          
16657          var cfg = {
16658             cls : 'fc fc-ltr',
16659             cn : [
16660                 header,
16661                 {
16662                     cls : 'fc-content',
16663                     style : "position: relative;",
16664                     cn : [
16665                         {
16666                             cls : 'fc-view fc-view-month fc-grid',
16667                             style : 'position: relative',
16668                             unselectable : 'on',
16669                             cn : [
16670                                 {
16671                                     cls : 'fc-event-container',
16672                                     style : 'position:absolute;z-index:8;top:0;left:0;'
16673                                 },
16674                                 cal_table
16675                             ]
16676                         }
16677                     ]
16678     
16679                 }
16680            ] 
16681             
16682         };
16683         
16684          
16685         
16686         return cfg;
16687     },
16688     
16689     
16690     initEvents : function()
16691     {
16692         if(!this.store){
16693             throw "can not find store for calendar";
16694         }
16695         
16696         var mark = {
16697             tag: "div",
16698             cls:"x-dlg-mask",
16699             style: "text-align:center",
16700             cn: [
16701                 {
16702                     tag: "div",
16703                     style: "background-color:white;width:50%;margin:250 auto",
16704                     cn: [
16705                         {
16706                             tag: "img",
16707                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
16708                         },
16709                         {
16710                             tag: "span",
16711                             html: "Loading"
16712                         }
16713                         
16714                     ]
16715                 }
16716             ]
16717         };
16718         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16719         
16720         var size = this.el.select('.fc-content', true).first().getSize();
16721         this.maskEl.setSize(size.width, size.height);
16722         this.maskEl.enableDisplayMode("block");
16723         if(!this.loadMask){
16724             this.maskEl.hide();
16725         }
16726         
16727         this.store = Roo.factory(this.store, Roo.data);
16728         this.store.on('load', this.onLoad, this);
16729         this.store.on('beforeload', this.onBeforeLoad, this);
16730         
16731         this.resize();
16732         
16733         this.cells = this.el.select('.fc-day',true);
16734         //Roo.log(this.cells);
16735         this.textNodes = this.el.query('.fc-day-number');
16736         this.cells.addClassOnOver('fc-state-hover');
16737         
16738         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16739         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16740         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16741         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16742         
16743         this.on('monthchange', this.onMonthChange, this);
16744         
16745         this.update(new Date().clearTime());
16746     },
16747     
16748     resize : function() {
16749         var sz  = this.el.getSize();
16750         
16751         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16752         this.el.select('.fc-day-content div',true).setHeight(34);
16753     },
16754     
16755     
16756     // private
16757     showPrevMonth : function(e){
16758         this.update(this.activeDate.add("mo", -1));
16759     },
16760     showToday : function(e){
16761         this.update(new Date().clearTime());
16762     },
16763     // private
16764     showNextMonth : function(e){
16765         this.update(this.activeDate.add("mo", 1));
16766     },
16767
16768     // private
16769     showPrevYear : function(){
16770         this.update(this.activeDate.add("y", -1));
16771     },
16772
16773     // private
16774     showNextYear : function(){
16775         this.update(this.activeDate.add("y", 1));
16776     },
16777
16778     
16779    // private
16780     update : function(date)
16781     {
16782         var vd = this.activeDate;
16783         this.activeDate = date;
16784 //        if(vd && this.el){
16785 //            var t = date.getTime();
16786 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16787 //                Roo.log('using add remove');
16788 //                
16789 //                this.fireEvent('monthchange', this, date);
16790 //                
16791 //                this.cells.removeClass("fc-state-highlight");
16792 //                this.cells.each(function(c){
16793 //                   if(c.dateValue == t){
16794 //                       c.addClass("fc-state-highlight");
16795 //                       setTimeout(function(){
16796 //                            try{c.dom.firstChild.focus();}catch(e){}
16797 //                       }, 50);
16798 //                       return false;
16799 //                   }
16800 //                   return true;
16801 //                });
16802 //                return;
16803 //            }
16804 //        }
16805         
16806         var days = date.getDaysInMonth();
16807         
16808         var firstOfMonth = date.getFirstDateOfMonth();
16809         var startingPos = firstOfMonth.getDay()-this.startDay;
16810         
16811         if(startingPos < this.startDay){
16812             startingPos += 7;
16813         }
16814         
16815         var pm = date.add(Date.MONTH, -1);
16816         var prevStart = pm.getDaysInMonth()-startingPos;
16817 //        
16818         this.cells = this.el.select('.fc-day',true);
16819         this.textNodes = this.el.query('.fc-day-number');
16820         this.cells.addClassOnOver('fc-state-hover');
16821         
16822         var cells = this.cells.elements;
16823         var textEls = this.textNodes;
16824         
16825         Roo.each(cells, function(cell){
16826             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16827         });
16828         
16829         days += startingPos;
16830
16831         // convert everything to numbers so it's fast
16832         var day = 86400000;
16833         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16834         //Roo.log(d);
16835         //Roo.log(pm);
16836         //Roo.log(prevStart);
16837         
16838         var today = new Date().clearTime().getTime();
16839         var sel = date.clearTime().getTime();
16840         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16841         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16842         var ddMatch = this.disabledDatesRE;
16843         var ddText = this.disabledDatesText;
16844         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16845         var ddaysText = this.disabledDaysText;
16846         var format = this.format;
16847         
16848         var setCellClass = function(cal, cell){
16849             cell.row = 0;
16850             cell.events = [];
16851             cell.more = [];
16852             //Roo.log('set Cell Class');
16853             cell.title = "";
16854             var t = d.getTime();
16855             
16856             //Roo.log(d);
16857             
16858             cell.dateValue = t;
16859             if(t == today){
16860                 cell.className += " fc-today";
16861                 cell.className += " fc-state-highlight";
16862                 cell.title = cal.todayText;
16863             }
16864             if(t == sel){
16865                 // disable highlight in other month..
16866                 //cell.className += " fc-state-highlight";
16867                 
16868             }
16869             // disabling
16870             if(t < min) {
16871                 cell.className = " fc-state-disabled";
16872                 cell.title = cal.minText;
16873                 return;
16874             }
16875             if(t > max) {
16876                 cell.className = " fc-state-disabled";
16877                 cell.title = cal.maxText;
16878                 return;
16879             }
16880             if(ddays){
16881                 if(ddays.indexOf(d.getDay()) != -1){
16882                     cell.title = ddaysText;
16883                     cell.className = " fc-state-disabled";
16884                 }
16885             }
16886             if(ddMatch && format){
16887                 var fvalue = d.dateFormat(format);
16888                 if(ddMatch.test(fvalue)){
16889                     cell.title = ddText.replace("%0", fvalue);
16890                     cell.className = " fc-state-disabled";
16891                 }
16892             }
16893             
16894             if (!cell.initialClassName) {
16895                 cell.initialClassName = cell.dom.className;
16896             }
16897             
16898             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
16899         };
16900
16901         var i = 0;
16902         
16903         for(; i < startingPos; i++) {
16904             textEls[i].innerHTML = (++prevStart);
16905             d.setDate(d.getDate()+1);
16906             
16907             cells[i].className = "fc-past fc-other-month";
16908             setCellClass(this, cells[i]);
16909         }
16910         
16911         var intDay = 0;
16912         
16913         for(; i < days; i++){
16914             intDay = i - startingPos + 1;
16915             textEls[i].innerHTML = (intDay);
16916             d.setDate(d.getDate()+1);
16917             
16918             cells[i].className = ''; // "x-date-active";
16919             setCellClass(this, cells[i]);
16920         }
16921         var extraDays = 0;
16922         
16923         for(; i < 42; i++) {
16924             textEls[i].innerHTML = (++extraDays);
16925             d.setDate(d.getDate()+1);
16926             
16927             cells[i].className = "fc-future fc-other-month";
16928             setCellClass(this, cells[i]);
16929         }
16930         
16931         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16932         
16933         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16934         
16935         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16936         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16937         
16938         if(totalRows != 6){
16939             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16940             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16941         }
16942         
16943         this.fireEvent('monthchange', this, date);
16944         
16945         
16946         /*
16947         if(!this.internalRender){
16948             var main = this.el.dom.firstChild;
16949             var w = main.offsetWidth;
16950             this.el.setWidth(w + this.el.getBorderWidth("lr"));
16951             Roo.fly(main).setWidth(w);
16952             this.internalRender = true;
16953             // opera does not respect the auto grow header center column
16954             // then, after it gets a width opera refuses to recalculate
16955             // without a second pass
16956             if(Roo.isOpera && !this.secondPass){
16957                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16958                 this.secondPass = true;
16959                 this.update.defer(10, this, [date]);
16960             }
16961         }
16962         */
16963         
16964     },
16965     
16966     findCell : function(dt) {
16967         dt = dt.clearTime().getTime();
16968         var ret = false;
16969         this.cells.each(function(c){
16970             //Roo.log("check " +c.dateValue + '?=' + dt);
16971             if(c.dateValue == dt){
16972                 ret = c;
16973                 return false;
16974             }
16975             return true;
16976         });
16977         
16978         return ret;
16979     },
16980     
16981     findCells : function(ev) {
16982         var s = ev.start.clone().clearTime().getTime();
16983        // Roo.log(s);
16984         var e= ev.end.clone().clearTime().getTime();
16985        // Roo.log(e);
16986         var ret = [];
16987         this.cells.each(function(c){
16988              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16989             
16990             if(c.dateValue > e){
16991                 return ;
16992             }
16993             if(c.dateValue < s){
16994                 return ;
16995             }
16996             ret.push(c);
16997         });
16998         
16999         return ret;    
17000     },
17001     
17002 //    findBestRow: function(cells)
17003 //    {
17004 //        var ret = 0;
17005 //        
17006 //        for (var i =0 ; i < cells.length;i++) {
17007 //            ret  = Math.max(cells[i].rows || 0,ret);
17008 //        }
17009 //        return ret;
17010 //        
17011 //    },
17012     
17013     
17014     addItem : function(ev)
17015     {
17016         // look for vertical location slot in
17017         var cells = this.findCells(ev);
17018         
17019 //        ev.row = this.findBestRow(cells);
17020         
17021         // work out the location.
17022         
17023         var crow = false;
17024         var rows = [];
17025         for(var i =0; i < cells.length; i++) {
17026             
17027             cells[i].row = cells[0].row;
17028             
17029             if(i == 0){
17030                 cells[i].row = cells[i].row + 1;
17031             }
17032             
17033             if (!crow) {
17034                 crow = {
17035                     start : cells[i],
17036                     end :  cells[i]
17037                 };
17038                 continue;
17039             }
17040             if (crow.start.getY() == cells[i].getY()) {
17041                 // on same row.
17042                 crow.end = cells[i];
17043                 continue;
17044             }
17045             // different row.
17046             rows.push(crow);
17047             crow = {
17048                 start: cells[i],
17049                 end : cells[i]
17050             };
17051             
17052         }
17053         
17054         rows.push(crow);
17055         ev.els = [];
17056         ev.rows = rows;
17057         ev.cells = cells;
17058         
17059         cells[0].events.push(ev);
17060         
17061         this.calevents.push(ev);
17062     },
17063     
17064     clearEvents: function() {
17065         
17066         if(!this.calevents){
17067             return;
17068         }
17069         
17070         Roo.each(this.cells.elements, function(c){
17071             c.row = 0;
17072             c.events = [];
17073             c.more = [];
17074         });
17075         
17076         Roo.each(this.calevents, function(e) {
17077             Roo.each(e.els, function(el) {
17078                 el.un('mouseenter' ,this.onEventEnter, this);
17079                 el.un('mouseleave' ,this.onEventLeave, this);
17080                 el.remove();
17081             },this);
17082         },this);
17083         
17084         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17085             e.remove();
17086         });
17087         
17088     },
17089     
17090     renderEvents: function()
17091     {   
17092         var _this = this;
17093         
17094         this.cells.each(function(c) {
17095             
17096             if(c.row < 5){
17097                 return;
17098             }
17099             
17100             var ev = c.events;
17101             
17102             var r = 4;
17103             if(c.row != c.events.length){
17104                 r = 4 - (4 - (c.row - c.events.length));
17105             }
17106             
17107             c.events = ev.slice(0, r);
17108             c.more = ev.slice(r);
17109             
17110             if(c.more.length && c.more.length == 1){
17111                 c.events.push(c.more.pop());
17112             }
17113             
17114             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17115             
17116         });
17117             
17118         this.cells.each(function(c) {
17119             
17120             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17121             
17122             
17123             for (var e = 0; e < c.events.length; e++){
17124                 var ev = c.events[e];
17125                 var rows = ev.rows;
17126                 
17127                 for(var i = 0; i < rows.length; i++) {
17128                 
17129                     // how many rows should it span..
17130
17131                     var  cfg = {
17132                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17133                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17134
17135                         unselectable : "on",
17136                         cn : [
17137                             {
17138                                 cls: 'fc-event-inner',
17139                                 cn : [
17140     //                                {
17141     //                                  tag:'span',
17142     //                                  cls: 'fc-event-time',
17143     //                                  html : cells.length > 1 ? '' : ev.time
17144     //                                },
17145                                     {
17146                                       tag:'span',
17147                                       cls: 'fc-event-title',
17148                                       html : String.format('{0}', ev.title)
17149                                     }
17150
17151
17152                                 ]
17153                             },
17154                             {
17155                                 cls: 'ui-resizable-handle ui-resizable-e',
17156                                 html : '&nbsp;&nbsp;&nbsp'
17157                             }
17158
17159                         ]
17160                     };
17161
17162                     if (i == 0) {
17163                         cfg.cls += ' fc-event-start';
17164                     }
17165                     if ((i+1) == rows.length) {
17166                         cfg.cls += ' fc-event-end';
17167                     }
17168
17169                     var ctr = _this.el.select('.fc-event-container',true).first();
17170                     var cg = ctr.createChild(cfg);
17171
17172                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17173                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17174
17175                     var r = (c.more.length) ? 1 : 0;
17176                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
17177                     cg.setWidth(ebox.right - sbox.x -2);
17178
17179                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17180                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17181                     cg.on('click', _this.onEventClick, _this, ev);
17182
17183                     ev.els.push(cg);
17184                     
17185                 }
17186                 
17187             }
17188             
17189             
17190             if(c.more.length){
17191                 var  cfg = {
17192                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17193                     style : 'position: absolute',
17194                     unselectable : "on",
17195                     cn : [
17196                         {
17197                             cls: 'fc-event-inner',
17198                             cn : [
17199                                 {
17200                                   tag:'span',
17201                                   cls: 'fc-event-title',
17202                                   html : 'More'
17203                                 }
17204
17205
17206                             ]
17207                         },
17208                         {
17209                             cls: 'ui-resizable-handle ui-resizable-e',
17210                             html : '&nbsp;&nbsp;&nbsp'
17211                         }
17212
17213                     ]
17214                 };
17215
17216                 var ctr = _this.el.select('.fc-event-container',true).first();
17217                 var cg = ctr.createChild(cfg);
17218
17219                 var sbox = c.select('.fc-day-content',true).first().getBox();
17220                 var ebox = c.select('.fc-day-content',true).first().getBox();
17221                 //Roo.log(cg);
17222                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
17223                 cg.setWidth(ebox.right - sbox.x -2);
17224
17225                 cg.on('click', _this.onMoreEventClick, _this, c.more);
17226                 
17227             }
17228             
17229         });
17230         
17231         
17232         
17233     },
17234     
17235     onEventEnter: function (e, el,event,d) {
17236         this.fireEvent('evententer', this, el, event);
17237     },
17238     
17239     onEventLeave: function (e, el,event,d) {
17240         this.fireEvent('eventleave', this, el, event);
17241     },
17242     
17243     onEventClick: function (e, el,event,d) {
17244         this.fireEvent('eventclick', this, el, event);
17245     },
17246     
17247     onMonthChange: function () {
17248         this.store.load();
17249     },
17250     
17251     onMoreEventClick: function(e, el, more)
17252     {
17253         var _this = this;
17254         
17255         this.calpopover.placement = 'right';
17256         this.calpopover.setTitle('More');
17257         
17258         this.calpopover.setContent('');
17259         
17260         var ctr = this.calpopover.el.select('.popover-content', true).first();
17261         
17262         Roo.each(more, function(m){
17263             var cfg = {
17264                 cls : 'fc-event-hori fc-event-draggable',
17265                 html : m.title
17266             };
17267             var cg = ctr.createChild(cfg);
17268             
17269             cg.on('click', _this.onEventClick, _this, m);
17270         });
17271         
17272         this.calpopover.show(el);
17273         
17274         
17275     },
17276     
17277     onLoad: function () 
17278     {   
17279         this.calevents = [];
17280         var cal = this;
17281         
17282         if(this.store.getCount() > 0){
17283             this.store.data.each(function(d){
17284                cal.addItem({
17285                     id : d.data.id,
17286                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17287                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17288                     time : d.data.start_time,
17289                     title : d.data.title,
17290                     description : d.data.description,
17291                     venue : d.data.venue
17292                 });
17293             });
17294         }
17295         
17296         this.renderEvents();
17297         
17298         if(this.calevents.length && this.loadMask){
17299             this.maskEl.hide();
17300         }
17301     },
17302     
17303     onBeforeLoad: function()
17304     {
17305         this.clearEvents();
17306         if(this.loadMask){
17307             this.maskEl.show();
17308         }
17309     }
17310 });
17311
17312  
17313  /*
17314  * - LGPL
17315  *
17316  * element
17317  * 
17318  */
17319
17320 /**
17321  * @class Roo.bootstrap.Popover
17322  * @extends Roo.bootstrap.Component
17323  * Bootstrap Popover class
17324  * @cfg {String} html contents of the popover   (or false to use children..)
17325  * @cfg {String} title of popover (or false to hide)
17326  * @cfg {String} placement how it is placed
17327  * @cfg {String} trigger click || hover (or false to trigger manually)
17328  * @cfg {String} over what (parent or false to trigger manually.)
17329  * @cfg {Number} delay - delay before showing
17330  
17331  * @constructor
17332  * Create a new Popover
17333  * @param {Object} config The config object
17334  */
17335
17336 Roo.bootstrap.Popover = function(config){
17337     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17338     
17339     this.addEvents({
17340         // raw events
17341          /**
17342          * @event show
17343          * After the popover show
17344          * 
17345          * @param {Roo.bootstrap.Popover} this
17346          */
17347         "show" : true,
17348         /**
17349          * @event hide
17350          * After the popover hide
17351          * 
17352          * @param {Roo.bootstrap.Popover} this
17353          */
17354         "hide" : true
17355     });
17356 };
17357
17358 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
17359     
17360     title: 'Fill in a title',
17361     html: false,
17362     
17363     placement : 'right',
17364     trigger : 'hover', // hover
17365     
17366     delay : 0,
17367     
17368     over: 'parent',
17369     
17370     can_build_overlaid : false,
17371     
17372     getChildContainer : function()
17373     {
17374         return this.el.select('.popover-content',true).first();
17375     },
17376     
17377     getAutoCreate : function(){
17378          
17379         var cfg = {
17380            cls : 'popover roo-dynamic',
17381            style: 'display:block',
17382            cn : [
17383                 {
17384                     cls : 'arrow'
17385                 },
17386                 {
17387                     cls : 'popover-inner',
17388                     cn : [
17389                         {
17390                             tag: 'h3',
17391                             cls: 'popover-title',
17392                             html : this.title
17393                         },
17394                         {
17395                             cls : 'popover-content',
17396                             html : this.html
17397                         }
17398                     ]
17399                     
17400                 }
17401            ]
17402         };
17403         
17404         return cfg;
17405     },
17406     setTitle: function(str)
17407     {
17408         this.title = str;
17409         this.el.select('.popover-title',true).first().dom.innerHTML = str;
17410     },
17411     setContent: function(str)
17412     {
17413         this.html = str;
17414         this.el.select('.popover-content',true).first().dom.innerHTML = str;
17415     },
17416     // as it get's added to the bottom of the page.
17417     onRender : function(ct, position)
17418     {
17419         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17420         if(!this.el){
17421             var cfg = Roo.apply({},  this.getAutoCreate());
17422             cfg.id = Roo.id();
17423             
17424             if (this.cls) {
17425                 cfg.cls += ' ' + this.cls;
17426             }
17427             if (this.style) {
17428                 cfg.style = this.style;
17429             }
17430             //Roo.log("adding to ");
17431             this.el = Roo.get(document.body).createChild(cfg, position);
17432 //            Roo.log(this.el);
17433         }
17434         this.initEvents();
17435     },
17436     
17437     initEvents : function()
17438     {
17439         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17440         this.el.enableDisplayMode('block');
17441         this.el.hide();
17442         if (this.over === false) {
17443             return; 
17444         }
17445         if (this.triggers === false) {
17446             return;
17447         }
17448         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17449         var triggers = this.trigger ? this.trigger.split(' ') : [];
17450         Roo.each(triggers, function(trigger) {
17451         
17452             if (trigger == 'click') {
17453                 on_el.on('click', this.toggle, this);
17454             } else if (trigger != 'manual') {
17455                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
17456                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17457       
17458                 on_el.on(eventIn  ,this.enter, this);
17459                 on_el.on(eventOut, this.leave, this);
17460             }
17461         }, this);
17462         
17463     },
17464     
17465     
17466     // private
17467     timeout : null,
17468     hoverState : null,
17469     
17470     toggle : function () {
17471         this.hoverState == 'in' ? this.leave() : this.enter();
17472     },
17473     
17474     enter : function () {
17475         
17476         clearTimeout(this.timeout);
17477     
17478         this.hoverState = 'in';
17479     
17480         if (!this.delay || !this.delay.show) {
17481             this.show();
17482             return;
17483         }
17484         var _t = this;
17485         this.timeout = setTimeout(function () {
17486             if (_t.hoverState == 'in') {
17487                 _t.show();
17488             }
17489         }, this.delay.show)
17490     },
17491     
17492     leave : function() {
17493         clearTimeout(this.timeout);
17494     
17495         this.hoverState = 'out';
17496     
17497         if (!this.delay || !this.delay.hide) {
17498             this.hide();
17499             return;
17500         }
17501         var _t = this;
17502         this.timeout = setTimeout(function () {
17503             if (_t.hoverState == 'out') {
17504                 _t.hide();
17505             }
17506         }, this.delay.hide)
17507     },
17508     
17509     show : function (on_el)
17510     {
17511         if (!on_el) {
17512             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17513         }
17514         
17515         // set content.
17516         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17517         if (this.html !== false) {
17518             this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17519         }
17520         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17521         if (!this.title.length) {
17522             this.el.select('.popover-title',true).hide();
17523         }
17524         
17525         var placement = typeof this.placement == 'function' ?
17526             this.placement.call(this, this.el, on_el) :
17527             this.placement;
17528             
17529         var autoToken = /\s?auto?\s?/i;
17530         var autoPlace = autoToken.test(placement);
17531         if (autoPlace) {
17532             placement = placement.replace(autoToken, '') || 'top';
17533         }
17534         
17535         //this.el.detach()
17536         //this.el.setXY([0,0]);
17537         this.el.show();
17538         this.el.dom.style.display='block';
17539         this.el.addClass(placement);
17540         
17541         //this.el.appendTo(on_el);
17542         
17543         var p = this.getPosition();
17544         var box = this.el.getBox();
17545         
17546         if (autoPlace) {
17547             // fixme..
17548         }
17549         var align = Roo.bootstrap.Popover.alignment[placement];
17550         
17551 //        Roo.log(align);
17552         this.el.alignTo(on_el, align[0],align[1]);
17553         //var arrow = this.el.select('.arrow',true).first();
17554         //arrow.set(align[2], 
17555         
17556         this.el.addClass('in');
17557         
17558         
17559         if (this.el.hasClass('fade')) {
17560             // fade it?
17561         }
17562         
17563         this.hoverState = 'in';
17564         
17565         this.fireEvent('show', this);
17566         
17567     },
17568     hide : function()
17569     {
17570         this.el.setXY([0,0]);
17571         this.el.removeClass('in');
17572         this.el.hide();
17573         this.hoverState = null;
17574         
17575         this.fireEvent('hide', this);
17576     }
17577     
17578 });
17579
17580 Roo.bootstrap.Popover.alignment = {
17581     'left' : ['r-l', [-10,0], 'right'],
17582     'right' : ['l-r', [10,0], 'left'],
17583     'bottom' : ['t-b', [0,10], 'top'],
17584     'top' : [ 'b-t', [0,-10], 'bottom']
17585 };
17586
17587  /*
17588  * - LGPL
17589  *
17590  * Progress
17591  * 
17592  */
17593
17594 /**
17595  * @class Roo.bootstrap.Progress
17596  * @extends Roo.bootstrap.Component
17597  * Bootstrap Progress class
17598  * @cfg {Boolean} striped striped of the progress bar
17599  * @cfg {Boolean} active animated of the progress bar
17600  * 
17601  * 
17602  * @constructor
17603  * Create a new Progress
17604  * @param {Object} config The config object
17605  */
17606
17607 Roo.bootstrap.Progress = function(config){
17608     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17609 };
17610
17611 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
17612     
17613     striped : false,
17614     active: false,
17615     
17616     getAutoCreate : function(){
17617         var cfg = {
17618             tag: 'div',
17619             cls: 'progress'
17620         };
17621         
17622         
17623         if(this.striped){
17624             cfg.cls += ' progress-striped';
17625         }
17626       
17627         if(this.active){
17628             cfg.cls += ' active';
17629         }
17630         
17631         
17632         return cfg;
17633     }
17634    
17635 });
17636
17637  
17638
17639  /*
17640  * - LGPL
17641  *
17642  * ProgressBar
17643  * 
17644  */
17645
17646 /**
17647  * @class Roo.bootstrap.ProgressBar
17648  * @extends Roo.bootstrap.Component
17649  * Bootstrap ProgressBar class
17650  * @cfg {Number} aria_valuenow aria-value now
17651  * @cfg {Number} aria_valuemin aria-value min
17652  * @cfg {Number} aria_valuemax aria-value max
17653  * @cfg {String} label label for the progress bar
17654  * @cfg {String} panel (success | info | warning | danger )
17655  * @cfg {String} role role of the progress bar
17656  * @cfg {String} sr_only text
17657  * 
17658  * 
17659  * @constructor
17660  * Create a new ProgressBar
17661  * @param {Object} config The config object
17662  */
17663
17664 Roo.bootstrap.ProgressBar = function(config){
17665     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17666 };
17667
17668 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
17669     
17670     aria_valuenow : 0,
17671     aria_valuemin : 0,
17672     aria_valuemax : 100,
17673     label : false,
17674     panel : false,
17675     role : false,
17676     sr_only: false,
17677     
17678     getAutoCreate : function()
17679     {
17680         
17681         var cfg = {
17682             tag: 'div',
17683             cls: 'progress-bar',
17684             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17685         };
17686         
17687         if(this.sr_only){
17688             cfg.cn = {
17689                 tag: 'span',
17690                 cls: 'sr-only',
17691                 html: this.sr_only
17692             }
17693         }
17694         
17695         if(this.role){
17696             cfg.role = this.role;
17697         }
17698         
17699         if(this.aria_valuenow){
17700             cfg['aria-valuenow'] = this.aria_valuenow;
17701         }
17702         
17703         if(this.aria_valuemin){
17704             cfg['aria-valuemin'] = this.aria_valuemin;
17705         }
17706         
17707         if(this.aria_valuemax){
17708             cfg['aria-valuemax'] = this.aria_valuemax;
17709         }
17710         
17711         if(this.label && !this.sr_only){
17712             cfg.html = this.label;
17713         }
17714         
17715         if(this.panel){
17716             cfg.cls += ' progress-bar-' + this.panel;
17717         }
17718         
17719         return cfg;
17720     },
17721     
17722     update : function(aria_valuenow)
17723     {
17724         this.aria_valuenow = aria_valuenow;
17725         
17726         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17727     }
17728    
17729 });
17730
17731  
17732
17733  /*
17734  * - LGPL
17735  *
17736  * column
17737  * 
17738  */
17739
17740 /**
17741  * @class Roo.bootstrap.TabGroup
17742  * @extends Roo.bootstrap.Column
17743  * Bootstrap Column class
17744  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17745  * @cfg {Boolean} carousel true to make the group behave like a carousel
17746  * @cfg {Boolean} bullets show bullets for the panels
17747  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17748  * @cfg {Number} timer auto slide timer .. default 0 millisecond
17749  * @cfg {Boolean} showarrow (true|false) show arrow default true
17750  * 
17751  * @constructor
17752  * Create a new TabGroup
17753  * @param {Object} config The config object
17754  */
17755
17756 Roo.bootstrap.TabGroup = function(config){
17757     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17758     if (!this.navId) {
17759         this.navId = Roo.id();
17760     }
17761     this.tabs = [];
17762     Roo.bootstrap.TabGroup.register(this);
17763     
17764 };
17765
17766 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
17767     
17768     carousel : false,
17769     transition : false,
17770     bullets : 0,
17771     timer : 0,
17772     autoslide : false,
17773     slideFn : false,
17774     slideOnTouch : false,
17775     showarrow : true,
17776     
17777     getAutoCreate : function()
17778     {
17779         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17780         
17781         cfg.cls += ' tab-content';
17782         
17783         if (this.carousel) {
17784             cfg.cls += ' carousel slide';
17785             
17786             cfg.cn = [{
17787                cls : 'carousel-inner',
17788                cn : []
17789             }];
17790         
17791             if(this.bullets  && !Roo.isTouch){
17792                 
17793                 var bullets = {
17794                     cls : 'carousel-bullets',
17795                     cn : []
17796                 };
17797                
17798                 if(this.bullets_cls){
17799                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17800                 }
17801                 
17802                 bullets.cn.push({
17803                     cls : 'clear'
17804                 });
17805                 
17806                 cfg.cn[0].cn.push(bullets);
17807             }
17808             
17809             if(this.showarrow){
17810                 cfg.cn[0].cn.push({
17811                     tag : 'div',
17812                     class : 'carousel-arrow',
17813                     cn : [
17814                         {
17815                             tag : 'div',
17816                             class : 'carousel-prev',
17817                             cn : [
17818                                 {
17819                                     tag : 'i',
17820                                     class : 'fa fa-chevron-left'
17821                                 }
17822                             ]
17823                         },
17824                         {
17825                             tag : 'div',
17826                             class : 'carousel-next',
17827                             cn : [
17828                                 {
17829                                     tag : 'i',
17830                                     class : 'fa fa-chevron-right'
17831                                 }
17832                             ]
17833                         }
17834                     ]
17835                 });
17836             }
17837             
17838         }
17839         
17840         return cfg;
17841     },
17842     
17843     initEvents:  function()
17844     {
17845 //        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17846 //            this.el.on("touchstart", this.onTouchStart, this);
17847 //        }
17848         
17849         if(this.autoslide){
17850             var _this = this;
17851             
17852             this.slideFn = window.setInterval(function() {
17853                 _this.showPanelNext();
17854             }, this.timer);
17855         }
17856         
17857         if(this.showarrow){
17858             this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17859             this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17860         }
17861         
17862         
17863     },
17864     
17865 //    onTouchStart : function(e, el, o)
17866 //    {
17867 //        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17868 //            return;
17869 //        }
17870 //        
17871 //        this.showPanelNext();
17872 //    },
17873     
17874     
17875     getChildContainer : function()
17876     {
17877         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17878     },
17879     
17880     /**
17881     * register a Navigation item
17882     * @param {Roo.bootstrap.NavItem} the navitem to add
17883     */
17884     register : function(item)
17885     {
17886         this.tabs.push( item);
17887         item.navId = this.navId; // not really needed..
17888         this.addBullet();
17889     
17890     },
17891     
17892     getActivePanel : function()
17893     {
17894         var r = false;
17895         Roo.each(this.tabs, function(t) {
17896             if (t.active) {
17897                 r = t;
17898                 return false;
17899             }
17900             return null;
17901         });
17902         return r;
17903         
17904     },
17905     getPanelByName : function(n)
17906     {
17907         var r = false;
17908         Roo.each(this.tabs, function(t) {
17909             if (t.tabId == n) {
17910                 r = t;
17911                 return false;
17912             }
17913             return null;
17914         });
17915         return r;
17916     },
17917     indexOfPanel : function(p)
17918     {
17919         var r = false;
17920         Roo.each(this.tabs, function(t,i) {
17921             if (t.tabId == p.tabId) {
17922                 r = i;
17923                 return false;
17924             }
17925             return null;
17926         });
17927         return r;
17928     },
17929     /**
17930      * show a specific panel
17931      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17932      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17933      */
17934     showPanel : function (pan)
17935     {
17936         if(this.transition || typeof(pan) == 'undefined'){
17937             Roo.log("waiting for the transitionend");
17938             return;
17939         }
17940         
17941         if (typeof(pan) == 'number') {
17942             pan = this.tabs[pan];
17943         }
17944         
17945         if (typeof(pan) == 'string') {
17946             pan = this.getPanelByName(pan);
17947         }
17948         
17949         var cur = this.getActivePanel();
17950         
17951         if(!pan || !cur){
17952             Roo.log('pan or acitve pan is undefined');
17953             return false;
17954         }
17955         
17956         if (pan.tabId == this.getActivePanel().tabId) {
17957             return true;
17958         }
17959         
17960         if (false === cur.fireEvent('beforedeactivate')) {
17961             return false;
17962         }
17963         
17964         if(this.bullets > 0 && !Roo.isTouch){
17965             this.setActiveBullet(this.indexOfPanel(pan));
17966         }
17967         
17968         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17969             
17970             this.transition = true;
17971             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
17972             var lr = dir == 'next' ? 'left' : 'right';
17973             pan.el.addClass(dir); // or prev
17974             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17975             cur.el.addClass(lr); // or right
17976             pan.el.addClass(lr);
17977             
17978             var _this = this;
17979             cur.el.on('transitionend', function() {
17980                 Roo.log("trans end?");
17981                 
17982                 pan.el.removeClass([lr,dir]);
17983                 pan.setActive(true);
17984                 
17985                 cur.el.removeClass([lr]);
17986                 cur.setActive(false);
17987                 
17988                 _this.transition = false;
17989                 
17990             }, this, { single:  true } );
17991             
17992             return true;
17993         }
17994         
17995         cur.setActive(false);
17996         pan.setActive(true);
17997         
17998         return true;
17999         
18000     },
18001     showPanelNext : function()
18002     {
18003         var i = this.indexOfPanel(this.getActivePanel());
18004         
18005         if (i >= this.tabs.length - 1 && !this.autoslide) {
18006             return;
18007         }
18008         
18009         if (i >= this.tabs.length - 1 && this.autoslide) {
18010             i = -1;
18011         }
18012         
18013         this.showPanel(this.tabs[i+1]);
18014     },
18015     
18016     showPanelPrev : function()
18017     {
18018         var i = this.indexOfPanel(this.getActivePanel());
18019         
18020         if (i  < 1 && !this.autoslide) {
18021             return;
18022         }
18023         
18024         if (i < 1 && this.autoslide) {
18025             i = this.tabs.length;
18026         }
18027         
18028         this.showPanel(this.tabs[i-1]);
18029     },
18030     
18031     
18032     addBullet: function()
18033     {
18034         if(!this.bullets || Roo.isTouch){
18035             return;
18036         }
18037         var ctr = this.el.select('.carousel-bullets',true).first();
18038         var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18039         var bullet = ctr.createChild({
18040             cls : 'bullet bullet-' + i
18041         },ctr.dom.lastChild);
18042         
18043         
18044         var _this = this;
18045         
18046         bullet.on('click', (function(e, el, o, ii, t){
18047
18048             e.preventDefault();
18049
18050             this.showPanel(ii);
18051
18052             if(this.autoslide && this.slideFn){
18053                 clearInterval(this.slideFn);
18054                 this.slideFn = window.setInterval(function() {
18055                     _this.showPanelNext();
18056                 }, this.timer);
18057             }
18058
18059         }).createDelegate(this, [i, bullet], true));
18060                 
18061         
18062     },
18063      
18064     setActiveBullet : function(i)
18065     {
18066         if(Roo.isTouch){
18067             return;
18068         }
18069         
18070         Roo.each(this.el.select('.bullet', true).elements, function(el){
18071             el.removeClass('selected');
18072         });
18073
18074         var bullet = this.el.select('.bullet-' + i, true).first();
18075         
18076         if(!bullet){
18077             return;
18078         }
18079         
18080         bullet.addClass('selected');
18081     }
18082     
18083     
18084   
18085 });
18086
18087  
18088
18089  
18090  
18091 Roo.apply(Roo.bootstrap.TabGroup, {
18092     
18093     groups: {},
18094      /**
18095     * register a Navigation Group
18096     * @param {Roo.bootstrap.NavGroup} the navgroup to add
18097     */
18098     register : function(navgrp)
18099     {
18100         this.groups[navgrp.navId] = navgrp;
18101         
18102     },
18103     /**
18104     * fetch a Navigation Group based on the navigation ID
18105     * if one does not exist , it will get created.
18106     * @param {string} the navgroup to add
18107     * @returns {Roo.bootstrap.NavGroup} the navgroup 
18108     */
18109     get: function(navId) {
18110         if (typeof(this.groups[navId]) == 'undefined') {
18111             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18112         }
18113         return this.groups[navId] ;
18114     }
18115     
18116     
18117     
18118 });
18119
18120  /*
18121  * - LGPL
18122  *
18123  * TabPanel
18124  * 
18125  */
18126
18127 /**
18128  * @class Roo.bootstrap.TabPanel
18129  * @extends Roo.bootstrap.Component
18130  * Bootstrap TabPanel class
18131  * @cfg {Boolean} active panel active
18132  * @cfg {String} html panel content
18133  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18134  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18135  * @cfg {String} href click to link..
18136  * 
18137  * 
18138  * @constructor
18139  * Create a new TabPanel
18140  * @param {Object} config The config object
18141  */
18142
18143 Roo.bootstrap.TabPanel = function(config){
18144     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18145     this.addEvents({
18146         /**
18147              * @event changed
18148              * Fires when the active status changes
18149              * @param {Roo.bootstrap.TabPanel} this
18150              * @param {Boolean} state the new state
18151             
18152          */
18153         'changed': true,
18154         /**
18155              * @event beforedeactivate
18156              * Fires before a tab is de-activated - can be used to do validation on a form.
18157              * @param {Roo.bootstrap.TabPanel} this
18158              * @return {Boolean} false if there is an error
18159             
18160          */
18161         'beforedeactivate': true
18162      });
18163     
18164     this.tabId = this.tabId || Roo.id();
18165   
18166 };
18167
18168 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
18169     
18170     active: false,
18171     html: false,
18172     tabId: false,
18173     navId : false,
18174     href : '',
18175     
18176     getAutoCreate : function(){
18177         var cfg = {
18178             tag: 'div',
18179             // item is needed for carousel - not sure if it has any effect otherwise
18180             cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18181             html: this.html || ''
18182         };
18183         
18184         if(this.active){
18185             cfg.cls += ' active';
18186         }
18187         
18188         if(this.tabId){
18189             cfg.tabId = this.tabId;
18190         }
18191         
18192         
18193         return cfg;
18194     },
18195     
18196     initEvents:  function()
18197     {
18198         var p = this.parent();
18199         
18200         this.navId = this.navId || p.navId;
18201         
18202         if (typeof(this.navId) != 'undefined') {
18203             // not really needed.. but just in case.. parent should be a NavGroup.
18204             var tg = Roo.bootstrap.TabGroup.get(this.navId);
18205             
18206             tg.register(this);
18207             
18208             var i = tg.tabs.length - 1;
18209             
18210             if(this.active && tg.bullets > 0 && i < tg.bullets){
18211                 tg.setActiveBullet(i);
18212             }
18213         }
18214         
18215         this.el.on('click', this.onClick, this);
18216         
18217         if(Roo.isTouch){
18218             this.el.on("touchstart", this.onTouchStart, this);
18219             this.el.on("touchmove", this.onTouchMove, this);
18220             this.el.on("touchend", this.onTouchEnd, this);
18221         }
18222         
18223     },
18224     
18225     onRender : function(ct, position)
18226     {
18227         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18228     },
18229     
18230     setActive : function(state)
18231     {
18232         Roo.log("panel - set active " + this.tabId + "=" + state);
18233         
18234         this.active = state;
18235         if (!state) {
18236             this.el.removeClass('active');
18237             
18238         } else  if (!this.el.hasClass('active')) {
18239             this.el.addClass('active');
18240         }
18241         
18242         this.fireEvent('changed', this, state);
18243     },
18244     
18245     onClick : function(e)
18246     {
18247         e.preventDefault();
18248         
18249         if(!this.href.length){
18250             return;
18251         }
18252         
18253         window.location.href = this.href;
18254     },
18255     
18256     startX : 0,
18257     startY : 0,
18258     endX : 0,
18259     endY : 0,
18260     swiping : false,
18261     
18262     onTouchStart : function(e)
18263     {
18264         this.swiping = false;
18265         
18266         this.startX = e.browserEvent.touches[0].clientX;
18267         this.startY = e.browserEvent.touches[0].clientY;
18268     },
18269     
18270     onTouchMove : function(e)
18271     {
18272         this.swiping = true;
18273         
18274         this.endX = e.browserEvent.touches[0].clientX;
18275         this.endY = e.browserEvent.touches[0].clientY;
18276     },
18277     
18278     onTouchEnd : function(e)
18279     {
18280         if(!this.swiping){
18281             this.onClick(e);
18282             return;
18283         }
18284         
18285         var tabGroup = this.parent();
18286         
18287         if(this.endX > this.startX){ // swiping right
18288             tabGroup.showPanelPrev();
18289             return;
18290         }
18291         
18292         if(this.startX > this.endX){ // swiping left
18293             tabGroup.showPanelNext();
18294             return;
18295         }
18296     }
18297     
18298     
18299 });
18300  
18301
18302  
18303
18304  /*
18305  * - LGPL
18306  *
18307  * DateField
18308  * 
18309  */
18310
18311 /**
18312  * @class Roo.bootstrap.DateField
18313  * @extends Roo.bootstrap.Input
18314  * Bootstrap DateField class
18315  * @cfg {Number} weekStart default 0
18316  * @cfg {String} viewMode default empty, (months|years)
18317  * @cfg {String} minViewMode default empty, (months|years)
18318  * @cfg {Number} startDate default -Infinity
18319  * @cfg {Number} endDate default Infinity
18320  * @cfg {Boolean} todayHighlight default false
18321  * @cfg {Boolean} todayBtn default false
18322  * @cfg {Boolean} calendarWeeks default false
18323  * @cfg {Object} daysOfWeekDisabled default empty
18324  * @cfg {Boolean} singleMode default false (true | false)
18325  * 
18326  * @cfg {Boolean} keyboardNavigation default true
18327  * @cfg {String} language default en
18328  * 
18329  * @constructor
18330  * Create a new DateField
18331  * @param {Object} config The config object
18332  */
18333
18334 Roo.bootstrap.DateField = function(config){
18335     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18336      this.addEvents({
18337             /**
18338              * @event show
18339              * Fires when this field show.
18340              * @param {Roo.bootstrap.DateField} this
18341              * @param {Mixed} date The date value
18342              */
18343             show : true,
18344             /**
18345              * @event show
18346              * Fires when this field hide.
18347              * @param {Roo.bootstrap.DateField} this
18348              * @param {Mixed} date The date value
18349              */
18350             hide : true,
18351             /**
18352              * @event select
18353              * Fires when select a date.
18354              * @param {Roo.bootstrap.DateField} this
18355              * @param {Mixed} date The date value
18356              */
18357             select : true,
18358             /**
18359              * @event beforeselect
18360              * Fires when before select a date.
18361              * @param {Roo.bootstrap.DateField} this
18362              * @param {Mixed} date The date value
18363              */
18364             beforeselect : true
18365         });
18366 };
18367
18368 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
18369     
18370     /**
18371      * @cfg {String} format
18372      * The default date format string which can be overriden for localization support.  The format must be
18373      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18374      */
18375     format : "m/d/y",
18376     /**
18377      * @cfg {String} altFormats
18378      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18379      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18380      */
18381     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18382     
18383     weekStart : 0,
18384     
18385     viewMode : '',
18386     
18387     minViewMode : '',
18388     
18389     todayHighlight : false,
18390     
18391     todayBtn: false,
18392     
18393     language: 'en',
18394     
18395     keyboardNavigation: true,
18396     
18397     calendarWeeks: false,
18398     
18399     startDate: -Infinity,
18400     
18401     endDate: Infinity,
18402     
18403     daysOfWeekDisabled: [],
18404     
18405     _events: [],
18406     
18407     singleMode : false,
18408     
18409     UTCDate: function()
18410     {
18411         return new Date(Date.UTC.apply(Date, arguments));
18412     },
18413     
18414     UTCToday: function()
18415     {
18416         var today = new Date();
18417         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18418     },
18419     
18420     getDate: function() {
18421             var d = this.getUTCDate();
18422             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18423     },
18424     
18425     getUTCDate: function() {
18426             return this.date;
18427     },
18428     
18429     setDate: function(d) {
18430             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18431     },
18432     
18433     setUTCDate: function(d) {
18434             this.date = d;
18435             this.setValue(this.formatDate(this.date));
18436     },
18437         
18438     onRender: function(ct, position)
18439     {
18440         
18441         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18442         
18443         this.language = this.language || 'en';
18444         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18445         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18446         
18447         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18448         this.format = this.format || 'm/d/y';
18449         this.isInline = false;
18450         this.isInput = true;
18451         this.component = this.el.select('.add-on', true).first() || false;
18452         this.component = (this.component && this.component.length === 0) ? false : this.component;
18453         this.hasInput = this.component && this.inputEl().length;
18454         
18455         if (typeof(this.minViewMode === 'string')) {
18456             switch (this.minViewMode) {
18457                 case 'months':
18458                     this.minViewMode = 1;
18459                     break;
18460                 case 'years':
18461                     this.minViewMode = 2;
18462                     break;
18463                 default:
18464                     this.minViewMode = 0;
18465                     break;
18466             }
18467         }
18468         
18469         if (typeof(this.viewMode === 'string')) {
18470             switch (this.viewMode) {
18471                 case 'months':
18472                     this.viewMode = 1;
18473                     break;
18474                 case 'years':
18475                     this.viewMode = 2;
18476                     break;
18477                 default:
18478                     this.viewMode = 0;
18479                     break;
18480             }
18481         }
18482                 
18483         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18484         
18485 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18486         
18487         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18488         
18489         this.picker().on('mousedown', this.onMousedown, this);
18490         this.picker().on('click', this.onClick, this);
18491         
18492         this.picker().addClass('datepicker-dropdown');
18493         
18494         this.startViewMode = this.viewMode;
18495         
18496         if(this.singleMode){
18497             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18498                 v.setVisibilityMode(Roo.Element.DISPLAY);
18499                 v.hide();
18500             });
18501             
18502             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18503                 v.setStyle('width', '189px');
18504             });
18505         }
18506         
18507         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18508             if(!this.calendarWeeks){
18509                 v.remove();
18510                 return;
18511             }
18512             
18513             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18514             v.attr('colspan', function(i, val){
18515                 return parseInt(val) + 1;
18516             });
18517         });
18518                         
18519         
18520         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18521         
18522         this.setStartDate(this.startDate);
18523         this.setEndDate(this.endDate);
18524         
18525         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18526         
18527         this.fillDow();
18528         this.fillMonths();
18529         this.update();
18530         this.showMode();
18531         
18532         if(this.isInline) {
18533             this.show();
18534         }
18535     },
18536     
18537     picker : function()
18538     {
18539         return this.pickerEl;
18540 //        return this.el.select('.datepicker', true).first();
18541     },
18542     
18543     fillDow: function()
18544     {
18545         var dowCnt = this.weekStart;
18546         
18547         var dow = {
18548             tag: 'tr',
18549             cn: [
18550                 
18551             ]
18552         };
18553         
18554         if(this.calendarWeeks){
18555             dow.cn.push({
18556                 tag: 'th',
18557                 cls: 'cw',
18558                 html: '&nbsp;'
18559             })
18560         }
18561         
18562         while (dowCnt < this.weekStart + 7) {
18563             dow.cn.push({
18564                 tag: 'th',
18565                 cls: 'dow',
18566                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18567             });
18568         }
18569         
18570         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18571     },
18572     
18573     fillMonths: function()
18574     {    
18575         var i = 0;
18576         var months = this.picker().select('>.datepicker-months td', true).first();
18577         
18578         months.dom.innerHTML = '';
18579         
18580         while (i < 12) {
18581             var month = {
18582                 tag: 'span',
18583                 cls: 'month',
18584                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18585             };
18586             
18587             months.createChild(month);
18588         }
18589         
18590     },
18591     
18592     update: function()
18593     {
18594         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;
18595         
18596         if (this.date < this.startDate) {
18597             this.viewDate = new Date(this.startDate);
18598         } else if (this.date > this.endDate) {
18599             this.viewDate = new Date(this.endDate);
18600         } else {
18601             this.viewDate = new Date(this.date);
18602         }
18603         
18604         this.fill();
18605     },
18606     
18607     fill: function() 
18608     {
18609         var d = new Date(this.viewDate),
18610                 year = d.getUTCFullYear(),
18611                 month = d.getUTCMonth(),
18612                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18613                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18614                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18615                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18616                 currentDate = this.date && this.date.valueOf(),
18617                 today = this.UTCToday();
18618         
18619         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18620         
18621 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18622         
18623 //        this.picker.select('>tfoot th.today').
18624 //                                              .text(dates[this.language].today)
18625 //                                              .toggle(this.todayBtn !== false);
18626     
18627         this.updateNavArrows();
18628         this.fillMonths();
18629                                                 
18630         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18631         
18632         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18633          
18634         prevMonth.setUTCDate(day);
18635         
18636         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18637         
18638         var nextMonth = new Date(prevMonth);
18639         
18640         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18641         
18642         nextMonth = nextMonth.valueOf();
18643         
18644         var fillMonths = false;
18645         
18646         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18647         
18648         while(prevMonth.valueOf() < nextMonth) {
18649             var clsName = '';
18650             
18651             if (prevMonth.getUTCDay() === this.weekStart) {
18652                 if(fillMonths){
18653                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18654                 }
18655                     
18656                 fillMonths = {
18657                     tag: 'tr',
18658                     cn: []
18659                 };
18660                 
18661                 if(this.calendarWeeks){
18662                     // ISO 8601: First week contains first thursday.
18663                     // ISO also states week starts on Monday, but we can be more abstract here.
18664                     var
18665                     // Start of current week: based on weekstart/current date
18666                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18667                     // Thursday of this week
18668                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18669                     // First Thursday of year, year from thursday
18670                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18671                     // Calendar week: ms between thursdays, div ms per day, div 7 days
18672                     calWeek =  (th - yth) / 864e5 / 7 + 1;
18673                     
18674                     fillMonths.cn.push({
18675                         tag: 'td',
18676                         cls: 'cw',
18677                         html: calWeek
18678                     });
18679                 }
18680             }
18681             
18682             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18683                 clsName += ' old';
18684             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18685                 clsName += ' new';
18686             }
18687             if (this.todayHighlight &&
18688                 prevMonth.getUTCFullYear() == today.getFullYear() &&
18689                 prevMonth.getUTCMonth() == today.getMonth() &&
18690                 prevMonth.getUTCDate() == today.getDate()) {
18691                 clsName += ' today';
18692             }
18693             
18694             if (currentDate && prevMonth.valueOf() === currentDate) {
18695                 clsName += ' active';
18696             }
18697             
18698             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18699                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18700                     clsName += ' disabled';
18701             }
18702             
18703             fillMonths.cn.push({
18704                 tag: 'td',
18705                 cls: 'day ' + clsName,
18706                 html: prevMonth.getDate()
18707             });
18708             
18709             prevMonth.setDate(prevMonth.getDate()+1);
18710         }
18711           
18712         var currentYear = this.date && this.date.getUTCFullYear();
18713         var currentMonth = this.date && this.date.getUTCMonth();
18714         
18715         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18716         
18717         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18718             v.removeClass('active');
18719             
18720             if(currentYear === year && k === currentMonth){
18721                 v.addClass('active');
18722             }
18723             
18724             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18725                 v.addClass('disabled');
18726             }
18727             
18728         });
18729         
18730         
18731         year = parseInt(year/10, 10) * 10;
18732         
18733         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18734         
18735         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18736         
18737         year -= 1;
18738         for (var i = -1; i < 11; i++) {
18739             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18740                 tag: 'span',
18741                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18742                 html: year
18743             });
18744             
18745             year += 1;
18746         }
18747     },
18748     
18749     showMode: function(dir) 
18750     {
18751         if (dir) {
18752             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18753         }
18754         
18755         Roo.each(this.picker().select('>div',true).elements, function(v){
18756             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18757             v.hide();
18758         });
18759         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18760     },
18761     
18762     place: function()
18763     {
18764         if(this.isInline) {
18765             return;
18766         }
18767         
18768         this.picker().removeClass(['bottom', 'top']);
18769         
18770         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18771             /*
18772              * place to the top of element!
18773              *
18774              */
18775             
18776             this.picker().addClass('top');
18777             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18778             
18779             return;
18780         }
18781         
18782         this.picker().addClass('bottom');
18783         
18784         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18785     },
18786     
18787     parseDate : function(value)
18788     {
18789         if(!value || value instanceof Date){
18790             return value;
18791         }
18792         var v = Date.parseDate(value, this.format);
18793         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18794             v = Date.parseDate(value, 'Y-m-d');
18795         }
18796         if(!v && this.altFormats){
18797             if(!this.altFormatsArray){
18798                 this.altFormatsArray = this.altFormats.split("|");
18799             }
18800             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18801                 v = Date.parseDate(value, this.altFormatsArray[i]);
18802             }
18803         }
18804         return v;
18805     },
18806     
18807     formatDate : function(date, fmt)
18808     {   
18809         return (!date || !(date instanceof Date)) ?
18810         date : date.dateFormat(fmt || this.format);
18811     },
18812     
18813     onFocus : function()
18814     {
18815         Roo.bootstrap.DateField.superclass.onFocus.call(this);
18816         this.show();
18817     },
18818     
18819     onBlur : function()
18820     {
18821         Roo.bootstrap.DateField.superclass.onBlur.call(this);
18822         
18823         var d = this.inputEl().getValue();
18824         
18825         this.setValue(d);
18826                 
18827         this.hide();
18828     },
18829     
18830     show : function()
18831     {
18832         this.picker().show();
18833         this.update();
18834         this.place();
18835         
18836         this.fireEvent('show', this, this.date);
18837     },
18838     
18839     hide : function()
18840     {
18841         if(this.isInline) {
18842             return;
18843         }
18844         this.picker().hide();
18845         this.viewMode = this.startViewMode;
18846         this.showMode();
18847         
18848         this.fireEvent('hide', this, this.date);
18849         
18850     },
18851     
18852     onMousedown: function(e)
18853     {
18854         e.stopPropagation();
18855         e.preventDefault();
18856     },
18857     
18858     keyup: function(e)
18859     {
18860         Roo.bootstrap.DateField.superclass.keyup.call(this);
18861         this.update();
18862     },
18863
18864     setValue: function(v)
18865     {
18866         if(this.fireEvent('beforeselect', this, v) !== false){
18867             var d = new Date(this.parseDate(v) ).clearTime();
18868         
18869             if(isNaN(d.getTime())){
18870                 this.date = this.viewDate = '';
18871                 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18872                 return;
18873             }
18874
18875             v = this.formatDate(d);
18876
18877             Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18878
18879             this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18880
18881             this.update();
18882
18883             this.fireEvent('select', this, this.date);
18884         }
18885     },
18886     
18887     getValue: function()
18888     {
18889         return this.formatDate(this.date);
18890     },
18891     
18892     fireKey: function(e)
18893     {
18894         if (!this.picker().isVisible()){
18895             if (e.keyCode == 27) { // allow escape to hide and re-show picker
18896                 this.show();
18897             }
18898             return;
18899         }
18900         
18901         var dateChanged = false,
18902         dir, day, month,
18903         newDate, newViewDate;
18904         
18905         switch(e.keyCode){
18906             case 27: // escape
18907                 this.hide();
18908                 e.preventDefault();
18909                 break;
18910             case 37: // left
18911             case 39: // right
18912                 if (!this.keyboardNavigation) {
18913                     break;
18914                 }
18915                 dir = e.keyCode == 37 ? -1 : 1;
18916                 
18917                 if (e.ctrlKey){
18918                     newDate = this.moveYear(this.date, dir);
18919                     newViewDate = this.moveYear(this.viewDate, dir);
18920                 } else if (e.shiftKey){
18921                     newDate = this.moveMonth(this.date, dir);
18922                     newViewDate = this.moveMonth(this.viewDate, dir);
18923                 } else {
18924                     newDate = new Date(this.date);
18925                     newDate.setUTCDate(this.date.getUTCDate() + dir);
18926                     newViewDate = new Date(this.viewDate);
18927                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18928                 }
18929                 if (this.dateWithinRange(newDate)){
18930                     this.date = newDate;
18931                     this.viewDate = newViewDate;
18932                     this.setValue(this.formatDate(this.date));
18933 //                    this.update();
18934                     e.preventDefault();
18935                     dateChanged = true;
18936                 }
18937                 break;
18938             case 38: // up
18939             case 40: // down
18940                 if (!this.keyboardNavigation) {
18941                     break;
18942                 }
18943                 dir = e.keyCode == 38 ? -1 : 1;
18944                 if (e.ctrlKey){
18945                     newDate = this.moveYear(this.date, dir);
18946                     newViewDate = this.moveYear(this.viewDate, dir);
18947                 } else if (e.shiftKey){
18948                     newDate = this.moveMonth(this.date, dir);
18949                     newViewDate = this.moveMonth(this.viewDate, dir);
18950                 } else {
18951                     newDate = new Date(this.date);
18952                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18953                     newViewDate = new Date(this.viewDate);
18954                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18955                 }
18956                 if (this.dateWithinRange(newDate)){
18957                     this.date = newDate;
18958                     this.viewDate = newViewDate;
18959                     this.setValue(this.formatDate(this.date));
18960 //                    this.update();
18961                     e.preventDefault();
18962                     dateChanged = true;
18963                 }
18964                 break;
18965             case 13: // enter
18966                 this.setValue(this.formatDate(this.date));
18967                 this.hide();
18968                 e.preventDefault();
18969                 break;
18970             case 9: // tab
18971                 this.setValue(this.formatDate(this.date));
18972                 this.hide();
18973                 break;
18974             case 16: // shift
18975             case 17: // ctrl
18976             case 18: // alt
18977                 break;
18978             default :
18979                 this.hide();
18980                 
18981         }
18982     },
18983     
18984     
18985     onClick: function(e) 
18986     {
18987         e.stopPropagation();
18988         e.preventDefault();
18989         
18990         var target = e.getTarget();
18991         
18992         if(target.nodeName.toLowerCase() === 'i'){
18993             target = Roo.get(target).dom.parentNode;
18994         }
18995         
18996         var nodeName = target.nodeName;
18997         var className = target.className;
18998         var html = target.innerHTML;
18999         //Roo.log(nodeName);
19000         
19001         switch(nodeName.toLowerCase()) {
19002             case 'th':
19003                 switch(className) {
19004                     case 'switch':
19005                         this.showMode(1);
19006                         break;
19007                     case 'prev':
19008                     case 'next':
19009                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19010                         switch(this.viewMode){
19011                                 case 0:
19012                                         this.viewDate = this.moveMonth(this.viewDate, dir);
19013                                         break;
19014                                 case 1:
19015                                 case 2:
19016                                         this.viewDate = this.moveYear(this.viewDate, dir);
19017                                         break;
19018                         }
19019                         this.fill();
19020                         break;
19021                     case 'today':
19022                         var date = new Date();
19023                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19024 //                        this.fill()
19025                         this.setValue(this.formatDate(this.date));
19026                         
19027                         this.hide();
19028                         break;
19029                 }
19030                 break;
19031             case 'span':
19032                 if (className.indexOf('disabled') < 0) {
19033                     this.viewDate.setUTCDate(1);
19034                     if (className.indexOf('month') > -1) {
19035                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19036                     } else {
19037                         var year = parseInt(html, 10) || 0;
19038                         this.viewDate.setUTCFullYear(year);
19039                         
19040                     }
19041                     
19042                     if(this.singleMode){
19043                         this.setValue(this.formatDate(this.viewDate));
19044                         this.hide();
19045                         return;
19046                     }
19047                     
19048                     this.showMode(-1);
19049                     this.fill();
19050                 }
19051                 break;
19052                 
19053             case 'td':
19054                 //Roo.log(className);
19055                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19056                     var day = parseInt(html, 10) || 1;
19057                     var year = this.viewDate.getUTCFullYear(),
19058                         month = this.viewDate.getUTCMonth();
19059
19060                     if (className.indexOf('old') > -1) {
19061                         if(month === 0 ){
19062                             month = 11;
19063                             year -= 1;
19064                         }else{
19065                             month -= 1;
19066                         }
19067                     } else if (className.indexOf('new') > -1) {
19068                         if (month == 11) {
19069                             month = 0;
19070                             year += 1;
19071                         } else {
19072                             month += 1;
19073                         }
19074                     }
19075                     //Roo.log([year,month,day]);
19076                     this.date = this.UTCDate(year, month, day,0,0,0,0);
19077                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19078 //                    this.fill();
19079                     //Roo.log(this.formatDate(this.date));
19080                     this.setValue(this.formatDate(this.date));
19081                     this.hide();
19082                 }
19083                 break;
19084         }
19085     },
19086     
19087     setStartDate: function(startDate)
19088     {
19089         this.startDate = startDate || -Infinity;
19090         if (this.startDate !== -Infinity) {
19091             this.startDate = this.parseDate(this.startDate);
19092         }
19093         this.update();
19094         this.updateNavArrows();
19095     },
19096
19097     setEndDate: function(endDate)
19098     {
19099         this.endDate = endDate || Infinity;
19100         if (this.endDate !== Infinity) {
19101             this.endDate = this.parseDate(this.endDate);
19102         }
19103         this.update();
19104         this.updateNavArrows();
19105     },
19106     
19107     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19108     {
19109         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19110         if (typeof(this.daysOfWeekDisabled) !== 'object') {
19111             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19112         }
19113         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19114             return parseInt(d, 10);
19115         });
19116         this.update();
19117         this.updateNavArrows();
19118     },
19119     
19120     updateNavArrows: function() 
19121     {
19122         if(this.singleMode){
19123             return;
19124         }
19125         
19126         var d = new Date(this.viewDate),
19127         year = d.getUTCFullYear(),
19128         month = d.getUTCMonth();
19129         
19130         Roo.each(this.picker().select('.prev', true).elements, function(v){
19131             v.show();
19132             switch (this.viewMode) {
19133                 case 0:
19134
19135                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19136                         v.hide();
19137                     }
19138                     break;
19139                 case 1:
19140                 case 2:
19141                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19142                         v.hide();
19143                     }
19144                     break;
19145             }
19146         });
19147         
19148         Roo.each(this.picker().select('.next', true).elements, function(v){
19149             v.show();
19150             switch (this.viewMode) {
19151                 case 0:
19152
19153                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19154                         v.hide();
19155                     }
19156                     break;
19157                 case 1:
19158                 case 2:
19159                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19160                         v.hide();
19161                     }
19162                     break;
19163             }
19164         })
19165     },
19166     
19167     moveMonth: function(date, dir)
19168     {
19169         if (!dir) {
19170             return date;
19171         }
19172         var new_date = new Date(date.valueOf()),
19173         day = new_date.getUTCDate(),
19174         month = new_date.getUTCMonth(),
19175         mag = Math.abs(dir),
19176         new_month, test;
19177         dir = dir > 0 ? 1 : -1;
19178         if (mag == 1){
19179             test = dir == -1
19180             // If going back one month, make sure month is not current month
19181             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19182             ? function(){
19183                 return new_date.getUTCMonth() == month;
19184             }
19185             // If going forward one month, make sure month is as expected
19186             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19187             : function(){
19188                 return new_date.getUTCMonth() != new_month;
19189             };
19190             new_month = month + dir;
19191             new_date.setUTCMonth(new_month);
19192             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19193             if (new_month < 0 || new_month > 11) {
19194                 new_month = (new_month + 12) % 12;
19195             }
19196         } else {
19197             // For magnitudes >1, move one month at a time...
19198             for (var i=0; i<mag; i++) {
19199                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19200                 new_date = this.moveMonth(new_date, dir);
19201             }
19202             // ...then reset the day, keeping it in the new month
19203             new_month = new_date.getUTCMonth();
19204             new_date.setUTCDate(day);
19205             test = function(){
19206                 return new_month != new_date.getUTCMonth();
19207             };
19208         }
19209         // Common date-resetting loop -- if date is beyond end of month, make it
19210         // end of month
19211         while (test()){
19212             new_date.setUTCDate(--day);
19213             new_date.setUTCMonth(new_month);
19214         }
19215         return new_date;
19216     },
19217
19218     moveYear: function(date, dir)
19219     {
19220         return this.moveMonth(date, dir*12);
19221     },
19222
19223     dateWithinRange: function(date)
19224     {
19225         return date >= this.startDate && date <= this.endDate;
19226     },
19227
19228     
19229     remove: function() 
19230     {
19231         this.picker().remove();
19232     },
19233     
19234     validateValue : function(value)
19235     {
19236         if(this.getVisibilityEl().hasClass('hidden')){
19237             return true;
19238         }
19239         
19240         if(value.length < 1)  {
19241             if(this.allowBlank){
19242                 return true;
19243             }
19244             return false;
19245         }
19246         
19247         if(value.length < this.minLength){
19248             return false;
19249         }
19250         if(value.length > this.maxLength){
19251             return false;
19252         }
19253         if(this.vtype){
19254             var vt = Roo.form.VTypes;
19255             if(!vt[this.vtype](value, this)){
19256                 return false;
19257             }
19258         }
19259         if(typeof this.validator == "function"){
19260             var msg = this.validator(value);
19261             if(msg !== true){
19262                 return false;
19263             }
19264         }
19265         
19266         if(this.regex && !this.regex.test(value)){
19267             return false;
19268         }
19269         
19270         if(typeof(this.parseDate(value)) == 'undefined'){
19271             return false;
19272         }
19273         
19274         if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19275             return false;
19276         }      
19277         
19278         if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19279             return false;
19280         } 
19281         
19282         
19283         return true;
19284     },
19285     
19286     setVisible : function(visible)
19287     {
19288         if(!this.getEl()){
19289             return;
19290         }
19291         
19292         this.getEl().removeClass('hidden');
19293         
19294         if(visible){
19295             return;
19296         }
19297         
19298         this.getEl().addClass('hidden');
19299     }
19300    
19301 });
19302
19303 Roo.apply(Roo.bootstrap.DateField,  {
19304     
19305     head : {
19306         tag: 'thead',
19307         cn: [
19308         {
19309             tag: 'tr',
19310             cn: [
19311             {
19312                 tag: 'th',
19313                 cls: 'prev',
19314                 html: '<i class="fa fa-arrow-left"/>'
19315             },
19316             {
19317                 tag: 'th',
19318                 cls: 'switch',
19319                 colspan: '5'
19320             },
19321             {
19322                 tag: 'th',
19323                 cls: 'next',
19324                 html: '<i class="fa fa-arrow-right"/>'
19325             }
19326
19327             ]
19328         }
19329         ]
19330     },
19331     
19332     content : {
19333         tag: 'tbody',
19334         cn: [
19335         {
19336             tag: 'tr',
19337             cn: [
19338             {
19339                 tag: 'td',
19340                 colspan: '7'
19341             }
19342             ]
19343         }
19344         ]
19345     },
19346     
19347     footer : {
19348         tag: 'tfoot',
19349         cn: [
19350         {
19351             tag: 'tr',
19352             cn: [
19353             {
19354                 tag: 'th',
19355                 colspan: '7',
19356                 cls: 'today'
19357             }
19358                     
19359             ]
19360         }
19361         ]
19362     },
19363     
19364     dates:{
19365         en: {
19366             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19367             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19368             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19369             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19370             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19371             today: "Today"
19372         }
19373     },
19374     
19375     modes: [
19376     {
19377         clsName: 'days',
19378         navFnc: 'Month',
19379         navStep: 1
19380     },
19381     {
19382         clsName: 'months',
19383         navFnc: 'FullYear',
19384         navStep: 1
19385     },
19386     {
19387         clsName: 'years',
19388         navFnc: 'FullYear',
19389         navStep: 10
19390     }]
19391 });
19392
19393 Roo.apply(Roo.bootstrap.DateField,  {
19394   
19395     template : {
19396         tag: 'div',
19397         cls: 'datepicker dropdown-menu roo-dynamic',
19398         cn: [
19399         {
19400             tag: 'div',
19401             cls: 'datepicker-days',
19402             cn: [
19403             {
19404                 tag: 'table',
19405                 cls: 'table-condensed',
19406                 cn:[
19407                 Roo.bootstrap.DateField.head,
19408                 {
19409                     tag: 'tbody'
19410                 },
19411                 Roo.bootstrap.DateField.footer
19412                 ]
19413             }
19414             ]
19415         },
19416         {
19417             tag: 'div',
19418             cls: 'datepicker-months',
19419             cn: [
19420             {
19421                 tag: 'table',
19422                 cls: 'table-condensed',
19423                 cn:[
19424                 Roo.bootstrap.DateField.head,
19425                 Roo.bootstrap.DateField.content,
19426                 Roo.bootstrap.DateField.footer
19427                 ]
19428             }
19429             ]
19430         },
19431         {
19432             tag: 'div',
19433             cls: 'datepicker-years',
19434             cn: [
19435             {
19436                 tag: 'table',
19437                 cls: 'table-condensed',
19438                 cn:[
19439                 Roo.bootstrap.DateField.head,
19440                 Roo.bootstrap.DateField.content,
19441                 Roo.bootstrap.DateField.footer
19442                 ]
19443             }
19444             ]
19445         }
19446         ]
19447     }
19448 });
19449
19450  
19451
19452  /*
19453  * - LGPL
19454  *
19455  * TimeField
19456  * 
19457  */
19458
19459 /**
19460  * @class Roo.bootstrap.TimeField
19461  * @extends Roo.bootstrap.Input
19462  * Bootstrap DateField class
19463  * 
19464  * 
19465  * @constructor
19466  * Create a new TimeField
19467  * @param {Object} config The config object
19468  */
19469
19470 Roo.bootstrap.TimeField = function(config){
19471     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19472     this.addEvents({
19473             /**
19474              * @event show
19475              * Fires when this field show.
19476              * @param {Roo.bootstrap.DateField} thisthis
19477              * @param {Mixed} date The date value
19478              */
19479             show : true,
19480             /**
19481              * @event show
19482              * Fires when this field hide.
19483              * @param {Roo.bootstrap.DateField} this
19484              * @param {Mixed} date The date value
19485              */
19486             hide : true,
19487             /**
19488              * @event select
19489              * Fires when select a date.
19490              * @param {Roo.bootstrap.DateField} this
19491              * @param {Mixed} date The date value
19492              */
19493             select : true
19494         });
19495 };
19496
19497 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
19498     
19499     /**
19500      * @cfg {String} format
19501      * The default time format string which can be overriden for localization support.  The format must be
19502      * valid according to {@link Date#parseDate} (defaults to 'H:i').
19503      */
19504     format : "H:i",
19505        
19506     onRender: function(ct, position)
19507     {
19508         
19509         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19510                 
19511         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19512         
19513         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19514         
19515         this.pop = this.picker().select('>.datepicker-time',true).first();
19516         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19517         
19518         this.picker().on('mousedown', this.onMousedown, this);
19519         this.picker().on('click', this.onClick, this);
19520         
19521         this.picker().addClass('datepicker-dropdown');
19522     
19523         this.fillTime();
19524         this.update();
19525             
19526         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19527         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19528         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19529         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19530         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19531         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19532
19533     },
19534     
19535     fireKey: function(e){
19536         if (!this.picker().isVisible()){
19537             if (e.keyCode == 27) { // allow escape to hide and re-show picker
19538                 this.show();
19539             }
19540             return;
19541         }
19542
19543         e.preventDefault();
19544         
19545         switch(e.keyCode){
19546             case 27: // escape
19547                 this.hide();
19548                 break;
19549             case 37: // left
19550             case 39: // right
19551                 this.onTogglePeriod();
19552                 break;
19553             case 38: // up
19554                 this.onIncrementMinutes();
19555                 break;
19556             case 40: // down
19557                 this.onDecrementMinutes();
19558                 break;
19559             case 13: // enter
19560             case 9: // tab
19561                 this.setTime();
19562                 break;
19563         }
19564     },
19565     
19566     onClick: function(e) {
19567         e.stopPropagation();
19568         e.preventDefault();
19569     },
19570     
19571     picker : function()
19572     {
19573         return this.el.select('.datepicker', true).first();
19574     },
19575     
19576     fillTime: function()
19577     {    
19578         var time = this.pop.select('tbody', true).first();
19579         
19580         time.dom.innerHTML = '';
19581         
19582         time.createChild({
19583             tag: 'tr',
19584             cn: [
19585                 {
19586                     tag: 'td',
19587                     cn: [
19588                         {
19589                             tag: 'a',
19590                             href: '#',
19591                             cls: 'btn',
19592                             cn: [
19593                                 {
19594                                     tag: 'span',
19595                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
19596                                 }
19597                             ]
19598                         } 
19599                     ]
19600                 },
19601                 {
19602                     tag: 'td',
19603                     cls: 'separator'
19604                 },
19605                 {
19606                     tag: 'td',
19607                     cn: [
19608                         {
19609                             tag: 'a',
19610                             href: '#',
19611                             cls: 'btn',
19612                             cn: [
19613                                 {
19614                                     tag: 'span',
19615                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
19616                                 }
19617                             ]
19618                         }
19619                     ]
19620                 },
19621                 {
19622                     tag: 'td',
19623                     cls: 'separator'
19624                 }
19625             ]
19626         });
19627         
19628         time.createChild({
19629             tag: 'tr',
19630             cn: [
19631                 {
19632                     tag: 'td',
19633                     cn: [
19634                         {
19635                             tag: 'span',
19636                             cls: 'timepicker-hour',
19637                             html: '00'
19638                         }  
19639                     ]
19640                 },
19641                 {
19642                     tag: 'td',
19643                     cls: 'separator',
19644                     html: ':'
19645                 },
19646                 {
19647                     tag: 'td',
19648                     cn: [
19649                         {
19650                             tag: 'span',
19651                             cls: 'timepicker-minute',
19652                             html: '00'
19653                         }  
19654                     ]
19655                 },
19656                 {
19657                     tag: 'td',
19658                     cls: 'separator'
19659                 },
19660                 {
19661                     tag: 'td',
19662                     cn: [
19663                         {
19664                             tag: 'button',
19665                             type: 'button',
19666                             cls: 'btn btn-primary period',
19667                             html: 'AM'
19668                             
19669                         }
19670                     ]
19671                 }
19672             ]
19673         });
19674         
19675         time.createChild({
19676             tag: 'tr',
19677             cn: [
19678                 {
19679                     tag: 'td',
19680                     cn: [
19681                         {
19682                             tag: 'a',
19683                             href: '#',
19684                             cls: 'btn',
19685                             cn: [
19686                                 {
19687                                     tag: 'span',
19688                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
19689                                 }
19690                             ]
19691                         }
19692                     ]
19693                 },
19694                 {
19695                     tag: 'td',
19696                     cls: 'separator'
19697                 },
19698                 {
19699                     tag: 'td',
19700                     cn: [
19701                         {
19702                             tag: 'a',
19703                             href: '#',
19704                             cls: 'btn',
19705                             cn: [
19706                                 {
19707                                     tag: 'span',
19708                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
19709                                 }
19710                             ]
19711                         }
19712                     ]
19713                 },
19714                 {
19715                     tag: 'td',
19716                     cls: 'separator'
19717                 }
19718             ]
19719         });
19720         
19721     },
19722     
19723     update: function()
19724     {
19725         
19726         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19727         
19728         this.fill();
19729     },
19730     
19731     fill: function() 
19732     {
19733         var hours = this.time.getHours();
19734         var minutes = this.time.getMinutes();
19735         var period = 'AM';
19736         
19737         if(hours > 11){
19738             period = 'PM';
19739         }
19740         
19741         if(hours == 0){
19742             hours = 12;
19743         }
19744         
19745         
19746         if(hours > 12){
19747             hours = hours - 12;
19748         }
19749         
19750         if(hours < 10){
19751             hours = '0' + hours;
19752         }
19753         
19754         if(minutes < 10){
19755             minutes = '0' + minutes;
19756         }
19757         
19758         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19759         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19760         this.pop.select('button', true).first().dom.innerHTML = period;
19761         
19762     },
19763     
19764     place: function()
19765     {   
19766         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19767         
19768         var cls = ['bottom'];
19769         
19770         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19771             cls.pop();
19772             cls.push('top');
19773         }
19774         
19775         cls.push('right');
19776         
19777         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19778             cls.pop();
19779             cls.push('left');
19780         }
19781         
19782         this.picker().addClass(cls.join('-'));
19783         
19784         var _this = this;
19785         
19786         Roo.each(cls, function(c){
19787             if(c == 'bottom'){
19788                 _this.picker().setTop(_this.inputEl().getHeight());
19789                 return;
19790             }
19791             if(c == 'top'){
19792                 _this.picker().setTop(0 - _this.picker().getHeight());
19793                 return;
19794             }
19795             
19796             if(c == 'left'){
19797                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19798                 return;
19799             }
19800             if(c == 'right'){
19801                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19802                 return;
19803             }
19804         });
19805         
19806     },
19807   
19808     onFocus : function()
19809     {
19810         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19811         this.show();
19812     },
19813     
19814     onBlur : function()
19815     {
19816         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19817         this.hide();
19818     },
19819     
19820     show : function()
19821     {
19822         this.picker().show();
19823         this.pop.show();
19824         this.update();
19825         this.place();
19826         
19827         this.fireEvent('show', this, this.date);
19828     },
19829     
19830     hide : function()
19831     {
19832         this.picker().hide();
19833         this.pop.hide();
19834         
19835         this.fireEvent('hide', this, this.date);
19836     },
19837     
19838     setTime : function()
19839     {
19840         this.hide();
19841         this.setValue(this.time.format(this.format));
19842         
19843         this.fireEvent('select', this, this.date);
19844         
19845         
19846     },
19847     
19848     onMousedown: function(e){
19849         e.stopPropagation();
19850         e.preventDefault();
19851     },
19852     
19853     onIncrementHours: function()
19854     {
19855         Roo.log('onIncrementHours');
19856         this.time = this.time.add(Date.HOUR, 1);
19857         this.update();
19858         
19859     },
19860     
19861     onDecrementHours: function()
19862     {
19863         Roo.log('onDecrementHours');
19864         this.time = this.time.add(Date.HOUR, -1);
19865         this.update();
19866     },
19867     
19868     onIncrementMinutes: function()
19869     {
19870         Roo.log('onIncrementMinutes');
19871         this.time = this.time.add(Date.MINUTE, 1);
19872         this.update();
19873     },
19874     
19875     onDecrementMinutes: function()
19876     {
19877         Roo.log('onDecrementMinutes');
19878         this.time = this.time.add(Date.MINUTE, -1);
19879         this.update();
19880     },
19881     
19882     onTogglePeriod: function()
19883     {
19884         Roo.log('onTogglePeriod');
19885         this.time = this.time.add(Date.HOUR, 12);
19886         this.update();
19887     }
19888     
19889    
19890 });
19891
19892 Roo.apply(Roo.bootstrap.TimeField,  {
19893     
19894     content : {
19895         tag: 'tbody',
19896         cn: [
19897             {
19898                 tag: 'tr',
19899                 cn: [
19900                 {
19901                     tag: 'td',
19902                     colspan: '7'
19903                 }
19904                 ]
19905             }
19906         ]
19907     },
19908     
19909     footer : {
19910         tag: 'tfoot',
19911         cn: [
19912             {
19913                 tag: 'tr',
19914                 cn: [
19915                 {
19916                     tag: 'th',
19917                     colspan: '7',
19918                     cls: '',
19919                     cn: [
19920                         {
19921                             tag: 'button',
19922                             cls: 'btn btn-info ok',
19923                             html: 'OK'
19924                         }
19925                     ]
19926                 }
19927
19928                 ]
19929             }
19930         ]
19931     }
19932 });
19933
19934 Roo.apply(Roo.bootstrap.TimeField,  {
19935   
19936     template : {
19937         tag: 'div',
19938         cls: 'datepicker dropdown-menu',
19939         cn: [
19940             {
19941                 tag: 'div',
19942                 cls: 'datepicker-time',
19943                 cn: [
19944                 {
19945                     tag: 'table',
19946                     cls: 'table-condensed',
19947                     cn:[
19948                     Roo.bootstrap.TimeField.content,
19949                     Roo.bootstrap.TimeField.footer
19950                     ]
19951                 }
19952                 ]
19953             }
19954         ]
19955     }
19956 });
19957
19958  
19959
19960  /*
19961  * - LGPL
19962  *
19963  * MonthField
19964  * 
19965  */
19966
19967 /**
19968  * @class Roo.bootstrap.MonthField
19969  * @extends Roo.bootstrap.Input
19970  * Bootstrap MonthField class
19971  * 
19972  * @cfg {String} language default en
19973  * 
19974  * @constructor
19975  * Create a new MonthField
19976  * @param {Object} config The config object
19977  */
19978
19979 Roo.bootstrap.MonthField = function(config){
19980     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19981     
19982     this.addEvents({
19983         /**
19984          * @event show
19985          * Fires when this field show.
19986          * @param {Roo.bootstrap.MonthField} this
19987          * @param {Mixed} date The date value
19988          */
19989         show : true,
19990         /**
19991          * @event show
19992          * Fires when this field hide.
19993          * @param {Roo.bootstrap.MonthField} this
19994          * @param {Mixed} date The date value
19995          */
19996         hide : true,
19997         /**
19998          * @event select
19999          * Fires when select a date.
20000          * @param {Roo.bootstrap.MonthField} this
20001          * @param {String} oldvalue The old value
20002          * @param {String} newvalue The new value
20003          */
20004         select : true
20005     });
20006 };
20007
20008 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
20009     
20010     onRender: function(ct, position)
20011     {
20012         
20013         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20014         
20015         this.language = this.language || 'en';
20016         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20017         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20018         
20019         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20020         this.isInline = false;
20021         this.isInput = true;
20022         this.component = this.el.select('.add-on', true).first() || false;
20023         this.component = (this.component && this.component.length === 0) ? false : this.component;
20024         this.hasInput = this.component && this.inputEL().length;
20025         
20026         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20027         
20028         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20029         
20030         this.picker().on('mousedown', this.onMousedown, this);
20031         this.picker().on('click', this.onClick, this);
20032         
20033         this.picker().addClass('datepicker-dropdown');
20034         
20035         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20036             v.setStyle('width', '189px');
20037         });
20038         
20039         this.fillMonths();
20040         
20041         this.update();
20042         
20043         if(this.isInline) {
20044             this.show();
20045         }
20046         
20047     },
20048     
20049     setValue: function(v, suppressEvent)
20050     {   
20051         var o = this.getValue();
20052         
20053         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20054         
20055         this.update();
20056
20057         if(suppressEvent !== true){
20058             this.fireEvent('select', this, o, v);
20059         }
20060         
20061     },
20062     
20063     getValue: function()
20064     {
20065         return this.value;
20066     },
20067     
20068     onClick: function(e) 
20069     {
20070         e.stopPropagation();
20071         e.preventDefault();
20072         
20073         var target = e.getTarget();
20074         
20075         if(target.nodeName.toLowerCase() === 'i'){
20076             target = Roo.get(target).dom.parentNode;
20077         }
20078         
20079         var nodeName = target.nodeName;
20080         var className = target.className;
20081         var html = target.innerHTML;
20082         
20083         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20084             return;
20085         }
20086         
20087         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20088         
20089         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20090         
20091         this.hide();
20092                         
20093     },
20094     
20095     picker : function()
20096     {
20097         return this.pickerEl;
20098     },
20099     
20100     fillMonths: function()
20101     {    
20102         var i = 0;
20103         var months = this.picker().select('>.datepicker-months td', true).first();
20104         
20105         months.dom.innerHTML = '';
20106         
20107         while (i < 12) {
20108             var month = {
20109                 tag: 'span',
20110                 cls: 'month',
20111                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20112             };
20113             
20114             months.createChild(month);
20115         }
20116         
20117     },
20118     
20119     update: function()
20120     {
20121         var _this = this;
20122         
20123         if(typeof(this.vIndex) == 'undefined' && this.value.length){
20124             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20125         }
20126         
20127         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20128             e.removeClass('active');
20129             
20130             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20131                 e.addClass('active');
20132             }
20133         })
20134     },
20135     
20136     place: function()
20137     {
20138         if(this.isInline) {
20139             return;
20140         }
20141         
20142         this.picker().removeClass(['bottom', 'top']);
20143         
20144         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20145             /*
20146              * place to the top of element!
20147              *
20148              */
20149             
20150             this.picker().addClass('top');
20151             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20152             
20153             return;
20154         }
20155         
20156         this.picker().addClass('bottom');
20157         
20158         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20159     },
20160     
20161     onFocus : function()
20162     {
20163         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20164         this.show();
20165     },
20166     
20167     onBlur : function()
20168     {
20169         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20170         
20171         var d = this.inputEl().getValue();
20172         
20173         this.setValue(d);
20174                 
20175         this.hide();
20176     },
20177     
20178     show : function()
20179     {
20180         this.picker().show();
20181         this.picker().select('>.datepicker-months', true).first().show();
20182         this.update();
20183         this.place();
20184         
20185         this.fireEvent('show', this, this.date);
20186     },
20187     
20188     hide : function()
20189     {
20190         if(this.isInline) {
20191             return;
20192         }
20193         this.picker().hide();
20194         this.fireEvent('hide', this, this.date);
20195         
20196     },
20197     
20198     onMousedown: function(e)
20199     {
20200         e.stopPropagation();
20201         e.preventDefault();
20202     },
20203     
20204     keyup: function(e)
20205     {
20206         Roo.bootstrap.MonthField.superclass.keyup.call(this);
20207         this.update();
20208     },
20209
20210     fireKey: function(e)
20211     {
20212         if (!this.picker().isVisible()){
20213             if (e.keyCode == 27)   {// allow escape to hide and re-show picker
20214                 this.show();
20215             }
20216             return;
20217         }
20218         
20219         var dir;
20220         
20221         switch(e.keyCode){
20222             case 27: // escape
20223                 this.hide();
20224                 e.preventDefault();
20225                 break;
20226             case 37: // left
20227             case 39: // right
20228                 dir = e.keyCode == 37 ? -1 : 1;
20229                 
20230                 this.vIndex = this.vIndex + dir;
20231                 
20232                 if(this.vIndex < 0){
20233                     this.vIndex = 0;
20234                 }
20235                 
20236                 if(this.vIndex > 11){
20237                     this.vIndex = 11;
20238                 }
20239                 
20240                 if(isNaN(this.vIndex)){
20241                     this.vIndex = 0;
20242                 }
20243                 
20244                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20245                 
20246                 break;
20247             case 38: // up
20248             case 40: // down
20249                 
20250                 dir = e.keyCode == 38 ? -1 : 1;
20251                 
20252                 this.vIndex = this.vIndex + dir * 4;
20253                 
20254                 if(this.vIndex < 0){
20255                     this.vIndex = 0;
20256                 }
20257                 
20258                 if(this.vIndex > 11){
20259                     this.vIndex = 11;
20260                 }
20261                 
20262                 if(isNaN(this.vIndex)){
20263                     this.vIndex = 0;
20264                 }
20265                 
20266                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20267                 break;
20268                 
20269             case 13: // enter
20270                 
20271                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20272                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20273                 }
20274                 
20275                 this.hide();
20276                 e.preventDefault();
20277                 break;
20278             case 9: // tab
20279                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20280                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20281                 }
20282                 this.hide();
20283                 break;
20284             case 16: // shift
20285             case 17: // ctrl
20286             case 18: // alt
20287                 break;
20288             default :
20289                 this.hide();
20290                 
20291         }
20292     },
20293     
20294     remove: function() 
20295     {
20296         this.picker().remove();
20297     }
20298    
20299 });
20300
20301 Roo.apply(Roo.bootstrap.MonthField,  {
20302     
20303     content : {
20304         tag: 'tbody',
20305         cn: [
20306         {
20307             tag: 'tr',
20308             cn: [
20309             {
20310                 tag: 'td',
20311                 colspan: '7'
20312             }
20313             ]
20314         }
20315         ]
20316     },
20317     
20318     dates:{
20319         en: {
20320             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20321             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20322         }
20323     }
20324 });
20325
20326 Roo.apply(Roo.bootstrap.MonthField,  {
20327   
20328     template : {
20329         tag: 'div',
20330         cls: 'datepicker dropdown-menu roo-dynamic',
20331         cn: [
20332             {
20333                 tag: 'div',
20334                 cls: 'datepicker-months',
20335                 cn: [
20336                 {
20337                     tag: 'table',
20338                     cls: 'table-condensed',
20339                     cn:[
20340                         Roo.bootstrap.DateField.content
20341                     ]
20342                 }
20343                 ]
20344             }
20345         ]
20346     }
20347 });
20348
20349  
20350
20351  
20352  /*
20353  * - LGPL
20354  *
20355  * CheckBox
20356  * 
20357  */
20358
20359 /**
20360  * @class Roo.bootstrap.CheckBox
20361  * @extends Roo.bootstrap.Input
20362  * Bootstrap CheckBox class
20363  * 
20364  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20365  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20366  * @cfg {String} boxLabel The text that appears beside the checkbox
20367  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20368  * @cfg {Boolean} checked initnal the element
20369  * @cfg {Boolean} inline inline the element (default false)
20370  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20371  * @cfg {String} tooltip label tooltip
20372  * 
20373  * @constructor
20374  * Create a new CheckBox
20375  * @param {Object} config The config object
20376  */
20377
20378 Roo.bootstrap.CheckBox = function(config){
20379     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20380    
20381     this.addEvents({
20382         /**
20383         * @event check
20384         * Fires when the element is checked or unchecked.
20385         * @param {Roo.bootstrap.CheckBox} this This input
20386         * @param {Boolean} checked The new checked value
20387         */
20388        check : true,
20389        /**
20390         * @event click
20391         * Fires when the element is click.
20392         * @param {Roo.bootstrap.CheckBox} this This input
20393         */
20394        click : true
20395     });
20396     
20397 };
20398
20399 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
20400   
20401     inputType: 'checkbox',
20402     inputValue: 1,
20403     valueOff: 0,
20404     boxLabel: false,
20405     checked: false,
20406     weight : false,
20407     inline: false,
20408     tooltip : '',
20409     
20410     getAutoCreate : function()
20411     {
20412         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20413         
20414         var id = Roo.id();
20415         
20416         var cfg = {};
20417         
20418         cfg.cls = 'form-group ' + this.inputType; //input-group
20419         
20420         if(this.inline){
20421             cfg.cls += ' ' + this.inputType + '-inline';
20422         }
20423         
20424         var input =  {
20425             tag: 'input',
20426             id : id,
20427             type : this.inputType,
20428             value : this.inputValue,
20429             cls : 'roo-' + this.inputType, //'form-box',
20430             placeholder : this.placeholder || ''
20431             
20432         };
20433         
20434         if(this.inputType != 'radio'){
20435             var hidden =  {
20436                 tag: 'input',
20437                 type : 'hidden',
20438                 cls : 'roo-hidden-value',
20439                 value : this.checked ? this.inputValue : this.valueOff
20440             };
20441         }
20442         
20443             
20444         if (this.weight) { // Validity check?
20445             cfg.cls += " " + this.inputType + "-" + this.weight;
20446         }
20447         
20448         if (this.disabled) {
20449             input.disabled=true;
20450         }
20451         
20452         if(this.checked){
20453             input.checked = this.checked;
20454         }
20455         
20456         if (this.name) {
20457             
20458             input.name = this.name;
20459             
20460             if(this.inputType != 'radio'){
20461                 hidden.name = this.name;
20462                 input.name = '_hidden_' + this.name;
20463             }
20464         }
20465         
20466         if (this.size) {
20467             input.cls += ' input-' + this.size;
20468         }
20469         
20470         var settings=this;
20471         
20472         ['xs','sm','md','lg'].map(function(size){
20473             if (settings[size]) {
20474                 cfg.cls += ' col-' + size + '-' + settings[size];
20475             }
20476         });
20477         
20478         var inputblock = input;
20479          
20480         if (this.before || this.after) {
20481             
20482             inputblock = {
20483                 cls : 'input-group',
20484                 cn :  [] 
20485             };
20486             
20487             if (this.before) {
20488                 inputblock.cn.push({
20489                     tag :'span',
20490                     cls : 'input-group-addon',
20491                     html : this.before
20492                 });
20493             }
20494             
20495             inputblock.cn.push(input);
20496             
20497             if(this.inputType != 'radio'){
20498                 inputblock.cn.push(hidden);
20499             }
20500             
20501             if (this.after) {
20502                 inputblock.cn.push({
20503                     tag :'span',
20504                     cls : 'input-group-addon',
20505                     html : this.after
20506                 });
20507             }
20508             
20509         }
20510         
20511         if (align ==='left' && this.fieldLabel.length) {
20512 //                Roo.log("left and has label");
20513             cfg.cn = [
20514                 {
20515                     tag: 'label',
20516                     'for' :  id,
20517                     cls : 'control-label',
20518                     html : this.fieldLabel
20519                 },
20520                 {
20521                     cls : "", 
20522                     cn: [
20523                         inputblock
20524                     ]
20525                 }
20526             ];
20527             
20528             if(this.labelWidth > 12){
20529                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20530             }
20531             
20532             if(this.labelWidth < 13 && this.labelmd == 0){
20533                 this.labelmd = this.labelWidth;
20534             }
20535             
20536             if(this.labellg > 0){
20537                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20538                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20539             }
20540             
20541             if(this.labelmd > 0){
20542                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20543                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20544             }
20545             
20546             if(this.labelsm > 0){
20547                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20548                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20549             }
20550             
20551             if(this.labelxs > 0){
20552                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20553                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20554             }
20555             
20556         } else if ( this.fieldLabel.length) {
20557 //                Roo.log(" label");
20558                 cfg.cn = [
20559                    
20560                     {
20561                         tag: this.boxLabel ? 'span' : 'label',
20562                         'for': id,
20563                         cls: 'control-label box-input-label',
20564                         //cls : 'input-group-addon',
20565                         html : this.fieldLabel
20566                     },
20567                     
20568                     inputblock
20569                     
20570                 ];
20571
20572         } else {
20573             
20574 //                Roo.log(" no label && no align");
20575                 cfg.cn = [  inputblock ] ;
20576                 
20577                 
20578         }
20579         
20580         if(this.boxLabel){
20581              var boxLabelCfg = {
20582                 tag: 'label',
20583                 //'for': id, // box label is handled by onclick - so no for...
20584                 cls: 'box-label',
20585                 html: this.boxLabel
20586             };
20587             
20588             if(this.tooltip){
20589                 boxLabelCfg.tooltip = this.tooltip;
20590             }
20591              
20592             cfg.cn.push(boxLabelCfg);
20593         }
20594         
20595         if(this.inputType != 'radio'){
20596             cfg.cn.push(hidden);
20597         }
20598         
20599         return cfg;
20600         
20601     },
20602     
20603     /**
20604      * return the real input element.
20605      */
20606     inputEl: function ()
20607     {
20608         return this.el.select('input.roo-' + this.inputType,true).first();
20609     },
20610     hiddenEl: function ()
20611     {
20612         return this.el.select('input.roo-hidden-value',true).first();
20613     },
20614     
20615     labelEl: function()
20616     {
20617         return this.el.select('label.control-label',true).first();
20618     },
20619     /* depricated... */
20620     
20621     label: function()
20622     {
20623         return this.labelEl();
20624     },
20625     
20626     boxLabelEl: function()
20627     {
20628         return this.el.select('label.box-label',true).first();
20629     },
20630     
20631     initEvents : function()
20632     {
20633 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20634         
20635         this.inputEl().on('click', this.onClick,  this);
20636         
20637         if (this.boxLabel) { 
20638             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
20639         }
20640         
20641         this.startValue = this.getValue();
20642         
20643         if(this.groupId){
20644             Roo.bootstrap.CheckBox.register(this);
20645         }
20646     },
20647     
20648     onClick : function(e)
20649     {   
20650         if(this.fireEvent('click', this, e) !== false){
20651             this.setChecked(!this.checked);
20652         }
20653         
20654     },
20655     
20656     setChecked : function(state,suppressEvent)
20657     {
20658         this.startValue = this.getValue();
20659
20660         if(this.inputType == 'radio'){
20661             
20662             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20663                 e.dom.checked = false;
20664             });
20665             
20666             this.inputEl().dom.checked = true;
20667             
20668             this.inputEl().dom.value = this.inputValue;
20669             
20670             if(suppressEvent !== true){
20671                 this.fireEvent('check', this, true);
20672             }
20673             
20674             this.validate();
20675             
20676             return;
20677         }
20678         
20679         this.checked = state;
20680         
20681         this.inputEl().dom.checked = state;
20682         
20683         
20684         this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20685         
20686         if(suppressEvent !== true){
20687             this.fireEvent('check', this, state);
20688         }
20689         
20690         this.validate();
20691     },
20692     
20693     getValue : function()
20694     {
20695         if(this.inputType == 'radio'){
20696             return this.getGroupValue();
20697         }
20698         
20699         return this.hiddenEl().dom.value;
20700         
20701     },
20702     
20703     getGroupValue : function()
20704     {
20705         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20706             return '';
20707         }
20708         
20709         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20710     },
20711     
20712     setValue : function(v,suppressEvent)
20713     {
20714         if(this.inputType == 'radio'){
20715             this.setGroupValue(v, suppressEvent);
20716             return;
20717         }
20718         
20719         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20720         
20721         this.validate();
20722     },
20723     
20724     setGroupValue : function(v, suppressEvent)
20725     {
20726         this.startValue = this.getValue();
20727         
20728         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20729             e.dom.checked = false;
20730             
20731             if(e.dom.value == v){
20732                 e.dom.checked = true;
20733             }
20734         });
20735         
20736         if(suppressEvent !== true){
20737             this.fireEvent('check', this, true);
20738         }
20739
20740         this.validate();
20741         
20742         return;
20743     },
20744     
20745     validate : function()
20746     {
20747         if(this.getVisibilityEl().hasClass('hidden')){
20748             return true;
20749         }
20750         
20751         if(
20752                 this.disabled || 
20753                 (this.inputType == 'radio' && this.validateRadio()) ||
20754                 (this.inputType == 'checkbox' && this.validateCheckbox())
20755         ){
20756             this.markValid();
20757             return true;
20758         }
20759         
20760         this.markInvalid();
20761         return false;
20762     },
20763     
20764     validateRadio : function()
20765     {
20766         if(this.getVisibilityEl().hasClass('hidden')){
20767             return true;
20768         }
20769         
20770         if(this.allowBlank){
20771             return true;
20772         }
20773         
20774         var valid = false;
20775         
20776         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20777             if(!e.dom.checked){
20778                 return;
20779             }
20780             
20781             valid = true;
20782             
20783             return false;
20784         });
20785         
20786         return valid;
20787     },
20788     
20789     validateCheckbox : function()
20790     {
20791         if(!this.groupId){
20792             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20793             //return (this.getValue() == this.inputValue) ? true : false;
20794         }
20795         
20796         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20797         
20798         if(!group){
20799             return false;
20800         }
20801         
20802         var r = false;
20803         
20804         for(var i in group){
20805             if(group[i].el.isVisible(true)){
20806                 r = false;
20807                 break;
20808             }
20809             
20810             r = true;
20811         }
20812         
20813         for(var i in group){
20814             if(r){
20815                 break;
20816             }
20817             
20818             r = (group[i].getValue() == group[i].inputValue) ? true : false;
20819         }
20820         
20821         return r;
20822     },
20823     
20824     /**
20825      * Mark this field as valid
20826      */
20827     markValid : function()
20828     {
20829         var _this = this;
20830         
20831         this.fireEvent('valid', this);
20832         
20833         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20834         
20835         if(this.groupId){
20836             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20837         }
20838         
20839         if(label){
20840             label.markValid();
20841         }
20842
20843         if(this.inputType == 'radio'){
20844             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20845                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20846                 e.findParent('.form-group', false, true).addClass(_this.validClass);
20847             });
20848             
20849             return;
20850         }
20851
20852         if(!this.groupId){
20853             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20854             this.el.findParent('.form-group', false, true).addClass(this.validClass);
20855             return;
20856         }
20857         
20858         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20859         
20860         if(!group){
20861             return;
20862         }
20863         
20864         for(var i in group){
20865             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20866             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20867         }
20868     },
20869     
20870      /**
20871      * Mark this field as invalid
20872      * @param {String} msg The validation message
20873      */
20874     markInvalid : function(msg)
20875     {
20876         if(this.allowBlank){
20877             return;
20878         }
20879         
20880         var _this = this;
20881         
20882         this.fireEvent('invalid', this, msg);
20883         
20884         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20885         
20886         if(this.groupId){
20887             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20888         }
20889         
20890         if(label){
20891             label.markInvalid();
20892         }
20893             
20894         if(this.inputType == 'radio'){
20895             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20896                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20897                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20898             });
20899             
20900             return;
20901         }
20902         
20903         if(!this.groupId){
20904             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20905             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20906             return;
20907         }
20908         
20909         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20910         
20911         if(!group){
20912             return;
20913         }
20914         
20915         for(var i in group){
20916             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20917             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20918         }
20919         
20920     },
20921     
20922     clearInvalid : function()
20923     {
20924         Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20925         
20926         // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20927         
20928         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20929         
20930         if (label && label.iconEl) {
20931             label.iconEl.removeClass(label.validClass);
20932             label.iconEl.removeClass(label.invalidClass);
20933         }
20934     },
20935     
20936     disable : function()
20937     {
20938         if(this.inputType != 'radio'){
20939             Roo.bootstrap.CheckBox.superclass.disable.call(this);
20940             return;
20941         }
20942         
20943         var _this = this;
20944         
20945         if(this.rendered){
20946             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20947                 _this.getActionEl().addClass(this.disabledClass);
20948                 e.dom.disabled = true;
20949             });
20950         }
20951         
20952         this.disabled = true;
20953         this.fireEvent("disable", this);
20954         return this;
20955     },
20956
20957     enable : function()
20958     {
20959         if(this.inputType != 'radio'){
20960             Roo.bootstrap.CheckBox.superclass.enable.call(this);
20961             return;
20962         }
20963         
20964         var _this = this;
20965         
20966         if(this.rendered){
20967             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20968                 _this.getActionEl().removeClass(this.disabledClass);
20969                 e.dom.disabled = false;
20970             });
20971         }
20972         
20973         this.disabled = false;
20974         this.fireEvent("enable", this);
20975         return this;
20976     },
20977     
20978     setBoxLabel : function(v)
20979     {
20980         this.boxLabel = v;
20981         
20982         if(this.rendered){
20983             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20984         }
20985     }
20986
20987 });
20988
20989 Roo.apply(Roo.bootstrap.CheckBox, {
20990     
20991     groups: {},
20992     
20993      /**
20994     * register a CheckBox Group
20995     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20996     */
20997     register : function(checkbox)
20998     {
20999         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21000             this.groups[checkbox.groupId] = {};
21001         }
21002         
21003         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21004             return;
21005         }
21006         
21007         this.groups[checkbox.groupId][checkbox.name] = checkbox;
21008         
21009     },
21010     /**
21011     * fetch a CheckBox Group based on the group ID
21012     * @param {string} the group ID
21013     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21014     */
21015     get: function(groupId) {
21016         if (typeof(this.groups[groupId]) == 'undefined') {
21017             return false;
21018         }
21019         
21020         return this.groups[groupId] ;
21021     }
21022     
21023     
21024 });
21025 /*
21026  * - LGPL
21027  *
21028  * RadioItem
21029  * 
21030  */
21031
21032 /**
21033  * @class Roo.bootstrap.Radio
21034  * @extends Roo.bootstrap.Component
21035  * Bootstrap Radio class
21036  * @cfg {String} boxLabel - the label associated
21037  * @cfg {String} value - the value of radio
21038  * 
21039  * @constructor
21040  * Create a new Radio
21041  * @param {Object} config The config object
21042  */
21043 Roo.bootstrap.Radio = function(config){
21044     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21045     
21046 };
21047
21048 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21049     
21050     boxLabel : '',
21051     
21052     value : '',
21053     
21054     getAutoCreate : function()
21055     {
21056         var cfg = {
21057             tag : 'div',
21058             cls : 'form-group radio',
21059             cn : [
21060                 {
21061                     tag : 'label',
21062                     cls : 'box-label',
21063                     html : this.boxLabel
21064                 }
21065             ]
21066         };
21067         
21068         return cfg;
21069     },
21070     
21071     initEvents : function() 
21072     {
21073         this.parent().register(this);
21074         
21075         this.el.on('click', this.onClick, this);
21076         
21077     },
21078     
21079     onClick : function(e)
21080     {
21081         if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21082             this.setChecked(true);
21083         }
21084     },
21085     
21086     setChecked : function(state, suppressEvent)
21087     {
21088         this.parent().setValue(this.value, suppressEvent);
21089         
21090     },
21091     
21092     setBoxLabel : function(v)
21093     {
21094         this.boxLabel = v;
21095         
21096         if(this.rendered){
21097             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21098         }
21099     }
21100     
21101 });
21102  
21103
21104  /*
21105  * - LGPL
21106  *
21107  * Input
21108  * 
21109  */
21110
21111 /**
21112  * @class Roo.bootstrap.SecurePass
21113  * @extends Roo.bootstrap.Input
21114  * Bootstrap SecurePass class
21115  *
21116  * 
21117  * @constructor
21118  * Create a new SecurePass
21119  * @param {Object} config The config object
21120  */
21121  
21122 Roo.bootstrap.SecurePass = function (config) {
21123     // these go here, so the translation tool can replace them..
21124     this.errors = {
21125         PwdEmpty: "Please type a password, and then retype it to confirm.",
21126         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21127         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21128         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21129         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21130         FNInPwd: "Your password can't contain your first name. Please type a different password.",
21131         LNInPwd: "Your password can't contain your last name. Please type a different password.",
21132         TooWeak: "Your password is Too Weak."
21133     },
21134     this.meterLabel = "Password strength:";
21135     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21136     this.meterClass = [
21137         "roo-password-meter-tooweak", 
21138         "roo-password-meter-weak", 
21139         "roo-password-meter-medium", 
21140         "roo-password-meter-strong", 
21141         "roo-password-meter-grey"
21142     ];
21143     
21144     this.errors = {};
21145     
21146     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21147 }
21148
21149 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21150     /**
21151      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21152      * {
21153      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
21154      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21155      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21156      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21157      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21158      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
21159      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
21160      * })
21161      */
21162     // private
21163     
21164     meterWidth: 300,
21165     errorMsg :'',    
21166     errors: false,
21167     imageRoot: '/',
21168     /**
21169      * @cfg {String/Object} Label for the strength meter (defaults to
21170      * 'Password strength:')
21171      */
21172     // private
21173     meterLabel: '',
21174     /**
21175      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21176      * ['Weak', 'Medium', 'Strong'])
21177      */
21178     // private    
21179     pwdStrengths: false,    
21180     // private
21181     strength: 0,
21182     // private
21183     _lastPwd: null,
21184     // private
21185     kCapitalLetter: 0,
21186     kSmallLetter: 1,
21187     kDigit: 2,
21188     kPunctuation: 3,
21189     
21190     insecure: false,
21191     // private
21192     initEvents: function ()
21193     {
21194         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21195
21196         if (this.el.is('input[type=password]') && Roo.isSafari) {
21197             this.el.on('keydown', this.SafariOnKeyDown, this);
21198         }
21199
21200         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21201     },
21202     // private
21203     onRender: function (ct, position)
21204     {
21205         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21206         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21207         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21208
21209         this.trigger.createChild({
21210                    cn: [
21211                     {
21212                     //id: 'PwdMeter',
21213                     tag: 'div',
21214                     cls: 'roo-password-meter-grey col-xs-12',
21215                     style: {
21216                         //width: 0,
21217                         //width: this.meterWidth + 'px'                                                
21218                         }
21219                     },
21220                     {                            
21221                          cls: 'roo-password-meter-text'                          
21222                     }
21223                 ]            
21224         });
21225
21226          
21227         if (this.hideTrigger) {
21228             this.trigger.setDisplayed(false);
21229         }
21230         this.setSize(this.width || '', this.height || '');
21231     },
21232     // private
21233     onDestroy: function ()
21234     {
21235         if (this.trigger) {
21236             this.trigger.removeAllListeners();
21237             this.trigger.remove();
21238         }
21239         if (this.wrap) {
21240             this.wrap.remove();
21241         }
21242         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21243     },
21244     // private
21245     checkStrength: function ()
21246     {
21247         var pwd = this.inputEl().getValue();
21248         if (pwd == this._lastPwd) {
21249             return;
21250         }
21251
21252         var strength;
21253         if (this.ClientSideStrongPassword(pwd)) {
21254             strength = 3;
21255         } else if (this.ClientSideMediumPassword(pwd)) {
21256             strength = 2;
21257         } else if (this.ClientSideWeakPassword(pwd)) {
21258             strength = 1;
21259         } else {
21260             strength = 0;
21261         }
21262         
21263         Roo.log('strength1: ' + strength);
21264         
21265         //var pm = this.trigger.child('div/div/div').dom;
21266         var pm = this.trigger.child('div/div');
21267         pm.removeClass(this.meterClass);
21268         pm.addClass(this.meterClass[strength]);
21269                 
21270         
21271         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21272                 
21273         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21274         
21275         this._lastPwd = pwd;
21276     },
21277     reset: function ()
21278     {
21279         Roo.bootstrap.SecurePass.superclass.reset.call(this);
21280         
21281         this._lastPwd = '';
21282         
21283         var pm = this.trigger.child('div/div');
21284         pm.removeClass(this.meterClass);
21285         pm.addClass('roo-password-meter-grey');        
21286         
21287         
21288         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21289         
21290         pt.innerHTML = '';
21291         this.inputEl().dom.type='password';
21292     },
21293     // private
21294     validateValue: function (value)
21295     {
21296         
21297         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21298             return false;
21299         }
21300         if (value.length == 0) {
21301             if (this.allowBlank) {
21302                 this.clearInvalid();
21303                 return true;
21304             }
21305
21306             this.markInvalid(this.errors.PwdEmpty);
21307             this.errorMsg = this.errors.PwdEmpty;
21308             return false;
21309         }
21310         
21311         if(this.insecure){
21312             return true;
21313         }
21314         
21315         if ('[\x21-\x7e]*'.match(value)) {
21316             this.markInvalid(this.errors.PwdBadChar);
21317             this.errorMsg = this.errors.PwdBadChar;
21318             return false;
21319         }
21320         if (value.length < 6) {
21321             this.markInvalid(this.errors.PwdShort);
21322             this.errorMsg = this.errors.PwdShort;
21323             return false;
21324         }
21325         if (value.length > 16) {
21326             this.markInvalid(this.errors.PwdLong);
21327             this.errorMsg = this.errors.PwdLong;
21328             return false;
21329         }
21330         var strength;
21331         if (this.ClientSideStrongPassword(value)) {
21332             strength = 3;
21333         } else if (this.ClientSideMediumPassword(value)) {
21334             strength = 2;
21335         } else if (this.ClientSideWeakPassword(value)) {
21336             strength = 1;
21337         } else {
21338             strength = 0;
21339         }
21340
21341         
21342         if (strength < 2) {
21343             //this.markInvalid(this.errors.TooWeak);
21344             this.errorMsg = this.errors.TooWeak;
21345             //return false;
21346         }
21347         
21348         
21349         console.log('strength2: ' + strength);
21350         
21351         //var pm = this.trigger.child('div/div/div').dom;
21352         
21353         var pm = this.trigger.child('div/div');
21354         pm.removeClass(this.meterClass);
21355         pm.addClass(this.meterClass[strength]);
21356                 
21357         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21358                 
21359         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21360         
21361         this.errorMsg = ''; 
21362         return true;
21363     },
21364     // private
21365     CharacterSetChecks: function (type)
21366     {
21367         this.type = type;
21368         this.fResult = false;
21369     },
21370     // private
21371     isctype: function (character, type)
21372     {
21373         switch (type) {  
21374             case this.kCapitalLetter:
21375                 if (character >= 'A' && character <= 'Z') {
21376                     return true;
21377                 }
21378                 break;
21379             
21380             case this.kSmallLetter:
21381                 if (character >= 'a' && character <= 'z') {
21382                     return true;
21383                 }
21384                 break;
21385             
21386             case this.kDigit:
21387                 if (character >= '0' && character <= '9') {
21388                     return true;
21389                 }
21390                 break;
21391             
21392             case this.kPunctuation:
21393                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21394                     return true;
21395                 }
21396                 break;
21397             
21398             default:
21399                 return false;
21400         }
21401
21402     },
21403     // private
21404     IsLongEnough: function (pwd, size)
21405     {
21406         return !(pwd == null || isNaN(size) || pwd.length < size);
21407     },
21408     // private
21409     SpansEnoughCharacterSets: function (word, nb)
21410     {
21411         if (!this.IsLongEnough(word, nb))
21412         {
21413             return false;
21414         }
21415
21416         var characterSetChecks = new Array(
21417             new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21418             new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21419         );
21420         
21421         for (var index = 0; index < word.length; ++index) {
21422             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21423                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21424                     characterSetChecks[nCharSet].fResult = true;
21425                     break;
21426                 }
21427             }
21428         }
21429
21430         var nCharSets = 0;
21431         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21432             if (characterSetChecks[nCharSet].fResult) {
21433                 ++nCharSets;
21434             }
21435         }
21436
21437         if (nCharSets < nb) {
21438             return false;
21439         }
21440         return true;
21441     },
21442     // private
21443     ClientSideStrongPassword: function (pwd)
21444     {
21445         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21446     },
21447     // private
21448     ClientSideMediumPassword: function (pwd)
21449     {
21450         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21451     },
21452     // private
21453     ClientSideWeakPassword: function (pwd)
21454     {
21455         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21456     }
21457           
21458 })//<script type="text/javascript">
21459
21460 /*
21461  * Based  Ext JS Library 1.1.1
21462  * Copyright(c) 2006-2007, Ext JS, LLC.
21463  * LGPL
21464  *
21465  */
21466  
21467 /**
21468  * @class Roo.HtmlEditorCore
21469  * @extends Roo.Component
21470  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21471  *
21472  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21473  */
21474
21475 Roo.HtmlEditorCore = function(config){
21476     
21477     
21478     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21479     
21480     
21481     this.addEvents({
21482         /**
21483          * @event initialize
21484          * Fires when the editor is fully initialized (including the iframe)
21485          * @param {Roo.HtmlEditorCore} this
21486          */
21487         initialize: true,
21488         /**
21489          * @event activate
21490          * Fires when the editor is first receives the focus. Any insertion must wait
21491          * until after this event.
21492          * @param {Roo.HtmlEditorCore} this
21493          */
21494         activate: true,
21495          /**
21496          * @event beforesync
21497          * Fires before the textarea is updated with content from the editor iframe. Return false
21498          * to cancel the sync.
21499          * @param {Roo.HtmlEditorCore} this
21500          * @param {String} html
21501          */
21502         beforesync: true,
21503          /**
21504          * @event beforepush
21505          * Fires before the iframe editor is updated with content from the textarea. Return false
21506          * to cancel the push.
21507          * @param {Roo.HtmlEditorCore} this
21508          * @param {String} html
21509          */
21510         beforepush: true,
21511          /**
21512          * @event sync
21513          * Fires when the textarea is updated with content from the editor iframe.
21514          * @param {Roo.HtmlEditorCore} this
21515          * @param {String} html
21516          */
21517         sync: true,
21518          /**
21519          * @event push
21520          * Fires when the iframe editor is updated with content from the textarea.
21521          * @param {Roo.HtmlEditorCore} this
21522          * @param {String} html
21523          */
21524         push: true,
21525         
21526         /**
21527          * @event editorevent
21528          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21529          * @param {Roo.HtmlEditorCore} this
21530          */
21531         editorevent: true
21532         
21533     });
21534     
21535     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21536     
21537     // defaults : white / black...
21538     this.applyBlacklists();
21539     
21540     
21541     
21542 };
21543
21544
21545 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
21546
21547
21548      /**
21549      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
21550      */
21551     
21552     owner : false,
21553     
21554      /**
21555      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
21556      *                        Roo.resizable.
21557      */
21558     resizable : false,
21559      /**
21560      * @cfg {Number} height (in pixels)
21561      */   
21562     height: 300,
21563    /**
21564      * @cfg {Number} width (in pixels)
21565      */   
21566     width: 500,
21567     
21568     /**
21569      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21570      * 
21571      */
21572     stylesheets: false,
21573     
21574     // id of frame..
21575     frameId: false,
21576     
21577     // private properties
21578     validationEvent : false,
21579     deferHeight: true,
21580     initialized : false,
21581     activated : false,
21582     sourceEditMode : false,
21583     onFocus : Roo.emptyFn,
21584     iframePad:3,
21585     hideMode:'offsets',
21586     
21587     clearUp: true,
21588     
21589     // blacklist + whitelisted elements..
21590     black: false,
21591     white: false,
21592      
21593     bodyCls : '',
21594
21595     /**
21596      * Protected method that will not generally be called directly. It
21597      * is called when the editor initializes the iframe with HTML contents. Override this method if you
21598      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21599      */
21600     getDocMarkup : function(){
21601         // body styles..
21602         var st = '';
21603         
21604         // inherit styels from page...?? 
21605         if (this.stylesheets === false) {
21606             
21607             Roo.get(document.head).select('style').each(function(node) {
21608                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21609             });
21610             
21611             Roo.get(document.head).select('link').each(function(node) { 
21612                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21613             });
21614             
21615         } else if (!this.stylesheets.length) {
21616                 // simple..
21617                 st = '<style type="text/css">' +
21618                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21619                    '</style>';
21620         } else { 
21621             st = '<style type="text/css">' +
21622                     this.stylesheets +
21623                 '</style>';
21624         }
21625         
21626         st +=  '<style type="text/css">' +
21627             'IMG { cursor: pointer } ' +
21628         '</style>';
21629
21630         var cls = 'roo-htmleditor-body';
21631         
21632         if(this.bodyCls.length){
21633             cls += ' ' + this.bodyCls;
21634         }
21635         
21636         return '<html><head>' + st  +
21637             //<style type="text/css">' +
21638             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21639             //'</style>' +
21640             ' </head><body class="' +  cls + '"></body></html>';
21641     },
21642
21643     // private
21644     onRender : function(ct, position)
21645     {
21646         var _t = this;
21647         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21648         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21649         
21650         
21651         this.el.dom.style.border = '0 none';
21652         this.el.dom.setAttribute('tabIndex', -1);
21653         this.el.addClass('x-hidden hide');
21654         
21655         
21656         
21657         if(Roo.isIE){ // fix IE 1px bogus margin
21658             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21659         }
21660        
21661         
21662         this.frameId = Roo.id();
21663         
21664          
21665         
21666         var iframe = this.owner.wrap.createChild({
21667             tag: 'iframe',
21668             cls: 'form-control', // bootstrap..
21669             id: this.frameId,
21670             name: this.frameId,
21671             frameBorder : 'no',
21672             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
21673         }, this.el
21674         );
21675         
21676         
21677         this.iframe = iframe.dom;
21678
21679          this.assignDocWin();
21680         
21681         this.doc.designMode = 'on';
21682        
21683         this.doc.open();
21684         this.doc.write(this.getDocMarkup());
21685         this.doc.close();
21686
21687         
21688         var task = { // must defer to wait for browser to be ready
21689             run : function(){
21690                 //console.log("run task?" + this.doc.readyState);
21691                 this.assignDocWin();
21692                 if(this.doc.body || this.doc.readyState == 'complete'){
21693                     try {
21694                         this.doc.designMode="on";
21695                     } catch (e) {
21696                         return;
21697                     }
21698                     Roo.TaskMgr.stop(task);
21699                     this.initEditor.defer(10, this);
21700                 }
21701             },
21702             interval : 10,
21703             duration: 10000,
21704             scope: this
21705         };
21706         Roo.TaskMgr.start(task);
21707
21708     },
21709
21710     // private
21711     onResize : function(w, h)
21712     {
21713          Roo.log('resize: ' +w + ',' + h );
21714         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21715         if(!this.iframe){
21716             return;
21717         }
21718         if(typeof w == 'number'){
21719             
21720             this.iframe.style.width = w + 'px';
21721         }
21722         if(typeof h == 'number'){
21723             
21724             this.iframe.style.height = h + 'px';
21725             if(this.doc){
21726                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21727             }
21728         }
21729         
21730     },
21731
21732     /**
21733      * Toggles the editor between standard and source edit mode.
21734      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21735      */
21736     toggleSourceEdit : function(sourceEditMode){
21737         
21738         this.sourceEditMode = sourceEditMode === true;
21739         
21740         if(this.sourceEditMode){
21741  
21742             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
21743             
21744         }else{
21745             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21746             //this.iframe.className = '';
21747             this.deferFocus();
21748         }
21749         //this.setSize(this.owner.wrap.getSize());
21750         //this.fireEvent('editmodechange', this, this.sourceEditMode);
21751     },
21752
21753     
21754   
21755
21756     /**
21757      * Protected method that will not generally be called directly. If you need/want
21758      * custom HTML cleanup, this is the method you should override.
21759      * @param {String} html The HTML to be cleaned
21760      * return {String} The cleaned HTML
21761      */
21762     cleanHtml : function(html){
21763         html = String(html);
21764         if(html.length > 5){
21765             if(Roo.isSafari){ // strip safari nonsense
21766                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21767             }
21768         }
21769         if(html == '&nbsp;'){
21770             html = '';
21771         }
21772         return html;
21773     },
21774
21775     /**
21776      * HTML Editor -> Textarea
21777      * Protected method that will not generally be called directly. Syncs the contents
21778      * of the editor iframe with the textarea.
21779      */
21780     syncValue : function(){
21781         if(this.initialized){
21782             var bd = (this.doc.body || this.doc.documentElement);
21783             //this.cleanUpPaste(); -- this is done else where and causes havoc..
21784             var html = bd.innerHTML;
21785             if(Roo.isSafari){
21786                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21787                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21788                 if(m && m[1]){
21789                     html = '<div style="'+m[0]+'">' + html + '</div>';
21790                 }
21791             }
21792             html = this.cleanHtml(html);
21793             // fix up the special chars.. normaly like back quotes in word...
21794             // however we do not want to do this with chinese..
21795             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21796                 var cc = b.charCodeAt();
21797                 if (
21798                     (cc >= 0x4E00 && cc < 0xA000 ) ||
21799                     (cc >= 0x3400 && cc < 0x4E00 ) ||
21800                     (cc >= 0xf900 && cc < 0xfb00 )
21801                 ) {
21802                         return b;
21803                 }
21804                 return "&#"+cc+";" 
21805             });
21806             if(this.owner.fireEvent('beforesync', this, html) !== false){
21807                 this.el.dom.value = html;
21808                 this.owner.fireEvent('sync', this, html);
21809             }
21810         }
21811     },
21812
21813     /**
21814      * Protected method that will not generally be called directly. Pushes the value of the textarea
21815      * into the iframe editor.
21816      */
21817     pushValue : function(){
21818         if(this.initialized){
21819             var v = this.el.dom.value.trim();
21820             
21821 //            if(v.length < 1){
21822 //                v = '&#160;';
21823 //            }
21824             
21825             if(this.owner.fireEvent('beforepush', this, v) !== false){
21826                 var d = (this.doc.body || this.doc.documentElement);
21827                 d.innerHTML = v;
21828                 this.cleanUpPaste();
21829                 this.el.dom.value = d.innerHTML;
21830                 this.owner.fireEvent('push', this, v);
21831             }
21832         }
21833     },
21834
21835     // private
21836     deferFocus : function(){
21837         this.focus.defer(10, this);
21838     },
21839
21840     // doc'ed in Field
21841     focus : function(){
21842         if(this.win && !this.sourceEditMode){
21843             this.win.focus();
21844         }else{
21845             this.el.focus();
21846         }
21847     },
21848     
21849     assignDocWin: function()
21850     {
21851         var iframe = this.iframe;
21852         
21853          if(Roo.isIE){
21854             this.doc = iframe.contentWindow.document;
21855             this.win = iframe.contentWindow;
21856         } else {
21857 //            if (!Roo.get(this.frameId)) {
21858 //                return;
21859 //            }
21860 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21861 //            this.win = Roo.get(this.frameId).dom.contentWindow;
21862             
21863             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21864                 return;
21865             }
21866             
21867             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21868             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21869         }
21870     },
21871     
21872     // private
21873     initEditor : function(){
21874         //console.log("INIT EDITOR");
21875         this.assignDocWin();
21876         
21877         
21878         
21879         this.doc.designMode="on";
21880         this.doc.open();
21881         this.doc.write(this.getDocMarkup());
21882         this.doc.close();
21883         
21884         var dbody = (this.doc.body || this.doc.documentElement);
21885         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21886         // this copies styles from the containing element into thsi one..
21887         // not sure why we need all of this..
21888         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21889         
21890         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21891         //ss['background-attachment'] = 'fixed'; // w3c
21892         dbody.bgProperties = 'fixed'; // ie
21893         //Roo.DomHelper.applyStyles(dbody, ss);
21894         Roo.EventManager.on(this.doc, {
21895             //'mousedown': this.onEditorEvent,
21896             'mouseup': this.onEditorEvent,
21897             'dblclick': this.onEditorEvent,
21898             'click': this.onEditorEvent,
21899             'keyup': this.onEditorEvent,
21900             buffer:100,
21901             scope: this
21902         });
21903         if(Roo.isGecko){
21904             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21905         }
21906         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21907             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21908         }
21909         this.initialized = true;
21910
21911         this.owner.fireEvent('initialize', this);
21912         this.pushValue();
21913     },
21914
21915     // private
21916     onDestroy : function(){
21917         
21918         
21919         
21920         if(this.rendered){
21921             
21922             //for (var i =0; i < this.toolbars.length;i++) {
21923             //    // fixme - ask toolbars for heights?
21924             //    this.toolbars[i].onDestroy();
21925            // }
21926             
21927             //this.wrap.dom.innerHTML = '';
21928             //this.wrap.remove();
21929         }
21930     },
21931
21932     // private
21933     onFirstFocus : function(){
21934         
21935         this.assignDocWin();
21936         
21937         
21938         this.activated = true;
21939          
21940     
21941         if(Roo.isGecko){ // prevent silly gecko errors
21942             this.win.focus();
21943             var s = this.win.getSelection();
21944             if(!s.focusNode || s.focusNode.nodeType != 3){
21945                 var r = s.getRangeAt(0);
21946                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21947                 r.collapse(true);
21948                 this.deferFocus();
21949             }
21950             try{
21951                 this.execCmd('useCSS', true);
21952                 this.execCmd('styleWithCSS', false);
21953             }catch(e){}
21954         }
21955         this.owner.fireEvent('activate', this);
21956     },
21957
21958     // private
21959     adjustFont: function(btn){
21960         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21961         //if(Roo.isSafari){ // safari
21962         //    adjust *= 2;
21963        // }
21964         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21965         if(Roo.isSafari){ // safari
21966             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21967             v =  (v < 10) ? 10 : v;
21968             v =  (v > 48) ? 48 : v;
21969             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21970             
21971         }
21972         
21973         
21974         v = Math.max(1, v+adjust);
21975         
21976         this.execCmd('FontSize', v  );
21977     },
21978
21979     onEditorEvent : function(e)
21980     {
21981         this.owner.fireEvent('editorevent', this, e);
21982       //  this.updateToolbar();
21983         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21984     },
21985
21986     insertTag : function(tg)
21987     {
21988         // could be a bit smarter... -> wrap the current selected tRoo..
21989         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21990             
21991             range = this.createRange(this.getSelection());
21992             var wrappingNode = this.doc.createElement(tg.toLowerCase());
21993             wrappingNode.appendChild(range.extractContents());
21994             range.insertNode(wrappingNode);
21995
21996             return;
21997             
21998             
21999             
22000         }
22001         this.execCmd("formatblock",   tg);
22002         
22003     },
22004     
22005     insertText : function(txt)
22006     {
22007         
22008         
22009         var range = this.createRange();
22010         range.deleteContents();
22011                //alert(Sender.getAttribute('label'));
22012                
22013         range.insertNode(this.doc.createTextNode(txt));
22014     } ,
22015     
22016      
22017
22018     /**
22019      * Executes a Midas editor command on the editor document and performs necessary focus and
22020      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22021      * @param {String} cmd The Midas command
22022      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22023      */
22024     relayCmd : function(cmd, value){
22025         this.win.focus();
22026         this.execCmd(cmd, value);
22027         this.owner.fireEvent('editorevent', this);
22028         //this.updateToolbar();
22029         this.owner.deferFocus();
22030     },
22031
22032     /**
22033      * Executes a Midas editor command directly on the editor document.
22034      * For visual commands, you should use {@link #relayCmd} instead.
22035      * <b>This should only be called after the editor is initialized.</b>
22036      * @param {String} cmd The Midas command
22037      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22038      */
22039     execCmd : function(cmd, value){
22040         this.doc.execCommand(cmd, false, value === undefined ? null : value);
22041         this.syncValue();
22042     },
22043  
22044  
22045    
22046     /**
22047      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22048      * to insert tRoo.
22049      * @param {String} text | dom node.. 
22050      */
22051     insertAtCursor : function(text)
22052     {
22053         
22054         if(!this.activated){
22055             return;
22056         }
22057         /*
22058         if(Roo.isIE){
22059             this.win.focus();
22060             var r = this.doc.selection.createRange();
22061             if(r){
22062                 r.collapse(true);
22063                 r.pasteHTML(text);
22064                 this.syncValue();
22065                 this.deferFocus();
22066             
22067             }
22068             return;
22069         }
22070         */
22071         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22072             this.win.focus();
22073             
22074             
22075             // from jquery ui (MIT licenced)
22076             var range, node;
22077             var win = this.win;
22078             
22079             if (win.getSelection && win.getSelection().getRangeAt) {
22080                 range = win.getSelection().getRangeAt(0);
22081                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22082                 range.insertNode(node);
22083             } else if (win.document.selection && win.document.selection.createRange) {
22084                 // no firefox support
22085                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22086                 win.document.selection.createRange().pasteHTML(txt);
22087             } else {
22088                 // no firefox support
22089                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22090                 this.execCmd('InsertHTML', txt);
22091             } 
22092             
22093             this.syncValue();
22094             
22095             this.deferFocus();
22096         }
22097     },
22098  // private
22099     mozKeyPress : function(e){
22100         if(e.ctrlKey){
22101             var c = e.getCharCode(), cmd;
22102           
22103             if(c > 0){
22104                 c = String.fromCharCode(c).toLowerCase();
22105                 switch(c){
22106                     case 'b':
22107                         cmd = 'bold';
22108                         break;
22109                     case 'i':
22110                         cmd = 'italic';
22111                         break;
22112                     
22113                     case 'u':
22114                         cmd = 'underline';
22115                         break;
22116                     
22117                     case 'v':
22118                         this.cleanUpPaste.defer(100, this);
22119                         return;
22120                         
22121                 }
22122                 if(cmd){
22123                     this.win.focus();
22124                     this.execCmd(cmd);
22125                     this.deferFocus();
22126                     e.preventDefault();
22127                 }
22128                 
22129             }
22130         }
22131     },
22132
22133     // private
22134     fixKeys : function(){ // load time branching for fastest keydown performance
22135         if(Roo.isIE){
22136             return function(e){
22137                 var k = e.getKey(), r;
22138                 if(k == e.TAB){
22139                     e.stopEvent();
22140                     r = this.doc.selection.createRange();
22141                     if(r){
22142                         r.collapse(true);
22143                         r.pasteHTML('&#160;&#160;&#160;&#160;');
22144                         this.deferFocus();
22145                     }
22146                     return;
22147                 }
22148                 
22149                 if(k == e.ENTER){
22150                     r = this.doc.selection.createRange();
22151                     if(r){
22152                         var target = r.parentElement();
22153                         if(!target || target.tagName.toLowerCase() != 'li'){
22154                             e.stopEvent();
22155                             r.pasteHTML('<br />');
22156                             r.collapse(false);
22157                             r.select();
22158                         }
22159                     }
22160                 }
22161                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22162                     this.cleanUpPaste.defer(100, this);
22163                     return;
22164                 }
22165                 
22166                 
22167             };
22168         }else if(Roo.isOpera){
22169             return function(e){
22170                 var k = e.getKey();
22171                 if(k == e.TAB){
22172                     e.stopEvent();
22173                     this.win.focus();
22174                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
22175                     this.deferFocus();
22176                 }
22177                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22178                     this.cleanUpPaste.defer(100, this);
22179                     return;
22180                 }
22181                 
22182             };
22183         }else if(Roo.isSafari){
22184             return function(e){
22185                 var k = e.getKey();
22186                 
22187                 if(k == e.TAB){
22188                     e.stopEvent();
22189                     this.execCmd('InsertText','\t');
22190                     this.deferFocus();
22191                     return;
22192                 }
22193                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22194                     this.cleanUpPaste.defer(100, this);
22195                     return;
22196                 }
22197                 
22198              };
22199         }
22200     }(),
22201     
22202     getAllAncestors: function()
22203     {
22204         var p = this.getSelectedNode();
22205         var a = [];
22206         if (!p) {
22207             a.push(p); // push blank onto stack..
22208             p = this.getParentElement();
22209         }
22210         
22211         
22212         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22213             a.push(p);
22214             p = p.parentNode;
22215         }
22216         a.push(this.doc.body);
22217         return a;
22218     },
22219     lastSel : false,
22220     lastSelNode : false,
22221     
22222     
22223     getSelection : function() 
22224     {
22225         this.assignDocWin();
22226         return Roo.isIE ? this.doc.selection : this.win.getSelection();
22227     },
22228     
22229     getSelectedNode: function() 
22230     {
22231         // this may only work on Gecko!!!
22232         
22233         // should we cache this!!!!
22234         
22235         
22236         
22237          
22238         var range = this.createRange(this.getSelection()).cloneRange();
22239         
22240         if (Roo.isIE) {
22241             var parent = range.parentElement();
22242             while (true) {
22243                 var testRange = range.duplicate();
22244                 testRange.moveToElementText(parent);
22245                 if (testRange.inRange(range)) {
22246                     break;
22247                 }
22248                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22249                     break;
22250                 }
22251                 parent = parent.parentElement;
22252             }
22253             return parent;
22254         }
22255         
22256         // is ancestor a text element.
22257         var ac =  range.commonAncestorContainer;
22258         if (ac.nodeType == 3) {
22259             ac = ac.parentNode;
22260         }
22261         
22262         var ar = ac.childNodes;
22263          
22264         var nodes = [];
22265         var other_nodes = [];
22266         var has_other_nodes = false;
22267         for (var i=0;i<ar.length;i++) {
22268             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
22269                 continue;
22270             }
22271             // fullly contained node.
22272             
22273             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22274                 nodes.push(ar[i]);
22275                 continue;
22276             }
22277             
22278             // probably selected..
22279             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22280                 other_nodes.push(ar[i]);
22281                 continue;
22282             }
22283             // outer..
22284             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
22285                 continue;
22286             }
22287             
22288             
22289             has_other_nodes = true;
22290         }
22291         if (!nodes.length && other_nodes.length) {
22292             nodes= other_nodes;
22293         }
22294         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22295             return false;
22296         }
22297         
22298         return nodes[0];
22299     },
22300     createRange: function(sel)
22301     {
22302         // this has strange effects when using with 
22303         // top toolbar - not sure if it's a great idea.
22304         //this.editor.contentWindow.focus();
22305         if (typeof sel != "undefined") {
22306             try {
22307                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22308             } catch(e) {
22309                 return this.doc.createRange();
22310             }
22311         } else {
22312             return this.doc.createRange();
22313         }
22314     },
22315     getParentElement: function()
22316     {
22317         
22318         this.assignDocWin();
22319         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22320         
22321         var range = this.createRange(sel);
22322          
22323         try {
22324             var p = range.commonAncestorContainer;
22325             while (p.nodeType == 3) { // text node
22326                 p = p.parentNode;
22327             }
22328             return p;
22329         } catch (e) {
22330             return null;
22331         }
22332     
22333     },
22334     /***
22335      *
22336      * Range intersection.. the hard stuff...
22337      *  '-1' = before
22338      *  '0' = hits..
22339      *  '1' = after.
22340      *         [ -- selected range --- ]
22341      *   [fail]                        [fail]
22342      *
22343      *    basically..
22344      *      if end is before start or  hits it. fail.
22345      *      if start is after end or hits it fail.
22346      *
22347      *   if either hits (but other is outside. - then it's not 
22348      *   
22349      *    
22350      **/
22351     
22352     
22353     // @see http://www.thismuchiknow.co.uk/?p=64.
22354     rangeIntersectsNode : function(range, node)
22355     {
22356         var nodeRange = node.ownerDocument.createRange();
22357         try {
22358             nodeRange.selectNode(node);
22359         } catch (e) {
22360             nodeRange.selectNodeContents(node);
22361         }
22362     
22363         var rangeStartRange = range.cloneRange();
22364         rangeStartRange.collapse(true);
22365     
22366         var rangeEndRange = range.cloneRange();
22367         rangeEndRange.collapse(false);
22368     
22369         var nodeStartRange = nodeRange.cloneRange();
22370         nodeStartRange.collapse(true);
22371     
22372         var nodeEndRange = nodeRange.cloneRange();
22373         nodeEndRange.collapse(false);
22374     
22375         return rangeStartRange.compareBoundaryPoints(
22376                  Range.START_TO_START, nodeEndRange) == -1 &&
22377                rangeEndRange.compareBoundaryPoints(
22378                  Range.START_TO_START, nodeStartRange) == 1;
22379         
22380          
22381     },
22382     rangeCompareNode : function(range, node)
22383     {
22384         var nodeRange = node.ownerDocument.createRange();
22385         try {
22386             nodeRange.selectNode(node);
22387         } catch (e) {
22388             nodeRange.selectNodeContents(node);
22389         }
22390         
22391         
22392         range.collapse(true);
22393     
22394         nodeRange.collapse(true);
22395      
22396         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22397         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
22398          
22399         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22400         
22401         var nodeIsBefore   =  ss == 1;
22402         var nodeIsAfter    = ee == -1;
22403         
22404         if (nodeIsBefore && nodeIsAfter) {
22405             return 0; // outer
22406         }
22407         if (!nodeIsBefore && nodeIsAfter) {
22408             return 1; //right trailed.
22409         }
22410         
22411         if (nodeIsBefore && !nodeIsAfter) {
22412             return 2;  // left trailed.
22413         }
22414         // fully contined.
22415         return 3;
22416     },
22417
22418     // private? - in a new class?
22419     cleanUpPaste :  function()
22420     {
22421         // cleans up the whole document..
22422         Roo.log('cleanuppaste');
22423         
22424         this.cleanUpChildren(this.doc.body);
22425         var clean = this.cleanWordChars(this.doc.body.innerHTML);
22426         if (clean != this.doc.body.innerHTML) {
22427             this.doc.body.innerHTML = clean;
22428         }
22429         
22430     },
22431     
22432     cleanWordChars : function(input) {// change the chars to hex code
22433         var he = Roo.HtmlEditorCore;
22434         
22435         var output = input;
22436         Roo.each(he.swapCodes, function(sw) { 
22437             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22438             
22439             output = output.replace(swapper, sw[1]);
22440         });
22441         
22442         return output;
22443     },
22444     
22445     
22446     cleanUpChildren : function (n)
22447     {
22448         if (!n.childNodes.length) {
22449             return;
22450         }
22451         for (var i = n.childNodes.length-1; i > -1 ; i--) {
22452            this.cleanUpChild(n.childNodes[i]);
22453         }
22454     },
22455     
22456     
22457         
22458     
22459     cleanUpChild : function (node)
22460     {
22461         var ed = this;
22462         //console.log(node);
22463         if (node.nodeName == "#text") {
22464             // clean up silly Windows -- stuff?
22465             return; 
22466         }
22467         if (node.nodeName == "#comment") {
22468             node.parentNode.removeChild(node);
22469             // clean up silly Windows -- stuff?
22470             return; 
22471         }
22472         var lcname = node.tagName.toLowerCase();
22473         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22474         // whitelist of tags..
22475         
22476         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22477             // remove node.
22478             node.parentNode.removeChild(node);
22479             return;
22480             
22481         }
22482         
22483         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22484         
22485         // remove <a name=....> as rendering on yahoo mailer is borked with this.
22486         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22487         
22488         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22489         //    remove_keep_children = true;
22490         //}
22491         
22492         if (remove_keep_children) {
22493             this.cleanUpChildren(node);
22494             // inserts everything just before this node...
22495             while (node.childNodes.length) {
22496                 var cn = node.childNodes[0];
22497                 node.removeChild(cn);
22498                 node.parentNode.insertBefore(cn, node);
22499             }
22500             node.parentNode.removeChild(node);
22501             return;
22502         }
22503         
22504         if (!node.attributes || !node.attributes.length) {
22505             this.cleanUpChildren(node);
22506             return;
22507         }
22508         
22509         function cleanAttr(n,v)
22510         {
22511             
22512             if (v.match(/^\./) || v.match(/^\//)) {
22513                 return;
22514             }
22515             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22516                 return;
22517             }
22518             if (v.match(/^#/)) {
22519                 return;
22520             }
22521 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22522             node.removeAttribute(n);
22523             
22524         }
22525         
22526         var cwhite = this.cwhite;
22527         var cblack = this.cblack;
22528             
22529         function cleanStyle(n,v)
22530         {
22531             if (v.match(/expression/)) { //XSS?? should we even bother..
22532                 node.removeAttribute(n);
22533                 return;
22534             }
22535             
22536             var parts = v.split(/;/);
22537             var clean = [];
22538             
22539             Roo.each(parts, function(p) {
22540                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22541                 if (!p.length) {
22542                     return true;
22543                 }
22544                 var l = p.split(':').shift().replace(/\s+/g,'');
22545                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22546                 
22547                 if ( cwhite.length && cblack.indexOf(l) > -1) {
22548 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22549                     //node.removeAttribute(n);
22550                     return true;
22551                 }
22552                 //Roo.log()
22553                 // only allow 'c whitelisted system attributes'
22554                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
22555 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22556                     //node.removeAttribute(n);
22557                     return true;
22558                 }
22559                 
22560                 
22561                  
22562                 
22563                 clean.push(p);
22564                 return true;
22565             });
22566             if (clean.length) { 
22567                 node.setAttribute(n, clean.join(';'));
22568             } else {
22569                 node.removeAttribute(n);
22570             }
22571             
22572         }
22573         
22574         
22575         for (var i = node.attributes.length-1; i > -1 ; i--) {
22576             var a = node.attributes[i];
22577             //console.log(a);
22578             
22579             if (a.name.toLowerCase().substr(0,2)=='on')  {
22580                 node.removeAttribute(a.name);
22581                 continue;
22582             }
22583             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22584                 node.removeAttribute(a.name);
22585                 continue;
22586             }
22587             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22588                 cleanAttr(a.name,a.value); // fixme..
22589                 continue;
22590             }
22591             if (a.name == 'style') {
22592                 cleanStyle(a.name,a.value);
22593                 continue;
22594             }
22595             /// clean up MS crap..
22596             // tecnically this should be a list of valid class'es..
22597             
22598             
22599             if (a.name == 'class') {
22600                 if (a.value.match(/^Mso/)) {
22601                     node.className = '';
22602                 }
22603                 
22604                 if (a.value.match(/^body$/)) {
22605                     node.className = '';
22606                 }
22607                 continue;
22608             }
22609             
22610             // style cleanup!?
22611             // class cleanup?
22612             
22613         }
22614         
22615         
22616         this.cleanUpChildren(node);
22617         
22618         
22619     },
22620     
22621     /**
22622      * Clean up MS wordisms...
22623      */
22624     cleanWord : function(node)
22625     {
22626         
22627         
22628         if (!node) {
22629             this.cleanWord(this.doc.body);
22630             return;
22631         }
22632         if (node.nodeName == "#text") {
22633             // clean up silly Windows -- stuff?
22634             return; 
22635         }
22636         if (node.nodeName == "#comment") {
22637             node.parentNode.removeChild(node);
22638             // clean up silly Windows -- stuff?
22639             return; 
22640         }
22641         
22642         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22643             node.parentNode.removeChild(node);
22644             return;
22645         }
22646         
22647         // remove - but keep children..
22648         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22649             while (node.childNodes.length) {
22650                 var cn = node.childNodes[0];
22651                 node.removeChild(cn);
22652                 node.parentNode.insertBefore(cn, node);
22653             }
22654             node.parentNode.removeChild(node);
22655             this.iterateChildren(node, this.cleanWord);
22656             return;
22657         }
22658         // clean styles
22659         if (node.className.length) {
22660             
22661             var cn = node.className.split(/\W+/);
22662             var cna = [];
22663             Roo.each(cn, function(cls) {
22664                 if (cls.match(/Mso[a-zA-Z]+/)) {
22665                     return;
22666                 }
22667                 cna.push(cls);
22668             });
22669             node.className = cna.length ? cna.join(' ') : '';
22670             if (!cna.length) {
22671                 node.removeAttribute("class");
22672             }
22673         }
22674         
22675         if (node.hasAttribute("lang")) {
22676             node.removeAttribute("lang");
22677         }
22678         
22679         if (node.hasAttribute("style")) {
22680             
22681             var styles = node.getAttribute("style").split(";");
22682             var nstyle = [];
22683             Roo.each(styles, function(s) {
22684                 if (!s.match(/:/)) {
22685                     return;
22686                 }
22687                 var kv = s.split(":");
22688                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22689                     return;
22690                 }
22691                 // what ever is left... we allow.
22692                 nstyle.push(s);
22693             });
22694             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22695             if (!nstyle.length) {
22696                 node.removeAttribute('style');
22697             }
22698         }
22699         this.iterateChildren(node, this.cleanWord);
22700         
22701         
22702         
22703     },
22704     /**
22705      * iterateChildren of a Node, calling fn each time, using this as the scole..
22706      * @param {DomNode} node node to iterate children of.
22707      * @param {Function} fn method of this class to call on each item.
22708      */
22709     iterateChildren : function(node, fn)
22710     {
22711         if (!node.childNodes.length) {
22712                 return;
22713         }
22714         for (var i = node.childNodes.length-1; i > -1 ; i--) {
22715            fn.call(this, node.childNodes[i])
22716         }
22717     },
22718     
22719     
22720     /**
22721      * cleanTableWidths.
22722      *
22723      * Quite often pasting from word etc.. results in tables with column and widths.
22724      * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22725      *
22726      */
22727     cleanTableWidths : function(node)
22728     {
22729          
22730          
22731         if (!node) {
22732             this.cleanTableWidths(this.doc.body);
22733             return;
22734         }
22735         
22736         // ignore list...
22737         if (node.nodeName == "#text" || node.nodeName == "#comment") {
22738             return; 
22739         }
22740         Roo.log(node.tagName);
22741         if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22742             this.iterateChildren(node, this.cleanTableWidths);
22743             return;
22744         }
22745         if (node.hasAttribute('width')) {
22746             node.removeAttribute('width');
22747         }
22748         
22749          
22750         if (node.hasAttribute("style")) {
22751             // pretty basic...
22752             
22753             var styles = node.getAttribute("style").split(";");
22754             var nstyle = [];
22755             Roo.each(styles, function(s) {
22756                 if (!s.match(/:/)) {
22757                     return;
22758                 }
22759                 var kv = s.split(":");
22760                 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22761                     return;
22762                 }
22763                 // what ever is left... we allow.
22764                 nstyle.push(s);
22765             });
22766             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22767             if (!nstyle.length) {
22768                 node.removeAttribute('style');
22769             }
22770         }
22771         
22772         this.iterateChildren(node, this.cleanTableWidths);
22773         
22774         
22775     },
22776     
22777     
22778     
22779     
22780     domToHTML : function(currentElement, depth, nopadtext) {
22781         
22782         depth = depth || 0;
22783         nopadtext = nopadtext || false;
22784     
22785         if (!currentElement) {
22786             return this.domToHTML(this.doc.body);
22787         }
22788         
22789         //Roo.log(currentElement);
22790         var j;
22791         var allText = false;
22792         var nodeName = currentElement.nodeName;
22793         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22794         
22795         if  (nodeName == '#text') {
22796             
22797             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22798         }
22799         
22800         
22801         var ret = '';
22802         if (nodeName != 'BODY') {
22803              
22804             var i = 0;
22805             // Prints the node tagName, such as <A>, <IMG>, etc
22806             if (tagName) {
22807                 var attr = [];
22808                 for(i = 0; i < currentElement.attributes.length;i++) {
22809                     // quoting?
22810                     var aname = currentElement.attributes.item(i).name;
22811                     if (!currentElement.attributes.item(i).value.length) {
22812                         continue;
22813                     }
22814                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22815                 }
22816                 
22817                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22818             } 
22819             else {
22820                 
22821                 // eack
22822             }
22823         } else {
22824             tagName = false;
22825         }
22826         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22827             return ret;
22828         }
22829         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22830             nopadtext = true;
22831         }
22832         
22833         
22834         // Traverse the tree
22835         i = 0;
22836         var currentElementChild = currentElement.childNodes.item(i);
22837         var allText = true;
22838         var innerHTML  = '';
22839         lastnode = '';
22840         while (currentElementChild) {
22841             // Formatting code (indent the tree so it looks nice on the screen)
22842             var nopad = nopadtext;
22843             if (lastnode == 'SPAN') {
22844                 nopad  = true;
22845             }
22846             // text
22847             if  (currentElementChild.nodeName == '#text') {
22848                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22849                 toadd = nopadtext ? toadd : toadd.trim();
22850                 if (!nopad && toadd.length > 80) {
22851                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
22852                 }
22853                 innerHTML  += toadd;
22854                 
22855                 i++;
22856                 currentElementChild = currentElement.childNodes.item(i);
22857                 lastNode = '';
22858                 continue;
22859             }
22860             allText = false;
22861             
22862             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
22863                 
22864             // Recursively traverse the tree structure of the child node
22865             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
22866             lastnode = currentElementChild.nodeName;
22867             i++;
22868             currentElementChild=currentElement.childNodes.item(i);
22869         }
22870         
22871         ret += innerHTML;
22872         
22873         if (!allText) {
22874                 // The remaining code is mostly for formatting the tree
22875             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
22876         }
22877         
22878         
22879         if (tagName) {
22880             ret+= "</"+tagName+">";
22881         }
22882         return ret;
22883         
22884     },
22885         
22886     applyBlacklists : function()
22887     {
22888         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
22889         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
22890         
22891         this.white = [];
22892         this.black = [];
22893         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22894             if (b.indexOf(tag) > -1) {
22895                 return;
22896             }
22897             this.white.push(tag);
22898             
22899         }, this);
22900         
22901         Roo.each(w, function(tag) {
22902             if (b.indexOf(tag) > -1) {
22903                 return;
22904             }
22905             if (this.white.indexOf(tag) > -1) {
22906                 return;
22907             }
22908             this.white.push(tag);
22909             
22910         }, this);
22911         
22912         
22913         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22914             if (w.indexOf(tag) > -1) {
22915                 return;
22916             }
22917             this.black.push(tag);
22918             
22919         }, this);
22920         
22921         Roo.each(b, function(tag) {
22922             if (w.indexOf(tag) > -1) {
22923                 return;
22924             }
22925             if (this.black.indexOf(tag) > -1) {
22926                 return;
22927             }
22928             this.black.push(tag);
22929             
22930         }, this);
22931         
22932         
22933         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
22934         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
22935         
22936         this.cwhite = [];
22937         this.cblack = [];
22938         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22939             if (b.indexOf(tag) > -1) {
22940                 return;
22941             }
22942             this.cwhite.push(tag);
22943             
22944         }, this);
22945         
22946         Roo.each(w, function(tag) {
22947             if (b.indexOf(tag) > -1) {
22948                 return;
22949             }
22950             if (this.cwhite.indexOf(tag) > -1) {
22951                 return;
22952             }
22953             this.cwhite.push(tag);
22954             
22955         }, this);
22956         
22957         
22958         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22959             if (w.indexOf(tag) > -1) {
22960                 return;
22961             }
22962             this.cblack.push(tag);
22963             
22964         }, this);
22965         
22966         Roo.each(b, function(tag) {
22967             if (w.indexOf(tag) > -1) {
22968                 return;
22969             }
22970             if (this.cblack.indexOf(tag) > -1) {
22971                 return;
22972             }
22973             this.cblack.push(tag);
22974             
22975         }, this);
22976     },
22977     
22978     setStylesheets : function(stylesheets)
22979     {
22980         if(typeof(stylesheets) == 'string'){
22981             Roo.get(this.iframe.contentDocument.head).createChild({
22982                 tag : 'link',
22983                 rel : 'stylesheet',
22984                 type : 'text/css',
22985                 href : stylesheets
22986             });
22987             
22988             return;
22989         }
22990         var _this = this;
22991      
22992         Roo.each(stylesheets, function(s) {
22993             if(!s.length){
22994                 return;
22995             }
22996             
22997             Roo.get(_this.iframe.contentDocument.head).createChild({
22998                 tag : 'link',
22999                 rel : 'stylesheet',
23000                 type : 'text/css',
23001                 href : s
23002             });
23003         });
23004
23005         
23006     },
23007     
23008     removeStylesheets : function()
23009     {
23010         var _this = this;
23011         
23012         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23013             s.remove();
23014         });
23015     },
23016     
23017     setStyle : function(style)
23018     {
23019         Roo.get(this.iframe.contentDocument.head).createChild({
23020             tag : 'style',
23021             type : 'text/css',
23022             html : style
23023         });
23024
23025         return;
23026     }
23027     
23028     // hide stuff that is not compatible
23029     /**
23030      * @event blur
23031      * @hide
23032      */
23033     /**
23034      * @event change
23035      * @hide
23036      */
23037     /**
23038      * @event focus
23039      * @hide
23040      */
23041     /**
23042      * @event specialkey
23043      * @hide
23044      */
23045     /**
23046      * @cfg {String} fieldClass @hide
23047      */
23048     /**
23049      * @cfg {String} focusClass @hide
23050      */
23051     /**
23052      * @cfg {String} autoCreate @hide
23053      */
23054     /**
23055      * @cfg {String} inputType @hide
23056      */
23057     /**
23058      * @cfg {String} invalidClass @hide
23059      */
23060     /**
23061      * @cfg {String} invalidText @hide
23062      */
23063     /**
23064      * @cfg {String} msgFx @hide
23065      */
23066     /**
23067      * @cfg {String} validateOnBlur @hide
23068      */
23069 });
23070
23071 Roo.HtmlEditorCore.white = [
23072         'area', 'br', 'img', 'input', 'hr', 'wbr',
23073         
23074        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
23075        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
23076        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
23077        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
23078        'table',   'ul',         'xmp', 
23079        
23080        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
23081       'thead',   'tr', 
23082      
23083       'dir', 'menu', 'ol', 'ul', 'dl',
23084        
23085       'embed',  'object'
23086 ];
23087
23088
23089 Roo.HtmlEditorCore.black = [
23090     //    'embed',  'object', // enable - backend responsiblity to clean thiese
23091         'applet', // 
23092         'base',   'basefont', 'bgsound', 'blink',  'body', 
23093         'frame',  'frameset', 'head',    'html',   'ilayer', 
23094         'iframe', 'layer',  'link',     'meta',    'object',   
23095         'script', 'style' ,'title',  'xml' // clean later..
23096 ];
23097 Roo.HtmlEditorCore.clean = [
23098     'script', 'style', 'title', 'xml'
23099 ];
23100 Roo.HtmlEditorCore.remove = [
23101     'font'
23102 ];
23103 // attributes..
23104
23105 Roo.HtmlEditorCore.ablack = [
23106     'on'
23107 ];
23108     
23109 Roo.HtmlEditorCore.aclean = [ 
23110     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
23111 ];
23112
23113 // protocols..
23114 Roo.HtmlEditorCore.pwhite= [
23115         'http',  'https',  'mailto'
23116 ];
23117
23118 // white listed style attributes.
23119 Roo.HtmlEditorCore.cwhite= [
23120       //  'text-align', /// default is to allow most things..
23121       
23122          
23123 //        'font-size'//??
23124 ];
23125
23126 // black listed style attributes.
23127 Roo.HtmlEditorCore.cblack= [
23128       //  'font-size' -- this can be set by the project 
23129 ];
23130
23131
23132 Roo.HtmlEditorCore.swapCodes   =[ 
23133     [    8211, "--" ], 
23134     [    8212, "--" ], 
23135     [    8216,  "'" ],  
23136     [    8217, "'" ],  
23137     [    8220, '"' ],  
23138     [    8221, '"' ],  
23139     [    8226, "*" ],  
23140     [    8230, "..." ]
23141 ]; 
23142
23143     /*
23144  * - LGPL
23145  *
23146  * HtmlEditor
23147  * 
23148  */
23149
23150 /**
23151  * @class Roo.bootstrap.HtmlEditor
23152  * @extends Roo.bootstrap.TextArea
23153  * Bootstrap HtmlEditor class
23154
23155  * @constructor
23156  * Create a new HtmlEditor
23157  * @param {Object} config The config object
23158  */
23159
23160 Roo.bootstrap.HtmlEditor = function(config){
23161     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23162     if (!this.toolbars) {
23163         this.toolbars = [];
23164     }
23165     
23166     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23167     this.addEvents({
23168             /**
23169              * @event initialize
23170              * Fires when the editor is fully initialized (including the iframe)
23171              * @param {HtmlEditor} this
23172              */
23173             initialize: true,
23174             /**
23175              * @event activate
23176              * Fires when the editor is first receives the focus. Any insertion must wait
23177              * until after this event.
23178              * @param {HtmlEditor} this
23179              */
23180             activate: true,
23181              /**
23182              * @event beforesync
23183              * Fires before the textarea is updated with content from the editor iframe. Return false
23184              * to cancel the sync.
23185              * @param {HtmlEditor} this
23186              * @param {String} html
23187              */
23188             beforesync: true,
23189              /**
23190              * @event beforepush
23191              * Fires before the iframe editor is updated with content from the textarea. Return false
23192              * to cancel the push.
23193              * @param {HtmlEditor} this
23194              * @param {String} html
23195              */
23196             beforepush: true,
23197              /**
23198              * @event sync
23199              * Fires when the textarea is updated with content from the editor iframe.
23200              * @param {HtmlEditor} this
23201              * @param {String} html
23202              */
23203             sync: true,
23204              /**
23205              * @event push
23206              * Fires when the iframe editor is updated with content from the textarea.
23207              * @param {HtmlEditor} this
23208              * @param {String} html
23209              */
23210             push: true,
23211              /**
23212              * @event editmodechange
23213              * Fires when the editor switches edit modes
23214              * @param {HtmlEditor} this
23215              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23216              */
23217             editmodechange: true,
23218             /**
23219              * @event editorevent
23220              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23221              * @param {HtmlEditor} this
23222              */
23223             editorevent: true,
23224             /**
23225              * @event firstfocus
23226              * Fires when on first focus - needed by toolbars..
23227              * @param {HtmlEditor} this
23228              */
23229             firstfocus: true,
23230             /**
23231              * @event autosave
23232              * Auto save the htmlEditor value as a file into Events
23233              * @param {HtmlEditor} this
23234              */
23235             autosave: true,
23236             /**
23237              * @event savedpreview
23238              * preview the saved version of htmlEditor
23239              * @param {HtmlEditor} this
23240              */
23241             savedpreview: true
23242         });
23243 };
23244
23245
23246 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
23247     
23248     
23249       /**
23250      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23251      */
23252     toolbars : false,
23253     
23254      /**
23255     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23256     */
23257     btns : [],
23258    
23259      /**
23260      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
23261      *                        Roo.resizable.
23262      */
23263     resizable : false,
23264      /**
23265      * @cfg {Number} height (in pixels)
23266      */   
23267     height: 300,
23268    /**
23269      * @cfg {Number} width (in pixels)
23270      */   
23271     width: false,
23272     
23273     /**
23274      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23275      * 
23276      */
23277     stylesheets: false,
23278     
23279     // id of frame..
23280     frameId: false,
23281     
23282     // private properties
23283     validationEvent : false,
23284     deferHeight: true,
23285     initialized : false,
23286     activated : false,
23287     
23288     onFocus : Roo.emptyFn,
23289     iframePad:3,
23290     hideMode:'offsets',
23291     
23292     tbContainer : false,
23293     
23294     bodyCls : '',
23295     
23296     toolbarContainer :function() {
23297         return this.wrap.select('.x-html-editor-tb',true).first();
23298     },
23299
23300     /**
23301      * Protected method that will not generally be called directly. It
23302      * is called when the editor creates its toolbar. Override this method if you need to
23303      * add custom toolbar buttons.
23304      * @param {HtmlEditor} editor
23305      */
23306     createToolbar : function(){
23307         Roo.log('renewing');
23308         Roo.log("create toolbars");
23309         
23310         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23311         this.toolbars[0].render(this.toolbarContainer());
23312         
23313         return;
23314         
23315 //        if (!editor.toolbars || !editor.toolbars.length) {
23316 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23317 //        }
23318 //        
23319 //        for (var i =0 ; i < editor.toolbars.length;i++) {
23320 //            editor.toolbars[i] = Roo.factory(
23321 //                    typeof(editor.toolbars[i]) == 'string' ?
23322 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
23323 //                Roo.bootstrap.HtmlEditor);
23324 //            editor.toolbars[i].init(editor);
23325 //        }
23326     },
23327
23328      
23329     // private
23330     onRender : function(ct, position)
23331     {
23332        // Roo.log("Call onRender: " + this.xtype);
23333         var _t = this;
23334         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23335       
23336         this.wrap = this.inputEl().wrap({
23337             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23338         });
23339         
23340         this.editorcore.onRender(ct, position);
23341          
23342         if (this.resizable) {
23343             this.resizeEl = new Roo.Resizable(this.wrap, {
23344                 pinned : true,
23345                 wrap: true,
23346                 dynamic : true,
23347                 minHeight : this.height,
23348                 height: this.height,
23349                 handles : this.resizable,
23350                 width: this.width,
23351                 listeners : {
23352                     resize : function(r, w, h) {
23353                         _t.onResize(w,h); // -something
23354                     }
23355                 }
23356             });
23357             
23358         }
23359         this.createToolbar(this);
23360        
23361         
23362         if(!this.width && this.resizable){
23363             this.setSize(this.wrap.getSize());
23364         }
23365         if (this.resizeEl) {
23366             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23367             // should trigger onReize..
23368         }
23369         
23370     },
23371
23372     // private
23373     onResize : function(w, h)
23374     {
23375         Roo.log('resize: ' +w + ',' + h );
23376         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23377         var ew = false;
23378         var eh = false;
23379         
23380         if(this.inputEl() ){
23381             if(typeof w == 'number'){
23382                 var aw = w - this.wrap.getFrameWidth('lr');
23383                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23384                 ew = aw;
23385             }
23386             if(typeof h == 'number'){
23387                  var tbh = -11;  // fixme it needs to tool bar size!
23388                 for (var i =0; i < this.toolbars.length;i++) {
23389                     // fixme - ask toolbars for heights?
23390                     tbh += this.toolbars[i].el.getHeight();
23391                     //if (this.toolbars[i].footer) {
23392                     //    tbh += this.toolbars[i].footer.el.getHeight();
23393                     //}
23394                 }
23395               
23396                 
23397                 
23398                 
23399                 
23400                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23401                 ah -= 5; // knock a few pixes off for look..
23402                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23403                 var eh = ah;
23404             }
23405         }
23406         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23407         this.editorcore.onResize(ew,eh);
23408         
23409     },
23410
23411     /**
23412      * Toggles the editor between standard and source edit mode.
23413      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23414      */
23415     toggleSourceEdit : function(sourceEditMode)
23416     {
23417         this.editorcore.toggleSourceEdit(sourceEditMode);
23418         
23419         if(this.editorcore.sourceEditMode){
23420             Roo.log('editor - showing textarea');
23421             
23422 //            Roo.log('in');
23423 //            Roo.log(this.syncValue());
23424             this.syncValue();
23425             this.inputEl().removeClass(['hide', 'x-hidden']);
23426             this.inputEl().dom.removeAttribute('tabIndex');
23427             this.inputEl().focus();
23428         }else{
23429             Roo.log('editor - hiding textarea');
23430 //            Roo.log('out')
23431 //            Roo.log(this.pushValue()); 
23432             this.pushValue();
23433             
23434             this.inputEl().addClass(['hide', 'x-hidden']);
23435             this.inputEl().dom.setAttribute('tabIndex', -1);
23436             //this.deferFocus();
23437         }
23438          
23439         if(this.resizable){
23440             this.setSize(this.wrap.getSize());
23441         }
23442         
23443         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23444     },
23445  
23446     // private (for BoxComponent)
23447     adjustSize : Roo.BoxComponent.prototype.adjustSize,
23448
23449     // private (for BoxComponent)
23450     getResizeEl : function(){
23451         return this.wrap;
23452     },
23453
23454     // private (for BoxComponent)
23455     getPositionEl : function(){
23456         return this.wrap;
23457     },
23458
23459     // private
23460     initEvents : function(){
23461         this.originalValue = this.getValue();
23462     },
23463
23464 //    /**
23465 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23466 //     * @method
23467 //     */
23468 //    markInvalid : Roo.emptyFn,
23469 //    /**
23470 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23471 //     * @method
23472 //     */
23473 //    clearInvalid : Roo.emptyFn,
23474
23475     setValue : function(v){
23476         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23477         this.editorcore.pushValue();
23478     },
23479
23480      
23481     // private
23482     deferFocus : function(){
23483         this.focus.defer(10, this);
23484     },
23485
23486     // doc'ed in Field
23487     focus : function(){
23488         this.editorcore.focus();
23489         
23490     },
23491       
23492
23493     // private
23494     onDestroy : function(){
23495         
23496         
23497         
23498         if(this.rendered){
23499             
23500             for (var i =0; i < this.toolbars.length;i++) {
23501                 // fixme - ask toolbars for heights?
23502                 this.toolbars[i].onDestroy();
23503             }
23504             
23505             this.wrap.dom.innerHTML = '';
23506             this.wrap.remove();
23507         }
23508     },
23509
23510     // private
23511     onFirstFocus : function(){
23512         //Roo.log("onFirstFocus");
23513         this.editorcore.onFirstFocus();
23514          for (var i =0; i < this.toolbars.length;i++) {
23515             this.toolbars[i].onFirstFocus();
23516         }
23517         
23518     },
23519     
23520     // private
23521     syncValue : function()
23522     {   
23523         this.editorcore.syncValue();
23524     },
23525     
23526     pushValue : function()
23527     {   
23528         this.editorcore.pushValue();
23529     }
23530      
23531     
23532     // hide stuff that is not compatible
23533     /**
23534      * @event blur
23535      * @hide
23536      */
23537     /**
23538      * @event change
23539      * @hide
23540      */
23541     /**
23542      * @event focus
23543      * @hide
23544      */
23545     /**
23546      * @event specialkey
23547      * @hide
23548      */
23549     /**
23550      * @cfg {String} fieldClass @hide
23551      */
23552     /**
23553      * @cfg {String} focusClass @hide
23554      */
23555     /**
23556      * @cfg {String} autoCreate @hide
23557      */
23558     /**
23559      * @cfg {String} inputType @hide
23560      */
23561     /**
23562      * @cfg {String} invalidClass @hide
23563      */
23564     /**
23565      * @cfg {String} invalidText @hide
23566      */
23567     /**
23568      * @cfg {String} msgFx @hide
23569      */
23570     /**
23571      * @cfg {String} validateOnBlur @hide
23572      */
23573 });
23574  
23575     
23576    
23577    
23578    
23579       
23580 Roo.namespace('Roo.bootstrap.htmleditor');
23581 /**
23582  * @class Roo.bootstrap.HtmlEditorToolbar1
23583  * Basic Toolbar
23584  * 
23585  * Usage:
23586  *
23587  new Roo.bootstrap.HtmlEditor({
23588     ....
23589     toolbars : [
23590         new Roo.bootstrap.HtmlEditorToolbar1({
23591             disable : { fonts: 1 , format: 1, ..., ... , ...],
23592             btns : [ .... ]
23593         })
23594     }
23595      
23596  * 
23597  * @cfg {Object} disable List of elements to disable..
23598  * @cfg {Array} btns List of additional buttons.
23599  * 
23600  * 
23601  * NEEDS Extra CSS? 
23602  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23603  */
23604  
23605 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23606 {
23607     
23608     Roo.apply(this, config);
23609     
23610     // default disabled, based on 'good practice'..
23611     this.disable = this.disable || {};
23612     Roo.applyIf(this.disable, {
23613         fontSize : true,
23614         colors : true,
23615         specialElements : true
23616     });
23617     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23618     
23619     this.editor = config.editor;
23620     this.editorcore = config.editor.editorcore;
23621     
23622     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23623     
23624     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23625     // dont call parent... till later.
23626 }
23627 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
23628      
23629     bar : true,
23630     
23631     editor : false,
23632     editorcore : false,
23633     
23634     
23635     formats : [
23636         "p" ,  
23637         "h1","h2","h3","h4","h5","h6", 
23638         "pre", "code", 
23639         "abbr", "acronym", "address", "cite", "samp", "var",
23640         'div','span'
23641     ],
23642     
23643     onRender : function(ct, position)
23644     {
23645        // Roo.log("Call onRender: " + this.xtype);
23646         
23647        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23648        Roo.log(this.el);
23649        this.el.dom.style.marginBottom = '0';
23650        var _this = this;
23651        var editorcore = this.editorcore;
23652        var editor= this.editor;
23653        
23654        var children = [];
23655        var btn = function(id,cmd , toggle, handler, html){
23656        
23657             var  event = toggle ? 'toggle' : 'click';
23658        
23659             var a = {
23660                 size : 'sm',
23661                 xtype: 'Button',
23662                 xns: Roo.bootstrap,
23663                 glyphicon : id,
23664                 cmd : id || cmd,
23665                 enableToggle:toggle !== false,
23666                 html : html || '',
23667                 pressed : toggle ? false : null,
23668                 listeners : {}
23669             };
23670             a.listeners[toggle ? 'toggle' : 'click'] = function() {
23671                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
23672             };
23673             children.push(a);
23674             return a;
23675        }
23676        
23677     //    var cb_box = function...
23678         
23679         var style = {
23680                 xtype: 'Button',
23681                 size : 'sm',
23682                 xns: Roo.bootstrap,
23683                 glyphicon : 'font',
23684                 //html : 'submit'
23685                 menu : {
23686                     xtype: 'Menu',
23687                     xns: Roo.bootstrap,
23688                     items:  []
23689                 }
23690         };
23691         Roo.each(this.formats, function(f) {
23692             style.menu.items.push({
23693                 xtype :'MenuItem',
23694                 xns: Roo.bootstrap,
23695                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23696                 tagname : f,
23697                 listeners : {
23698                     click : function()
23699                     {
23700                         editorcore.insertTag(this.tagname);
23701                         editor.focus();
23702                     }
23703                 }
23704                 
23705             });
23706         });
23707         children.push(style);   
23708         
23709         btn('bold',false,true);
23710         btn('italic',false,true);
23711         btn('align-left', 'justifyleft',true);
23712         btn('align-center', 'justifycenter',true);
23713         btn('align-right' , 'justifyright',true);
23714         btn('link', false, false, function(btn) {
23715             //Roo.log("create link?");
23716             var url = prompt(this.createLinkText, this.defaultLinkValue);
23717             if(url && url != 'http:/'+'/'){
23718                 this.editorcore.relayCmd('createlink', url);
23719             }
23720         }),
23721         btn('list','insertunorderedlist',true);
23722         btn('pencil', false,true, function(btn){
23723                 Roo.log(this);
23724                 this.toggleSourceEdit(btn.pressed);
23725         });
23726         
23727         if (this.editor.btns.length > 0) {
23728             for (var i = 0; i<this.editor.btns.length; i++) {
23729                 children.push(this.editor.btns[i]);
23730             }
23731         }
23732         
23733         /*
23734         var cog = {
23735                 xtype: 'Button',
23736                 size : 'sm',
23737                 xns: Roo.bootstrap,
23738                 glyphicon : 'cog',
23739                 //html : 'submit'
23740                 menu : {
23741                     xtype: 'Menu',
23742                     xns: Roo.bootstrap,
23743                     items:  []
23744                 }
23745         };
23746         
23747         cog.menu.items.push({
23748             xtype :'MenuItem',
23749             xns: Roo.bootstrap,
23750             html : Clean styles,
23751             tagname : f,
23752             listeners : {
23753                 click : function()
23754                 {
23755                     editorcore.insertTag(this.tagname);
23756                     editor.focus();
23757                 }
23758             }
23759             
23760         });
23761        */
23762         
23763          
23764        this.xtype = 'NavSimplebar';
23765         
23766         for(var i=0;i< children.length;i++) {
23767             
23768             this.buttons.add(this.addxtypeChild(children[i]));
23769             
23770         }
23771         
23772         editor.on('editorevent', this.updateToolbar, this);
23773     },
23774     onBtnClick : function(id)
23775     {
23776        this.editorcore.relayCmd(id);
23777        this.editorcore.focus();
23778     },
23779     
23780     /**
23781      * Protected method that will not generally be called directly. It triggers
23782      * a toolbar update by reading the markup state of the current selection in the editor.
23783      */
23784     updateToolbar: function(){
23785
23786         if(!this.editorcore.activated){
23787             this.editor.onFirstFocus(); // is this neeed?
23788             return;
23789         }
23790
23791         var btns = this.buttons; 
23792         var doc = this.editorcore.doc;
23793         btns.get('bold').setActive(doc.queryCommandState('bold'));
23794         btns.get('italic').setActive(doc.queryCommandState('italic'));
23795         //btns.get('underline').setActive(doc.queryCommandState('underline'));
23796         
23797         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23798         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23799         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23800         
23801         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23802         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23803          /*
23804         
23805         var ans = this.editorcore.getAllAncestors();
23806         if (this.formatCombo) {
23807             
23808             
23809             var store = this.formatCombo.store;
23810             this.formatCombo.setValue("");
23811             for (var i =0; i < ans.length;i++) {
23812                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23813                     // select it..
23814                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23815                     break;
23816                 }
23817             }
23818         }
23819         
23820         
23821         
23822         // hides menus... - so this cant be on a menu...
23823         Roo.bootstrap.MenuMgr.hideAll();
23824         */
23825         Roo.bootstrap.MenuMgr.hideAll();
23826         //this.editorsyncValue();
23827     },
23828     onFirstFocus: function() {
23829         this.buttons.each(function(item){
23830            item.enable();
23831         });
23832     },
23833     toggleSourceEdit : function(sourceEditMode){
23834         
23835           
23836         if(sourceEditMode){
23837             Roo.log("disabling buttons");
23838            this.buttons.each( function(item){
23839                 if(item.cmd != 'pencil'){
23840                     item.disable();
23841                 }
23842             });
23843           
23844         }else{
23845             Roo.log("enabling buttons");
23846             if(this.editorcore.initialized){
23847                 this.buttons.each( function(item){
23848                     item.enable();
23849                 });
23850             }
23851             
23852         }
23853         Roo.log("calling toggole on editor");
23854         // tell the editor that it's been pressed..
23855         this.editor.toggleSourceEdit(sourceEditMode);
23856        
23857     }
23858 });
23859
23860
23861
23862
23863
23864 /**
23865  * @class Roo.bootstrap.Table.AbstractSelectionModel
23866  * @extends Roo.util.Observable
23867  * Abstract base class for grid SelectionModels.  It provides the interface that should be
23868  * implemented by descendant classes.  This class should not be directly instantiated.
23869  * @constructor
23870  */
23871 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23872     this.locked = false;
23873     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23874 };
23875
23876
23877 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
23878     /** @ignore Called by the grid automatically. Do not call directly. */
23879     init : function(grid){
23880         this.grid = grid;
23881         this.initEvents();
23882     },
23883
23884     /**
23885      * Locks the selections.
23886      */
23887     lock : function(){
23888         this.locked = true;
23889     },
23890
23891     /**
23892      * Unlocks the selections.
23893      */
23894     unlock : function(){
23895         this.locked = false;
23896     },
23897
23898     /**
23899      * Returns true if the selections are locked.
23900      * @return {Boolean}
23901      */
23902     isLocked : function(){
23903         return this.locked;
23904     }
23905 });
23906 /**
23907  * @extends Roo.bootstrap.Table.AbstractSelectionModel
23908  * @class Roo.bootstrap.Table.RowSelectionModel
23909  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23910  * It supports multiple selections and keyboard selection/navigation. 
23911  * @constructor
23912  * @param {Object} config
23913  */
23914
23915 Roo.bootstrap.Table.RowSelectionModel = function(config){
23916     Roo.apply(this, config);
23917     this.selections = new Roo.util.MixedCollection(false, function(o){
23918         return o.id;
23919     });
23920
23921     this.last = false;
23922     this.lastActive = false;
23923
23924     this.addEvents({
23925         /**
23926              * @event selectionchange
23927              * Fires when the selection changes
23928              * @param {SelectionModel} this
23929              */
23930             "selectionchange" : true,
23931         /**
23932              * @event afterselectionchange
23933              * Fires after the selection changes (eg. by key press or clicking)
23934              * @param {SelectionModel} this
23935              */
23936             "afterselectionchange" : true,
23937         /**
23938              * @event beforerowselect
23939              * Fires when a row is selected being selected, return false to cancel.
23940              * @param {SelectionModel} this
23941              * @param {Number} rowIndex The selected index
23942              * @param {Boolean} keepExisting False if other selections will be cleared
23943              */
23944             "beforerowselect" : true,
23945         /**
23946              * @event rowselect
23947              * Fires when a row is selected.
23948              * @param {SelectionModel} this
23949              * @param {Number} rowIndex The selected index
23950              * @param {Roo.data.Record} r The record
23951              */
23952             "rowselect" : true,
23953         /**
23954              * @event rowdeselect
23955              * Fires when a row is deselected.
23956              * @param {SelectionModel} this
23957              * @param {Number} rowIndex The selected index
23958              */
23959         "rowdeselect" : true
23960     });
23961     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23962     this.locked = false;
23963  };
23964
23965 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
23966     /**
23967      * @cfg {Boolean} singleSelect
23968      * True to allow selection of only one row at a time (defaults to false)
23969      */
23970     singleSelect : false,
23971
23972     // private
23973     initEvents : function()
23974     {
23975
23976         //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23977         //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
23978         //}else{ // allow click to work like normal
23979          //   this.grid.on("rowclick", this.handleDragableRowClick, this);
23980         //}
23981         //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23982         this.grid.on("rowclick", this.handleMouseDown, this);
23983         
23984         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23985             "up" : function(e){
23986                 if(!e.shiftKey){
23987                     this.selectPrevious(e.shiftKey);
23988                 }else if(this.last !== false && this.lastActive !== false){
23989                     var last = this.last;
23990                     this.selectRange(this.last,  this.lastActive-1);
23991                     this.grid.getView().focusRow(this.lastActive);
23992                     if(last !== false){
23993                         this.last = last;
23994                     }
23995                 }else{
23996                     this.selectFirstRow();
23997                 }
23998                 this.fireEvent("afterselectionchange", this);
23999             },
24000             "down" : function(e){
24001                 if(!e.shiftKey){
24002                     this.selectNext(e.shiftKey);
24003                 }else if(this.last !== false && this.lastActive !== false){
24004                     var last = this.last;
24005                     this.selectRange(this.last,  this.lastActive+1);
24006                     this.grid.getView().focusRow(this.lastActive);
24007                     if(last !== false){
24008                         this.last = last;
24009                     }
24010                 }else{
24011                     this.selectFirstRow();
24012                 }
24013                 this.fireEvent("afterselectionchange", this);
24014             },
24015             scope: this
24016         });
24017         this.grid.store.on('load', function(){
24018             this.selections.clear();
24019         },this);
24020         /*
24021         var view = this.grid.view;
24022         view.on("refresh", this.onRefresh, this);
24023         view.on("rowupdated", this.onRowUpdated, this);
24024         view.on("rowremoved", this.onRemove, this);
24025         */
24026     },
24027
24028     // private
24029     onRefresh : function()
24030     {
24031         var ds = this.grid.store, i, v = this.grid.view;
24032         var s = this.selections;
24033         s.each(function(r){
24034             if((i = ds.indexOfId(r.id)) != -1){
24035                 v.onRowSelect(i);
24036             }else{
24037                 s.remove(r);
24038             }
24039         });
24040     },
24041
24042     // private
24043     onRemove : function(v, index, r){
24044         this.selections.remove(r);
24045     },
24046
24047     // private
24048     onRowUpdated : function(v, index, r){
24049         if(this.isSelected(r)){
24050             v.onRowSelect(index);
24051         }
24052     },
24053
24054     /**
24055      * Select records.
24056      * @param {Array} records The records to select
24057      * @param {Boolean} keepExisting (optional) True to keep existing selections
24058      */
24059     selectRecords : function(records, keepExisting)
24060     {
24061         if(!keepExisting){
24062             this.clearSelections();
24063         }
24064             var ds = this.grid.store;
24065         for(var i = 0, len = records.length; i < len; i++){
24066             this.selectRow(ds.indexOf(records[i]), true);
24067         }
24068     },
24069
24070     /**
24071      * Gets the number of selected rows.
24072      * @return {Number}
24073      */
24074     getCount : function(){
24075         return this.selections.length;
24076     },
24077
24078     /**
24079      * Selects the first row in the grid.
24080      */
24081     selectFirstRow : function(){
24082         this.selectRow(0);
24083     },
24084
24085     /**
24086      * Select the last row.
24087      * @param {Boolean} keepExisting (optional) True to keep existing selections
24088      */
24089     selectLastRow : function(keepExisting){
24090         //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24091         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24092     },
24093
24094     /**
24095      * Selects the row immediately following the last selected row.
24096      * @param {Boolean} keepExisting (optional) True to keep existing selections
24097      */
24098     selectNext : function(keepExisting)
24099     {
24100             if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24101             this.selectRow(this.last+1, keepExisting);
24102             this.grid.getView().focusRow(this.last);
24103         }
24104     },
24105
24106     /**
24107      * Selects the row that precedes the last selected row.
24108      * @param {Boolean} keepExisting (optional) True to keep existing selections
24109      */
24110     selectPrevious : function(keepExisting){
24111         if(this.last){
24112             this.selectRow(this.last-1, keepExisting);
24113             this.grid.getView().focusRow(this.last);
24114         }
24115     },
24116
24117     /**
24118      * Returns the selected records
24119      * @return {Array} Array of selected records
24120      */
24121     getSelections : function(){
24122         return [].concat(this.selections.items);
24123     },
24124
24125     /**
24126      * Returns the first selected record.
24127      * @return {Record}
24128      */
24129     getSelected : function(){
24130         return this.selections.itemAt(0);
24131     },
24132
24133
24134     /**
24135      * Clears all selections.
24136      */
24137     clearSelections : function(fast)
24138     {
24139         if(this.locked) {
24140             return;
24141         }
24142         if(fast !== true){
24143                 var ds = this.grid.store;
24144             var s = this.selections;
24145             s.each(function(r){
24146                 this.deselectRow(ds.indexOfId(r.id));
24147             }, this);
24148             s.clear();
24149         }else{
24150             this.selections.clear();
24151         }
24152         this.last = false;
24153     },
24154
24155
24156     /**
24157      * Selects all rows.
24158      */
24159     selectAll : function(){
24160         if(this.locked) {
24161             return;
24162         }
24163         this.selections.clear();
24164         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24165             this.selectRow(i, true);
24166         }
24167     },
24168
24169     /**
24170      * Returns True if there is a selection.
24171      * @return {Boolean}
24172      */
24173     hasSelection : function(){
24174         return this.selections.length > 0;
24175     },
24176
24177     /**
24178      * Returns True if the specified row is selected.
24179      * @param {Number/Record} record The record or index of the record to check
24180      * @return {Boolean}
24181      */
24182     isSelected : function(index){
24183             var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24184         return (r && this.selections.key(r.id) ? true : false);
24185     },
24186
24187     /**
24188      * Returns True if the specified record id is selected.
24189      * @param {String} id The id of record to check
24190      * @return {Boolean}
24191      */
24192     isIdSelected : function(id){
24193         return (this.selections.key(id) ? true : false);
24194     },
24195
24196
24197     // private
24198     handleMouseDBClick : function(e, t){
24199         
24200     },
24201     // private
24202     handleMouseDown : function(e, t)
24203     {
24204             var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24205         if(this.isLocked() || rowIndex < 0 ){
24206             return;
24207         };
24208         if(e.shiftKey && this.last !== false){
24209             var last = this.last;
24210             this.selectRange(last, rowIndex, e.ctrlKey);
24211             this.last = last; // reset the last
24212             t.focus();
24213     
24214         }else{
24215             var isSelected = this.isSelected(rowIndex);
24216             //Roo.log("select row:" + rowIndex);
24217             if(isSelected){
24218                 this.deselectRow(rowIndex);
24219             } else {
24220                         this.selectRow(rowIndex, true);
24221             }
24222     
24223             /*
24224                 if(e.button !== 0 && isSelected){
24225                 alert('rowIndex 2: ' + rowIndex);
24226                     view.focusRow(rowIndex);
24227                 }else if(e.ctrlKey && isSelected){
24228                     this.deselectRow(rowIndex);
24229                 }else if(!isSelected){
24230                     this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24231                     view.focusRow(rowIndex);
24232                 }
24233             */
24234         }
24235         this.fireEvent("afterselectionchange", this);
24236     },
24237     // private
24238     handleDragableRowClick :  function(grid, rowIndex, e) 
24239     {
24240         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24241             this.selectRow(rowIndex, false);
24242             grid.view.focusRow(rowIndex);
24243              this.fireEvent("afterselectionchange", this);
24244         }
24245     },
24246     
24247     /**
24248      * Selects multiple rows.
24249      * @param {Array} rows Array of the indexes of the row to select
24250      * @param {Boolean} keepExisting (optional) True to keep existing selections
24251      */
24252     selectRows : function(rows, keepExisting){
24253         if(!keepExisting){
24254             this.clearSelections();
24255         }
24256         for(var i = 0, len = rows.length; i < len; i++){
24257             this.selectRow(rows[i], true);
24258         }
24259     },
24260
24261     /**
24262      * Selects a range of rows. All rows in between startRow and endRow are also selected.
24263      * @param {Number} startRow The index of the first row in the range
24264      * @param {Number} endRow The index of the last row in the range
24265      * @param {Boolean} keepExisting (optional) True to retain existing selections
24266      */
24267     selectRange : function(startRow, endRow, keepExisting){
24268         if(this.locked) {
24269             return;
24270         }
24271         if(!keepExisting){
24272             this.clearSelections();
24273         }
24274         if(startRow <= endRow){
24275             for(var i = startRow; i <= endRow; i++){
24276                 this.selectRow(i, true);
24277             }
24278         }else{
24279             for(var i = startRow; i >= endRow; i--){
24280                 this.selectRow(i, true);
24281             }
24282         }
24283     },
24284
24285     /**
24286      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24287      * @param {Number} startRow The index of the first row in the range
24288      * @param {Number} endRow The index of the last row in the range
24289      */
24290     deselectRange : function(startRow, endRow, preventViewNotify){
24291         if(this.locked) {
24292             return;
24293         }
24294         for(var i = startRow; i <= endRow; i++){
24295             this.deselectRow(i, preventViewNotify);
24296         }
24297     },
24298
24299     /**
24300      * Selects a row.
24301      * @param {Number} row The index of the row to select
24302      * @param {Boolean} keepExisting (optional) True to keep existing selections
24303      */
24304     selectRow : function(index, keepExisting, preventViewNotify)
24305     {
24306             if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24307             return;
24308         }
24309         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24310             if(!keepExisting || this.singleSelect){
24311                 this.clearSelections();
24312             }
24313             
24314             var r = this.grid.store.getAt(index);
24315             //console.log('selectRow - record id :' + r.id);
24316             
24317             this.selections.add(r);
24318             this.last = this.lastActive = index;
24319             if(!preventViewNotify){
24320                 var proxy = new Roo.Element(
24321                                 this.grid.getRowDom(index)
24322                 );
24323                 proxy.addClass('bg-info info');
24324             }
24325             this.fireEvent("rowselect", this, index, r);
24326             this.fireEvent("selectionchange", this);
24327         }
24328     },
24329
24330     /**
24331      * Deselects a row.
24332      * @param {Number} row The index of the row to deselect
24333      */
24334     deselectRow : function(index, preventViewNotify)
24335     {
24336         if(this.locked) {
24337             return;
24338         }
24339         if(this.last == index){
24340             this.last = false;
24341         }
24342         if(this.lastActive == index){
24343             this.lastActive = false;
24344         }
24345         
24346         var r = this.grid.store.getAt(index);
24347         if (!r) {
24348             return;
24349         }
24350         
24351         this.selections.remove(r);
24352         //.console.log('deselectRow - record id :' + r.id);
24353         if(!preventViewNotify){
24354         
24355             var proxy = new Roo.Element(
24356                 this.grid.getRowDom(index)
24357             );
24358             proxy.removeClass('bg-info info');
24359         }
24360         this.fireEvent("rowdeselect", this, index);
24361         this.fireEvent("selectionchange", this);
24362     },
24363
24364     // private
24365     restoreLast : function(){
24366         if(this._last){
24367             this.last = this._last;
24368         }
24369     },
24370
24371     // private
24372     acceptsNav : function(row, col, cm){
24373         return !cm.isHidden(col) && cm.isCellEditable(col, row);
24374     },
24375
24376     // private
24377     onEditorKey : function(field, e){
24378         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24379         if(k == e.TAB){
24380             e.stopEvent();
24381             ed.completeEdit();
24382             if(e.shiftKey){
24383                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24384             }else{
24385                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24386             }
24387         }else if(k == e.ENTER && !e.ctrlKey){
24388             e.stopEvent();
24389             ed.completeEdit();
24390             if(e.shiftKey){
24391                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24392             }else{
24393                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24394             }
24395         }else if(k == e.ESC){
24396             ed.cancelEdit();
24397         }
24398         if(newCell){
24399             g.startEditing(newCell[0], newCell[1]);
24400         }
24401     }
24402 });
24403 /*
24404  * Based on:
24405  * Ext JS Library 1.1.1
24406  * Copyright(c) 2006-2007, Ext JS, LLC.
24407  *
24408  * Originally Released Under LGPL - original licence link has changed is not relivant.
24409  *
24410  * Fork - LGPL
24411  * <script type="text/javascript">
24412  */
24413  
24414 /**
24415  * @class Roo.bootstrap.PagingToolbar
24416  * @extends Roo.bootstrap.NavSimplebar
24417  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24418  * @constructor
24419  * Create a new PagingToolbar
24420  * @param {Object} config The config object
24421  * @param {Roo.data.Store} store
24422  */
24423 Roo.bootstrap.PagingToolbar = function(config)
24424 {
24425     // old args format still supported... - xtype is prefered..
24426         // created from xtype...
24427     
24428     this.ds = config.dataSource;
24429     
24430     if (config.store && !this.ds) {
24431         this.store= Roo.factory(config.store, Roo.data);
24432         this.ds = this.store;
24433         this.ds.xmodule = this.xmodule || false;
24434     }
24435     
24436     this.toolbarItems = [];
24437     if (config.items) {
24438         this.toolbarItems = config.items;
24439     }
24440     
24441     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24442     
24443     this.cursor = 0;
24444     
24445     if (this.ds) { 
24446         this.bind(this.ds);
24447     }
24448     
24449     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24450     
24451 };
24452
24453 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24454     /**
24455      * @cfg {Roo.data.Store} dataSource
24456      * The underlying data store providing the paged data
24457      */
24458     /**
24459      * @cfg {String/HTMLElement/Element} container
24460      * container The id or element that will contain the toolbar
24461      */
24462     /**
24463      * @cfg {Boolean} displayInfo
24464      * True to display the displayMsg (defaults to false)
24465      */
24466     /**
24467      * @cfg {Number} pageSize
24468      * The number of records to display per page (defaults to 20)
24469      */
24470     pageSize: 20,
24471     /**
24472      * @cfg {String} displayMsg
24473      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24474      */
24475     displayMsg : 'Displaying {0} - {1} of {2}',
24476     /**
24477      * @cfg {String} emptyMsg
24478      * The message to display when no records are found (defaults to "No data to display")
24479      */
24480     emptyMsg : 'No data to display',
24481     /**
24482      * Customizable piece of the default paging text (defaults to "Page")
24483      * @type String
24484      */
24485     beforePageText : "Page",
24486     /**
24487      * Customizable piece of the default paging text (defaults to "of %0")
24488      * @type String
24489      */
24490     afterPageText : "of {0}",
24491     /**
24492      * Customizable piece of the default paging text (defaults to "First Page")
24493      * @type String
24494      */
24495     firstText : "First Page",
24496     /**
24497      * Customizable piece of the default paging text (defaults to "Previous Page")
24498      * @type String
24499      */
24500     prevText : "Previous Page",
24501     /**
24502      * Customizable piece of the default paging text (defaults to "Next Page")
24503      * @type String
24504      */
24505     nextText : "Next Page",
24506     /**
24507      * Customizable piece of the default paging text (defaults to "Last Page")
24508      * @type String
24509      */
24510     lastText : "Last Page",
24511     /**
24512      * Customizable piece of the default paging text (defaults to "Refresh")
24513      * @type String
24514      */
24515     refreshText : "Refresh",
24516
24517     buttons : false,
24518     // private
24519     onRender : function(ct, position) 
24520     {
24521         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24522         this.navgroup.parentId = this.id;
24523         this.navgroup.onRender(this.el, null);
24524         // add the buttons to the navgroup
24525         
24526         if(this.displayInfo){
24527             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24528             this.displayEl = this.el.select('.x-paging-info', true).first();
24529 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24530 //            this.displayEl = navel.el.select('span',true).first();
24531         }
24532         
24533         var _this = this;
24534         
24535         if(this.buttons){
24536             Roo.each(_this.buttons, function(e){ // this might need to use render????
24537                Roo.factory(e).render(_this.el);
24538             });
24539         }
24540             
24541         Roo.each(_this.toolbarItems, function(e) {
24542             _this.navgroup.addItem(e);
24543         });
24544         
24545         
24546         this.first = this.navgroup.addItem({
24547             tooltip: this.firstText,
24548             cls: "prev",
24549             icon : 'fa fa-backward',
24550             disabled: true,
24551             preventDefault: true,
24552             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24553         });
24554         
24555         this.prev =  this.navgroup.addItem({
24556             tooltip: this.prevText,
24557             cls: "prev",
24558             icon : 'fa fa-step-backward',
24559             disabled: true,
24560             preventDefault: true,
24561             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
24562         });
24563     //this.addSeparator();
24564         
24565         
24566         var field = this.navgroup.addItem( {
24567             tagtype : 'span',
24568             cls : 'x-paging-position',
24569             
24570             html : this.beforePageText  +
24571                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24572                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
24573          } ); //?? escaped?
24574         
24575         this.field = field.el.select('input', true).first();
24576         this.field.on("keydown", this.onPagingKeydown, this);
24577         this.field.on("focus", function(){this.dom.select();});
24578     
24579     
24580         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
24581         //this.field.setHeight(18);
24582         //this.addSeparator();
24583         this.next = this.navgroup.addItem({
24584             tooltip: this.nextText,
24585             cls: "next",
24586             html : ' <i class="fa fa-step-forward">',
24587             disabled: true,
24588             preventDefault: true,
24589             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
24590         });
24591         this.last = this.navgroup.addItem({
24592             tooltip: this.lastText,
24593             icon : 'fa fa-forward',
24594             cls: "next",
24595             disabled: true,
24596             preventDefault: true,
24597             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
24598         });
24599     //this.addSeparator();
24600         this.loading = this.navgroup.addItem({
24601             tooltip: this.refreshText,
24602             icon: 'fa fa-refresh',
24603             preventDefault: true,
24604             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24605         });
24606         
24607     },
24608
24609     // private
24610     updateInfo : function(){
24611         if(this.displayEl){
24612             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24613             var msg = count == 0 ?
24614                 this.emptyMsg :
24615                 String.format(
24616                     this.displayMsg,
24617                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
24618                 );
24619             this.displayEl.update(msg);
24620         }
24621     },
24622
24623     // private
24624     onLoad : function(ds, r, o)
24625     {
24626         this.cursor = o.params.start ? o.params.start : 0;
24627         
24628         var d = this.getPageData(),
24629             ap = d.activePage,
24630             ps = d.pages;
24631         
24632         
24633         this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24634         this.field.dom.value = ap;
24635         this.first.setDisabled(ap == 1);
24636         this.prev.setDisabled(ap == 1);
24637         this.next.setDisabled(ap == ps);
24638         this.last.setDisabled(ap == ps);
24639         this.loading.enable();
24640         this.updateInfo();
24641     },
24642
24643     // private
24644     getPageData : function(){
24645         var total = this.ds.getTotalCount();
24646         return {
24647             total : total,
24648             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24649             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24650         };
24651     },
24652
24653     // private
24654     onLoadError : function(){
24655         this.loading.enable();
24656     },
24657
24658     // private
24659     onPagingKeydown : function(e){
24660         var k = e.getKey();
24661         var d = this.getPageData();
24662         if(k == e.RETURN){
24663             var v = this.field.dom.value, pageNum;
24664             if(!v || isNaN(pageNum = parseInt(v, 10))){
24665                 this.field.dom.value = d.activePage;
24666                 return;
24667             }
24668             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24669             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24670             e.stopEvent();
24671         }
24672         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))
24673         {
24674           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24675           this.field.dom.value = pageNum;
24676           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24677           e.stopEvent();
24678         }
24679         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24680         {
24681           var v = this.field.dom.value, pageNum; 
24682           var increment = (e.shiftKey) ? 10 : 1;
24683           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24684                 increment *= -1;
24685           }
24686           if(!v || isNaN(pageNum = parseInt(v, 10))) {
24687             this.field.dom.value = d.activePage;
24688             return;
24689           }
24690           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24691           {
24692             this.field.dom.value = parseInt(v, 10) + increment;
24693             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24694             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24695           }
24696           e.stopEvent();
24697         }
24698     },
24699
24700     // private
24701     beforeLoad : function(){
24702         if(this.loading){
24703             this.loading.disable();
24704         }
24705     },
24706
24707     // private
24708     onClick : function(which){
24709         
24710         var ds = this.ds;
24711         if (!ds) {
24712             return;
24713         }
24714         
24715         switch(which){
24716             case "first":
24717                 ds.load({params:{start: 0, limit: this.pageSize}});
24718             break;
24719             case "prev":
24720                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24721             break;
24722             case "next":
24723                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24724             break;
24725             case "last":
24726                 var total = ds.getTotalCount();
24727                 var extra = total % this.pageSize;
24728                 var lastStart = extra ? (total - extra) : total-this.pageSize;
24729                 ds.load({params:{start: lastStart, limit: this.pageSize}});
24730             break;
24731             case "refresh":
24732                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24733             break;
24734         }
24735     },
24736
24737     /**
24738      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24739      * @param {Roo.data.Store} store The data store to unbind
24740      */
24741     unbind : function(ds){
24742         ds.un("beforeload", this.beforeLoad, this);
24743         ds.un("load", this.onLoad, this);
24744         ds.un("loadexception", this.onLoadError, this);
24745         ds.un("remove", this.updateInfo, this);
24746         ds.un("add", this.updateInfo, this);
24747         this.ds = undefined;
24748     },
24749
24750     /**
24751      * Binds the paging toolbar to the specified {@link Roo.data.Store}
24752      * @param {Roo.data.Store} store The data store to bind
24753      */
24754     bind : function(ds){
24755         ds.on("beforeload", this.beforeLoad, this);
24756         ds.on("load", this.onLoad, this);
24757         ds.on("loadexception", this.onLoadError, this);
24758         ds.on("remove", this.updateInfo, this);
24759         ds.on("add", this.updateInfo, this);
24760         this.ds = ds;
24761     }
24762 });/*
24763  * - LGPL
24764  *
24765  * element
24766  * 
24767  */
24768
24769 /**
24770  * @class Roo.bootstrap.MessageBar
24771  * @extends Roo.bootstrap.Component
24772  * Bootstrap MessageBar class
24773  * @cfg {String} html contents of the MessageBar
24774  * @cfg {String} weight (info | success | warning | danger) default info
24775  * @cfg {String} beforeClass insert the bar before the given class
24776  * @cfg {Boolean} closable (true | false) default false
24777  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24778  * 
24779  * @constructor
24780  * Create a new Element
24781  * @param {Object} config The config object
24782  */
24783
24784 Roo.bootstrap.MessageBar = function(config){
24785     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24786 };
24787
24788 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
24789     
24790     html: '',
24791     weight: 'info',
24792     closable: false,
24793     fixed: false,
24794     beforeClass: 'bootstrap-sticky-wrap',
24795     
24796     getAutoCreate : function(){
24797         
24798         var cfg = {
24799             tag: 'div',
24800             cls: 'alert alert-dismissable alert-' + this.weight,
24801             cn: [
24802                 {
24803                     tag: 'span',
24804                     cls: 'message',
24805                     html: this.html || ''
24806                 }
24807             ]
24808         };
24809         
24810         if(this.fixed){
24811             cfg.cls += ' alert-messages-fixed';
24812         }
24813         
24814         if(this.closable){
24815             cfg.cn.push({
24816                 tag: 'button',
24817                 cls: 'close',
24818                 html: 'x'
24819             });
24820         }
24821         
24822         return cfg;
24823     },
24824     
24825     onRender : function(ct, position)
24826     {
24827         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24828         
24829         if(!this.el){
24830             var cfg = Roo.apply({},  this.getAutoCreate());
24831             cfg.id = Roo.id();
24832             
24833             if (this.cls) {
24834                 cfg.cls += ' ' + this.cls;
24835             }
24836             if (this.style) {
24837                 cfg.style = this.style;
24838             }
24839             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24840             
24841             this.el.setVisibilityMode(Roo.Element.DISPLAY);
24842         }
24843         
24844         this.el.select('>button.close').on('click', this.hide, this);
24845         
24846     },
24847     
24848     show : function()
24849     {
24850         if (!this.rendered) {
24851             this.render();
24852         }
24853         
24854         this.el.show();
24855         
24856         this.fireEvent('show', this);
24857         
24858     },
24859     
24860     hide : function()
24861     {
24862         if (!this.rendered) {
24863             this.render();
24864         }
24865         
24866         this.el.hide();
24867         
24868         this.fireEvent('hide', this);
24869     },
24870     
24871     update : function()
24872     {
24873 //        var e = this.el.dom.firstChild;
24874 //        
24875 //        if(this.closable){
24876 //            e = e.nextSibling;
24877 //        }
24878 //        
24879 //        e.data = this.html || '';
24880
24881         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24882     }
24883    
24884 });
24885
24886  
24887
24888      /*
24889  * - LGPL
24890  *
24891  * Graph
24892  * 
24893  */
24894
24895
24896 /**
24897  * @class Roo.bootstrap.Graph
24898  * @extends Roo.bootstrap.Component
24899  * Bootstrap Graph class
24900 > Prameters
24901  -sm {number} sm 4
24902  -md {number} md 5
24903  @cfg {String} graphtype  bar | vbar | pie
24904  @cfg {number} g_x coodinator | centre x (pie)
24905  @cfg {number} g_y coodinator | centre y (pie)
24906  @cfg {number} g_r radius (pie)
24907  @cfg {number} g_height height of the chart (respected by all elements in the set)
24908  @cfg {number} g_width width of the chart (respected by all elements in the set)
24909  @cfg {Object} title The title of the chart
24910     
24911  -{Array}  values
24912  -opts (object) options for the chart 
24913      o {
24914      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24915      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24916      o vgutter (number)
24917      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.
24918      o stacked (boolean) whether or not to tread values as in a stacked bar chart
24919      o to
24920      o stretch (boolean)
24921      o }
24922  -opts (object) options for the pie
24923      o{
24924      o cut
24925      o startAngle (number)
24926      o endAngle (number)
24927      } 
24928  *
24929  * @constructor
24930  * Create a new Input
24931  * @param {Object} config The config object
24932  */
24933
24934 Roo.bootstrap.Graph = function(config){
24935     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24936     
24937     this.addEvents({
24938         // img events
24939         /**
24940          * @event click
24941          * The img click event for the img.
24942          * @param {Roo.EventObject} e
24943          */
24944         "click" : true
24945     });
24946 };
24947
24948 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
24949     
24950     sm: 4,
24951     md: 5,
24952     graphtype: 'bar',
24953     g_height: 250,
24954     g_width: 400,
24955     g_x: 50,
24956     g_y: 50,
24957     g_r: 30,
24958     opts:{
24959         //g_colors: this.colors,
24960         g_type: 'soft',
24961         g_gutter: '20%'
24962
24963     },
24964     title : false,
24965
24966     getAutoCreate : function(){
24967         
24968         var cfg = {
24969             tag: 'div',
24970             html : null
24971         };
24972         
24973         
24974         return  cfg;
24975     },
24976
24977     onRender : function(ct,position){
24978         
24979         
24980         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24981         
24982         if (typeof(Raphael) == 'undefined') {
24983             Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24984             return;
24985         }
24986         
24987         this.raphael = Raphael(this.el.dom);
24988         
24989                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24990                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24991                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24992                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24993                 /*
24994                 r.text(160, 10, "Single Series Chart").attr(txtattr);
24995                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24996                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24997                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24998                 
24999                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25000                 r.barchart(330, 10, 300, 220, data1);
25001                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25002                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25003                 */
25004                 
25005                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25006                 // r.barchart(30, 30, 560, 250,  xdata, {
25007                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25008                 //     axis : "0 0 1 1",
25009                 //     axisxlabels :  xdata
25010                 //     //yvalues : cols,
25011                    
25012                 // });
25013 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25014 //        
25015 //        this.load(null,xdata,{
25016 //                axis : "0 0 1 1",
25017 //                axisxlabels :  xdata
25018 //                });
25019
25020     },
25021
25022     load : function(graphtype,xdata,opts)
25023     {
25024         this.raphael.clear();
25025         if(!graphtype) {
25026             graphtype = this.graphtype;
25027         }
25028         if(!opts){
25029             opts = this.opts;
25030         }
25031         var r = this.raphael,
25032             fin = function () {
25033                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25034             },
25035             fout = function () {
25036                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25037             },
25038             pfin = function() {
25039                 this.sector.stop();
25040                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25041
25042                 if (this.label) {
25043                     this.label[0].stop();
25044                     this.label[0].attr({ r: 7.5 });
25045                     this.label[1].attr({ "font-weight": 800 });
25046                 }
25047             },
25048             pfout = function() {
25049                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25050
25051                 if (this.label) {
25052                     this.label[0].animate({ r: 5 }, 500, "bounce");
25053                     this.label[1].attr({ "font-weight": 400 });
25054                 }
25055             };
25056
25057         switch(graphtype){
25058             case 'bar':
25059                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25060                 break;
25061             case 'hbar':
25062                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25063                 break;
25064             case 'pie':
25065 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
25066 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25067 //            
25068                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25069                 
25070                 break;
25071
25072         }
25073         
25074         if(this.title){
25075             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25076         }
25077         
25078     },
25079     
25080     setTitle: function(o)
25081     {
25082         this.title = o;
25083     },
25084     
25085     initEvents: function() {
25086         
25087         if(!this.href){
25088             this.el.on('click', this.onClick, this);
25089         }
25090     },
25091     
25092     onClick : function(e)
25093     {
25094         Roo.log('img onclick');
25095         this.fireEvent('click', this, e);
25096     }
25097    
25098 });
25099
25100  
25101 /*
25102  * - LGPL
25103  *
25104  * numberBox
25105  * 
25106  */
25107 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25108
25109 /**
25110  * @class Roo.bootstrap.dash.NumberBox
25111  * @extends Roo.bootstrap.Component
25112  * Bootstrap NumberBox class
25113  * @cfg {String} headline Box headline
25114  * @cfg {String} content Box content
25115  * @cfg {String} icon Box icon
25116  * @cfg {String} footer Footer text
25117  * @cfg {String} fhref Footer href
25118  * 
25119  * @constructor
25120  * Create a new NumberBox
25121  * @param {Object} config The config object
25122  */
25123
25124
25125 Roo.bootstrap.dash.NumberBox = function(config){
25126     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25127     
25128 };
25129
25130 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
25131     
25132     headline : '',
25133     content : '',
25134     icon : '',
25135     footer : '',
25136     fhref : '',
25137     ficon : '',
25138     
25139     getAutoCreate : function(){
25140         
25141         var cfg = {
25142             tag : 'div',
25143             cls : 'small-box ',
25144             cn : [
25145                 {
25146                     tag : 'div',
25147                     cls : 'inner',
25148                     cn :[
25149                         {
25150                             tag : 'h3',
25151                             cls : 'roo-headline',
25152                             html : this.headline
25153                         },
25154                         {
25155                             tag : 'p',
25156                             cls : 'roo-content',
25157                             html : this.content
25158                         }
25159                     ]
25160                 }
25161             ]
25162         };
25163         
25164         if(this.icon){
25165             cfg.cn.push({
25166                 tag : 'div',
25167                 cls : 'icon',
25168                 cn :[
25169                     {
25170                         tag : 'i',
25171                         cls : 'ion ' + this.icon
25172                     }
25173                 ]
25174             });
25175         }
25176         
25177         if(this.footer){
25178             var footer = {
25179                 tag : 'a',
25180                 cls : 'small-box-footer',
25181                 href : this.fhref || '#',
25182                 html : this.footer
25183             };
25184             
25185             cfg.cn.push(footer);
25186             
25187         }
25188         
25189         return  cfg;
25190     },
25191
25192     onRender : function(ct,position){
25193         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25194
25195
25196        
25197                 
25198     },
25199
25200     setHeadline: function (value)
25201     {
25202         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25203     },
25204     
25205     setFooter: function (value, href)
25206     {
25207         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25208         
25209         if(href){
25210             this.el.select('a.small-box-footer',true).first().attr('href', href);
25211         }
25212         
25213     },
25214
25215     setContent: function (value)
25216     {
25217         this.el.select('.roo-content',true).first().dom.innerHTML = value;
25218     },
25219
25220     initEvents: function() 
25221     {   
25222         
25223     }
25224     
25225 });
25226
25227  
25228 /*
25229  * - LGPL
25230  *
25231  * TabBox
25232  * 
25233  */
25234 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25235
25236 /**
25237  * @class Roo.bootstrap.dash.TabBox
25238  * @extends Roo.bootstrap.Component
25239  * Bootstrap TabBox class
25240  * @cfg {String} title Title of the TabBox
25241  * @cfg {String} icon Icon of the TabBox
25242  * @cfg {Boolean} showtabs (true|false) show the tabs default true
25243  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25244  * 
25245  * @constructor
25246  * Create a new TabBox
25247  * @param {Object} config The config object
25248  */
25249
25250
25251 Roo.bootstrap.dash.TabBox = function(config){
25252     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25253     this.addEvents({
25254         // raw events
25255         /**
25256          * @event addpane
25257          * When a pane is added
25258          * @param {Roo.bootstrap.dash.TabPane} pane
25259          */
25260         "addpane" : true,
25261         /**
25262          * @event activatepane
25263          * When a pane is activated
25264          * @param {Roo.bootstrap.dash.TabPane} pane
25265          */
25266         "activatepane" : true
25267         
25268          
25269     });
25270     
25271     this.panes = [];
25272 };
25273
25274 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
25275
25276     title : '',
25277     icon : false,
25278     showtabs : true,
25279     tabScrollable : false,
25280     
25281     getChildContainer : function()
25282     {
25283         return this.el.select('.tab-content', true).first();
25284     },
25285     
25286     getAutoCreate : function(){
25287         
25288         var header = {
25289             tag: 'li',
25290             cls: 'pull-left header',
25291             html: this.title,
25292             cn : []
25293         };
25294         
25295         if(this.icon){
25296             header.cn.push({
25297                 tag: 'i',
25298                 cls: 'fa ' + this.icon
25299             });
25300         }
25301         
25302         var h = {
25303             tag: 'ul',
25304             cls: 'nav nav-tabs pull-right',
25305             cn: [
25306                 header
25307             ]
25308         };
25309         
25310         if(this.tabScrollable){
25311             h = {
25312                 tag: 'div',
25313                 cls: 'tab-header',
25314                 cn: [
25315                     {
25316                         tag: 'ul',
25317                         cls: 'nav nav-tabs pull-right',
25318                         cn: [
25319                             header
25320                         ]
25321                     }
25322                 ]
25323             };
25324         }
25325         
25326         var cfg = {
25327             tag: 'div',
25328             cls: 'nav-tabs-custom',
25329             cn: [
25330                 h,
25331                 {
25332                     tag: 'div',
25333                     cls: 'tab-content no-padding',
25334                     cn: []
25335                 }
25336             ]
25337         };
25338
25339         return  cfg;
25340     },
25341     initEvents : function()
25342     {
25343         //Roo.log('add add pane handler');
25344         this.on('addpane', this.onAddPane, this);
25345     },
25346      /**
25347      * Updates the box title
25348      * @param {String} html to set the title to.
25349      */
25350     setTitle : function(value)
25351     {
25352         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25353     },
25354     onAddPane : function(pane)
25355     {
25356         this.panes.push(pane);
25357         //Roo.log('addpane');
25358         //Roo.log(pane);
25359         // tabs are rendere left to right..
25360         if(!this.showtabs){
25361             return;
25362         }
25363         
25364         var ctr = this.el.select('.nav-tabs', true).first();
25365          
25366          
25367         var existing = ctr.select('.nav-tab',true);
25368         var qty = existing.getCount();;
25369         
25370         
25371         var tab = ctr.createChild({
25372             tag : 'li',
25373             cls : 'nav-tab' + (qty ? '' : ' active'),
25374             cn : [
25375                 {
25376                     tag : 'a',
25377                     href:'#',
25378                     html : pane.title
25379                 }
25380             ]
25381         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25382         pane.tab = tab;
25383         
25384         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25385         if (!qty) {
25386             pane.el.addClass('active');
25387         }
25388         
25389                 
25390     },
25391     onTabClick : function(ev,un,ob,pane)
25392     {
25393         //Roo.log('tab - prev default');
25394         ev.preventDefault();
25395         
25396         
25397         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25398         pane.tab.addClass('active');
25399         //Roo.log(pane.title);
25400         this.getChildContainer().select('.tab-pane',true).removeClass('active');
25401         // technically we should have a deactivate event.. but maybe add later.
25402         // and it should not de-activate the selected tab...
25403         this.fireEvent('activatepane', pane);
25404         pane.el.addClass('active');
25405         pane.fireEvent('activate');
25406         
25407         
25408     },
25409     
25410     getActivePane : function()
25411     {
25412         var r = false;
25413         Roo.each(this.panes, function(p) {
25414             if(p.el.hasClass('active')){
25415                 r = p;
25416                 return false;
25417             }
25418             
25419             return;
25420         });
25421         
25422         return r;
25423     }
25424     
25425     
25426 });
25427
25428  
25429 /*
25430  * - LGPL
25431  *
25432  * Tab pane
25433  * 
25434  */
25435 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25436 /**
25437  * @class Roo.bootstrap.TabPane
25438  * @extends Roo.bootstrap.Component
25439  * Bootstrap TabPane class
25440  * @cfg {Boolean} active (false | true) Default false
25441  * @cfg {String} title title of panel
25442
25443  * 
25444  * @constructor
25445  * Create a new TabPane
25446  * @param {Object} config The config object
25447  */
25448
25449 Roo.bootstrap.dash.TabPane = function(config){
25450     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25451     
25452     this.addEvents({
25453         // raw events
25454         /**
25455          * @event activate
25456          * When a pane is activated
25457          * @param {Roo.bootstrap.dash.TabPane} pane
25458          */
25459         "activate" : true
25460          
25461     });
25462 };
25463
25464 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
25465     
25466     active : false,
25467     title : '',
25468     
25469     // the tabBox that this is attached to.
25470     tab : false,
25471      
25472     getAutoCreate : function() 
25473     {
25474         var cfg = {
25475             tag: 'div',
25476             cls: 'tab-pane'
25477         };
25478         
25479         if(this.active){
25480             cfg.cls += ' active';
25481         }
25482         
25483         return cfg;
25484     },
25485     initEvents  : function()
25486     {
25487         //Roo.log('trigger add pane handler');
25488         this.parent().fireEvent('addpane', this)
25489     },
25490     
25491      /**
25492      * Updates the tab title 
25493      * @param {String} html to set the title to.
25494      */
25495     setTitle: function(str)
25496     {
25497         if (!this.tab) {
25498             return;
25499         }
25500         this.title = str;
25501         this.tab.select('a', true).first().dom.innerHTML = str;
25502         
25503     }
25504     
25505     
25506     
25507 });
25508
25509  
25510
25511
25512  /*
25513  * - LGPL
25514  *
25515  * menu
25516  * 
25517  */
25518 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25519
25520 /**
25521  * @class Roo.bootstrap.menu.Menu
25522  * @extends Roo.bootstrap.Component
25523  * Bootstrap Menu class - container for Menu
25524  * @cfg {String} html Text of the menu
25525  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25526  * @cfg {String} icon Font awesome icon
25527  * @cfg {String} pos Menu align to (top | bottom) default bottom
25528  * 
25529  * 
25530  * @constructor
25531  * Create a new Menu
25532  * @param {Object} config The config object
25533  */
25534
25535
25536 Roo.bootstrap.menu.Menu = function(config){
25537     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25538     
25539     this.addEvents({
25540         /**
25541          * @event beforeshow
25542          * Fires before this menu is displayed
25543          * @param {Roo.bootstrap.menu.Menu} this
25544          */
25545         beforeshow : true,
25546         /**
25547          * @event beforehide
25548          * Fires before this menu is hidden
25549          * @param {Roo.bootstrap.menu.Menu} this
25550          */
25551         beforehide : true,
25552         /**
25553          * @event show
25554          * Fires after this menu is displayed
25555          * @param {Roo.bootstrap.menu.Menu} this
25556          */
25557         show : true,
25558         /**
25559          * @event hide
25560          * Fires after this menu is hidden
25561          * @param {Roo.bootstrap.menu.Menu} this
25562          */
25563         hide : true,
25564         /**
25565          * @event click
25566          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25567          * @param {Roo.bootstrap.menu.Menu} this
25568          * @param {Roo.EventObject} e
25569          */
25570         click : true
25571     });
25572     
25573 };
25574
25575 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
25576     
25577     submenu : false,
25578     html : '',
25579     weight : 'default',
25580     icon : false,
25581     pos : 'bottom',
25582     
25583     
25584     getChildContainer : function() {
25585         if(this.isSubMenu){
25586             return this.el;
25587         }
25588         
25589         return this.el.select('ul.dropdown-menu', true).first();  
25590     },
25591     
25592     getAutoCreate : function()
25593     {
25594         var text = [
25595             {
25596                 tag : 'span',
25597                 cls : 'roo-menu-text',
25598                 html : this.html
25599             }
25600         ];
25601         
25602         if(this.icon){
25603             text.unshift({
25604                 tag : 'i',
25605                 cls : 'fa ' + this.icon
25606             })
25607         }
25608         
25609         
25610         var cfg = {
25611             tag : 'div',
25612             cls : 'btn-group',
25613             cn : [
25614                 {
25615                     tag : 'button',
25616                     cls : 'dropdown-button btn btn-' + this.weight,
25617                     cn : text
25618                 },
25619                 {
25620                     tag : 'button',
25621                     cls : 'dropdown-toggle btn btn-' + this.weight,
25622                     cn : [
25623                         {
25624                             tag : 'span',
25625                             cls : 'caret'
25626                         }
25627                     ]
25628                 },
25629                 {
25630                     tag : 'ul',
25631                     cls : 'dropdown-menu'
25632                 }
25633             ]
25634             
25635         };
25636         
25637         if(this.pos == 'top'){
25638             cfg.cls += ' dropup';
25639         }
25640         
25641         if(this.isSubMenu){
25642             cfg = {
25643                 tag : 'ul',
25644                 cls : 'dropdown-menu'
25645             }
25646         }
25647         
25648         return cfg;
25649     },
25650     
25651     onRender : function(ct, position)
25652     {
25653         this.isSubMenu = ct.hasClass('dropdown-submenu');
25654         
25655         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25656     },
25657     
25658     initEvents : function() 
25659     {
25660         if(this.isSubMenu){
25661             return;
25662         }
25663         
25664         this.hidden = true;
25665         
25666         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25667         this.triggerEl.on('click', this.onTriggerPress, this);
25668         
25669         this.buttonEl = this.el.select('button.dropdown-button', true).first();
25670         this.buttonEl.on('click', this.onClick, this);
25671         
25672     },
25673     
25674     list : function()
25675     {
25676         if(this.isSubMenu){
25677             return this.el;
25678         }
25679         
25680         return this.el.select('ul.dropdown-menu', true).first();
25681     },
25682     
25683     onClick : function(e)
25684     {
25685         this.fireEvent("click", this, e);
25686     },
25687     
25688     onTriggerPress  : function(e)
25689     {   
25690         if (this.isVisible()) {
25691             this.hide();
25692         } else {
25693             this.show();
25694         }
25695     },
25696     
25697     isVisible : function(){
25698         return !this.hidden;
25699     },
25700     
25701     show : function()
25702     {
25703         this.fireEvent("beforeshow", this);
25704         
25705         this.hidden = false;
25706         this.el.addClass('open');
25707         
25708         Roo.get(document).on("mouseup", this.onMouseUp, this);
25709         
25710         this.fireEvent("show", this);
25711         
25712         
25713     },
25714     
25715     hide : function()
25716     {
25717         this.fireEvent("beforehide", this);
25718         
25719         this.hidden = true;
25720         this.el.removeClass('open');
25721         
25722         Roo.get(document).un("mouseup", this.onMouseUp);
25723         
25724         this.fireEvent("hide", this);
25725     },
25726     
25727     onMouseUp : function()
25728     {
25729         this.hide();
25730     }
25731     
25732 });
25733
25734  
25735  /*
25736  * - LGPL
25737  *
25738  * menu item
25739  * 
25740  */
25741 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25742
25743 /**
25744  * @class Roo.bootstrap.menu.Item
25745  * @extends Roo.bootstrap.Component
25746  * Bootstrap MenuItem class
25747  * @cfg {Boolean} submenu (true | false) default false
25748  * @cfg {String} html text of the item
25749  * @cfg {String} href the link
25750  * @cfg {Boolean} disable (true | false) default false
25751  * @cfg {Boolean} preventDefault (true | false) default true
25752  * @cfg {String} icon Font awesome icon
25753  * @cfg {String} pos Submenu align to (left | right) default right 
25754  * 
25755  * 
25756  * @constructor
25757  * Create a new Item
25758  * @param {Object} config The config object
25759  */
25760
25761
25762 Roo.bootstrap.menu.Item = function(config){
25763     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25764     this.addEvents({
25765         /**
25766          * @event mouseover
25767          * Fires when the mouse is hovering over this menu
25768          * @param {Roo.bootstrap.menu.Item} this
25769          * @param {Roo.EventObject} e
25770          */
25771         mouseover : true,
25772         /**
25773          * @event mouseout
25774          * Fires when the mouse exits this menu
25775          * @param {Roo.bootstrap.menu.Item} this
25776          * @param {Roo.EventObject} e
25777          */
25778         mouseout : true,
25779         // raw events
25780         /**
25781          * @event click
25782          * The raw click event for the entire grid.
25783          * @param {Roo.EventObject} e
25784          */
25785         click : true
25786     });
25787 };
25788
25789 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
25790     
25791     submenu : false,
25792     href : '',
25793     html : '',
25794     preventDefault: true,
25795     disable : false,
25796     icon : false,
25797     pos : 'right',
25798     
25799     getAutoCreate : function()
25800     {
25801         var text = [
25802             {
25803                 tag : 'span',
25804                 cls : 'roo-menu-item-text',
25805                 html : this.html
25806             }
25807         ];
25808         
25809         if(this.icon){
25810             text.unshift({
25811                 tag : 'i',
25812                 cls : 'fa ' + this.icon
25813             })
25814         }
25815         
25816         var cfg = {
25817             tag : 'li',
25818             cn : [
25819                 {
25820                     tag : 'a',
25821                     href : this.href || '#',
25822                     cn : text
25823                 }
25824             ]
25825         };
25826         
25827         if(this.disable){
25828             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25829         }
25830         
25831         if(this.submenu){
25832             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25833             
25834             if(this.pos == 'left'){
25835                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25836             }
25837         }
25838         
25839         return cfg;
25840     },
25841     
25842     initEvents : function() 
25843     {
25844         this.el.on('mouseover', this.onMouseOver, this);
25845         this.el.on('mouseout', this.onMouseOut, this);
25846         
25847         this.el.select('a', true).first().on('click', this.onClick, this);
25848         
25849     },
25850     
25851     onClick : function(e)
25852     {
25853         if(this.preventDefault){
25854             e.preventDefault();
25855         }
25856         
25857         this.fireEvent("click", this, e);
25858     },
25859     
25860     onMouseOver : function(e)
25861     {
25862         if(this.submenu && this.pos == 'left'){
25863             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25864         }
25865         
25866         this.fireEvent("mouseover", this, e);
25867     },
25868     
25869     onMouseOut : function(e)
25870     {
25871         this.fireEvent("mouseout", this, e);
25872     }
25873 });
25874
25875  
25876
25877  /*
25878  * - LGPL
25879  *
25880  * menu separator
25881  * 
25882  */
25883 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25884
25885 /**
25886  * @class Roo.bootstrap.menu.Separator
25887  * @extends Roo.bootstrap.Component
25888  * Bootstrap Separator class
25889  * 
25890  * @constructor
25891  * Create a new Separator
25892  * @param {Object} config The config object
25893  */
25894
25895
25896 Roo.bootstrap.menu.Separator = function(config){
25897     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25898 };
25899
25900 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
25901     
25902     getAutoCreate : function(){
25903         var cfg = {
25904             tag : 'li',
25905             cls: 'divider'
25906         };
25907         
25908         return cfg;
25909     }
25910    
25911 });
25912
25913  
25914
25915  /*
25916  * - LGPL
25917  *
25918  * Tooltip
25919  * 
25920  */
25921
25922 /**
25923  * @class Roo.bootstrap.Tooltip
25924  * Bootstrap Tooltip class
25925  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25926  * to determine which dom element triggers the tooltip.
25927  * 
25928  * It needs to add support for additional attributes like tooltip-position
25929  * 
25930  * @constructor
25931  * Create a new Toolti
25932  * @param {Object} config The config object
25933  */
25934
25935 Roo.bootstrap.Tooltip = function(config){
25936     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25937     
25938     this.alignment = Roo.bootstrap.Tooltip.alignment;
25939     
25940     if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25941         this.alignment = config.alignment;
25942     }
25943     
25944 };
25945
25946 Roo.apply(Roo.bootstrap.Tooltip, {
25947     /**
25948      * @function init initialize tooltip monitoring.
25949      * @static
25950      */
25951     currentEl : false,
25952     currentTip : false,
25953     currentRegion : false,
25954     
25955     //  init : delay?
25956     
25957     init : function()
25958     {
25959         Roo.get(document).on('mouseover', this.enter ,this);
25960         Roo.get(document).on('mouseout', this.leave, this);
25961          
25962         
25963         this.currentTip = new Roo.bootstrap.Tooltip();
25964     },
25965     
25966     enter : function(ev)
25967     {
25968         var dom = ev.getTarget();
25969         
25970         //Roo.log(['enter',dom]);
25971         var el = Roo.fly(dom);
25972         if (this.currentEl) {
25973             //Roo.log(dom);
25974             //Roo.log(this.currentEl);
25975             //Roo.log(this.currentEl.contains(dom));
25976             if (this.currentEl == el) {
25977                 return;
25978             }
25979             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25980                 return;
25981             }
25982
25983         }
25984         
25985         if (this.currentTip.el) {
25986             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25987         }    
25988         //Roo.log(ev);
25989         
25990         if(!el || el.dom == document){
25991             return;
25992         }
25993         
25994         var bindEl = el;
25995         
25996         // you can not look for children, as if el is the body.. then everythign is the child..
25997         if (!el.attr('tooltip')) { //
25998             if (!el.select("[tooltip]").elements.length) {
25999                 return;
26000             }
26001             // is the mouse over this child...?
26002             bindEl = el.select("[tooltip]").first();
26003             var xy = ev.getXY();
26004             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26005                 //Roo.log("not in region.");
26006                 return;
26007             }
26008             //Roo.log("child element over..");
26009             
26010         }
26011         this.currentEl = bindEl;
26012         this.currentTip.bind(bindEl);
26013         this.currentRegion = Roo.lib.Region.getRegion(dom);
26014         this.currentTip.enter();
26015         
26016     },
26017     leave : function(ev)
26018     {
26019         var dom = ev.getTarget();
26020         //Roo.log(['leave',dom]);
26021         if (!this.currentEl) {
26022             return;
26023         }
26024         
26025         
26026         if (dom != this.currentEl.dom) {
26027             return;
26028         }
26029         var xy = ev.getXY();
26030         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
26031             return;
26032         }
26033         // only activate leave if mouse cursor is outside... bounding box..
26034         
26035         
26036         
26037         
26038         if (this.currentTip) {
26039             this.currentTip.leave();
26040         }
26041         //Roo.log('clear currentEl');
26042         this.currentEl = false;
26043         
26044         
26045     },
26046     alignment : {
26047         'left' : ['r-l', [-2,0], 'right'],
26048         'right' : ['l-r', [2,0], 'left'],
26049         'bottom' : ['t-b', [0,2], 'top'],
26050         'top' : [ 'b-t', [0,-2], 'bottom']
26051     }
26052     
26053 });
26054
26055
26056 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
26057     
26058     
26059     bindEl : false,
26060     
26061     delay : null, // can be { show : 300 , hide: 500}
26062     
26063     timeout : null,
26064     
26065     hoverState : null, //???
26066     
26067     placement : 'bottom', 
26068     
26069     alignment : false,
26070     
26071     getAutoCreate : function(){
26072     
26073         var cfg = {
26074            cls : 'tooltip',
26075            role : 'tooltip',
26076            cn : [
26077                 {
26078                     cls : 'tooltip-arrow'
26079                 },
26080                 {
26081                     cls : 'tooltip-inner'
26082                 }
26083            ]
26084         };
26085         
26086         return cfg;
26087     },
26088     bind : function(el)
26089     {
26090         this.bindEl = el;
26091     },
26092       
26093     
26094     enter : function () {
26095        
26096         if (this.timeout != null) {
26097             clearTimeout(this.timeout);
26098         }
26099         
26100         this.hoverState = 'in';
26101          //Roo.log("enter - show");
26102         if (!this.delay || !this.delay.show) {
26103             this.show();
26104             return;
26105         }
26106         var _t = this;
26107         this.timeout = setTimeout(function () {
26108             if (_t.hoverState == 'in') {
26109                 _t.show();
26110             }
26111         }, this.delay.show);
26112     },
26113     leave : function()
26114     {
26115         clearTimeout(this.timeout);
26116     
26117         this.hoverState = 'out';
26118          if (!this.delay || !this.delay.hide) {
26119             this.hide();
26120             return;
26121         }
26122        
26123         var _t = this;
26124         this.timeout = setTimeout(function () {
26125             //Roo.log("leave - timeout");
26126             
26127             if (_t.hoverState == 'out') {
26128                 _t.hide();
26129                 Roo.bootstrap.Tooltip.currentEl = false;
26130             }
26131         }, delay);
26132     },
26133     
26134     show : function (msg)
26135     {
26136         if (!this.el) {
26137             this.render(document.body);
26138         }
26139         // set content.
26140         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26141         
26142         var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26143         
26144         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26145         
26146         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26147         
26148         var placement = typeof this.placement == 'function' ?
26149             this.placement.call(this, this.el, on_el) :
26150             this.placement;
26151             
26152         var autoToken = /\s?auto?\s?/i;
26153         var autoPlace = autoToken.test(placement);
26154         if (autoPlace) {
26155             placement = placement.replace(autoToken, '') || 'top';
26156         }
26157         
26158         //this.el.detach()
26159         //this.el.setXY([0,0]);
26160         this.el.show();
26161         //this.el.dom.style.display='block';
26162         
26163         //this.el.appendTo(on_el);
26164         
26165         var p = this.getPosition();
26166         var box = this.el.getBox();
26167         
26168         if (autoPlace) {
26169             // fixme..
26170         }
26171         
26172         var align = this.alignment[placement];
26173         
26174         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26175         
26176         if(placement == 'top' || placement == 'bottom'){
26177             if(xy[0] < 0){
26178                 placement = 'right';
26179             }
26180             
26181             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26182                 placement = 'left';
26183             }
26184             
26185             var scroll = Roo.select('body', true).first().getScroll();
26186             
26187             if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26188                 placement = 'top';
26189             }
26190             
26191         }
26192         
26193         this.el.alignTo(this.bindEl, align[0],align[1]);
26194         //var arrow = this.el.select('.arrow',true).first();
26195         //arrow.set(align[2], 
26196         
26197         this.el.addClass(placement);
26198         
26199         this.el.addClass('in fade');
26200         
26201         this.hoverState = null;
26202         
26203         if (this.el.hasClass('fade')) {
26204             // fade it?
26205         }
26206         
26207     },
26208     hide : function()
26209     {
26210          
26211         if (!this.el) {
26212             return;
26213         }
26214         //this.el.setXY([0,0]);
26215         this.el.removeClass('in');
26216         //this.el.hide();
26217         
26218     }
26219     
26220 });
26221  
26222
26223  /*
26224  * - LGPL
26225  *
26226  * Location Picker
26227  * 
26228  */
26229
26230 /**
26231  * @class Roo.bootstrap.LocationPicker
26232  * @extends Roo.bootstrap.Component
26233  * Bootstrap LocationPicker class
26234  * @cfg {Number} latitude Position when init default 0
26235  * @cfg {Number} longitude Position when init default 0
26236  * @cfg {Number} zoom default 15
26237  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26238  * @cfg {Boolean} mapTypeControl default false
26239  * @cfg {Boolean} disableDoubleClickZoom default false
26240  * @cfg {Boolean} scrollwheel default true
26241  * @cfg {Boolean} streetViewControl default false
26242  * @cfg {Number} radius default 0
26243  * @cfg {String} locationName
26244  * @cfg {Boolean} draggable default true
26245  * @cfg {Boolean} enableAutocomplete default false
26246  * @cfg {Boolean} enableReverseGeocode default true
26247  * @cfg {String} markerTitle
26248  * 
26249  * @constructor
26250  * Create a new LocationPicker
26251  * @param {Object} config The config object
26252  */
26253
26254
26255 Roo.bootstrap.LocationPicker = function(config){
26256     
26257     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26258     
26259     this.addEvents({
26260         /**
26261          * @event initial
26262          * Fires when the picker initialized.
26263          * @param {Roo.bootstrap.LocationPicker} this
26264          * @param {Google Location} location
26265          */
26266         initial : true,
26267         /**
26268          * @event positionchanged
26269          * Fires when the picker position changed.
26270          * @param {Roo.bootstrap.LocationPicker} this
26271          * @param {Google Location} location
26272          */
26273         positionchanged : true,
26274         /**
26275          * @event resize
26276          * Fires when the map resize.
26277          * @param {Roo.bootstrap.LocationPicker} this
26278          */
26279         resize : true,
26280         /**
26281          * @event show
26282          * Fires when the map show.
26283          * @param {Roo.bootstrap.LocationPicker} this
26284          */
26285         show : true,
26286         /**
26287          * @event hide
26288          * Fires when the map hide.
26289          * @param {Roo.bootstrap.LocationPicker} this
26290          */
26291         hide : true,
26292         /**
26293          * @event mapClick
26294          * Fires when click the map.
26295          * @param {Roo.bootstrap.LocationPicker} this
26296          * @param {Map event} e
26297          */
26298         mapClick : true,
26299         /**
26300          * @event mapRightClick
26301          * Fires when right click the map.
26302          * @param {Roo.bootstrap.LocationPicker} this
26303          * @param {Map event} e
26304          */
26305         mapRightClick : true,
26306         /**
26307          * @event markerClick
26308          * Fires when click the marker.
26309          * @param {Roo.bootstrap.LocationPicker} this
26310          * @param {Map event} e
26311          */
26312         markerClick : true,
26313         /**
26314          * @event markerRightClick
26315          * Fires when right click the marker.
26316          * @param {Roo.bootstrap.LocationPicker} this
26317          * @param {Map event} e
26318          */
26319         markerRightClick : true,
26320         /**
26321          * @event OverlayViewDraw
26322          * Fires when OverlayView Draw
26323          * @param {Roo.bootstrap.LocationPicker} this
26324          */
26325         OverlayViewDraw : true,
26326         /**
26327          * @event OverlayViewOnAdd
26328          * Fires when OverlayView Draw
26329          * @param {Roo.bootstrap.LocationPicker} this
26330          */
26331         OverlayViewOnAdd : true,
26332         /**
26333          * @event OverlayViewOnRemove
26334          * Fires when OverlayView Draw
26335          * @param {Roo.bootstrap.LocationPicker} this
26336          */
26337         OverlayViewOnRemove : true,
26338         /**
26339          * @event OverlayViewShow
26340          * Fires when OverlayView Draw
26341          * @param {Roo.bootstrap.LocationPicker} this
26342          * @param {Pixel} cpx
26343          */
26344         OverlayViewShow : true,
26345         /**
26346          * @event OverlayViewHide
26347          * Fires when OverlayView Draw
26348          * @param {Roo.bootstrap.LocationPicker} this
26349          */
26350         OverlayViewHide : true,
26351         /**
26352          * @event loadexception
26353          * Fires when load google lib failed.
26354          * @param {Roo.bootstrap.LocationPicker} this
26355          */
26356         loadexception : true
26357     });
26358         
26359 };
26360
26361 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
26362     
26363     gMapContext: false,
26364     
26365     latitude: 0,
26366     longitude: 0,
26367     zoom: 15,
26368     mapTypeId: false,
26369     mapTypeControl: false,
26370     disableDoubleClickZoom: false,
26371     scrollwheel: true,
26372     streetViewControl: false,
26373     radius: 0,
26374     locationName: '',
26375     draggable: true,
26376     enableAutocomplete: false,
26377     enableReverseGeocode: true,
26378     markerTitle: '',
26379     
26380     getAutoCreate: function()
26381     {
26382
26383         var cfg = {
26384             tag: 'div',
26385             cls: 'roo-location-picker'
26386         };
26387         
26388         return cfg
26389     },
26390     
26391     initEvents: function(ct, position)
26392     {       
26393         if(!this.el.getWidth() || this.isApplied()){
26394             return;
26395         }
26396         
26397         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26398         
26399         this.initial();
26400     },
26401     
26402     initial: function()
26403     {
26404         if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26405             this.fireEvent('loadexception', this);
26406             return;
26407         }
26408         
26409         if(!this.mapTypeId){
26410             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26411         }
26412         
26413         this.gMapContext = this.GMapContext();
26414         
26415         this.initOverlayView();
26416         
26417         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26418         
26419         var _this = this;
26420                 
26421         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26422             _this.setPosition(_this.gMapContext.marker.position);
26423         });
26424         
26425         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26426             _this.fireEvent('mapClick', this, event);
26427             
26428         });
26429
26430         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26431             _this.fireEvent('mapRightClick', this, event);
26432             
26433         });
26434         
26435         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26436             _this.fireEvent('markerClick', this, event);
26437             
26438         });
26439
26440         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26441             _this.fireEvent('markerRightClick', this, event);
26442             
26443         });
26444         
26445         this.setPosition(this.gMapContext.location);
26446         
26447         this.fireEvent('initial', this, this.gMapContext.location);
26448     },
26449     
26450     initOverlayView: function()
26451     {
26452         var _this = this;
26453         
26454         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26455             
26456             draw: function()
26457             {
26458                 _this.fireEvent('OverlayViewDraw', _this);
26459             },
26460             
26461             onAdd: function()
26462             {
26463                 _this.fireEvent('OverlayViewOnAdd', _this);
26464             },
26465             
26466             onRemove: function()
26467             {
26468                 _this.fireEvent('OverlayViewOnRemove', _this);
26469             },
26470             
26471             show: function(cpx)
26472             {
26473                 _this.fireEvent('OverlayViewShow', _this, cpx);
26474             },
26475             
26476             hide: function()
26477             {
26478                 _this.fireEvent('OverlayViewHide', _this);
26479             }
26480             
26481         });
26482     },
26483     
26484     fromLatLngToContainerPixel: function(event)
26485     {
26486         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26487     },
26488     
26489     isApplied: function() 
26490     {
26491         return this.getGmapContext() == false ? false : true;
26492     },
26493     
26494     getGmapContext: function() 
26495     {
26496         return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26497     },
26498     
26499     GMapContext: function() 
26500     {
26501         var position = new google.maps.LatLng(this.latitude, this.longitude);
26502         
26503         var _map = new google.maps.Map(this.el.dom, {
26504             center: position,
26505             zoom: this.zoom,
26506             mapTypeId: this.mapTypeId,
26507             mapTypeControl: this.mapTypeControl,
26508             disableDoubleClickZoom: this.disableDoubleClickZoom,
26509             scrollwheel: this.scrollwheel,
26510             streetViewControl: this.streetViewControl,
26511             locationName: this.locationName,
26512             draggable: this.draggable,
26513             enableAutocomplete: this.enableAutocomplete,
26514             enableReverseGeocode: this.enableReverseGeocode
26515         });
26516         
26517         var _marker = new google.maps.Marker({
26518             position: position,
26519             map: _map,
26520             title: this.markerTitle,
26521             draggable: this.draggable
26522         });
26523         
26524         return {
26525             map: _map,
26526             marker: _marker,
26527             circle: null,
26528             location: position,
26529             radius: this.radius,
26530             locationName: this.locationName,
26531             addressComponents: {
26532                 formatted_address: null,
26533                 addressLine1: null,
26534                 addressLine2: null,
26535                 streetName: null,
26536                 streetNumber: null,
26537                 city: null,
26538                 district: null,
26539                 state: null,
26540                 stateOrProvince: null
26541             },
26542             settings: this,
26543             domContainer: this.el.dom,
26544             geodecoder: new google.maps.Geocoder()
26545         };
26546     },
26547     
26548     drawCircle: function(center, radius, options) 
26549     {
26550         if (this.gMapContext.circle != null) {
26551             this.gMapContext.circle.setMap(null);
26552         }
26553         if (radius > 0) {
26554             radius *= 1;
26555             options = Roo.apply({}, options, {
26556                 strokeColor: "#0000FF",
26557                 strokeOpacity: .35,
26558                 strokeWeight: 2,
26559                 fillColor: "#0000FF",
26560                 fillOpacity: .2
26561             });
26562             
26563             options.map = this.gMapContext.map;
26564             options.radius = radius;
26565             options.center = center;
26566             this.gMapContext.circle = new google.maps.Circle(options);
26567             return this.gMapContext.circle;
26568         }
26569         
26570         return null;
26571     },
26572     
26573     setPosition: function(location) 
26574     {
26575         this.gMapContext.location = location;
26576         this.gMapContext.marker.setPosition(location);
26577         this.gMapContext.map.panTo(location);
26578         this.drawCircle(location, this.gMapContext.radius, {});
26579         
26580         var _this = this;
26581         
26582         if (this.gMapContext.settings.enableReverseGeocode) {
26583             this.gMapContext.geodecoder.geocode({
26584                 latLng: this.gMapContext.location
26585             }, function(results, status) {
26586                 
26587                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26588                     _this.gMapContext.locationName = results[0].formatted_address;
26589                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26590                     
26591                     _this.fireEvent('positionchanged', this, location);
26592                 }
26593             });
26594             
26595             return;
26596         }
26597         
26598         this.fireEvent('positionchanged', this, location);
26599     },
26600     
26601     resize: function()
26602     {
26603         google.maps.event.trigger(this.gMapContext.map, "resize");
26604         
26605         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26606         
26607         this.fireEvent('resize', this);
26608     },
26609     
26610     setPositionByLatLng: function(latitude, longitude)
26611     {
26612         this.setPosition(new google.maps.LatLng(latitude, longitude));
26613     },
26614     
26615     getCurrentPosition: function() 
26616     {
26617         return {
26618             latitude: this.gMapContext.location.lat(),
26619             longitude: this.gMapContext.location.lng()
26620         };
26621     },
26622     
26623     getAddressName: function() 
26624     {
26625         return this.gMapContext.locationName;
26626     },
26627     
26628     getAddressComponents: function() 
26629     {
26630         return this.gMapContext.addressComponents;
26631     },
26632     
26633     address_component_from_google_geocode: function(address_components) 
26634     {
26635         var result = {};
26636         
26637         for (var i = 0; i < address_components.length; i++) {
26638             var component = address_components[i];
26639             if (component.types.indexOf("postal_code") >= 0) {
26640                 result.postalCode = component.short_name;
26641             } else if (component.types.indexOf("street_number") >= 0) {
26642                 result.streetNumber = component.short_name;
26643             } else if (component.types.indexOf("route") >= 0) {
26644                 result.streetName = component.short_name;
26645             } else if (component.types.indexOf("neighborhood") >= 0) {
26646                 result.city = component.short_name;
26647             } else if (component.types.indexOf("locality") >= 0) {
26648                 result.city = component.short_name;
26649             } else if (component.types.indexOf("sublocality") >= 0) {
26650                 result.district = component.short_name;
26651             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26652                 result.stateOrProvince = component.short_name;
26653             } else if (component.types.indexOf("country") >= 0) {
26654                 result.country = component.short_name;
26655             }
26656         }
26657         
26658         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26659         result.addressLine2 = "";
26660         return result;
26661     },
26662     
26663     setZoomLevel: function(zoom)
26664     {
26665         this.gMapContext.map.setZoom(zoom);
26666     },
26667     
26668     show: function()
26669     {
26670         if(!this.el){
26671             return;
26672         }
26673         
26674         this.el.show();
26675         
26676         this.resize();
26677         
26678         this.fireEvent('show', this);
26679     },
26680     
26681     hide: function()
26682     {
26683         if(!this.el){
26684             return;
26685         }
26686         
26687         this.el.hide();
26688         
26689         this.fireEvent('hide', this);
26690     }
26691     
26692 });
26693
26694 Roo.apply(Roo.bootstrap.LocationPicker, {
26695     
26696     OverlayView : function(map, options)
26697     {
26698         options = options || {};
26699         
26700         this.setMap(map);
26701     }
26702     
26703     
26704 });/*
26705  * - LGPL
26706  *
26707  * Alert
26708  * 
26709  */
26710
26711 /**
26712  * @class Roo.bootstrap.Alert
26713  * @extends Roo.bootstrap.Component
26714  * Bootstrap Alert class
26715  * @cfg {String} title The title of alert
26716  * @cfg {String} html The content of alert
26717  * @cfg {String} weight (  success | info | warning | danger )
26718  * @cfg {String} faicon font-awesomeicon
26719  * 
26720  * @constructor
26721  * Create a new alert
26722  * @param {Object} config The config object
26723  */
26724
26725
26726 Roo.bootstrap.Alert = function(config){
26727     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26728     
26729 };
26730
26731 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
26732     
26733     title: '',
26734     html: '',
26735     weight: false,
26736     faicon: false,
26737     
26738     getAutoCreate : function()
26739     {
26740         
26741         var cfg = {
26742             tag : 'div',
26743             cls : 'alert',
26744             cn : [
26745                 {
26746                     tag : 'i',
26747                     cls : 'roo-alert-icon'
26748                     
26749                 },
26750                 {
26751                     tag : 'b',
26752                     cls : 'roo-alert-title',
26753                     html : this.title
26754                 },
26755                 {
26756                     tag : 'span',
26757                     cls : 'roo-alert-text',
26758                     html : this.html
26759                 }
26760             ]
26761         };
26762         
26763         if(this.faicon){
26764             cfg.cn[0].cls += ' fa ' + this.faicon;
26765         }
26766         
26767         if(this.weight){
26768             cfg.cls += ' alert-' + this.weight;
26769         }
26770         
26771         return cfg;
26772     },
26773     
26774     initEvents: function() 
26775     {
26776         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26777     },
26778     
26779     setTitle : function(str)
26780     {
26781         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26782     },
26783     
26784     setText : function(str)
26785     {
26786         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26787     },
26788     
26789     setWeight : function(weight)
26790     {
26791         if(this.weight){
26792             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26793         }
26794         
26795         this.weight = weight;
26796         
26797         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26798     },
26799     
26800     setIcon : function(icon)
26801     {
26802         if(this.faicon){
26803             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26804         }
26805         
26806         this.faicon = icon;
26807         
26808         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26809     },
26810     
26811     hide: function() 
26812     {
26813         this.el.hide();   
26814     },
26815     
26816     show: function() 
26817     {  
26818         this.el.show();   
26819     }
26820     
26821 });
26822
26823  
26824 /*
26825 * Licence: LGPL
26826 */
26827
26828 /**
26829  * @class Roo.bootstrap.UploadCropbox
26830  * @extends Roo.bootstrap.Component
26831  * Bootstrap UploadCropbox class
26832  * @cfg {String} emptyText show when image has been loaded
26833  * @cfg {String} rotateNotify show when image too small to rotate
26834  * @cfg {Number} errorTimeout default 3000
26835  * @cfg {Number} minWidth default 300
26836  * @cfg {Number} minHeight default 300
26837  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26838  * @cfg {Boolean} isDocument (true|false) default false
26839  * @cfg {String} url action url
26840  * @cfg {String} paramName default 'imageUpload'
26841  * @cfg {String} method default POST
26842  * @cfg {Boolean} loadMask (true|false) default true
26843  * @cfg {Boolean} loadingText default 'Loading...'
26844  * 
26845  * @constructor
26846  * Create a new UploadCropbox
26847  * @param {Object} config The config object
26848  */
26849
26850 Roo.bootstrap.UploadCropbox = function(config){
26851     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26852     
26853     this.addEvents({
26854         /**
26855          * @event beforeselectfile
26856          * Fire before select file
26857          * @param {Roo.bootstrap.UploadCropbox} this
26858          */
26859         "beforeselectfile" : true,
26860         /**
26861          * @event initial
26862          * Fire after initEvent
26863          * @param {Roo.bootstrap.UploadCropbox} this
26864          */
26865         "initial" : true,
26866         /**
26867          * @event crop
26868          * Fire after initEvent
26869          * @param {Roo.bootstrap.UploadCropbox} this
26870          * @param {String} data
26871          */
26872         "crop" : true,
26873         /**
26874          * @event prepare
26875          * Fire when preparing the file data
26876          * @param {Roo.bootstrap.UploadCropbox} this
26877          * @param {Object} file
26878          */
26879         "prepare" : true,
26880         /**
26881          * @event exception
26882          * Fire when get exception
26883          * @param {Roo.bootstrap.UploadCropbox} this
26884          * @param {XMLHttpRequest} xhr
26885          */
26886         "exception" : true,
26887         /**
26888          * @event beforeloadcanvas
26889          * Fire before load the canvas
26890          * @param {Roo.bootstrap.UploadCropbox} this
26891          * @param {String} src
26892          */
26893         "beforeloadcanvas" : true,
26894         /**
26895          * @event trash
26896          * Fire when trash image
26897          * @param {Roo.bootstrap.UploadCropbox} this
26898          */
26899         "trash" : true,
26900         /**
26901          * @event download
26902          * Fire when download the image
26903          * @param {Roo.bootstrap.UploadCropbox} this
26904          */
26905         "download" : true,
26906         /**
26907          * @event footerbuttonclick
26908          * Fire when footerbuttonclick
26909          * @param {Roo.bootstrap.UploadCropbox} this
26910          * @param {String} type
26911          */
26912         "footerbuttonclick" : true,
26913         /**
26914          * @event resize
26915          * Fire when resize
26916          * @param {Roo.bootstrap.UploadCropbox} this
26917          */
26918         "resize" : true,
26919         /**
26920          * @event rotate
26921          * Fire when rotate the image
26922          * @param {Roo.bootstrap.UploadCropbox} this
26923          * @param {String} pos
26924          */
26925         "rotate" : true,
26926         /**
26927          * @event inspect
26928          * Fire when inspect the file
26929          * @param {Roo.bootstrap.UploadCropbox} this
26930          * @param {Object} file
26931          */
26932         "inspect" : true,
26933         /**
26934          * @event upload
26935          * Fire when xhr upload the file
26936          * @param {Roo.bootstrap.UploadCropbox} this
26937          * @param {Object} data
26938          */
26939         "upload" : true,
26940         /**
26941          * @event arrange
26942          * Fire when arrange the file data
26943          * @param {Roo.bootstrap.UploadCropbox} this
26944          * @param {Object} formData
26945          */
26946         "arrange" : true
26947     });
26948     
26949     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26950 };
26951
26952 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
26953     
26954     emptyText : 'Click to upload image',
26955     rotateNotify : 'Image is too small to rotate',
26956     errorTimeout : 3000,
26957     scale : 0,
26958     baseScale : 1,
26959     rotate : 0,
26960     dragable : false,
26961     pinching : false,
26962     mouseX : 0,
26963     mouseY : 0,
26964     cropData : false,
26965     minWidth : 300,
26966     minHeight : 300,
26967     file : false,
26968     exif : {},
26969     baseRotate : 1,
26970     cropType : 'image/jpeg',
26971     buttons : false,
26972     canvasLoaded : false,
26973     isDocument : false,
26974     method : 'POST',
26975     paramName : 'imageUpload',
26976     loadMask : true,
26977     loadingText : 'Loading...',
26978     maskEl : false,
26979     
26980     getAutoCreate : function()
26981     {
26982         var cfg = {
26983             tag : 'div',
26984             cls : 'roo-upload-cropbox',
26985             cn : [
26986                 {
26987                     tag : 'input',
26988                     cls : 'roo-upload-cropbox-selector',
26989                     type : 'file'
26990                 },
26991                 {
26992                     tag : 'div',
26993                     cls : 'roo-upload-cropbox-body',
26994                     style : 'cursor:pointer',
26995                     cn : [
26996                         {
26997                             tag : 'div',
26998                             cls : 'roo-upload-cropbox-preview'
26999                         },
27000                         {
27001                             tag : 'div',
27002                             cls : 'roo-upload-cropbox-thumb'
27003                         },
27004                         {
27005                             tag : 'div',
27006                             cls : 'roo-upload-cropbox-empty-notify',
27007                             html : this.emptyText
27008                         },
27009                         {
27010                             tag : 'div',
27011                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27012                             html : this.rotateNotify
27013                         }
27014                     ]
27015                 },
27016                 {
27017                     tag : 'div',
27018                     cls : 'roo-upload-cropbox-footer',
27019                     cn : {
27020                         tag : 'div',
27021                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27022                         cn : []
27023                     }
27024                 }
27025             ]
27026         };
27027         
27028         return cfg;
27029     },
27030     
27031     onRender : function(ct, position)
27032     {
27033         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27034         
27035         if (this.buttons.length) {
27036             
27037             Roo.each(this.buttons, function(bb) {
27038                 
27039                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27040                 
27041                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27042                 
27043             }, this);
27044         }
27045         
27046         if(this.loadMask){
27047             this.maskEl = this.el;
27048         }
27049     },
27050     
27051     initEvents : function()
27052     {
27053         this.urlAPI = (window.createObjectURL && window) || 
27054                                 (window.URL && URL.revokeObjectURL && URL) || 
27055                                 (window.webkitURL && webkitURL);
27056                         
27057         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27058         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27059         
27060         this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27061         this.selectorEl.hide();
27062         
27063         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27064         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27065         
27066         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27067         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27068         this.thumbEl.hide();
27069         
27070         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27071         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27072         
27073         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27074         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27075         this.errorEl.hide();
27076         
27077         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27078         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27079         this.footerEl.hide();
27080         
27081         this.setThumbBoxSize();
27082         
27083         this.bind();
27084         
27085         this.resize();
27086         
27087         this.fireEvent('initial', this);
27088     },
27089
27090     bind : function()
27091     {
27092         var _this = this;
27093         
27094         window.addEventListener("resize", function() { _this.resize(); } );
27095         
27096         this.bodyEl.on('click', this.beforeSelectFile, this);
27097         
27098         if(Roo.isTouch){
27099             this.bodyEl.on('touchstart', this.onTouchStart, this);
27100             this.bodyEl.on('touchmove', this.onTouchMove, this);
27101             this.bodyEl.on('touchend', this.onTouchEnd, this);
27102         }
27103         
27104         if(!Roo.isTouch){
27105             this.bodyEl.on('mousedown', this.onMouseDown, this);
27106             this.bodyEl.on('mousemove', this.onMouseMove, this);
27107             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27108             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27109             Roo.get(document).on('mouseup', this.onMouseUp, this);
27110         }
27111         
27112         this.selectorEl.on('change', this.onFileSelected, this);
27113     },
27114     
27115     reset : function()
27116     {    
27117         this.scale = 0;
27118         this.baseScale = 1;
27119         this.rotate = 0;
27120         this.baseRotate = 1;
27121         this.dragable = false;
27122         this.pinching = false;
27123         this.mouseX = 0;
27124         this.mouseY = 0;
27125         this.cropData = false;
27126         this.notifyEl.dom.innerHTML = this.emptyText;
27127         
27128         this.selectorEl.dom.value = '';
27129         
27130     },
27131     
27132     resize : function()
27133     {
27134         if(this.fireEvent('resize', this) != false){
27135             this.setThumbBoxPosition();
27136             this.setCanvasPosition();
27137         }
27138     },
27139     
27140     onFooterButtonClick : function(e, el, o, type)
27141     {
27142         switch (type) {
27143             case 'rotate-left' :
27144                 this.onRotateLeft(e);
27145                 break;
27146             case 'rotate-right' :
27147                 this.onRotateRight(e);
27148                 break;
27149             case 'picture' :
27150                 this.beforeSelectFile(e);
27151                 break;
27152             case 'trash' :
27153                 this.trash(e);
27154                 break;
27155             case 'crop' :
27156                 this.crop(e);
27157                 break;
27158             case 'download' :
27159                 this.download(e);
27160                 break;
27161             default :
27162                 break;
27163         }
27164         
27165         this.fireEvent('footerbuttonclick', this, type);
27166     },
27167     
27168     beforeSelectFile : function(e)
27169     {
27170         e.preventDefault();
27171         
27172         if(this.fireEvent('beforeselectfile', this) != false){
27173             this.selectorEl.dom.click();
27174         }
27175     },
27176     
27177     onFileSelected : function(e)
27178     {
27179         e.preventDefault();
27180         
27181         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27182             return;
27183         }
27184         
27185         var file = this.selectorEl.dom.files[0];
27186         
27187         if(this.fireEvent('inspect', this, file) != false){
27188             this.prepare(file);
27189         }
27190         
27191     },
27192     
27193     trash : function(e)
27194     {
27195         this.fireEvent('trash', this);
27196     },
27197     
27198     download : function(e)
27199     {
27200         this.fireEvent('download', this);
27201     },
27202     
27203     loadCanvas : function(src)
27204     {   
27205         if(this.fireEvent('beforeloadcanvas', this, src) != false){
27206             
27207             this.reset();
27208             
27209             this.imageEl = document.createElement('img');
27210             
27211             var _this = this;
27212             
27213             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27214             
27215             this.imageEl.src = src;
27216         }
27217     },
27218     
27219     onLoadCanvas : function()
27220     {   
27221         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27222         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27223         
27224         this.bodyEl.un('click', this.beforeSelectFile, this);
27225         
27226         this.notifyEl.hide();
27227         this.thumbEl.show();
27228         this.footerEl.show();
27229         
27230         this.baseRotateLevel();
27231         
27232         if(this.isDocument){
27233             this.setThumbBoxSize();
27234         }
27235         
27236         this.setThumbBoxPosition();
27237         
27238         this.baseScaleLevel();
27239         
27240         this.draw();
27241         
27242         this.resize();
27243         
27244         this.canvasLoaded = true;
27245         
27246         if(this.loadMask){
27247             this.maskEl.unmask();
27248         }
27249         
27250     },
27251     
27252     setCanvasPosition : function()
27253     {   
27254         if(!this.canvasEl){
27255             return;
27256         }
27257         
27258         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27259         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27260         
27261         this.previewEl.setLeft(pw);
27262         this.previewEl.setTop(ph);
27263         
27264     },
27265     
27266     onMouseDown : function(e)
27267     {   
27268         e.stopEvent();
27269         
27270         this.dragable = true;
27271         this.pinching = false;
27272         
27273         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27274             this.dragable = false;
27275             return;
27276         }
27277         
27278         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27279         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27280         
27281     },
27282     
27283     onMouseMove : function(e)
27284     {   
27285         e.stopEvent();
27286         
27287         if(!this.canvasLoaded){
27288             return;
27289         }
27290         
27291         if (!this.dragable){
27292             return;
27293         }
27294         
27295         var minX = Math.ceil(this.thumbEl.getLeft(true));
27296         var minY = Math.ceil(this.thumbEl.getTop(true));
27297         
27298         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27299         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27300         
27301         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27302         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27303         
27304         x = x - this.mouseX;
27305         y = y - this.mouseY;
27306         
27307         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27308         var bgY = Math.ceil(y + this.previewEl.getTop(true));
27309         
27310         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27311         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27312         
27313         this.previewEl.setLeft(bgX);
27314         this.previewEl.setTop(bgY);
27315         
27316         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27317         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27318     },
27319     
27320     onMouseUp : function(e)
27321     {   
27322         e.stopEvent();
27323         
27324         this.dragable = false;
27325     },
27326     
27327     onMouseWheel : function(e)
27328     {   
27329         e.stopEvent();
27330         
27331         this.startScale = this.scale;
27332         
27333         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27334         
27335         if(!this.zoomable()){
27336             this.scale = this.startScale;
27337             return;
27338         }
27339         
27340         this.draw();
27341         
27342         return;
27343     },
27344     
27345     zoomable : function()
27346     {
27347         var minScale = this.thumbEl.getWidth() / this.minWidth;
27348         
27349         if(this.minWidth < this.minHeight){
27350             minScale = this.thumbEl.getHeight() / this.minHeight;
27351         }
27352         
27353         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27354         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27355         
27356         if(
27357                 this.isDocument &&
27358                 (this.rotate == 0 || this.rotate == 180) && 
27359                 (
27360                     width > this.imageEl.OriginWidth || 
27361                     height > this.imageEl.OriginHeight ||
27362                     (width < this.minWidth && height < this.minHeight)
27363                 )
27364         ){
27365             return false;
27366         }
27367         
27368         if(
27369                 this.isDocument &&
27370                 (this.rotate == 90 || this.rotate == 270) && 
27371                 (
27372                     width > this.imageEl.OriginWidth || 
27373                     height > this.imageEl.OriginHeight ||
27374                     (width < this.minHeight && height < this.minWidth)
27375                 )
27376         ){
27377             return false;
27378         }
27379         
27380         if(
27381                 !this.isDocument &&
27382                 (this.rotate == 0 || this.rotate == 180) && 
27383                 (
27384                     width < this.minWidth || 
27385                     width > this.imageEl.OriginWidth || 
27386                     height < this.minHeight || 
27387                     height > this.imageEl.OriginHeight
27388                 )
27389         ){
27390             return false;
27391         }
27392         
27393         if(
27394                 !this.isDocument &&
27395                 (this.rotate == 90 || this.rotate == 270) && 
27396                 (
27397                     width < this.minHeight || 
27398                     width > this.imageEl.OriginWidth || 
27399                     height < this.minWidth || 
27400                     height > this.imageEl.OriginHeight
27401                 )
27402         ){
27403             return false;
27404         }
27405         
27406         return true;
27407         
27408     },
27409     
27410     onRotateLeft : function(e)
27411     {   
27412         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27413             
27414             var minScale = this.thumbEl.getWidth() / this.minWidth;
27415             
27416             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27417             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27418             
27419             this.startScale = this.scale;
27420             
27421             while (this.getScaleLevel() < minScale){
27422             
27423                 this.scale = this.scale + 1;
27424                 
27425                 if(!this.zoomable()){
27426                     break;
27427                 }
27428                 
27429                 if(
27430                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27431                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27432                 ){
27433                     continue;
27434                 }
27435                 
27436                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27437
27438                 this.draw();
27439                 
27440                 return;
27441             }
27442             
27443             this.scale = this.startScale;
27444             
27445             this.onRotateFail();
27446             
27447             return false;
27448         }
27449         
27450         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27451
27452         if(this.isDocument){
27453             this.setThumbBoxSize();
27454             this.setThumbBoxPosition();
27455             this.setCanvasPosition();
27456         }
27457         
27458         this.draw();
27459         
27460         this.fireEvent('rotate', this, 'left');
27461         
27462     },
27463     
27464     onRotateRight : function(e)
27465     {
27466         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27467             
27468             var minScale = this.thumbEl.getWidth() / this.minWidth;
27469         
27470             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27471             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27472             
27473             this.startScale = this.scale;
27474             
27475             while (this.getScaleLevel() < minScale){
27476             
27477                 this.scale = this.scale + 1;
27478                 
27479                 if(!this.zoomable()){
27480                     break;
27481                 }
27482                 
27483                 if(
27484                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27485                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27486                 ){
27487                     continue;
27488                 }
27489                 
27490                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27491
27492                 this.draw();
27493                 
27494                 return;
27495             }
27496             
27497             this.scale = this.startScale;
27498             
27499             this.onRotateFail();
27500             
27501             return false;
27502         }
27503         
27504         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27505
27506         if(this.isDocument){
27507             this.setThumbBoxSize();
27508             this.setThumbBoxPosition();
27509             this.setCanvasPosition();
27510         }
27511         
27512         this.draw();
27513         
27514         this.fireEvent('rotate', this, 'right');
27515     },
27516     
27517     onRotateFail : function()
27518     {
27519         this.errorEl.show(true);
27520         
27521         var _this = this;
27522         
27523         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27524     },
27525     
27526     draw : function()
27527     {
27528         this.previewEl.dom.innerHTML = '';
27529         
27530         var canvasEl = document.createElement("canvas");
27531         
27532         var contextEl = canvasEl.getContext("2d");
27533         
27534         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27535         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27536         var center = this.imageEl.OriginWidth / 2;
27537         
27538         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27539             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27540             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27541             center = this.imageEl.OriginHeight / 2;
27542         }
27543         
27544         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27545         
27546         contextEl.translate(center, center);
27547         contextEl.rotate(this.rotate * Math.PI / 180);
27548
27549         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27550         
27551         this.canvasEl = document.createElement("canvas");
27552         
27553         this.contextEl = this.canvasEl.getContext("2d");
27554         
27555         switch (this.rotate) {
27556             case 0 :
27557                 
27558                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27559                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27560                 
27561                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27562                 
27563                 break;
27564             case 90 : 
27565                 
27566                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27567                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27568                 
27569                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27570                     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);
27571                     break;
27572                 }
27573                 
27574                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27575                 
27576                 break;
27577             case 180 :
27578                 
27579                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27580                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27581                 
27582                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27583                     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);
27584                     break;
27585                 }
27586                 
27587                 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);
27588                 
27589                 break;
27590             case 270 :
27591                 
27592                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27593                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27594         
27595                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27596                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27597                     break;
27598                 }
27599                 
27600                 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);
27601                 
27602                 break;
27603             default : 
27604                 break;
27605         }
27606         
27607         this.previewEl.appendChild(this.canvasEl);
27608         
27609         this.setCanvasPosition();
27610     },
27611     
27612     crop : function()
27613     {
27614         if(!this.canvasLoaded){
27615             return;
27616         }
27617         
27618         var imageCanvas = document.createElement("canvas");
27619         
27620         var imageContext = imageCanvas.getContext("2d");
27621         
27622         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27623         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27624         
27625         var center = imageCanvas.width / 2;
27626         
27627         imageContext.translate(center, center);
27628         
27629         imageContext.rotate(this.rotate * Math.PI / 180);
27630         
27631         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27632         
27633         var canvas = document.createElement("canvas");
27634         
27635         var context = canvas.getContext("2d");
27636                 
27637         canvas.width = this.minWidth;
27638         canvas.height = this.minHeight;
27639
27640         switch (this.rotate) {
27641             case 0 :
27642                 
27643                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27644                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27645                 
27646                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27647                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27648                 
27649                 var targetWidth = this.minWidth - 2 * x;
27650                 var targetHeight = this.minHeight - 2 * y;
27651                 
27652                 var scale = 1;
27653                 
27654                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27655                     scale = targetWidth / width;
27656                 }
27657                 
27658                 if(x > 0 && y == 0){
27659                     scale = targetHeight / height;
27660                 }
27661                 
27662                 if(x > 0 && y > 0){
27663                     scale = targetWidth / width;
27664                     
27665                     if(width < height){
27666                         scale = targetHeight / height;
27667                     }
27668                 }
27669                 
27670                 context.scale(scale, scale);
27671                 
27672                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27673                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27674
27675                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27676                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27677
27678                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27679                 
27680                 break;
27681             case 90 : 
27682                 
27683                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27684                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27685                 
27686                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27687                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27688                 
27689                 var targetWidth = this.minWidth - 2 * x;
27690                 var targetHeight = this.minHeight - 2 * y;
27691                 
27692                 var scale = 1;
27693                 
27694                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27695                     scale = targetWidth / width;
27696                 }
27697                 
27698                 if(x > 0 && y == 0){
27699                     scale = targetHeight / height;
27700                 }
27701                 
27702                 if(x > 0 && y > 0){
27703                     scale = targetWidth / width;
27704                     
27705                     if(width < height){
27706                         scale = targetHeight / height;
27707                     }
27708                 }
27709                 
27710                 context.scale(scale, scale);
27711                 
27712                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27713                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27714
27715                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27716                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27717                 
27718                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27719                 
27720                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27721                 
27722                 break;
27723             case 180 :
27724                 
27725                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27726                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27727                 
27728                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27729                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27730                 
27731                 var targetWidth = this.minWidth - 2 * x;
27732                 var targetHeight = this.minHeight - 2 * y;
27733                 
27734                 var scale = 1;
27735                 
27736                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27737                     scale = targetWidth / width;
27738                 }
27739                 
27740                 if(x > 0 && y == 0){
27741                     scale = targetHeight / height;
27742                 }
27743                 
27744                 if(x > 0 && y > 0){
27745                     scale = targetWidth / width;
27746                     
27747                     if(width < height){
27748                         scale = targetHeight / height;
27749                     }
27750                 }
27751                 
27752                 context.scale(scale, scale);
27753                 
27754                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27755                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27756
27757                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27758                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27759
27760                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27761                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27762                 
27763                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27764                 
27765                 break;
27766             case 270 :
27767                 
27768                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27769                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27770                 
27771                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27772                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27773                 
27774                 var targetWidth = this.minWidth - 2 * x;
27775                 var targetHeight = this.minHeight - 2 * y;
27776                 
27777                 var scale = 1;
27778                 
27779                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27780                     scale = targetWidth / width;
27781                 }
27782                 
27783                 if(x > 0 && y == 0){
27784                     scale = targetHeight / height;
27785                 }
27786                 
27787                 if(x > 0 && y > 0){
27788                     scale = targetWidth / width;
27789                     
27790                     if(width < height){
27791                         scale = targetHeight / height;
27792                     }
27793                 }
27794                 
27795                 context.scale(scale, scale);
27796                 
27797                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27798                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27799
27800                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27801                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27802                 
27803                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27804                 
27805                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27806                 
27807                 break;
27808             default : 
27809                 break;
27810         }
27811         
27812         this.cropData = canvas.toDataURL(this.cropType);
27813         
27814         if(this.fireEvent('crop', this, this.cropData) !== false){
27815             this.process(this.file, this.cropData);
27816         }
27817         
27818         return;
27819         
27820     },
27821     
27822     setThumbBoxSize : function()
27823     {
27824         var width, height;
27825         
27826         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27827             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27828             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27829             
27830             this.minWidth = width;
27831             this.minHeight = height;
27832             
27833             if(this.rotate == 90 || this.rotate == 270){
27834                 this.minWidth = height;
27835                 this.minHeight = width;
27836             }
27837         }
27838         
27839         height = 300;
27840         width = Math.ceil(this.minWidth * height / this.minHeight);
27841         
27842         if(this.minWidth > this.minHeight){
27843             width = 300;
27844             height = Math.ceil(this.minHeight * width / this.minWidth);
27845         }
27846         
27847         this.thumbEl.setStyle({
27848             width : width + 'px',
27849             height : height + 'px'
27850         });
27851
27852         return;
27853             
27854     },
27855     
27856     setThumbBoxPosition : function()
27857     {
27858         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27859         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27860         
27861         this.thumbEl.setLeft(x);
27862         this.thumbEl.setTop(y);
27863         
27864     },
27865     
27866     baseRotateLevel : function()
27867     {
27868         this.baseRotate = 1;
27869         
27870         if(
27871                 typeof(this.exif) != 'undefined' &&
27872                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27873                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27874         ){
27875             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27876         }
27877         
27878         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27879         
27880     },
27881     
27882     baseScaleLevel : function()
27883     {
27884         var width, height;
27885         
27886         if(this.isDocument){
27887             
27888             if(this.baseRotate == 6 || this.baseRotate == 8){
27889             
27890                 height = this.thumbEl.getHeight();
27891                 this.baseScale = height / this.imageEl.OriginWidth;
27892
27893                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27894                     width = this.thumbEl.getWidth();
27895                     this.baseScale = width / this.imageEl.OriginHeight;
27896                 }
27897
27898                 return;
27899             }
27900
27901             height = this.thumbEl.getHeight();
27902             this.baseScale = height / this.imageEl.OriginHeight;
27903
27904             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27905                 width = this.thumbEl.getWidth();
27906                 this.baseScale = width / this.imageEl.OriginWidth;
27907             }
27908
27909             return;
27910         }
27911         
27912         if(this.baseRotate == 6 || this.baseRotate == 8){
27913             
27914             width = this.thumbEl.getHeight();
27915             this.baseScale = width / this.imageEl.OriginHeight;
27916             
27917             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27918                 height = this.thumbEl.getWidth();
27919                 this.baseScale = height / this.imageEl.OriginHeight;
27920             }
27921             
27922             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27923                 height = this.thumbEl.getWidth();
27924                 this.baseScale = height / this.imageEl.OriginHeight;
27925                 
27926                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27927                     width = this.thumbEl.getHeight();
27928                     this.baseScale = width / this.imageEl.OriginWidth;
27929                 }
27930             }
27931             
27932             return;
27933         }
27934         
27935         width = this.thumbEl.getWidth();
27936         this.baseScale = width / this.imageEl.OriginWidth;
27937         
27938         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27939             height = this.thumbEl.getHeight();
27940             this.baseScale = height / this.imageEl.OriginHeight;
27941         }
27942         
27943         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27944             
27945             height = this.thumbEl.getHeight();
27946             this.baseScale = height / this.imageEl.OriginHeight;
27947             
27948             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27949                 width = this.thumbEl.getWidth();
27950                 this.baseScale = width / this.imageEl.OriginWidth;
27951             }
27952             
27953         }
27954         
27955         return;
27956     },
27957     
27958     getScaleLevel : function()
27959     {
27960         return this.baseScale * Math.pow(1.1, this.scale);
27961     },
27962     
27963     onTouchStart : function(e)
27964     {
27965         if(!this.canvasLoaded){
27966             this.beforeSelectFile(e);
27967             return;
27968         }
27969         
27970         var touches = e.browserEvent.touches;
27971         
27972         if(!touches){
27973             return;
27974         }
27975         
27976         if(touches.length == 1){
27977             this.onMouseDown(e);
27978             return;
27979         }
27980         
27981         if(touches.length != 2){
27982             return;
27983         }
27984         
27985         var coords = [];
27986         
27987         for(var i = 0, finger; finger = touches[i]; i++){
27988             coords.push(finger.pageX, finger.pageY);
27989         }
27990         
27991         var x = Math.pow(coords[0] - coords[2], 2);
27992         var y = Math.pow(coords[1] - coords[3], 2);
27993         
27994         this.startDistance = Math.sqrt(x + y);
27995         
27996         this.startScale = this.scale;
27997         
27998         this.pinching = true;
27999         this.dragable = false;
28000         
28001     },
28002     
28003     onTouchMove : function(e)
28004     {
28005         if(!this.pinching && !this.dragable){
28006             return;
28007         }
28008         
28009         var touches = e.browserEvent.touches;
28010         
28011         if(!touches){
28012             return;
28013         }
28014         
28015         if(this.dragable){
28016             this.onMouseMove(e);
28017             return;
28018         }
28019         
28020         var coords = [];
28021         
28022         for(var i = 0, finger; finger = touches[i]; i++){
28023             coords.push(finger.pageX, finger.pageY);
28024         }
28025         
28026         var x = Math.pow(coords[0] - coords[2], 2);
28027         var y = Math.pow(coords[1] - coords[3], 2);
28028         
28029         this.endDistance = Math.sqrt(x + y);
28030         
28031         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28032         
28033         if(!this.zoomable()){
28034             this.scale = this.startScale;
28035             return;
28036         }
28037         
28038         this.draw();
28039         
28040     },
28041     
28042     onTouchEnd : function(e)
28043     {
28044         this.pinching = false;
28045         this.dragable = false;
28046         
28047     },
28048     
28049     process : function(file, crop)
28050     {
28051         if(this.loadMask){
28052             this.maskEl.mask(this.loadingText);
28053         }
28054         
28055         this.xhr = new XMLHttpRequest();
28056         
28057         file.xhr = this.xhr;
28058
28059         this.xhr.open(this.method, this.url, true);
28060         
28061         var headers = {
28062             "Accept": "application/json",
28063             "Cache-Control": "no-cache",
28064             "X-Requested-With": "XMLHttpRequest"
28065         };
28066         
28067         for (var headerName in headers) {
28068             var headerValue = headers[headerName];
28069             if (headerValue) {
28070                 this.xhr.setRequestHeader(headerName, headerValue);
28071             }
28072         }
28073         
28074         var _this = this;
28075         
28076         this.xhr.onload = function()
28077         {
28078             _this.xhrOnLoad(_this.xhr);
28079         }
28080         
28081         this.xhr.onerror = function()
28082         {
28083             _this.xhrOnError(_this.xhr);
28084         }
28085         
28086         var formData = new FormData();
28087
28088         formData.append('returnHTML', 'NO');
28089         
28090         if(crop){
28091             formData.append('crop', crop);
28092         }
28093         
28094         if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28095             formData.append(this.paramName, file, file.name);
28096         }
28097         
28098         if(typeof(file.filename) != 'undefined'){
28099             formData.append('filename', file.filename);
28100         }
28101         
28102         if(typeof(file.mimetype) != 'undefined'){
28103             formData.append('mimetype', file.mimetype);
28104         }
28105         
28106         if(this.fireEvent('arrange', this, formData) != false){
28107             this.xhr.send(formData);
28108         };
28109     },
28110     
28111     xhrOnLoad : function(xhr)
28112     {
28113         if(this.loadMask){
28114             this.maskEl.unmask();
28115         }
28116         
28117         if (xhr.readyState !== 4) {
28118             this.fireEvent('exception', this, xhr);
28119             return;
28120         }
28121
28122         var response = Roo.decode(xhr.responseText);
28123         
28124         if(!response.success){
28125             this.fireEvent('exception', this, xhr);
28126             return;
28127         }
28128         
28129         var response = Roo.decode(xhr.responseText);
28130         
28131         this.fireEvent('upload', this, response);
28132         
28133     },
28134     
28135     xhrOnError : function()
28136     {
28137         if(this.loadMask){
28138             this.maskEl.unmask();
28139         }
28140         
28141         Roo.log('xhr on error');
28142         
28143         var response = Roo.decode(xhr.responseText);
28144           
28145         Roo.log(response);
28146         
28147     },
28148     
28149     prepare : function(file)
28150     {   
28151         if(this.loadMask){
28152             this.maskEl.mask(this.loadingText);
28153         }
28154         
28155         this.file = false;
28156         this.exif = {};
28157         
28158         if(typeof(file) === 'string'){
28159             this.loadCanvas(file);
28160             return;
28161         }
28162         
28163         if(!file || !this.urlAPI){
28164             return;
28165         }
28166         
28167         this.file = file;
28168         this.cropType = file.type;
28169         
28170         var _this = this;
28171         
28172         if(this.fireEvent('prepare', this, this.file) != false){
28173             
28174             var reader = new FileReader();
28175             
28176             reader.onload = function (e) {
28177                 if (e.target.error) {
28178                     Roo.log(e.target.error);
28179                     return;
28180                 }
28181                 
28182                 var buffer = e.target.result,
28183                     dataView = new DataView(buffer),
28184                     offset = 2,
28185                     maxOffset = dataView.byteLength - 4,
28186                     markerBytes,
28187                     markerLength;
28188                 
28189                 if (dataView.getUint16(0) === 0xffd8) {
28190                     while (offset < maxOffset) {
28191                         markerBytes = dataView.getUint16(offset);
28192                         
28193                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28194                             markerLength = dataView.getUint16(offset + 2) + 2;
28195                             if (offset + markerLength > dataView.byteLength) {
28196                                 Roo.log('Invalid meta data: Invalid segment size.');
28197                                 break;
28198                             }
28199                             
28200                             if(markerBytes == 0xffe1){
28201                                 _this.parseExifData(
28202                                     dataView,
28203                                     offset,
28204                                     markerLength
28205                                 );
28206                             }
28207                             
28208                             offset += markerLength;
28209                             
28210                             continue;
28211                         }
28212                         
28213                         break;
28214                     }
28215                     
28216                 }
28217                 
28218                 var url = _this.urlAPI.createObjectURL(_this.file);
28219                 
28220                 _this.loadCanvas(url);
28221                 
28222                 return;
28223             }
28224             
28225             reader.readAsArrayBuffer(this.file);
28226             
28227         }
28228         
28229     },
28230     
28231     parseExifData : function(dataView, offset, length)
28232     {
28233         var tiffOffset = offset + 10,
28234             littleEndian,
28235             dirOffset;
28236     
28237         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28238             // No Exif data, might be XMP data instead
28239             return;
28240         }
28241         
28242         // Check for the ASCII code for "Exif" (0x45786966):
28243         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28244             // No Exif data, might be XMP data instead
28245             return;
28246         }
28247         if (tiffOffset + 8 > dataView.byteLength) {
28248             Roo.log('Invalid Exif data: Invalid segment size.');
28249             return;
28250         }
28251         // Check for the two null bytes:
28252         if (dataView.getUint16(offset + 8) !== 0x0000) {
28253             Roo.log('Invalid Exif data: Missing byte alignment offset.');
28254             return;
28255         }
28256         // Check the byte alignment:
28257         switch (dataView.getUint16(tiffOffset)) {
28258         case 0x4949:
28259             littleEndian = true;
28260             break;
28261         case 0x4D4D:
28262             littleEndian = false;
28263             break;
28264         default:
28265             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28266             return;
28267         }
28268         // Check for the TIFF tag marker (0x002A):
28269         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28270             Roo.log('Invalid Exif data: Missing TIFF marker.');
28271             return;
28272         }
28273         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28274         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28275         
28276         this.parseExifTags(
28277             dataView,
28278             tiffOffset,
28279             tiffOffset + dirOffset,
28280             littleEndian
28281         );
28282     },
28283     
28284     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28285     {
28286         var tagsNumber,
28287             dirEndOffset,
28288             i;
28289         if (dirOffset + 6 > dataView.byteLength) {
28290             Roo.log('Invalid Exif data: Invalid directory offset.');
28291             return;
28292         }
28293         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28294         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28295         if (dirEndOffset + 4 > dataView.byteLength) {
28296             Roo.log('Invalid Exif data: Invalid directory size.');
28297             return;
28298         }
28299         for (i = 0; i < tagsNumber; i += 1) {
28300             this.parseExifTag(
28301                 dataView,
28302                 tiffOffset,
28303                 dirOffset + 2 + 12 * i, // tag offset
28304                 littleEndian
28305             );
28306         }
28307         // Return the offset to the next directory:
28308         return dataView.getUint32(dirEndOffset, littleEndian);
28309     },
28310     
28311     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
28312     {
28313         var tag = dataView.getUint16(offset, littleEndian);
28314         
28315         this.exif[tag] = this.getExifValue(
28316             dataView,
28317             tiffOffset,
28318             offset,
28319             dataView.getUint16(offset + 2, littleEndian), // tag type
28320             dataView.getUint32(offset + 4, littleEndian), // tag length
28321             littleEndian
28322         );
28323     },
28324     
28325     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28326     {
28327         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28328             tagSize,
28329             dataOffset,
28330             values,
28331             i,
28332             str,
28333             c;
28334     
28335         if (!tagType) {
28336             Roo.log('Invalid Exif data: Invalid tag type.');
28337             return;
28338         }
28339         
28340         tagSize = tagType.size * length;
28341         // Determine if the value is contained in the dataOffset bytes,
28342         // or if the value at the dataOffset is a pointer to the actual data:
28343         dataOffset = tagSize > 4 ?
28344                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28345         if (dataOffset + tagSize > dataView.byteLength) {
28346             Roo.log('Invalid Exif data: Invalid data offset.');
28347             return;
28348         }
28349         if (length === 1) {
28350             return tagType.getValue(dataView, dataOffset, littleEndian);
28351         }
28352         values = [];
28353         for (i = 0; i < length; i += 1) {
28354             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28355         }
28356         
28357         if (tagType.ascii) {
28358             str = '';
28359             // Concatenate the chars:
28360             for (i = 0; i < values.length; i += 1) {
28361                 c = values[i];
28362                 // Ignore the terminating NULL byte(s):
28363                 if (c === '\u0000') {
28364                     break;
28365                 }
28366                 str += c;
28367             }
28368             return str;
28369         }
28370         return values;
28371     }
28372     
28373 });
28374
28375 Roo.apply(Roo.bootstrap.UploadCropbox, {
28376     tags : {
28377         'Orientation': 0x0112
28378     },
28379     
28380     Orientation: {
28381             1: 0, //'top-left',
28382 //            2: 'top-right',
28383             3: 180, //'bottom-right',
28384 //            4: 'bottom-left',
28385 //            5: 'left-top',
28386             6: 90, //'right-top',
28387 //            7: 'right-bottom',
28388             8: 270 //'left-bottom'
28389     },
28390     
28391     exifTagTypes : {
28392         // byte, 8-bit unsigned int:
28393         1: {
28394             getValue: function (dataView, dataOffset) {
28395                 return dataView.getUint8(dataOffset);
28396             },
28397             size: 1
28398         },
28399         // ascii, 8-bit byte:
28400         2: {
28401             getValue: function (dataView, dataOffset) {
28402                 return String.fromCharCode(dataView.getUint8(dataOffset));
28403             },
28404             size: 1,
28405             ascii: true
28406         },
28407         // short, 16 bit int:
28408         3: {
28409             getValue: function (dataView, dataOffset, littleEndian) {
28410                 return dataView.getUint16(dataOffset, littleEndian);
28411             },
28412             size: 2
28413         },
28414         // long, 32 bit int:
28415         4: {
28416             getValue: function (dataView, dataOffset, littleEndian) {
28417                 return dataView.getUint32(dataOffset, littleEndian);
28418             },
28419             size: 4
28420         },
28421         // rational = two long values, first is numerator, second is denominator:
28422         5: {
28423             getValue: function (dataView, dataOffset, littleEndian) {
28424                 return dataView.getUint32(dataOffset, littleEndian) /
28425                     dataView.getUint32(dataOffset + 4, littleEndian);
28426             },
28427             size: 8
28428         },
28429         // slong, 32 bit signed int:
28430         9: {
28431             getValue: function (dataView, dataOffset, littleEndian) {
28432                 return dataView.getInt32(dataOffset, littleEndian);
28433             },
28434             size: 4
28435         },
28436         // srational, two slongs, first is numerator, second is denominator:
28437         10: {
28438             getValue: function (dataView, dataOffset, littleEndian) {
28439                 return dataView.getInt32(dataOffset, littleEndian) /
28440                     dataView.getInt32(dataOffset + 4, littleEndian);
28441             },
28442             size: 8
28443         }
28444     },
28445     
28446     footer : {
28447         STANDARD : [
28448             {
28449                 tag : 'div',
28450                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28451                 action : 'rotate-left',
28452                 cn : [
28453                     {
28454                         tag : 'button',
28455                         cls : 'btn btn-default',
28456                         html : '<i class="fa fa-undo"></i>'
28457                     }
28458                 ]
28459             },
28460             {
28461                 tag : 'div',
28462                 cls : 'btn-group roo-upload-cropbox-picture',
28463                 action : 'picture',
28464                 cn : [
28465                     {
28466                         tag : 'button',
28467                         cls : 'btn btn-default',
28468                         html : '<i class="fa fa-picture-o"></i>'
28469                     }
28470                 ]
28471             },
28472             {
28473                 tag : 'div',
28474                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28475                 action : 'rotate-right',
28476                 cn : [
28477                     {
28478                         tag : 'button',
28479                         cls : 'btn btn-default',
28480                         html : '<i class="fa fa-repeat"></i>'
28481                     }
28482                 ]
28483             }
28484         ],
28485         DOCUMENT : [
28486             {
28487                 tag : 'div',
28488                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28489                 action : 'rotate-left',
28490                 cn : [
28491                     {
28492                         tag : 'button',
28493                         cls : 'btn btn-default',
28494                         html : '<i class="fa fa-undo"></i>'
28495                     }
28496                 ]
28497             },
28498             {
28499                 tag : 'div',
28500                 cls : 'btn-group roo-upload-cropbox-download',
28501                 action : 'download',
28502                 cn : [
28503                     {
28504                         tag : 'button',
28505                         cls : 'btn btn-default',
28506                         html : '<i class="fa fa-download"></i>'
28507                     }
28508                 ]
28509             },
28510             {
28511                 tag : 'div',
28512                 cls : 'btn-group roo-upload-cropbox-crop',
28513                 action : 'crop',
28514                 cn : [
28515                     {
28516                         tag : 'button',
28517                         cls : 'btn btn-default',
28518                         html : '<i class="fa fa-crop"></i>'
28519                     }
28520                 ]
28521             },
28522             {
28523                 tag : 'div',
28524                 cls : 'btn-group roo-upload-cropbox-trash',
28525                 action : 'trash',
28526                 cn : [
28527                     {
28528                         tag : 'button',
28529                         cls : 'btn btn-default',
28530                         html : '<i class="fa fa-trash"></i>'
28531                     }
28532                 ]
28533             },
28534             {
28535                 tag : 'div',
28536                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28537                 action : 'rotate-right',
28538                 cn : [
28539                     {
28540                         tag : 'button',
28541                         cls : 'btn btn-default',
28542                         html : '<i class="fa fa-repeat"></i>'
28543                     }
28544                 ]
28545             }
28546         ],
28547         ROTATOR : [
28548             {
28549                 tag : 'div',
28550                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28551                 action : 'rotate-left',
28552                 cn : [
28553                     {
28554                         tag : 'button',
28555                         cls : 'btn btn-default',
28556                         html : '<i class="fa fa-undo"></i>'
28557                     }
28558                 ]
28559             },
28560             {
28561                 tag : 'div',
28562                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28563                 action : 'rotate-right',
28564                 cn : [
28565                     {
28566                         tag : 'button',
28567                         cls : 'btn btn-default',
28568                         html : '<i class="fa fa-repeat"></i>'
28569                     }
28570                 ]
28571             }
28572         ]
28573     }
28574 });
28575
28576 /*
28577 * Licence: LGPL
28578 */
28579
28580 /**
28581  * @class Roo.bootstrap.DocumentManager
28582  * @extends Roo.bootstrap.Component
28583  * Bootstrap DocumentManager class
28584  * @cfg {String} paramName default 'imageUpload'
28585  * @cfg {String} toolTipName default 'filename'
28586  * @cfg {String} method default POST
28587  * @cfg {String} url action url
28588  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28589  * @cfg {Boolean} multiple multiple upload default true
28590  * @cfg {Number} thumbSize default 300
28591  * @cfg {String} fieldLabel
28592  * @cfg {Number} labelWidth default 4
28593  * @cfg {String} labelAlign (left|top) default left
28594  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28595 * @cfg {Number} labellg set the width of label (1-12)
28596  * @cfg {Number} labelmd set the width of label (1-12)
28597  * @cfg {Number} labelsm set the width of label (1-12)
28598  * @cfg {Number} labelxs set the width of label (1-12)
28599  * 
28600  * @constructor
28601  * Create a new DocumentManager
28602  * @param {Object} config The config object
28603  */
28604
28605 Roo.bootstrap.DocumentManager = function(config){
28606     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28607     
28608     this.files = [];
28609     this.delegates = [];
28610     
28611     this.addEvents({
28612         /**
28613          * @event initial
28614          * Fire when initial the DocumentManager
28615          * @param {Roo.bootstrap.DocumentManager} this
28616          */
28617         "initial" : true,
28618         /**
28619          * @event inspect
28620          * inspect selected file
28621          * @param {Roo.bootstrap.DocumentManager} this
28622          * @param {File} file
28623          */
28624         "inspect" : true,
28625         /**
28626          * @event exception
28627          * Fire when xhr load exception
28628          * @param {Roo.bootstrap.DocumentManager} this
28629          * @param {XMLHttpRequest} xhr
28630          */
28631         "exception" : true,
28632         /**
28633          * @event afterupload
28634          * Fire when xhr load exception
28635          * @param {Roo.bootstrap.DocumentManager} this
28636          * @param {XMLHttpRequest} xhr
28637          */
28638         "afterupload" : true,
28639         /**
28640          * @event prepare
28641          * prepare the form data
28642          * @param {Roo.bootstrap.DocumentManager} this
28643          * @param {Object} formData
28644          */
28645         "prepare" : true,
28646         /**
28647          * @event remove
28648          * Fire when remove the file
28649          * @param {Roo.bootstrap.DocumentManager} this
28650          * @param {Object} file
28651          */
28652         "remove" : true,
28653         /**
28654          * @event refresh
28655          * Fire after refresh the file
28656          * @param {Roo.bootstrap.DocumentManager} this
28657          */
28658         "refresh" : true,
28659         /**
28660          * @event click
28661          * Fire after click the image
28662          * @param {Roo.bootstrap.DocumentManager} this
28663          * @param {Object} file
28664          */
28665         "click" : true,
28666         /**
28667          * @event edit
28668          * Fire when upload a image and editable set to true
28669          * @param {Roo.bootstrap.DocumentManager} this
28670          * @param {Object} file
28671          */
28672         "edit" : true,
28673         /**
28674          * @event beforeselectfile
28675          * Fire before select file
28676          * @param {Roo.bootstrap.DocumentManager} this
28677          */
28678         "beforeselectfile" : true,
28679         /**
28680          * @event process
28681          * Fire before process file
28682          * @param {Roo.bootstrap.DocumentManager} this
28683          * @param {Object} file
28684          */
28685         "process" : true,
28686         /**
28687          * @event previewrendered
28688          * Fire when preview rendered
28689          * @param {Roo.bootstrap.DocumentManager} this
28690          * @param {Object} file
28691          */
28692         "previewrendered" : true
28693         
28694     });
28695 };
28696
28697 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
28698     
28699     boxes : 0,
28700     inputName : '',
28701     thumbSize : 300,
28702     multiple : true,
28703     files : false,
28704     method : 'POST',
28705     url : '',
28706     paramName : 'imageUpload',
28707     toolTipName : 'filename',
28708     fieldLabel : '',
28709     labelWidth : 4,
28710     labelAlign : 'left',
28711     editable : true,
28712     delegates : false,
28713     xhr : false, 
28714     
28715     labellg : 0,
28716     labelmd : 0,
28717     labelsm : 0,
28718     labelxs : 0,
28719     
28720     getAutoCreate : function()
28721     {   
28722         var managerWidget = {
28723             tag : 'div',
28724             cls : 'roo-document-manager',
28725             cn : [
28726                 {
28727                     tag : 'input',
28728                     cls : 'roo-document-manager-selector',
28729                     type : 'file'
28730                 },
28731                 {
28732                     tag : 'div',
28733                     cls : 'roo-document-manager-uploader',
28734                     cn : [
28735                         {
28736                             tag : 'div',
28737                             cls : 'roo-document-manager-upload-btn',
28738                             html : '<i class="fa fa-plus"></i>'
28739                         }
28740                     ]
28741                     
28742                 }
28743             ]
28744         };
28745         
28746         var content = [
28747             {
28748                 tag : 'div',
28749                 cls : 'column col-md-12',
28750                 cn : managerWidget
28751             }
28752         ];
28753         
28754         if(this.fieldLabel.length){
28755             
28756             content = [
28757                 {
28758                     tag : 'div',
28759                     cls : 'column col-md-12',
28760                     html : this.fieldLabel
28761                 },
28762                 {
28763                     tag : 'div',
28764                     cls : 'column col-md-12',
28765                     cn : managerWidget
28766                 }
28767             ];
28768
28769             if(this.labelAlign == 'left'){
28770                 content = [
28771                     {
28772                         tag : 'div',
28773                         cls : 'column',
28774                         html : this.fieldLabel
28775                     },
28776                     {
28777                         tag : 'div',
28778                         cls : 'column',
28779                         cn : managerWidget
28780                     }
28781                 ];
28782                 
28783                 if(this.labelWidth > 12){
28784                     content[0].style = "width: " + this.labelWidth + 'px';
28785                 }
28786
28787                 if(this.labelWidth < 13 && this.labelmd == 0){
28788                     this.labelmd = this.labelWidth;
28789                 }
28790
28791                 if(this.labellg > 0){
28792                     content[0].cls += ' col-lg-' + this.labellg;
28793                     content[1].cls += ' col-lg-' + (12 - this.labellg);
28794                 }
28795
28796                 if(this.labelmd > 0){
28797                     content[0].cls += ' col-md-' + this.labelmd;
28798                     content[1].cls += ' col-md-' + (12 - this.labelmd);
28799                 }
28800
28801                 if(this.labelsm > 0){
28802                     content[0].cls += ' col-sm-' + this.labelsm;
28803                     content[1].cls += ' col-sm-' + (12 - this.labelsm);
28804                 }
28805
28806                 if(this.labelxs > 0){
28807                     content[0].cls += ' col-xs-' + this.labelxs;
28808                     content[1].cls += ' col-xs-' + (12 - this.labelxs);
28809                 }
28810                 
28811             }
28812         }
28813         
28814         var cfg = {
28815             tag : 'div',
28816             cls : 'row clearfix',
28817             cn : content
28818         };
28819         
28820         return cfg;
28821         
28822     },
28823     
28824     initEvents : function()
28825     {
28826         this.managerEl = this.el.select('.roo-document-manager', true).first();
28827         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28828         
28829         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28830         this.selectorEl.hide();
28831         
28832         if(this.multiple){
28833             this.selectorEl.attr('multiple', 'multiple');
28834         }
28835         
28836         this.selectorEl.on('change', this.onFileSelected, this);
28837         
28838         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28839         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28840         
28841         this.uploader.on('click', this.onUploaderClick, this);
28842         
28843         this.renderProgressDialog();
28844         
28845         var _this = this;
28846         
28847         window.addEventListener("resize", function() { _this.refresh(); } );
28848         
28849         this.fireEvent('initial', this);
28850     },
28851     
28852     renderProgressDialog : function()
28853     {
28854         var _this = this;
28855         
28856         this.progressDialog = new Roo.bootstrap.Modal({
28857             cls : 'roo-document-manager-progress-dialog',
28858             allow_close : false,
28859             title : '',
28860             buttons : [
28861                 {
28862                     name  :'cancel',
28863                     weight : 'danger',
28864                     html : 'Cancel'
28865                 }
28866             ], 
28867             listeners : { 
28868                 btnclick : function() {
28869                     _this.uploadCancel();
28870                     this.hide();
28871                 }
28872             }
28873         });
28874          
28875         this.progressDialog.render(Roo.get(document.body));
28876          
28877         this.progress = new Roo.bootstrap.Progress({
28878             cls : 'roo-document-manager-progress',
28879             active : true,
28880             striped : true
28881         });
28882         
28883         this.progress.render(this.progressDialog.getChildContainer());
28884         
28885         this.progressBar = new Roo.bootstrap.ProgressBar({
28886             cls : 'roo-document-manager-progress-bar',
28887             aria_valuenow : 0,
28888             aria_valuemin : 0,
28889             aria_valuemax : 12,
28890             panel : 'success'
28891         });
28892         
28893         this.progressBar.render(this.progress.getChildContainer());
28894     },
28895     
28896     onUploaderClick : function(e)
28897     {
28898         e.preventDefault();
28899      
28900         if(this.fireEvent('beforeselectfile', this) != false){
28901             this.selectorEl.dom.click();
28902         }
28903         
28904     },
28905     
28906     onFileSelected : function(e)
28907     {
28908         e.preventDefault();
28909         
28910         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28911             return;
28912         }
28913         
28914         Roo.each(this.selectorEl.dom.files, function(file){
28915             if(this.fireEvent('inspect', this, file) != false){
28916                 this.files.push(file);
28917             }
28918         }, this);
28919         
28920         this.queue();
28921         
28922     },
28923     
28924     queue : function()
28925     {
28926         this.selectorEl.dom.value = '';
28927         
28928         if(!this.files || !this.files.length){
28929             return;
28930         }
28931         
28932         if(this.boxes > 0 && this.files.length > this.boxes){
28933             this.files = this.files.slice(0, this.boxes);
28934         }
28935         
28936         this.uploader.show();
28937         
28938         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28939             this.uploader.hide();
28940         }
28941         
28942         var _this = this;
28943         
28944         var files = [];
28945         
28946         var docs = [];
28947         
28948         Roo.each(this.files, function(file){
28949             
28950             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28951                 var f = this.renderPreview(file);
28952                 files.push(f);
28953                 return;
28954             }
28955             
28956             if(file.type.indexOf('image') != -1){
28957                 this.delegates.push(
28958                     (function(){
28959                         _this.process(file);
28960                     }).createDelegate(this)
28961                 );
28962         
28963                 return;
28964             }
28965             
28966             docs.push(
28967                 (function(){
28968                     _this.process(file);
28969                 }).createDelegate(this)
28970             );
28971             
28972         }, this);
28973         
28974         this.files = files;
28975         
28976         this.delegates = this.delegates.concat(docs);
28977         
28978         if(!this.delegates.length){
28979             this.refresh();
28980             return;
28981         }
28982         
28983         this.progressBar.aria_valuemax = this.delegates.length;
28984         
28985         this.arrange();
28986         
28987         return;
28988     },
28989     
28990     arrange : function()
28991     {
28992         if(!this.delegates.length){
28993             this.progressDialog.hide();
28994             this.refresh();
28995             return;
28996         }
28997         
28998         var delegate = this.delegates.shift();
28999         
29000         this.progressDialog.show();
29001         
29002         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29003         
29004         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29005         
29006         delegate();
29007     },
29008     
29009     refresh : function()
29010     {
29011         this.uploader.show();
29012         
29013         if(this.boxes > 0 && this.files.length > this.boxes - 1){
29014             this.uploader.hide();
29015         }
29016         
29017         Roo.isTouch ? this.closable(false) : this.closable(true);
29018         
29019         this.fireEvent('refresh', this);
29020     },
29021     
29022     onRemove : function(e, el, o)
29023     {
29024         e.preventDefault();
29025         
29026         this.fireEvent('remove', this, o);
29027         
29028     },
29029     
29030     remove : function(o)
29031     {
29032         var files = [];
29033         
29034         Roo.each(this.files, function(file){
29035             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29036                 files.push(file);
29037                 return;
29038             }
29039
29040             o.target.remove();
29041
29042         }, this);
29043         
29044         this.files = files;
29045         
29046         this.refresh();
29047     },
29048     
29049     clear : function()
29050     {
29051         Roo.each(this.files, function(file){
29052             if(!file.target){
29053                 return;
29054             }
29055             
29056             file.target.remove();
29057
29058         }, this);
29059         
29060         this.files = [];
29061         
29062         this.refresh();
29063     },
29064     
29065     onClick : function(e, el, o)
29066     {
29067         e.preventDefault();
29068         
29069         this.fireEvent('click', this, o);
29070         
29071     },
29072     
29073     closable : function(closable)
29074     {
29075         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29076             
29077             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29078             
29079             if(closable){
29080                 el.show();
29081                 return;
29082             }
29083             
29084             el.hide();
29085             
29086         }, this);
29087     },
29088     
29089     xhrOnLoad : function(xhr)
29090     {
29091         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29092             el.remove();
29093         }, this);
29094         
29095         if (xhr.readyState !== 4) {
29096             this.arrange();
29097             this.fireEvent('exception', this, xhr);
29098             return;
29099         }
29100
29101         var response = Roo.decode(xhr.responseText);
29102         
29103         if(!response.success){
29104             this.arrange();
29105             this.fireEvent('exception', this, xhr);
29106             return;
29107         }
29108         
29109         var file = this.renderPreview(response.data);
29110         
29111         this.files.push(file);
29112         
29113         this.arrange();
29114         
29115         this.fireEvent('afterupload', this, xhr);
29116         
29117     },
29118     
29119     xhrOnError : function(xhr)
29120     {
29121         Roo.log('xhr on error');
29122         
29123         var response = Roo.decode(xhr.responseText);
29124           
29125         Roo.log(response);
29126         
29127         this.arrange();
29128     },
29129     
29130     process : function(file)
29131     {
29132         if(this.fireEvent('process', this, file) !== false){
29133             if(this.editable && file.type.indexOf('image') != -1){
29134                 this.fireEvent('edit', this, file);
29135                 return;
29136             }
29137
29138             this.uploadStart(file, false);
29139
29140             return;
29141         }
29142         
29143     },
29144     
29145     uploadStart : function(file, crop)
29146     {
29147         this.xhr = new XMLHttpRequest();
29148         
29149         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29150             this.arrange();
29151             return;
29152         }
29153         
29154         file.xhr = this.xhr;
29155             
29156         this.managerEl.createChild({
29157             tag : 'div',
29158             cls : 'roo-document-manager-loading',
29159             cn : [
29160                 {
29161                     tag : 'div',
29162                     tooltip : file.name,
29163                     cls : 'roo-document-manager-thumb',
29164                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29165                 }
29166             ]
29167
29168         });
29169
29170         this.xhr.open(this.method, this.url, true);
29171         
29172         var headers = {
29173             "Accept": "application/json",
29174             "Cache-Control": "no-cache",
29175             "X-Requested-With": "XMLHttpRequest"
29176         };
29177         
29178         for (var headerName in headers) {
29179             var headerValue = headers[headerName];
29180             if (headerValue) {
29181                 this.xhr.setRequestHeader(headerName, headerValue);
29182             }
29183         }
29184         
29185         var _this = this;
29186         
29187         this.xhr.onload = function()
29188         {
29189             _this.xhrOnLoad(_this.xhr);
29190         }
29191         
29192         this.xhr.onerror = function()
29193         {
29194             _this.xhrOnError(_this.xhr);
29195         }
29196         
29197         var formData = new FormData();
29198
29199         formData.append('returnHTML', 'NO');
29200         
29201         if(crop){
29202             formData.append('crop', crop);
29203         }
29204         
29205         formData.append(this.paramName, file, file.name);
29206         
29207         var options = {
29208             file : file, 
29209             manually : false
29210         };
29211         
29212         if(this.fireEvent('prepare', this, formData, options) != false){
29213             
29214             if(options.manually){
29215                 return;
29216             }
29217             
29218             this.xhr.send(formData);
29219             return;
29220         };
29221         
29222         this.uploadCancel();
29223     },
29224     
29225     uploadCancel : function()
29226     {
29227         if (this.xhr) {
29228             this.xhr.abort();
29229         }
29230         
29231         this.delegates = [];
29232         
29233         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29234             el.remove();
29235         }, this);
29236         
29237         this.arrange();
29238     },
29239     
29240     renderPreview : function(file)
29241     {
29242         if(typeof(file.target) != 'undefined' && file.target){
29243             return file;
29244         }
29245         
29246         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29247         
29248         var previewEl = this.managerEl.createChild({
29249             tag : 'div',
29250             cls : 'roo-document-manager-preview',
29251             cn : [
29252                 {
29253                     tag : 'div',
29254                     tooltip : file[this.toolTipName],
29255                     cls : 'roo-document-manager-thumb',
29256                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29257                 },
29258                 {
29259                     tag : 'button',
29260                     cls : 'close',
29261                     html : '<i class="fa fa-times-circle"></i>'
29262                 }
29263             ]
29264         });
29265
29266         var close = previewEl.select('button.close', true).first();
29267
29268         close.on('click', this.onRemove, this, file);
29269
29270         file.target = previewEl;
29271
29272         var image = previewEl.select('img', true).first();
29273         
29274         var _this = this;
29275         
29276         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29277         
29278         image.on('click', this.onClick, this, file);
29279         
29280         this.fireEvent('previewrendered', this, file);
29281         
29282         return file;
29283         
29284     },
29285     
29286     onPreviewLoad : function(file, image)
29287     {
29288         if(typeof(file.target) == 'undefined' || !file.target){
29289             return;
29290         }
29291         
29292         var width = image.dom.naturalWidth || image.dom.width;
29293         var height = image.dom.naturalHeight || image.dom.height;
29294         
29295         if(width > height){
29296             file.target.addClass('wide');
29297             return;
29298         }
29299         
29300         file.target.addClass('tall');
29301         return;
29302         
29303     },
29304     
29305     uploadFromSource : function(file, crop)
29306     {
29307         this.xhr = new XMLHttpRequest();
29308         
29309         this.managerEl.createChild({
29310             tag : 'div',
29311             cls : 'roo-document-manager-loading',
29312             cn : [
29313                 {
29314                     tag : 'div',
29315                     tooltip : file.name,
29316                     cls : 'roo-document-manager-thumb',
29317                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29318                 }
29319             ]
29320
29321         });
29322
29323         this.xhr.open(this.method, this.url, true);
29324         
29325         var headers = {
29326             "Accept": "application/json",
29327             "Cache-Control": "no-cache",
29328             "X-Requested-With": "XMLHttpRequest"
29329         };
29330         
29331         for (var headerName in headers) {
29332             var headerValue = headers[headerName];
29333             if (headerValue) {
29334                 this.xhr.setRequestHeader(headerName, headerValue);
29335             }
29336         }
29337         
29338         var _this = this;
29339         
29340         this.xhr.onload = function()
29341         {
29342             _this.xhrOnLoad(_this.xhr);
29343         }
29344         
29345         this.xhr.onerror = function()
29346         {
29347             _this.xhrOnError(_this.xhr);
29348         }
29349         
29350         var formData = new FormData();
29351
29352         formData.append('returnHTML', 'NO');
29353         
29354         formData.append('crop', crop);
29355         
29356         if(typeof(file.filename) != 'undefined'){
29357             formData.append('filename', file.filename);
29358         }
29359         
29360         if(typeof(file.mimetype) != 'undefined'){
29361             formData.append('mimetype', file.mimetype);
29362         }
29363         
29364         Roo.log(formData);
29365         
29366         if(this.fireEvent('prepare', this, formData) != false){
29367             this.xhr.send(formData);
29368         };
29369     }
29370 });
29371
29372 /*
29373 * Licence: LGPL
29374 */
29375
29376 /**
29377  * @class Roo.bootstrap.DocumentViewer
29378  * @extends Roo.bootstrap.Component
29379  * Bootstrap DocumentViewer class
29380  * @cfg {Boolean} showDownload (true|false) show download button (default true)
29381  * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29382  * 
29383  * @constructor
29384  * Create a new DocumentViewer
29385  * @param {Object} config The config object
29386  */
29387
29388 Roo.bootstrap.DocumentViewer = function(config){
29389     Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29390     
29391     this.addEvents({
29392         /**
29393          * @event initial
29394          * Fire after initEvent
29395          * @param {Roo.bootstrap.DocumentViewer} this
29396          */
29397         "initial" : true,
29398         /**
29399          * @event click
29400          * Fire after click
29401          * @param {Roo.bootstrap.DocumentViewer} this
29402          */
29403         "click" : true,
29404         /**
29405          * @event download
29406          * Fire after download button
29407          * @param {Roo.bootstrap.DocumentViewer} this
29408          */
29409         "download" : true,
29410         /**
29411          * @event trash
29412          * Fire after trash button
29413          * @param {Roo.bootstrap.DocumentViewer} this
29414          */
29415         "trash" : true
29416         
29417     });
29418 };
29419
29420 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
29421     
29422     showDownload : true,
29423     
29424     showTrash : true,
29425     
29426     getAutoCreate : function()
29427     {
29428         var cfg = {
29429             tag : 'div',
29430             cls : 'roo-document-viewer',
29431             cn : [
29432                 {
29433                     tag : 'div',
29434                     cls : 'roo-document-viewer-body',
29435                     cn : [
29436                         {
29437                             tag : 'div',
29438                             cls : 'roo-document-viewer-thumb',
29439                             cn : [
29440                                 {
29441                                     tag : 'img',
29442                                     cls : 'roo-document-viewer-image'
29443                                 }
29444                             ]
29445                         }
29446                     ]
29447                 },
29448                 {
29449                     tag : 'div',
29450                     cls : 'roo-document-viewer-footer',
29451                     cn : {
29452                         tag : 'div',
29453                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29454                         cn : [
29455                             {
29456                                 tag : 'div',
29457                                 cls : 'btn-group roo-document-viewer-download',
29458                                 cn : [
29459                                     {
29460                                         tag : 'button',
29461                                         cls : 'btn btn-default',
29462                                         html : '<i class="fa fa-download"></i>'
29463                                     }
29464                                 ]
29465                             },
29466                             {
29467                                 tag : 'div',
29468                                 cls : 'btn-group roo-document-viewer-trash',
29469                                 cn : [
29470                                     {
29471                                         tag : 'button',
29472                                         cls : 'btn btn-default',
29473                                         html : '<i class="fa fa-trash"></i>'
29474                                     }
29475                                 ]
29476                             }
29477                         ]
29478                     }
29479                 }
29480             ]
29481         };
29482         
29483         return cfg;
29484     },
29485     
29486     initEvents : function()
29487     {
29488         this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29489         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29490         
29491         this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29492         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29493         
29494         this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29495         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29496         
29497         this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29498         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29499         
29500         this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29501         this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29502         
29503         this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29504         this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29505         
29506         this.bodyEl.on('click', this.onClick, this);
29507         this.downloadBtn.on('click', this.onDownload, this);
29508         this.trashBtn.on('click', this.onTrash, this);
29509         
29510         this.downloadBtn.hide();
29511         this.trashBtn.hide();
29512         
29513         if(this.showDownload){
29514             this.downloadBtn.show();
29515         }
29516         
29517         if(this.showTrash){
29518             this.trashBtn.show();
29519         }
29520         
29521         if(!this.showDownload && !this.showTrash) {
29522             this.footerEl.hide();
29523         }
29524         
29525     },
29526     
29527     initial : function()
29528     {
29529         this.fireEvent('initial', this);
29530         
29531     },
29532     
29533     onClick : function(e)
29534     {
29535         e.preventDefault();
29536         
29537         this.fireEvent('click', this);
29538     },
29539     
29540     onDownload : function(e)
29541     {
29542         e.preventDefault();
29543         
29544         this.fireEvent('download', this);
29545     },
29546     
29547     onTrash : function(e)
29548     {
29549         e.preventDefault();
29550         
29551         this.fireEvent('trash', this);
29552     }
29553     
29554 });
29555 /*
29556  * - LGPL
29557  *
29558  * nav progress bar
29559  * 
29560  */
29561
29562 /**
29563  * @class Roo.bootstrap.NavProgressBar
29564  * @extends Roo.bootstrap.Component
29565  * Bootstrap NavProgressBar class
29566  * 
29567  * @constructor
29568  * Create a new nav progress bar
29569  * @param {Object} config The config object
29570  */
29571
29572 Roo.bootstrap.NavProgressBar = function(config){
29573     Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29574
29575     this.bullets = this.bullets || [];
29576    
29577 //    Roo.bootstrap.NavProgressBar.register(this);
29578      this.addEvents({
29579         /**
29580              * @event changed
29581              * Fires when the active item changes
29582              * @param {Roo.bootstrap.NavProgressBar} this
29583              * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29584              * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
29585          */
29586         'changed': true
29587      });
29588     
29589 };
29590
29591 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
29592     
29593     bullets : [],
29594     barItems : [],
29595     
29596     getAutoCreate : function()
29597     {
29598         var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29599         
29600         cfg = {
29601             tag : 'div',
29602             cls : 'roo-navigation-bar-group',
29603             cn : [
29604                 {
29605                     tag : 'div',
29606                     cls : 'roo-navigation-top-bar'
29607                 },
29608                 {
29609                     tag : 'div',
29610                     cls : 'roo-navigation-bullets-bar',
29611                     cn : [
29612                         {
29613                             tag : 'ul',
29614                             cls : 'roo-navigation-bar'
29615                         }
29616                     ]
29617                 },
29618                 
29619                 {
29620                     tag : 'div',
29621                     cls : 'roo-navigation-bottom-bar'
29622                 }
29623             ]
29624             
29625         };
29626         
29627         return cfg;
29628         
29629     },
29630     
29631     initEvents: function() 
29632     {
29633         
29634     },
29635     
29636     onRender : function(ct, position) 
29637     {
29638         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29639         
29640         if(this.bullets.length){
29641             Roo.each(this.bullets, function(b){
29642                this.addItem(b);
29643             }, this);
29644         }
29645         
29646         this.format();
29647         
29648     },
29649     
29650     addItem : function(cfg)
29651     {
29652         var item = new Roo.bootstrap.NavProgressItem(cfg);
29653         
29654         item.parentId = this.id;
29655         item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29656         
29657         if(cfg.html){
29658             var top = new Roo.bootstrap.Element({
29659                 tag : 'div',
29660                 cls : 'roo-navigation-bar-text'
29661             });
29662             
29663             var bottom = new Roo.bootstrap.Element({
29664                 tag : 'div',
29665                 cls : 'roo-navigation-bar-text'
29666             });
29667             
29668             top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29669             bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29670             
29671             var topText = new Roo.bootstrap.Element({
29672                 tag : 'span',
29673                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29674             });
29675             
29676             var bottomText = new Roo.bootstrap.Element({
29677                 tag : 'span',
29678                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29679             });
29680             
29681             topText.onRender(top.el, null);
29682             bottomText.onRender(bottom.el, null);
29683             
29684             item.topEl = top;
29685             item.bottomEl = bottom;
29686         }
29687         
29688         this.barItems.push(item);
29689         
29690         return item;
29691     },
29692     
29693     getActive : function()
29694     {
29695         var active = false;
29696         
29697         Roo.each(this.barItems, function(v){
29698             
29699             if (!v.isActive()) {
29700                 return;
29701             }
29702             
29703             active = v;
29704             return false;
29705             
29706         });
29707         
29708         return active;
29709     },
29710     
29711     setActiveItem : function(item)
29712     {
29713         var prev = false;
29714         
29715         Roo.each(this.barItems, function(v){
29716             if (v.rid == item.rid) {
29717                 return ;
29718             }
29719             
29720             if (v.isActive()) {
29721                 v.setActive(false);
29722                 prev = v;
29723             }
29724         });
29725
29726         item.setActive(true);
29727         
29728         this.fireEvent('changed', this, item, prev);
29729     },
29730     
29731     getBarItem: function(rid)
29732     {
29733         var ret = false;
29734         
29735         Roo.each(this.barItems, function(e) {
29736             if (e.rid != rid) {
29737                 return;
29738             }
29739             
29740             ret =  e;
29741             return false;
29742         });
29743         
29744         return ret;
29745     },
29746     
29747     indexOfItem : function(item)
29748     {
29749         var index = false;
29750         
29751         Roo.each(this.barItems, function(v, i){
29752             
29753             if (v.rid != item.rid) {
29754                 return;
29755             }
29756             
29757             index = i;
29758             return false
29759         });
29760         
29761         return index;
29762     },
29763     
29764     setActiveNext : function()
29765     {
29766         var i = this.indexOfItem(this.getActive());
29767         
29768         if (i > this.barItems.length) {
29769             return;
29770         }
29771         
29772         this.setActiveItem(this.barItems[i+1]);
29773     },
29774     
29775     setActivePrev : function()
29776     {
29777         var i = this.indexOfItem(this.getActive());
29778         
29779         if (i  < 1) {
29780             return;
29781         }
29782         
29783         this.setActiveItem(this.barItems[i-1]);
29784     },
29785     
29786     format : function()
29787     {
29788         if(!this.barItems.length){
29789             return;
29790         }
29791      
29792         var width = 100 / this.barItems.length;
29793         
29794         Roo.each(this.barItems, function(i){
29795             i.el.setStyle('width', width + '%');
29796             i.topEl.el.setStyle('width', width + '%');
29797             i.bottomEl.el.setStyle('width', width + '%');
29798         }, this);
29799         
29800     }
29801     
29802 });
29803 /*
29804  * - LGPL
29805  *
29806  * Nav Progress Item
29807  * 
29808  */
29809
29810 /**
29811  * @class Roo.bootstrap.NavProgressItem
29812  * @extends Roo.bootstrap.Component
29813  * Bootstrap NavProgressItem class
29814  * @cfg {String} rid the reference id
29815  * @cfg {Boolean} active (true|false) Is item active default false
29816  * @cfg {Boolean} disabled (true|false) Is item active default false
29817  * @cfg {String} html
29818  * @cfg {String} position (top|bottom) text position default bottom
29819  * @cfg {String} icon show icon instead of number
29820  * 
29821  * @constructor
29822  * Create a new NavProgressItem
29823  * @param {Object} config The config object
29824  */
29825 Roo.bootstrap.NavProgressItem = function(config){
29826     Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29827     this.addEvents({
29828         // raw events
29829         /**
29830          * @event click
29831          * The raw click event for the entire grid.
29832          * @param {Roo.bootstrap.NavProgressItem} this
29833          * @param {Roo.EventObject} e
29834          */
29835         "click" : true
29836     });
29837    
29838 };
29839
29840 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
29841     
29842     rid : '',
29843     active : false,
29844     disabled : false,
29845     html : '',
29846     position : 'bottom',
29847     icon : false,
29848     
29849     getAutoCreate : function()
29850     {
29851         var iconCls = 'roo-navigation-bar-item-icon';
29852         
29853         iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29854         
29855         var cfg = {
29856             tag: 'li',
29857             cls: 'roo-navigation-bar-item',
29858             cn : [
29859                 {
29860                     tag : 'i',
29861                     cls : iconCls
29862                 }
29863             ]
29864         };
29865         
29866         if(this.active){
29867             cfg.cls += ' active';
29868         }
29869         if(this.disabled){
29870             cfg.cls += ' disabled';
29871         }
29872         
29873         return cfg;
29874     },
29875     
29876     disable : function()
29877     {
29878         this.setDisabled(true);
29879     },
29880     
29881     enable : function()
29882     {
29883         this.setDisabled(false);
29884     },
29885     
29886     initEvents: function() 
29887     {
29888         this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29889         
29890         this.iconEl.on('click', this.onClick, this);
29891     },
29892     
29893     onClick : function(e)
29894     {
29895         e.preventDefault();
29896         
29897         if(this.disabled){
29898             return;
29899         }
29900         
29901         if(this.fireEvent('click', this, e) === false){
29902             return;
29903         };
29904         
29905         this.parent().setActiveItem(this);
29906     },
29907     
29908     isActive: function () 
29909     {
29910         return this.active;
29911     },
29912     
29913     setActive : function(state)
29914     {
29915         if(this.active == state){
29916             return;
29917         }
29918         
29919         this.active = state;
29920         
29921         if (state) {
29922             this.el.addClass('active');
29923             return;
29924         }
29925         
29926         this.el.removeClass('active');
29927         
29928         return;
29929     },
29930     
29931     setDisabled : function(state)
29932     {
29933         if(this.disabled == state){
29934             return;
29935         }
29936         
29937         this.disabled = state;
29938         
29939         if (state) {
29940             this.el.addClass('disabled');
29941             return;
29942         }
29943         
29944         this.el.removeClass('disabled');
29945     },
29946     
29947     tooltipEl : function()
29948     {
29949         return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29950     }
29951 });
29952  
29953
29954  /*
29955  * - LGPL
29956  *
29957  * FieldLabel
29958  * 
29959  */
29960
29961 /**
29962  * @class Roo.bootstrap.FieldLabel
29963  * @extends Roo.bootstrap.Component
29964  * Bootstrap FieldLabel class
29965  * @cfg {String} html contents of the element
29966  * @cfg {String} tag tag of the element default label
29967  * @cfg {String} cls class of the element
29968  * @cfg {String} target label target 
29969  * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29970  * @cfg {String} invalidClass default "text-warning"
29971  * @cfg {String} validClass default "text-success"
29972  * @cfg {String} iconTooltip default "This field is required"
29973  * @cfg {String} indicatorpos (left|right) default left
29974  * 
29975  * @constructor
29976  * Create a new FieldLabel
29977  * @param {Object} config The config object
29978  */
29979
29980 Roo.bootstrap.FieldLabel = function(config){
29981     Roo.bootstrap.Element.superclass.constructor.call(this, config);
29982     
29983     this.addEvents({
29984             /**
29985              * @event invalid
29986              * Fires after the field has been marked as invalid.
29987              * @param {Roo.form.FieldLabel} this
29988              * @param {String} msg The validation message
29989              */
29990             invalid : true,
29991             /**
29992              * @event valid
29993              * Fires after the field has been validated with no errors.
29994              * @param {Roo.form.FieldLabel} this
29995              */
29996             valid : true
29997         });
29998 };
29999
30000 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
30001     
30002     tag: 'label',
30003     cls: '',
30004     html: '',
30005     target: '',
30006     allowBlank : true,
30007     invalidClass : 'has-warning',
30008     validClass : 'has-success',
30009     iconTooltip : 'This field is required',
30010     indicatorpos : 'left',
30011     
30012     getAutoCreate : function(){
30013         
30014         var cfg = {
30015             tag : this.tag,
30016             cls : 'roo-bootstrap-field-label ' + this.cls,
30017             for : this.target,
30018             cn : [
30019                 {
30020                     tag : 'i',
30021                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
30022                     tooltip : this.iconTooltip
30023                 },
30024                 {
30025                     tag : 'span',
30026                     html : this.html
30027                 }
30028             ] 
30029         };
30030         
30031         if(this.indicatorpos == 'right'){
30032             var cfg = {
30033                 tag : this.tag,
30034                 cls : 'roo-bootstrap-field-label ' + this.cls,
30035                 for : this.target,
30036                 cn : [
30037                     {
30038                         tag : 'span',
30039                         html : this.html
30040                     },
30041                     {
30042                         tag : 'i',
30043                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30044                         tooltip : this.iconTooltip
30045                     }
30046                 ] 
30047             };
30048         }
30049         
30050         return cfg;
30051     },
30052     
30053     initEvents: function() 
30054     {
30055         Roo.bootstrap.Element.superclass.initEvents.call(this);
30056         
30057         this.indicator = this.indicatorEl();
30058         
30059         if(this.indicator){
30060             this.indicator.removeClass('visible');
30061             this.indicator.addClass('invisible');
30062         }
30063         
30064         Roo.bootstrap.FieldLabel.register(this);
30065     },
30066     
30067     indicatorEl : function()
30068     {
30069         var indicator = this.el.select('i.roo-required-indicator',true).first();
30070         
30071         if(!indicator){
30072             return false;
30073         }
30074         
30075         return indicator;
30076         
30077     },
30078     
30079     /**
30080      * Mark this field as valid
30081      */
30082     markValid : function()
30083     {
30084         if(this.indicator){
30085             this.indicator.removeClass('visible');
30086             this.indicator.addClass('invisible');
30087         }
30088         
30089         this.el.removeClass(this.invalidClass);
30090         
30091         this.el.addClass(this.validClass);
30092         
30093         this.fireEvent('valid', this);
30094     },
30095     
30096     /**
30097      * Mark this field as invalid
30098      * @param {String} msg The validation message
30099      */
30100     markInvalid : function(msg)
30101     {
30102         if(this.indicator){
30103             this.indicator.removeClass('invisible');
30104             this.indicator.addClass('visible');
30105         }
30106         
30107         this.el.removeClass(this.validClass);
30108         
30109         this.el.addClass(this.invalidClass);
30110         
30111         this.fireEvent('invalid', this, msg);
30112     }
30113     
30114    
30115 });
30116
30117 Roo.apply(Roo.bootstrap.FieldLabel, {
30118     
30119     groups: {},
30120     
30121      /**
30122     * register a FieldLabel Group
30123     * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30124     */
30125     register : function(label)
30126     {
30127         if(this.groups.hasOwnProperty(label.target)){
30128             return;
30129         }
30130      
30131         this.groups[label.target] = label;
30132         
30133     },
30134     /**
30135     * fetch a FieldLabel Group based on the target
30136     * @param {string} target
30137     * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30138     */
30139     get: function(target) {
30140         if (typeof(this.groups[target]) == 'undefined') {
30141             return false;
30142         }
30143         
30144         return this.groups[target] ;
30145     }
30146 });
30147
30148  
30149
30150  /*
30151  * - LGPL
30152  *
30153  * page DateSplitField.
30154  * 
30155  */
30156
30157
30158 /**
30159  * @class Roo.bootstrap.DateSplitField
30160  * @extends Roo.bootstrap.Component
30161  * Bootstrap DateSplitField class
30162  * @cfg {string} fieldLabel - the label associated
30163  * @cfg {Number} labelWidth set the width of label (0-12)
30164  * @cfg {String} labelAlign (top|left)
30165  * @cfg {Boolean} dayAllowBlank (true|false) default false
30166  * @cfg {Boolean} monthAllowBlank (true|false) default false
30167  * @cfg {Boolean} yearAllowBlank (true|false) default false
30168  * @cfg {string} dayPlaceholder 
30169  * @cfg {string} monthPlaceholder
30170  * @cfg {string} yearPlaceholder
30171  * @cfg {string} dayFormat default 'd'
30172  * @cfg {string} monthFormat default 'm'
30173  * @cfg {string} yearFormat default 'Y'
30174  * @cfg {Number} labellg set the width of label (1-12)
30175  * @cfg {Number} labelmd set the width of label (1-12)
30176  * @cfg {Number} labelsm set the width of label (1-12)
30177  * @cfg {Number} labelxs set the width of label (1-12)
30178
30179  *     
30180  * @constructor
30181  * Create a new DateSplitField
30182  * @param {Object} config The config object
30183  */
30184
30185 Roo.bootstrap.DateSplitField = function(config){
30186     Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30187     
30188     this.addEvents({
30189         // raw events
30190          /**
30191          * @event years
30192          * getting the data of years
30193          * @param {Roo.bootstrap.DateSplitField} this
30194          * @param {Object} years
30195          */
30196         "years" : true,
30197         /**
30198          * @event days
30199          * getting the data of days
30200          * @param {Roo.bootstrap.DateSplitField} this
30201          * @param {Object} days
30202          */
30203         "days" : true,
30204         /**
30205          * @event invalid
30206          * Fires after the field has been marked as invalid.
30207          * @param {Roo.form.Field} this
30208          * @param {String} msg The validation message
30209          */
30210         invalid : true,
30211        /**
30212          * @event valid
30213          * Fires after the field has been validated with no errors.
30214          * @param {Roo.form.Field} this
30215          */
30216         valid : true
30217     });
30218 };
30219
30220 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
30221     
30222     fieldLabel : '',
30223     labelAlign : 'top',
30224     labelWidth : 3,
30225     dayAllowBlank : false,
30226     monthAllowBlank : false,
30227     yearAllowBlank : false,
30228     dayPlaceholder : '',
30229     monthPlaceholder : '',
30230     yearPlaceholder : '',
30231     dayFormat : 'd',
30232     monthFormat : 'm',
30233     yearFormat : 'Y',
30234     isFormField : true,
30235     labellg : 0,
30236     labelmd : 0,
30237     labelsm : 0,
30238     labelxs : 0,
30239     
30240     getAutoCreate : function()
30241     {
30242         var cfg = {
30243             tag : 'div',
30244             cls : 'row roo-date-split-field-group',
30245             cn : [
30246                 {
30247                     tag : 'input',
30248                     type : 'hidden',
30249                     cls : 'form-hidden-field roo-date-split-field-group-value',
30250                     name : this.name
30251                 }
30252             ]
30253         };
30254         
30255         var labelCls = 'col-md-12';
30256         var contentCls = 'col-md-4';
30257         
30258         if(this.fieldLabel){
30259             
30260             var label = {
30261                 tag : 'div',
30262                 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30263                 cn : [
30264                     {
30265                         tag : 'label',
30266                         html : this.fieldLabel
30267                     }
30268                 ]
30269             };
30270             
30271             if(this.labelAlign == 'left'){
30272             
30273                 if(this.labelWidth > 12){
30274                     label.style = "width: " + this.labelWidth + 'px';
30275                 }
30276
30277                 if(this.labelWidth < 13 && this.labelmd == 0){
30278                     this.labelmd = this.labelWidth;
30279                 }
30280
30281                 if(this.labellg > 0){
30282                     labelCls = ' col-lg-' + this.labellg;
30283                     contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30284                 }
30285
30286                 if(this.labelmd > 0){
30287                     labelCls = ' col-md-' + this.labelmd;
30288                     contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30289                 }
30290
30291                 if(this.labelsm > 0){
30292                     labelCls = ' col-sm-' + this.labelsm;
30293                     contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30294                 }
30295
30296                 if(this.labelxs > 0){
30297                     labelCls = ' col-xs-' + this.labelxs;
30298                     contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30299                 }
30300             }
30301             
30302             label.cls += ' ' + labelCls;
30303             
30304             cfg.cn.push(label);
30305         }
30306         
30307         Roo.each(['day', 'month', 'year'], function(t){
30308             cfg.cn.push({
30309                 tag : 'div',
30310                 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30311             });
30312         }, this);
30313         
30314         return cfg;
30315     },
30316     
30317     inputEl: function ()
30318     {
30319         return this.el.select('.roo-date-split-field-group-value', true).first();
30320     },
30321     
30322     onRender : function(ct, position) 
30323     {
30324         var _this = this;
30325         
30326         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30327         
30328         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30329         
30330         this.dayField = new Roo.bootstrap.ComboBox({
30331             allowBlank : this.dayAllowBlank,
30332             alwaysQuery : true,
30333             displayField : 'value',
30334             editable : false,
30335             fieldLabel : '',
30336             forceSelection : true,
30337             mode : 'local',
30338             placeholder : this.dayPlaceholder,
30339             selectOnFocus : true,
30340             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30341             triggerAction : 'all',
30342             typeAhead : true,
30343             valueField : 'value',
30344             store : new Roo.data.SimpleStore({
30345                 data : (function() {    
30346                     var days = [];
30347                     _this.fireEvent('days', _this, days);
30348                     return days;
30349                 })(),
30350                 fields : [ 'value' ]
30351             }),
30352             listeners : {
30353                 select : function (_self, record, index)
30354                 {
30355                     _this.setValue(_this.getValue());
30356                 }
30357             }
30358         });
30359
30360         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30361         
30362         this.monthField = new Roo.bootstrap.MonthField({
30363             after : '<i class=\"fa fa-calendar\"></i>',
30364             allowBlank : this.monthAllowBlank,
30365             placeholder : this.monthPlaceholder,
30366             readOnly : true,
30367             listeners : {
30368                 render : function (_self)
30369                 {
30370                     this.el.select('span.input-group-addon', true).first().on('click', function(e){
30371                         e.preventDefault();
30372                         _self.focus();
30373                     });
30374                 },
30375                 select : function (_self, oldvalue, newvalue)
30376                 {
30377                     _this.setValue(_this.getValue());
30378                 }
30379             }
30380         });
30381         
30382         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30383         
30384         this.yearField = new Roo.bootstrap.ComboBox({
30385             allowBlank : this.yearAllowBlank,
30386             alwaysQuery : true,
30387             displayField : 'value',
30388             editable : false,
30389             fieldLabel : '',
30390             forceSelection : true,
30391             mode : 'local',
30392             placeholder : this.yearPlaceholder,
30393             selectOnFocus : true,
30394             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30395             triggerAction : 'all',
30396             typeAhead : true,
30397             valueField : 'value',
30398             store : new Roo.data.SimpleStore({
30399                 data : (function() {
30400                     var years = [];
30401                     _this.fireEvent('years', _this, years);
30402                     return years;
30403                 })(),
30404                 fields : [ 'value' ]
30405             }),
30406             listeners : {
30407                 select : function (_self, record, index)
30408                 {
30409                     _this.setValue(_this.getValue());
30410                 }
30411             }
30412         });
30413
30414         this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30415     },
30416     
30417     setValue : function(v, format)
30418     {
30419         this.inputEl.dom.value = v;
30420         
30421         var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30422         
30423         var d = Date.parseDate(v, f);
30424         
30425         if(!d){
30426             this.validate();
30427             return;
30428         }
30429         
30430         this.setDay(d.format(this.dayFormat));
30431         this.setMonth(d.format(this.monthFormat));
30432         this.setYear(d.format(this.yearFormat));
30433         
30434         this.validate();
30435         
30436         return;
30437     },
30438     
30439     setDay : function(v)
30440     {
30441         this.dayField.setValue(v);
30442         this.inputEl.dom.value = this.getValue();
30443         this.validate();
30444         return;
30445     },
30446     
30447     setMonth : function(v)
30448     {
30449         this.monthField.setValue(v, true);
30450         this.inputEl.dom.value = this.getValue();
30451         this.validate();
30452         return;
30453     },
30454     
30455     setYear : function(v)
30456     {
30457         this.yearField.setValue(v);
30458         this.inputEl.dom.value = this.getValue();
30459         this.validate();
30460         return;
30461     },
30462     
30463     getDay : function()
30464     {
30465         return this.dayField.getValue();
30466     },
30467     
30468     getMonth : function()
30469     {
30470         return this.monthField.getValue();
30471     },
30472     
30473     getYear : function()
30474     {
30475         return this.yearField.getValue();
30476     },
30477     
30478     getValue : function()
30479     {
30480         var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30481         
30482         var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30483         
30484         return date;
30485     },
30486     
30487     reset : function()
30488     {
30489         this.setDay('');
30490         this.setMonth('');
30491         this.setYear('');
30492         this.inputEl.dom.value = '';
30493         this.validate();
30494         return;
30495     },
30496     
30497     validate : function()
30498     {
30499         var d = this.dayField.validate();
30500         var m = this.monthField.validate();
30501         var y = this.yearField.validate();
30502         
30503         var valid = true;
30504         
30505         if(
30506                 (!this.dayAllowBlank && !d) ||
30507                 (!this.monthAllowBlank && !m) ||
30508                 (!this.yearAllowBlank && !y)
30509         ){
30510             valid = false;
30511         }
30512         
30513         if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30514             return valid;
30515         }
30516         
30517         if(valid){
30518             this.markValid();
30519             return valid;
30520         }
30521         
30522         this.markInvalid();
30523         
30524         return valid;
30525     },
30526     
30527     markValid : function()
30528     {
30529         
30530         var label = this.el.select('label', true).first();
30531         var icon = this.el.select('i.fa-star', true).first();
30532
30533         if(label && icon){
30534             icon.remove();
30535         }
30536         
30537         this.fireEvent('valid', this);
30538     },
30539     
30540      /**
30541      * Mark this field as invalid
30542      * @param {String} msg The validation message
30543      */
30544     markInvalid : function(msg)
30545     {
30546         
30547         var label = this.el.select('label', true).first();
30548         var icon = this.el.select('i.fa-star', true).first();
30549
30550         if(label && !icon){
30551             this.el.select('.roo-date-split-field-label', true).createChild({
30552                 tag : 'i',
30553                 cls : 'text-danger fa fa-lg fa-star',
30554                 tooltip : 'This field is required',
30555                 style : 'margin-right:5px;'
30556             }, label, true);
30557         }
30558         
30559         this.fireEvent('invalid', this, msg);
30560     },
30561     
30562     clearInvalid : function()
30563     {
30564         var label = this.el.select('label', true).first();
30565         var icon = this.el.select('i.fa-star', true).first();
30566
30567         if(label && icon){
30568             icon.remove();
30569         }
30570         
30571         this.fireEvent('valid', this);
30572     },
30573     
30574     getName: function()
30575     {
30576         return this.name;
30577     }
30578     
30579 });
30580
30581  /**
30582  *
30583  * This is based on 
30584  * http://masonry.desandro.com
30585  *
30586  * The idea is to render all the bricks based on vertical width...
30587  *
30588  * The original code extends 'outlayer' - we might need to use that....
30589  * 
30590  */
30591
30592
30593 /**
30594  * @class Roo.bootstrap.LayoutMasonry
30595  * @extends Roo.bootstrap.Component
30596  * Bootstrap Layout Masonry class
30597  * 
30598  * @constructor
30599  * Create a new Element
30600  * @param {Object} config The config object
30601  */
30602
30603 Roo.bootstrap.LayoutMasonry = function(config){
30604     
30605     Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30606     
30607     this.bricks = [];
30608     
30609     Roo.bootstrap.LayoutMasonry.register(this);
30610     
30611     this.addEvents({
30612         // raw events
30613         /**
30614          * @event layout
30615          * Fire after layout the items
30616          * @param {Roo.bootstrap.LayoutMasonry} this
30617          * @param {Roo.EventObject} e
30618          */
30619         "layout" : true
30620     });
30621     
30622 };
30623
30624 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component,  {
30625     
30626     /**
30627      * @cfg {Boolean} isLayoutInstant = no animation?
30628      */   
30629     isLayoutInstant : false, // needed?
30630    
30631     /**
30632      * @cfg {Number} boxWidth  width of the columns
30633      */   
30634     boxWidth : 450,
30635     
30636       /**
30637      * @cfg {Number} boxHeight  - 0 for square, or fix it at a certian height
30638      */   
30639     boxHeight : 0,
30640     
30641     /**
30642      * @cfg {Number} padWidth padding below box..
30643      */   
30644     padWidth : 10, 
30645     
30646     /**
30647      * @cfg {Number} gutter gutter width..
30648      */   
30649     gutter : 10,
30650     
30651      /**
30652      * @cfg {Number} maxCols maximum number of columns
30653      */   
30654     
30655     maxCols: 0,
30656     
30657     /**
30658      * @cfg {Boolean} isAutoInitial defalut true
30659      */   
30660     isAutoInitial : true, 
30661     
30662     containerWidth: 0,
30663     
30664     /**
30665      * @cfg {Boolean} isHorizontal defalut false
30666      */   
30667     isHorizontal : false, 
30668
30669     currentSize : null,
30670     
30671     tag: 'div',
30672     
30673     cls: '',
30674     
30675     bricks: null, //CompositeElement
30676     
30677     cols : 1,
30678     
30679     _isLayoutInited : false,
30680     
30681 //    isAlternative : false, // only use for vertical layout...
30682     
30683     /**
30684      * @cfg {Number} alternativePadWidth padding below box..
30685      */   
30686     alternativePadWidth : 50,
30687     
30688     selectedBrick : [],
30689     
30690     getAutoCreate : function(){
30691         
30692         var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30693         
30694         var cfg = {
30695             tag: this.tag,
30696             cls: 'blog-masonary-wrapper ' + this.cls,
30697             cn : {
30698                 cls : 'mas-boxes masonary'
30699             }
30700         };
30701         
30702         return cfg;
30703     },
30704     
30705     getChildContainer: function( )
30706     {
30707         if (this.boxesEl) {
30708             return this.boxesEl;
30709         }
30710         
30711         this.boxesEl = this.el.select('.mas-boxes').first();
30712         
30713         return this.boxesEl;
30714     },
30715     
30716     
30717     initEvents : function()
30718     {
30719         var _this = this;
30720         
30721         if(this.isAutoInitial){
30722             Roo.log('hook children rendered');
30723             this.on('childrenrendered', function() {
30724                 Roo.log('children rendered');
30725                 _this.initial();
30726             } ,this);
30727         }
30728     },
30729     
30730     initial : function()
30731     {
30732         this.selectedBrick = [];
30733         
30734         this.currentSize = this.el.getBox(true);
30735         
30736         Roo.EventManager.onWindowResize(this.resize, this); 
30737
30738         if(!this.isAutoInitial){
30739             this.layout();
30740             return;
30741         }
30742         
30743         this.layout();
30744         
30745         return;
30746         //this.layout.defer(500,this);
30747         
30748     },
30749     
30750     resize : function()
30751     {
30752         var cs = this.el.getBox(true);
30753         
30754         if (
30755                 this.currentSize.width == cs.width && 
30756                 this.currentSize.x == cs.x && 
30757                 this.currentSize.height == cs.height && 
30758                 this.currentSize.y == cs.y 
30759         ) {
30760             Roo.log("no change in with or X or Y");
30761             return;
30762         }
30763         
30764         this.currentSize = cs;
30765         
30766         this.layout();
30767         
30768     },
30769     
30770     layout : function()
30771     {   
30772         this._resetLayout();
30773         
30774         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30775         
30776         this.layoutItems( isInstant );
30777       
30778         this._isLayoutInited = true;
30779         
30780         this.fireEvent('layout', this);
30781         
30782     },
30783     
30784     _resetLayout : function()
30785     {
30786         if(this.isHorizontal){
30787             this.horizontalMeasureColumns();
30788             return;
30789         }
30790         
30791         this.verticalMeasureColumns();
30792         
30793     },
30794     
30795     verticalMeasureColumns : function()
30796     {
30797         this.getContainerWidth();
30798         
30799 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30800 //            this.colWidth = Math.floor(this.containerWidth * 0.8);
30801 //            return;
30802 //        }
30803         
30804         var boxWidth = this.boxWidth + this.padWidth;
30805         
30806         if(this.containerWidth < this.boxWidth){
30807             boxWidth = this.containerWidth
30808         }
30809         
30810         var containerWidth = this.containerWidth;
30811         
30812         var cols = Math.floor(containerWidth / boxWidth);
30813         
30814         this.cols = Math.max( cols, 1 );
30815         
30816         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30817         
30818         var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30819         
30820         var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30821         
30822         this.colWidth = boxWidth + avail - this.padWidth;
30823         
30824         this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30825         this.unitHeight = this.boxHeight > 0 ? this.boxHeight  : this.unitWidth;
30826     },
30827     
30828     horizontalMeasureColumns : function()
30829     {
30830         this.getContainerWidth();
30831         
30832         var boxWidth = this.boxWidth;
30833         
30834         if(this.containerWidth < boxWidth){
30835             boxWidth = this.containerWidth;
30836         }
30837         
30838         this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30839         
30840         this.el.setHeight(boxWidth);
30841         
30842     },
30843     
30844     getContainerWidth : function()
30845     {
30846         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
30847     },
30848     
30849     layoutItems : function( isInstant )
30850     {
30851         Roo.log(this.bricks);
30852         
30853         var items = Roo.apply([], this.bricks);
30854         
30855         if(this.isHorizontal){
30856             this._horizontalLayoutItems( items , isInstant );
30857             return;
30858         }
30859         
30860 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30861 //            this._verticalAlternativeLayoutItems( items , isInstant );
30862 //            return;
30863 //        }
30864         
30865         this._verticalLayoutItems( items , isInstant );
30866         
30867     },
30868     
30869     _verticalLayoutItems : function ( items , isInstant)
30870     {
30871         if ( !items || !items.length ) {
30872             return;
30873         }
30874         
30875         var standard = [
30876             ['xs', 'xs', 'xs', 'tall'],
30877             ['xs', 'xs', 'tall'],
30878             ['xs', 'xs', 'sm'],
30879             ['xs', 'xs', 'xs'],
30880             ['xs', 'tall'],
30881             ['xs', 'sm'],
30882             ['xs', 'xs'],
30883             ['xs'],
30884             
30885             ['sm', 'xs', 'xs'],
30886             ['sm', 'xs'],
30887             ['sm'],
30888             
30889             ['tall', 'xs', 'xs', 'xs'],
30890             ['tall', 'xs', 'xs'],
30891             ['tall', 'xs'],
30892             ['tall']
30893             
30894         ];
30895         
30896         var queue = [];
30897         
30898         var boxes = [];
30899         
30900         var box = [];
30901         
30902         Roo.each(items, function(item, k){
30903             
30904             switch (item.size) {
30905                 // these layouts take up a full box,
30906                 case 'md' :
30907                 case 'md-left' :
30908                 case 'md-right' :
30909                 case 'wide' :
30910                     
30911                     if(box.length){
30912                         boxes.push(box);
30913                         box = [];
30914                     }
30915                     
30916                     boxes.push([item]);
30917                     
30918                     break;
30919                     
30920                 case 'xs' :
30921                 case 'sm' :
30922                 case 'tall' :
30923                     
30924                     box.push(item);
30925                     
30926                     break;
30927                 default :
30928                     break;
30929                     
30930             }
30931             
30932         }, this);
30933         
30934         if(box.length){
30935             boxes.push(box);
30936             box = [];
30937         }
30938         
30939         var filterPattern = function(box, length)
30940         {
30941             if(!box.length){
30942                 return;
30943             }
30944             
30945             var match = false;
30946             
30947             var pattern = box.slice(0, length);
30948             
30949             var format = [];
30950             
30951             Roo.each(pattern, function(i){
30952                 format.push(i.size);
30953             }, this);
30954             
30955             Roo.each(standard, function(s){
30956                 
30957                 if(String(s) != String(format)){
30958                     return;
30959                 }
30960                 
30961                 match = true;
30962                 return false;
30963                 
30964             }, this);
30965             
30966             if(!match && length == 1){
30967                 return;
30968             }
30969             
30970             if(!match){
30971                 filterPattern(box, length - 1);
30972                 return;
30973             }
30974                 
30975             queue.push(pattern);
30976
30977             box = box.slice(length, box.length);
30978
30979             filterPattern(box, 4);
30980
30981             return;
30982             
30983         }
30984         
30985         Roo.each(boxes, function(box, k){
30986             
30987             if(!box.length){
30988                 return;
30989             }
30990             
30991             if(box.length == 1){
30992                 queue.push(box);
30993                 return;
30994             }
30995             
30996             filterPattern(box, 4);
30997             
30998         }, this);
30999         
31000         this._processVerticalLayoutQueue( queue, isInstant );
31001         
31002     },
31003     
31004 //    _verticalAlternativeLayoutItems : function( items , isInstant )
31005 //    {
31006 //        if ( !items || !items.length ) {
31007 //            return;
31008 //        }
31009 //
31010 //        this._processVerticalAlternativeLayoutQueue( items, isInstant );
31011 //        
31012 //    },
31013     
31014     _horizontalLayoutItems : function ( items , isInstant)
31015     {
31016         if ( !items || !items.length || items.length < 3) {
31017             return;
31018         }
31019         
31020         items.reverse();
31021         
31022         var eItems = items.slice(0, 3);
31023         
31024         items = items.slice(3, items.length);
31025         
31026         var standard = [
31027             ['xs', 'xs', 'xs', 'wide'],
31028             ['xs', 'xs', 'wide'],
31029             ['xs', 'xs', 'sm'],
31030             ['xs', 'xs', 'xs'],
31031             ['xs', 'wide'],
31032             ['xs', 'sm'],
31033             ['xs', 'xs'],
31034             ['xs'],
31035             
31036             ['sm', 'xs', 'xs'],
31037             ['sm', 'xs'],
31038             ['sm'],
31039             
31040             ['wide', 'xs', 'xs', 'xs'],
31041             ['wide', 'xs', 'xs'],
31042             ['wide', 'xs'],
31043             ['wide'],
31044             
31045             ['wide-thin']
31046         ];
31047         
31048         var queue = [];
31049         
31050         var boxes = [];
31051         
31052         var box = [];
31053         
31054         Roo.each(items, function(item, k){
31055             
31056             switch (item.size) {
31057                 case 'md' :
31058                 case 'md-left' :
31059                 case 'md-right' :
31060                 case 'tall' :
31061                     
31062                     if(box.length){
31063                         boxes.push(box);
31064                         box = [];
31065                     }
31066                     
31067                     boxes.push([item]);
31068                     
31069                     break;
31070                     
31071                 case 'xs' :
31072                 case 'sm' :
31073                 case 'wide' :
31074                 case 'wide-thin' :
31075                     
31076                     box.push(item);
31077                     
31078                     break;
31079                 default :
31080                     break;
31081                     
31082             }
31083             
31084         }, this);
31085         
31086         if(box.length){
31087             boxes.push(box);
31088             box = [];
31089         }
31090         
31091         var filterPattern = function(box, length)
31092         {
31093             if(!box.length){
31094                 return;
31095             }
31096             
31097             var match = false;
31098             
31099             var pattern = box.slice(0, length);
31100             
31101             var format = [];
31102             
31103             Roo.each(pattern, function(i){
31104                 format.push(i.size);
31105             }, this);
31106             
31107             Roo.each(standard, function(s){
31108                 
31109                 if(String(s) != String(format)){
31110                     return;
31111                 }
31112                 
31113                 match = true;
31114                 return false;
31115                 
31116             }, this);
31117             
31118             if(!match && length == 1){
31119                 return;
31120             }
31121             
31122             if(!match){
31123                 filterPattern(box, length - 1);
31124                 return;
31125             }
31126                 
31127             queue.push(pattern);
31128
31129             box = box.slice(length, box.length);
31130
31131             filterPattern(box, 4);
31132
31133             return;
31134             
31135         }
31136         
31137         Roo.each(boxes, function(box, k){
31138             
31139             if(!box.length){
31140                 return;
31141             }
31142             
31143             if(box.length == 1){
31144                 queue.push(box);
31145                 return;
31146             }
31147             
31148             filterPattern(box, 4);
31149             
31150         }, this);
31151         
31152         
31153         var prune = [];
31154         
31155         var pos = this.el.getBox(true);
31156         
31157         var minX = pos.x;
31158         
31159         var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31160         
31161         var hit_end = false;
31162         
31163         Roo.each(queue, function(box){
31164             
31165             if(hit_end){
31166                 
31167                 Roo.each(box, function(b){
31168                 
31169                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31170                     b.el.hide();
31171
31172                 }, this);
31173
31174                 return;
31175             }
31176             
31177             var mx = 0;
31178             
31179             Roo.each(box, function(b){
31180                 
31181                 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31182                 b.el.show();
31183
31184                 mx = Math.max(mx, b.x);
31185                 
31186             }, this);
31187             
31188             maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31189             
31190             if(maxX < minX){
31191                 
31192                 Roo.each(box, function(b){
31193                 
31194                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31195                     b.el.hide();
31196                     
31197                 }, this);
31198                 
31199                 hit_end = true;
31200                 
31201                 return;
31202             }
31203             
31204             prune.push(box);
31205             
31206         }, this);
31207         
31208         this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31209     },
31210     
31211     /** Sets position of item in DOM
31212     * @param {Element} item
31213     * @param {Number} x - horizontal position
31214     * @param {Number} y - vertical position
31215     * @param {Boolean} isInstant - disables transitions
31216     */
31217     _processVerticalLayoutQueue : function( queue, isInstant )
31218     {
31219         var pos = this.el.getBox(true);
31220         var x = pos.x;
31221         var y = pos.y;
31222         var maxY = [];
31223         
31224         for (var i = 0; i < this.cols; i++){
31225             maxY[i] = pos.y;
31226         }
31227         
31228         Roo.each(queue, function(box, k){
31229             
31230             var col = k % this.cols;
31231             
31232             Roo.each(box, function(b,kk){
31233                 
31234                 b.el.position('absolute');
31235                 
31236                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31237                 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31238                 
31239                 if(b.size == 'md-left' || b.size == 'md-right'){
31240                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31241                     height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31242                 }
31243                 
31244                 b.el.setWidth(width);
31245                 b.el.setHeight(height);
31246                 // iframe?
31247                 b.el.select('iframe',true).setSize(width,height);
31248                 
31249             }, this);
31250             
31251             for (var i = 0; i < this.cols; i++){
31252                 
31253                 if(maxY[i] < maxY[col]){
31254                     col = i;
31255                     continue;
31256                 }
31257                 
31258                 col = Math.min(col, i);
31259                 
31260             }
31261             
31262             x = pos.x + col * (this.colWidth + this.padWidth);
31263             
31264             y = maxY[col];
31265             
31266             var positions = [];
31267             
31268             switch (box.length){
31269                 case 1 :
31270                     positions = this.getVerticalOneBoxColPositions(x, y, box);
31271                     break;
31272                 case 2 :
31273                     positions = this.getVerticalTwoBoxColPositions(x, y, box);
31274                     break;
31275                 case 3 :
31276                     positions = this.getVerticalThreeBoxColPositions(x, y, box);
31277                     break;
31278                 case 4 :
31279                     positions = this.getVerticalFourBoxColPositions(x, y, box);
31280                     break;
31281                 default :
31282                     break;
31283             }
31284             
31285             Roo.each(box, function(b,kk){
31286                 
31287                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31288                 
31289                 var sz = b.el.getSize();
31290                 
31291                 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31292                 
31293             }, this);
31294             
31295         }, this);
31296         
31297         var mY = 0;
31298         
31299         for (var i = 0; i < this.cols; i++){
31300             mY = Math.max(mY, maxY[i]);
31301         }
31302         
31303         this.el.setHeight(mY - pos.y);
31304         
31305     },
31306     
31307 //    _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31308 //    {
31309 //        var pos = this.el.getBox(true);
31310 //        var x = pos.x;
31311 //        var y = pos.y;
31312 //        var maxX = pos.right;
31313 //        
31314 //        var maxHeight = 0;
31315 //        
31316 //        Roo.each(items, function(item, k){
31317 //            
31318 //            var c = k % 2;
31319 //            
31320 //            item.el.position('absolute');
31321 //                
31322 //            var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31323 //
31324 //            item.el.setWidth(width);
31325 //
31326 //            var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31327 //
31328 //            item.el.setHeight(height);
31329 //            
31330 //            if(c == 0){
31331 //                item.el.setXY([x, y], isInstant ? false : true);
31332 //            } else {
31333 //                item.el.setXY([maxX - width, y], isInstant ? false : true);
31334 //            }
31335 //            
31336 //            y = y + height + this.alternativePadWidth;
31337 //            
31338 //            maxHeight = maxHeight + height + this.alternativePadWidth;
31339 //            
31340 //        }, this);
31341 //        
31342 //        this.el.setHeight(maxHeight);
31343 //        
31344 //    },
31345     
31346     _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31347     {
31348         var pos = this.el.getBox(true);
31349         
31350         var minX = pos.x;
31351         var minY = pos.y;
31352         
31353         var maxX = pos.right;
31354         
31355         this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31356         
31357         var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31358         
31359         Roo.each(queue, function(box, k){
31360             
31361             Roo.each(box, function(b, kk){
31362                 
31363                 b.el.position('absolute');
31364                 
31365                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31366                 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31367                 
31368                 if(b.size == 'md-left' || b.size == 'md-right'){
31369                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31370                     height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31371                 }
31372                 
31373                 b.el.setWidth(width);
31374                 b.el.setHeight(height);
31375                 
31376             }, this);
31377             
31378             if(!box.length){
31379                 return;
31380             }
31381             
31382             var positions = [];
31383             
31384             switch (box.length){
31385                 case 1 :
31386                     positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31387                     break;
31388                 case 2 :
31389                     positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31390                     break;
31391                 case 3 :
31392                     positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31393                     break;
31394                 case 4 :
31395                     positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31396                     break;
31397                 default :
31398                     break;
31399             }
31400             
31401             Roo.each(box, function(b,kk){
31402                 
31403                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31404                 
31405                 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31406                 
31407             }, this);
31408             
31409         }, this);
31410         
31411     },
31412     
31413     _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31414     {
31415         Roo.each(eItems, function(b,k){
31416             
31417             b.size = (k == 0) ? 'sm' : 'xs';
31418             b.x = (k == 0) ? 2 : 1;
31419             b.y = (k == 0) ? 2 : 1;
31420             
31421             b.el.position('absolute');
31422             
31423             var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31424                 
31425             b.el.setWidth(width);
31426             
31427             var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31428             
31429             b.el.setHeight(height);
31430             
31431         }, this);
31432
31433         var positions = [];
31434         
31435         positions.push({
31436             x : maxX - this.unitWidth * 2 - this.gutter,
31437             y : minY
31438         });
31439         
31440         positions.push({
31441             x : maxX - this.unitWidth,
31442             y : minY + (this.unitWidth + this.gutter) * 2
31443         });
31444         
31445         positions.push({
31446             x : maxX - this.unitWidth * 3 - this.gutter * 2,
31447             y : minY
31448         });
31449         
31450         Roo.each(eItems, function(b,k){
31451             
31452             b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31453
31454         }, this);
31455         
31456     },
31457     
31458     getVerticalOneBoxColPositions : function(x, y, box)
31459     {
31460         var pos = [];
31461         
31462         var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31463         
31464         if(box[0].size == 'md-left'){
31465             rand = 0;
31466         }
31467         
31468         if(box[0].size == 'md-right'){
31469             rand = 1;
31470         }
31471         
31472         pos.push({
31473             x : x + (this.unitWidth + this.gutter) * rand,
31474             y : y
31475         });
31476         
31477         return pos;
31478     },
31479     
31480     getVerticalTwoBoxColPositions : function(x, y, box)
31481     {
31482         var pos = [];
31483         
31484         if(box[0].size == 'xs'){
31485             
31486             pos.push({
31487                 x : x,
31488                 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31489             });
31490
31491             pos.push({
31492                 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31493                 y : y
31494             });
31495             
31496             return pos;
31497             
31498         }
31499         
31500         pos.push({
31501             x : x,
31502             y : y
31503         });
31504
31505         pos.push({
31506             x : x + (this.unitWidth + this.gutter) * 2,
31507             y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31508         });
31509         
31510         return pos;
31511         
31512     },
31513     
31514     getVerticalThreeBoxColPositions : function(x, y, box)
31515     {
31516         var pos = [];
31517         
31518         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31519             
31520             pos.push({
31521                 x : x,
31522                 y : y
31523             });
31524
31525             pos.push({
31526                 x : x + (this.unitWidth + this.gutter) * 1,
31527                 y : y
31528             });
31529             
31530             pos.push({
31531                 x : x + (this.unitWidth + this.gutter) * 2,
31532                 y : y
31533             });
31534             
31535             return pos;
31536             
31537         }
31538         
31539         if(box[0].size == 'xs' && box[1].size == 'xs'){
31540             
31541             pos.push({
31542                 x : x,
31543                 y : y
31544             });
31545
31546             pos.push({
31547                 x : x,
31548                 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31549             });
31550             
31551             pos.push({
31552                 x : x + (this.unitWidth + this.gutter) * 1,
31553                 y : y
31554             });
31555             
31556             return pos;
31557             
31558         }
31559         
31560         pos.push({
31561             x : x,
31562             y : y
31563         });
31564
31565         pos.push({
31566             x : x + (this.unitWidth + this.gutter) * 2,
31567             y : y
31568         });
31569
31570         pos.push({
31571             x : x + (this.unitWidth + this.gutter) * 2,
31572             y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31573         });
31574             
31575         return pos;
31576         
31577     },
31578     
31579     getVerticalFourBoxColPositions : function(x, y, box)
31580     {
31581         var pos = [];
31582         
31583         if(box[0].size == 'xs'){
31584             
31585             pos.push({
31586                 x : x,
31587                 y : y
31588             });
31589
31590             pos.push({
31591                 x : x,
31592                 y : y + (this.unitHeight + this.gutter) * 1
31593             });
31594             
31595             pos.push({
31596                 x : x,
31597                 y : y + (this.unitHeight + this.gutter) * 2
31598             });
31599             
31600             pos.push({
31601                 x : x + (this.unitWidth + this.gutter) * 1,
31602                 y : y
31603             });
31604             
31605             return pos;
31606             
31607         }
31608         
31609         pos.push({
31610             x : x,
31611             y : y
31612         });
31613
31614         pos.push({
31615             x : x + (this.unitWidth + this.gutter) * 2,
31616             y : y
31617         });
31618
31619         pos.push({
31620             x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31621             y : y + (this.unitHeight + this.gutter) * 1
31622         });
31623
31624         pos.push({
31625             x : x + (this.unitWidth + this.gutter) * 2,
31626             y : y + (this.unitWidth + this.gutter) * 2
31627         });
31628
31629         return pos;
31630         
31631     },
31632     
31633     getHorizontalOneBoxColPositions : function(maxX, minY, box)
31634     {
31635         var pos = [];
31636         
31637         if(box[0].size == 'md-left'){
31638             pos.push({
31639                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31640                 y : minY
31641             });
31642             
31643             return pos;
31644         }
31645         
31646         if(box[0].size == 'md-right'){
31647             pos.push({
31648                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31649                 y : minY + (this.unitWidth + this.gutter) * 1
31650             });
31651             
31652             return pos;
31653         }
31654         
31655         var rand = Math.floor(Math.random() * (4 - box[0].y));
31656         
31657         pos.push({
31658             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31659             y : minY + (this.unitWidth + this.gutter) * rand
31660         });
31661         
31662         return pos;
31663         
31664     },
31665     
31666     getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31667     {
31668         var pos = [];
31669         
31670         if(box[0].size == 'xs'){
31671             
31672             pos.push({
31673                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31674                 y : minY
31675             });
31676
31677             pos.push({
31678                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31679                 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31680             });
31681             
31682             return pos;
31683             
31684         }
31685         
31686         pos.push({
31687             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31688             y : minY
31689         });
31690
31691         pos.push({
31692             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31693             y : minY + (this.unitWidth + this.gutter) * 2
31694         });
31695         
31696         return pos;
31697         
31698     },
31699     
31700     getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31701     {
31702         var pos = [];
31703         
31704         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31705             
31706             pos.push({
31707                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31708                 y : minY
31709             });
31710
31711             pos.push({
31712                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31713                 y : minY + (this.unitWidth + this.gutter) * 1
31714             });
31715             
31716             pos.push({
31717                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31718                 y : minY + (this.unitWidth + this.gutter) * 2
31719             });
31720             
31721             return pos;
31722             
31723         }
31724         
31725         if(box[0].size == 'xs' && box[1].size == 'xs'){
31726             
31727             pos.push({
31728                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31729                 y : minY
31730             });
31731
31732             pos.push({
31733                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31734                 y : minY
31735             });
31736             
31737             pos.push({
31738                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31739                 y : minY + (this.unitWidth + this.gutter) * 1
31740             });
31741             
31742             return pos;
31743             
31744         }
31745         
31746         pos.push({
31747             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31748             y : minY
31749         });
31750
31751         pos.push({
31752             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31753             y : minY + (this.unitWidth + this.gutter) * 2
31754         });
31755
31756         pos.push({
31757             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31758             y : minY + (this.unitWidth + this.gutter) * 2
31759         });
31760             
31761         return pos;
31762         
31763     },
31764     
31765     getHorizontalFourBoxColPositions : function(maxX, minY, box)
31766     {
31767         var pos = [];
31768         
31769         if(box[0].size == 'xs'){
31770             
31771             pos.push({
31772                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31773                 y : minY
31774             });
31775
31776             pos.push({
31777                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31778                 y : minY
31779             });
31780             
31781             pos.push({
31782                 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),
31783                 y : minY
31784             });
31785             
31786             pos.push({
31787                 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31788                 y : minY + (this.unitWidth + this.gutter) * 1
31789             });
31790             
31791             return pos;
31792             
31793         }
31794         
31795         pos.push({
31796             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31797             y : minY
31798         });
31799         
31800         pos.push({
31801             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31802             y : minY + (this.unitWidth + this.gutter) * 2
31803         });
31804         
31805         pos.push({
31806             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31807             y : minY + (this.unitWidth + this.gutter) * 2
31808         });
31809         
31810         pos.push({
31811             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),
31812             y : minY + (this.unitWidth + this.gutter) * 2
31813         });
31814
31815         return pos;
31816         
31817     },
31818     
31819     /**
31820     * remove a Masonry Brick
31821     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31822     */
31823     removeBrick : function(brick_id)
31824     {
31825         if (!brick_id) {
31826             return;
31827         }
31828         
31829         for (var i = 0; i<this.bricks.length; i++) {
31830             if (this.bricks[i].id == brick_id) {
31831                 this.bricks.splice(i,1);
31832                 this.el.dom.removeChild(Roo.get(brick_id).dom);
31833                 this.initial();
31834             }
31835         }
31836     },
31837     
31838     /**
31839     * adds a Masonry Brick
31840     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31841     */
31842     addBrick : function(cfg)
31843     {
31844         var cn = new Roo.bootstrap.MasonryBrick(cfg);
31845         //this.register(cn);
31846         cn.parentId = this.id;
31847         cn.onRender(this.el, null);
31848         return cn;
31849     },
31850     
31851     /**
31852     * register a Masonry Brick
31853     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31854     */
31855     
31856     register : function(brick)
31857     {
31858         this.bricks.push(brick);
31859         brick.masonryId = this.id;
31860     },
31861     
31862     /**
31863     * clear all the Masonry Brick
31864     */
31865     clearAll : function()
31866     {
31867         this.bricks = [];
31868         //this.getChildContainer().dom.innerHTML = "";
31869         this.el.dom.innerHTML = '';
31870     },
31871     
31872     getSelected : function()
31873     {
31874         if (!this.selectedBrick) {
31875             return false;
31876         }
31877         
31878         return this.selectedBrick;
31879     }
31880 });
31881
31882 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31883     
31884     groups: {},
31885      /**
31886     * register a Masonry Layout
31887     * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31888     */
31889     
31890     register : function(layout)
31891     {
31892         this.groups[layout.id] = layout;
31893     },
31894     /**
31895     * fetch a  Masonry Layout based on the masonry layout ID
31896     * @param {string} the masonry layout to add
31897     * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31898     */
31899     
31900     get: function(layout_id) {
31901         if (typeof(this.groups[layout_id]) == 'undefined') {
31902             return false;
31903         }
31904         return this.groups[layout_id] ;
31905     }
31906     
31907     
31908     
31909 });
31910
31911  
31912
31913  /**
31914  *
31915  * This is based on 
31916  * http://masonry.desandro.com
31917  *
31918  * The idea is to render all the bricks based on vertical width...
31919  *
31920  * The original code extends 'outlayer' - we might need to use that....
31921  * 
31922  */
31923
31924
31925 /**
31926  * @class Roo.bootstrap.LayoutMasonryAuto
31927  * @extends Roo.bootstrap.Component
31928  * Bootstrap Layout Masonry class
31929  * 
31930  * @constructor
31931  * Create a new Element
31932  * @param {Object} config The config object
31933  */
31934
31935 Roo.bootstrap.LayoutMasonryAuto = function(config){
31936     Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31937 };
31938
31939 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component,  {
31940     
31941       /**
31942      * @cfg {Boolean} isFitWidth  - resize the width..
31943      */   
31944     isFitWidth : false,  // options..
31945     /**
31946      * @cfg {Boolean} isOriginLeft = left align?
31947      */   
31948     isOriginLeft : true,
31949     /**
31950      * @cfg {Boolean} isOriginTop = top align?
31951      */   
31952     isOriginTop : false,
31953     /**
31954      * @cfg {Boolean} isLayoutInstant = no animation?
31955      */   
31956     isLayoutInstant : false, // needed?
31957     /**
31958      * @cfg {Boolean} isResizingContainer = not sure if this is used..
31959      */   
31960     isResizingContainer : true,
31961     /**
31962      * @cfg {Number} columnWidth  width of the columns 
31963      */   
31964     
31965     columnWidth : 0,
31966     
31967     /**
31968      * @cfg {Number} maxCols maximum number of columns
31969      */   
31970     
31971     maxCols: 0,
31972     /**
31973      * @cfg {Number} padHeight padding below box..
31974      */   
31975     
31976     padHeight : 10, 
31977     
31978     /**
31979      * @cfg {Boolean} isAutoInitial defalut true
31980      */   
31981     
31982     isAutoInitial : true, 
31983     
31984     // private?
31985     gutter : 0,
31986     
31987     containerWidth: 0,
31988     initialColumnWidth : 0,
31989     currentSize : null,
31990     
31991     colYs : null, // array.
31992     maxY : 0,
31993     padWidth: 10,
31994     
31995     
31996     tag: 'div',
31997     cls: '',
31998     bricks: null, //CompositeElement
31999     cols : 0, // array?
32000     // element : null, // wrapped now this.el
32001     _isLayoutInited : null, 
32002     
32003     
32004     getAutoCreate : function(){
32005         
32006         var cfg = {
32007             tag: this.tag,
32008             cls: 'blog-masonary-wrapper ' + this.cls,
32009             cn : {
32010                 cls : 'mas-boxes masonary'
32011             }
32012         };
32013         
32014         return cfg;
32015     },
32016     
32017     getChildContainer: function( )
32018     {
32019         if (this.boxesEl) {
32020             return this.boxesEl;
32021         }
32022         
32023         this.boxesEl = this.el.select('.mas-boxes').first();
32024         
32025         return this.boxesEl;
32026     },
32027     
32028     
32029     initEvents : function()
32030     {
32031         var _this = this;
32032         
32033         if(this.isAutoInitial){
32034             Roo.log('hook children rendered');
32035             this.on('childrenrendered', function() {
32036                 Roo.log('children rendered');
32037                 _this.initial();
32038             } ,this);
32039         }
32040         
32041     },
32042     
32043     initial : function()
32044     {
32045         this.reloadItems();
32046
32047         this.currentSize = this.el.getBox(true);
32048
32049         /// was window resize... - let's see if this works..
32050         Roo.EventManager.onWindowResize(this.resize, this); 
32051
32052         if(!this.isAutoInitial){
32053             this.layout();
32054             return;
32055         }
32056         
32057         this.layout.defer(500,this);
32058     },
32059     
32060     reloadItems: function()
32061     {
32062         this.bricks = this.el.select('.masonry-brick', true);
32063         
32064         this.bricks.each(function(b) {
32065             //Roo.log(b.getSize());
32066             if (!b.attr('originalwidth')) {
32067                 b.attr('originalwidth',  b.getSize().width);
32068             }
32069             
32070         });
32071         
32072         Roo.log(this.bricks.elements.length);
32073     },
32074     
32075     resize : function()
32076     {
32077         Roo.log('resize');
32078         var cs = this.el.getBox(true);
32079         
32080         if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32081             Roo.log("no change in with or X");
32082             return;
32083         }
32084         this.currentSize = cs;
32085         this.layout();
32086     },
32087     
32088     layout : function()
32089     {
32090          Roo.log('layout');
32091         this._resetLayout();
32092         //this._manageStamps();
32093       
32094         // don't animate first layout
32095         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32096         this.layoutItems( isInstant );
32097       
32098         // flag for initalized
32099         this._isLayoutInited = true;
32100     },
32101     
32102     layoutItems : function( isInstant )
32103     {
32104         //var items = this._getItemsForLayout( this.items );
32105         // original code supports filtering layout items.. we just ignore it..
32106         
32107         this._layoutItems( this.bricks , isInstant );
32108       
32109         this._postLayout();
32110     },
32111     _layoutItems : function ( items , isInstant)
32112     {
32113        //this.fireEvent( 'layout', this, items );
32114     
32115
32116         if ( !items || !items.elements.length ) {
32117           // no items, emit event with empty array
32118             return;
32119         }
32120
32121         var queue = [];
32122         items.each(function(item) {
32123             Roo.log("layout item");
32124             Roo.log(item);
32125             // get x/y object from method
32126             var position = this._getItemLayoutPosition( item );
32127             // enqueue
32128             position.item = item;
32129             position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32130             queue.push( position );
32131         }, this);
32132       
32133         this._processLayoutQueue( queue );
32134     },
32135     /** Sets position of item in DOM
32136     * @param {Element} item
32137     * @param {Number} x - horizontal position
32138     * @param {Number} y - vertical position
32139     * @param {Boolean} isInstant - disables transitions
32140     */
32141     _processLayoutQueue : function( queue )
32142     {
32143         for ( var i=0, len = queue.length; i < len; i++ ) {
32144             var obj = queue[i];
32145             obj.item.position('absolute');
32146             obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32147         }
32148     },
32149       
32150     
32151     /**
32152     * Any logic you want to do after each layout,
32153     * i.e. size the container
32154     */
32155     _postLayout : function()
32156     {
32157         this.resizeContainer();
32158     },
32159     
32160     resizeContainer : function()
32161     {
32162         if ( !this.isResizingContainer ) {
32163             return;
32164         }
32165         var size = this._getContainerSize();
32166         if ( size ) {
32167             this.el.setSize(size.width,size.height);
32168             this.boxesEl.setSize(size.width,size.height);
32169         }
32170     },
32171     
32172     
32173     
32174     _resetLayout : function()
32175     {
32176         //this.getSize();  // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32177         this.colWidth = this.el.getWidth();
32178         //this.gutter = this.el.getWidth(); 
32179         
32180         this.measureColumns();
32181
32182         // reset column Y
32183         var i = this.cols;
32184         this.colYs = [];
32185         while (i--) {
32186             this.colYs.push( 0 );
32187         }
32188     
32189         this.maxY = 0;
32190     },
32191
32192     measureColumns : function()
32193     {
32194         this.getContainerWidth();
32195       // if columnWidth is 0, default to outerWidth of first item
32196         if ( !this.columnWidth ) {
32197             var firstItem = this.bricks.first();
32198             Roo.log(firstItem);
32199             this.columnWidth  = this.containerWidth;
32200             if (firstItem && firstItem.attr('originalwidth') ) {
32201                 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32202             }
32203             // columnWidth fall back to item of first element
32204             Roo.log("set column width?");
32205                         this.initialColumnWidth = this.columnWidth  ;
32206
32207             // if first elem has no width, default to size of container
32208             
32209         }
32210         
32211         
32212         if (this.initialColumnWidth) {
32213             this.columnWidth = this.initialColumnWidth;
32214         }
32215         
32216         
32217             
32218         // column width is fixed at the top - however if container width get's smaller we should
32219         // reduce it...
32220         
32221         // this bit calcs how man columns..
32222             
32223         var columnWidth = this.columnWidth += this.gutter;
32224       
32225         // calculate columns
32226         var containerWidth = this.containerWidth + this.gutter;
32227         
32228         var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32229         // fix rounding errors, typically with gutters
32230         var excess = columnWidth - containerWidth % columnWidth;
32231         
32232         
32233         // if overshoot is less than a pixel, round up, otherwise floor it
32234         var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32235         cols = Math[ mathMethod ]( cols );
32236         this.cols = Math.max( cols, 1 );
32237         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32238         
32239          // padding positioning..
32240         var totalColWidth = this.cols * this.columnWidth;
32241         var padavail = this.containerWidth - totalColWidth;
32242         // so for 2 columns - we need 3 'pads'
32243         
32244         var padNeeded = (1+this.cols) * this.padWidth;
32245         
32246         var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32247         
32248         this.columnWidth += padExtra
32249         //this.padWidth = Math.floor(padavail /  ( this.cols));
32250         
32251         // adjust colum width so that padding is fixed??
32252         
32253         // we have 3 columns ... total = width * 3
32254         // we have X left over... that should be used by 
32255         
32256         //if (this.expandC) {
32257             
32258         //}
32259         
32260         
32261         
32262     },
32263     
32264     getContainerWidth : function()
32265     {
32266        /* // container is parent if fit width
32267         var container = this.isFitWidth ? this.element.parentNode : this.element;
32268         // check that this.size and size are there
32269         // IE8 triggers resize on body size change, so they might not be
32270         
32271         var size = getSize( container );  //FIXME
32272         this.containerWidth = size && size.innerWidth; //FIXME
32273         */
32274          
32275         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
32276         
32277     },
32278     
32279     _getItemLayoutPosition : function( item )  // what is item?
32280     {
32281         // we resize the item to our columnWidth..
32282       
32283         item.setWidth(this.columnWidth);
32284         item.autoBoxAdjust  = false;
32285         
32286         var sz = item.getSize();
32287  
32288         // how many columns does this brick span
32289         var remainder = this.containerWidth % this.columnWidth;
32290         
32291         var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32292         // round if off by 1 pixel, otherwise use ceil
32293         var colSpan = Math[ mathMethod ]( sz.width  / this.columnWidth );
32294         colSpan = Math.min( colSpan, this.cols );
32295         
32296         // normally this should be '1' as we dont' currently allow multi width columns..
32297         
32298         var colGroup = this._getColGroup( colSpan );
32299         // get the minimum Y value from the columns
32300         var minimumY = Math.min.apply( Math, colGroup );
32301         Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32302         
32303         var shortColIndex = colGroup.indexOf(  minimumY ); // broken on ie8..?? probably...
32304          
32305         // position the brick
32306         var position = {
32307             x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32308             y: this.currentSize.y + minimumY + this.padHeight
32309         };
32310         
32311         Roo.log(position);
32312         // apply setHeight to necessary columns
32313         var setHeight = minimumY + sz.height + this.padHeight;
32314         //Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32315         
32316         var setSpan = this.cols + 1 - colGroup.length;
32317         for ( var i = 0; i < setSpan; i++ ) {
32318           this.colYs[ shortColIndex + i ] = setHeight ;
32319         }
32320       
32321         return position;
32322     },
32323     
32324     /**
32325      * @param {Number} colSpan - number of columns the element spans
32326      * @returns {Array} colGroup
32327      */
32328     _getColGroup : function( colSpan )
32329     {
32330         if ( colSpan < 2 ) {
32331           // if brick spans only one column, use all the column Ys
32332           return this.colYs;
32333         }
32334       
32335         var colGroup = [];
32336         // how many different places could this brick fit horizontally
32337         var groupCount = this.cols + 1 - colSpan;
32338         // for each group potential horizontal position
32339         for ( var i = 0; i < groupCount; i++ ) {
32340           // make an array of colY values for that one group
32341           var groupColYs = this.colYs.slice( i, i + colSpan );
32342           // and get the max value of the array
32343           colGroup[i] = Math.max.apply( Math, groupColYs );
32344         }
32345         return colGroup;
32346     },
32347     /*
32348     _manageStamp : function( stamp )
32349     {
32350         var stampSize =  stamp.getSize();
32351         var offset = stamp.getBox();
32352         // get the columns that this stamp affects
32353         var firstX = this.isOriginLeft ? offset.x : offset.right;
32354         var lastX = firstX + stampSize.width;
32355         var firstCol = Math.floor( firstX / this.columnWidth );
32356         firstCol = Math.max( 0, firstCol );
32357         
32358         var lastCol = Math.floor( lastX / this.columnWidth );
32359         // lastCol should not go over if multiple of columnWidth #425
32360         lastCol -= lastX % this.columnWidth ? 0 : 1;
32361         lastCol = Math.min( this.cols - 1, lastCol );
32362         
32363         // set colYs to bottom of the stamp
32364         var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32365             stampSize.height;
32366             
32367         for ( var i = firstCol; i <= lastCol; i++ ) {
32368           this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32369         }
32370     },
32371     */
32372     
32373     _getContainerSize : function()
32374     {
32375         this.maxY = Math.max.apply( Math, this.colYs );
32376         var size = {
32377             height: this.maxY
32378         };
32379       
32380         if ( this.isFitWidth ) {
32381             size.width = this._getContainerFitWidth();
32382         }
32383       
32384         return size;
32385     },
32386     
32387     _getContainerFitWidth : function()
32388     {
32389         var unusedCols = 0;
32390         // count unused columns
32391         var i = this.cols;
32392         while ( --i ) {
32393           if ( this.colYs[i] !== 0 ) {
32394             break;
32395           }
32396           unusedCols++;
32397         }
32398         // fit container to columns that have been used
32399         return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32400     },
32401     
32402     needsResizeLayout : function()
32403     {
32404         var previousWidth = this.containerWidth;
32405         this.getContainerWidth();
32406         return previousWidth !== this.containerWidth;
32407     }
32408  
32409 });
32410
32411  
32412
32413  /*
32414  * - LGPL
32415  *
32416  * element
32417  * 
32418  */
32419
32420 /**
32421  * @class Roo.bootstrap.MasonryBrick
32422  * @extends Roo.bootstrap.Component
32423  * Bootstrap MasonryBrick class
32424  * 
32425  * @constructor
32426  * Create a new MasonryBrick
32427  * @param {Object} config The config object
32428  */
32429
32430 Roo.bootstrap.MasonryBrick = function(config){
32431     
32432     Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32433     
32434     Roo.bootstrap.MasonryBrick.register(this);
32435     
32436     this.addEvents({
32437         // raw events
32438         /**
32439          * @event click
32440          * When a MasonryBrick is clcik
32441          * @param {Roo.bootstrap.MasonryBrick} this
32442          * @param {Roo.EventObject} e
32443          */
32444         "click" : true
32445     });
32446 };
32447
32448 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component,  {
32449     
32450     /**
32451      * @cfg {String} title
32452      */   
32453     title : '',
32454     /**
32455      * @cfg {String} html
32456      */   
32457     html : '',
32458     /**
32459      * @cfg {String} bgimage
32460      */   
32461     bgimage : '',
32462     /**
32463      * @cfg {String} videourl
32464      */   
32465     videourl : '',
32466     /**
32467      * @cfg {String} cls
32468      */   
32469     cls : '',
32470     /**
32471      * @cfg {String} href
32472      */   
32473     href : '',
32474     /**
32475      * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32476      */   
32477     size : 'xs',
32478     
32479     /**
32480      * @cfg {String} placetitle (center|bottom)
32481      */   
32482     placetitle : '',
32483     
32484     /**
32485      * @cfg {Boolean} isFitContainer defalut true
32486      */   
32487     isFitContainer : true, 
32488     
32489     /**
32490      * @cfg {Boolean} preventDefault defalut false
32491      */   
32492     preventDefault : false, 
32493     
32494     /**
32495      * @cfg {Boolean} inverse defalut false
32496      */   
32497     maskInverse : false, 
32498     
32499     getAutoCreate : function()
32500     {
32501         if(!this.isFitContainer){
32502             return this.getSplitAutoCreate();
32503         }
32504         
32505         var cls = 'masonry-brick masonry-brick-full';
32506         
32507         if(this.href.length){
32508             cls += ' masonry-brick-link';
32509         }
32510         
32511         if(this.bgimage.length){
32512             cls += ' masonry-brick-image';
32513         }
32514         
32515         if(this.maskInverse){
32516             cls += ' mask-inverse';
32517         }
32518         
32519         if(!this.html.length && !this.maskInverse && !this.videourl.length){
32520             cls += ' enable-mask';
32521         }
32522         
32523         if(this.size){
32524             cls += ' masonry-' + this.size + '-brick';
32525         }
32526         
32527         if(this.placetitle.length){
32528             
32529             switch (this.placetitle) {
32530                 case 'center' :
32531                     cls += ' masonry-center-title';
32532                     break;
32533                 case 'bottom' :
32534                     cls += ' masonry-bottom-title';
32535                     break;
32536                 default:
32537                     break;
32538             }
32539             
32540         } else {
32541             if(!this.html.length && !this.bgimage.length){
32542                 cls += ' masonry-center-title';
32543             }
32544
32545             if(!this.html.length && this.bgimage.length){
32546                 cls += ' masonry-bottom-title';
32547             }
32548         }
32549         
32550         if(this.cls){
32551             cls += ' ' + this.cls;
32552         }
32553         
32554         var cfg = {
32555             tag: (this.href.length) ? 'a' : 'div',
32556             cls: cls,
32557             cn: [
32558                 {
32559                     tag: 'div',
32560                     cls: 'masonry-brick-mask'
32561                 },
32562                 {
32563                     tag: 'div',
32564                     cls: 'masonry-brick-paragraph',
32565                     cn: []
32566                 }
32567             ]
32568         };
32569         
32570         if(this.href.length){
32571             cfg.href = this.href;
32572         }
32573         
32574         var cn = cfg.cn[1].cn;
32575         
32576         if(this.title.length){
32577             cn.push({
32578                 tag: 'h4',
32579                 cls: 'masonry-brick-title',
32580                 html: this.title
32581             });
32582         }
32583         
32584         if(this.html.length){
32585             cn.push({
32586                 tag: 'p',
32587                 cls: 'masonry-brick-text',
32588                 html: this.html
32589             });
32590         }
32591         
32592         if (!this.title.length && !this.html.length) {
32593             cfg.cn[1].cls += ' hide';
32594         }
32595         
32596         if(this.bgimage.length){
32597             cfg.cn.push({
32598                 tag: 'img',
32599                 cls: 'masonry-brick-image-view',
32600                 src: this.bgimage
32601             });
32602         }
32603         
32604         if(this.videourl.length){
32605             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32606             // youtube support only?
32607             cfg.cn.push({
32608                 tag: 'iframe',
32609                 cls: 'masonry-brick-image-view',
32610                 src: vurl,
32611                 frameborder : 0,
32612                 allowfullscreen : true
32613             });
32614         }
32615         
32616         return cfg;
32617         
32618     },
32619     
32620     getSplitAutoCreate : function()
32621     {
32622         var cls = 'masonry-brick masonry-brick-split';
32623         
32624         if(this.href.length){
32625             cls += ' masonry-brick-link';
32626         }
32627         
32628         if(this.bgimage.length){
32629             cls += ' masonry-brick-image';
32630         }
32631         
32632         if(this.size){
32633             cls += ' masonry-' + this.size + '-brick';
32634         }
32635         
32636         switch (this.placetitle) {
32637             case 'center' :
32638                 cls += ' masonry-center-title';
32639                 break;
32640             case 'bottom' :
32641                 cls += ' masonry-bottom-title';
32642                 break;
32643             default:
32644                 if(!this.bgimage.length){
32645                     cls += ' masonry-center-title';
32646                 }
32647
32648                 if(this.bgimage.length){
32649                     cls += ' masonry-bottom-title';
32650                 }
32651                 break;
32652         }
32653         
32654         if(this.cls){
32655             cls += ' ' + this.cls;
32656         }
32657         
32658         var cfg = {
32659             tag: (this.href.length) ? 'a' : 'div',
32660             cls: cls,
32661             cn: [
32662                 {
32663                     tag: 'div',
32664                     cls: 'masonry-brick-split-head',
32665                     cn: [
32666                         {
32667                             tag: 'div',
32668                             cls: 'masonry-brick-paragraph',
32669                             cn: []
32670                         }
32671                     ]
32672                 },
32673                 {
32674                     tag: 'div',
32675                     cls: 'masonry-brick-split-body',
32676                     cn: []
32677                 }
32678             ]
32679         };
32680         
32681         if(this.href.length){
32682             cfg.href = this.href;
32683         }
32684         
32685         if(this.title.length){
32686             cfg.cn[0].cn[0].cn.push({
32687                 tag: 'h4',
32688                 cls: 'masonry-brick-title',
32689                 html: this.title
32690             });
32691         }
32692         
32693         if(this.html.length){
32694             cfg.cn[1].cn.push({
32695                 tag: 'p',
32696                 cls: 'masonry-brick-text',
32697                 html: this.html
32698             });
32699         }
32700
32701         if(this.bgimage.length){
32702             cfg.cn[0].cn.push({
32703                 tag: 'img',
32704                 cls: 'masonry-brick-image-view',
32705                 src: this.bgimage
32706             });
32707         }
32708         
32709         if(this.videourl.length){
32710             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32711             // youtube support only?
32712             cfg.cn[0].cn.cn.push({
32713                 tag: 'iframe',
32714                 cls: 'masonry-brick-image-view',
32715                 src: vurl,
32716                 frameborder : 0,
32717                 allowfullscreen : true
32718             });
32719         }
32720         
32721         return cfg;
32722     },
32723     
32724     initEvents: function() 
32725     {
32726         switch (this.size) {
32727             case 'xs' :
32728                 this.x = 1;
32729                 this.y = 1;
32730                 break;
32731             case 'sm' :
32732                 this.x = 2;
32733                 this.y = 2;
32734                 break;
32735             case 'md' :
32736             case 'md-left' :
32737             case 'md-right' :
32738                 this.x = 3;
32739                 this.y = 3;
32740                 break;
32741             case 'tall' :
32742                 this.x = 2;
32743                 this.y = 3;
32744                 break;
32745             case 'wide' :
32746                 this.x = 3;
32747                 this.y = 2;
32748                 break;
32749             case 'wide-thin' :
32750                 this.x = 3;
32751                 this.y = 1;
32752                 break;
32753                         
32754             default :
32755                 break;
32756         }
32757         
32758         if(Roo.isTouch){
32759             this.el.on('touchstart', this.onTouchStart, this);
32760             this.el.on('touchmove', this.onTouchMove, this);
32761             this.el.on('touchend', this.onTouchEnd, this);
32762             this.el.on('contextmenu', this.onContextMenu, this);
32763         } else {
32764             this.el.on('mouseenter'  ,this.enter, this);
32765             this.el.on('mouseleave', this.leave, this);
32766             this.el.on('click', this.onClick, this);
32767         }
32768         
32769         if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32770             this.parent().bricks.push(this);   
32771         }
32772         
32773     },
32774     
32775     onClick: function(e, el)
32776     {
32777         var time = this.endTimer - this.startTimer;
32778         // Roo.log(e.preventDefault());
32779         if(Roo.isTouch){
32780             if(time > 1000){
32781                 e.preventDefault();
32782                 return;
32783             }
32784         }
32785         
32786         if(!this.preventDefault){
32787             return;
32788         }
32789         
32790         e.preventDefault();
32791         
32792         if (this.activeClass != '') {
32793             this.selectBrick();
32794         }
32795         
32796         this.fireEvent('click', this, e);
32797     },
32798     
32799     enter: function(e, el)
32800     {
32801         e.preventDefault();
32802         
32803         if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32804             return;
32805         }
32806         
32807         if(this.bgimage.length && this.html.length){
32808             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32809         }
32810     },
32811     
32812     leave: function(e, el)
32813     {
32814         e.preventDefault();
32815         
32816         if(!this.isFitContainer || this.maskInverse  || this.videourl.length){
32817             return;
32818         }
32819         
32820         if(this.bgimage.length && this.html.length){
32821             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32822         }
32823     },
32824     
32825     onTouchStart: function(e, el)
32826     {
32827 //        e.preventDefault();
32828         
32829         this.touchmoved = false;
32830         
32831         if(!this.isFitContainer){
32832             return;
32833         }
32834         
32835         if(!this.bgimage.length || !this.html.length){
32836             return;
32837         }
32838         
32839         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32840         
32841         this.timer = new Date().getTime();
32842         
32843     },
32844     
32845     onTouchMove: function(e, el)
32846     {
32847         this.touchmoved = true;
32848     },
32849     
32850     onContextMenu : function(e,el)
32851     {
32852         e.preventDefault();
32853         e.stopPropagation();
32854         return false;
32855     },
32856     
32857     onTouchEnd: function(e, el)
32858     {
32859 //        e.preventDefault();
32860         
32861         if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32862         
32863             this.leave(e,el);
32864             
32865             return;
32866         }
32867         
32868         if(!this.bgimage.length || !this.html.length){
32869             
32870             if(this.href.length){
32871                 window.location.href = this.href;
32872             }
32873             
32874             return;
32875         }
32876         
32877         if(!this.isFitContainer){
32878             return;
32879         }
32880         
32881         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32882         
32883         window.location.href = this.href;
32884     },
32885     
32886     //selection on single brick only
32887     selectBrick : function() {
32888         
32889         if (!this.parentId) {
32890             return;
32891         }
32892         
32893         var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32894         var index = m.selectedBrick.indexOf(this.id);
32895         
32896         if ( index > -1) {
32897             m.selectedBrick.splice(index,1);
32898             this.el.removeClass(this.activeClass);
32899             return;
32900         }
32901         
32902         for(var i = 0; i < m.selectedBrick.length; i++) {
32903             var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32904             b.el.removeClass(b.activeClass);
32905         }
32906         
32907         m.selectedBrick = [];
32908         
32909         m.selectedBrick.push(this.id);
32910         this.el.addClass(this.activeClass);
32911         return;
32912     },
32913     
32914     isSelected : function(){
32915         return this.el.hasClass(this.activeClass);
32916         
32917     }
32918 });
32919
32920 Roo.apply(Roo.bootstrap.MasonryBrick, {
32921     
32922     //groups: {},
32923     groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32924      /**
32925     * register a Masonry Brick
32926     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32927     */
32928     
32929     register : function(brick)
32930     {
32931         //this.groups[brick.id] = brick;
32932         this.groups.add(brick.id, brick);
32933     },
32934     /**
32935     * fetch a  masonry brick based on the masonry brick ID
32936     * @param {string} the masonry brick to add
32937     * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32938     */
32939     
32940     get: function(brick_id) 
32941     {
32942         // if (typeof(this.groups[brick_id]) == 'undefined') {
32943         //     return false;
32944         // }
32945         // return this.groups[brick_id] ;
32946         
32947         if(this.groups.key(brick_id)) {
32948             return this.groups.key(brick_id);
32949         }
32950         
32951         return false;
32952     }
32953     
32954     
32955     
32956 });
32957
32958  /*
32959  * - LGPL
32960  *
32961  * element
32962  * 
32963  */
32964
32965 /**
32966  * @class Roo.bootstrap.Brick
32967  * @extends Roo.bootstrap.Component
32968  * Bootstrap Brick class
32969  * 
32970  * @constructor
32971  * Create a new Brick
32972  * @param {Object} config The config object
32973  */
32974
32975 Roo.bootstrap.Brick = function(config){
32976     Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32977     
32978     this.addEvents({
32979         // raw events
32980         /**
32981          * @event click
32982          * When a Brick is click
32983          * @param {Roo.bootstrap.Brick} this
32984          * @param {Roo.EventObject} e
32985          */
32986         "click" : true
32987     });
32988 };
32989
32990 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
32991     
32992     /**
32993      * @cfg {String} title
32994      */   
32995     title : '',
32996     /**
32997      * @cfg {String} html
32998      */   
32999     html : '',
33000     /**
33001      * @cfg {String} bgimage
33002      */   
33003     bgimage : '',
33004     /**
33005      * @cfg {String} cls
33006      */   
33007     cls : '',
33008     /**
33009      * @cfg {String} href
33010      */   
33011     href : '',
33012     /**
33013      * @cfg {String} video
33014      */   
33015     video : '',
33016     /**
33017      * @cfg {Boolean} square
33018      */   
33019     square : true,
33020     
33021     getAutoCreate : function()
33022     {
33023         var cls = 'roo-brick';
33024         
33025         if(this.href.length){
33026             cls += ' roo-brick-link';
33027         }
33028         
33029         if(this.bgimage.length){
33030             cls += ' roo-brick-image';
33031         }
33032         
33033         if(!this.html.length && !this.bgimage.length){
33034             cls += ' roo-brick-center-title';
33035         }
33036         
33037         if(!this.html.length && this.bgimage.length){
33038             cls += ' roo-brick-bottom-title';
33039         }
33040         
33041         if(this.cls){
33042             cls += ' ' + this.cls;
33043         }
33044         
33045         var cfg = {
33046             tag: (this.href.length) ? 'a' : 'div',
33047             cls: cls,
33048             cn: [
33049                 {
33050                     tag: 'div',
33051                     cls: 'roo-brick-paragraph',
33052                     cn: []
33053                 }
33054             ]
33055         };
33056         
33057         if(this.href.length){
33058             cfg.href = this.href;
33059         }
33060         
33061         var cn = cfg.cn[0].cn;
33062         
33063         if(this.title.length){
33064             cn.push({
33065                 tag: 'h4',
33066                 cls: 'roo-brick-title',
33067                 html: this.title
33068             });
33069         }
33070         
33071         if(this.html.length){
33072             cn.push({
33073                 tag: 'p',
33074                 cls: 'roo-brick-text',
33075                 html: this.html
33076             });
33077         } else {
33078             cn.cls += ' hide';
33079         }
33080         
33081         if(this.bgimage.length){
33082             cfg.cn.push({
33083                 tag: 'img',
33084                 cls: 'roo-brick-image-view',
33085                 src: this.bgimage
33086             });
33087         }
33088         
33089         return cfg;
33090     },
33091     
33092     initEvents: function() 
33093     {
33094         if(this.title.length || this.html.length){
33095             this.el.on('mouseenter'  ,this.enter, this);
33096             this.el.on('mouseleave', this.leave, this);
33097         }
33098         
33099         Roo.EventManager.onWindowResize(this.resize, this); 
33100         
33101         if(this.bgimage.length){
33102             this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33103             this.imageEl.on('load', this.onImageLoad, this);
33104             return;
33105         }
33106         
33107         this.resize();
33108     },
33109     
33110     onImageLoad : function()
33111     {
33112         this.resize();
33113     },
33114     
33115     resize : function()
33116     {
33117         var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33118         
33119         paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33120         
33121         if(this.bgimage.length){
33122             var image = this.el.select('.roo-brick-image-view', true).first();
33123             
33124             image.setWidth(paragraph.getWidth());
33125             
33126             if(this.square){
33127                 image.setHeight(paragraph.getWidth());
33128             }
33129             
33130             this.el.setHeight(image.getHeight());
33131             paragraph.setHeight(image.getHeight());
33132             
33133         }
33134         
33135     },
33136     
33137     enter: function(e, el)
33138     {
33139         e.preventDefault();
33140         
33141         if(this.bgimage.length){
33142             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33143             this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33144         }
33145     },
33146     
33147     leave: function(e, el)
33148     {
33149         e.preventDefault();
33150         
33151         if(this.bgimage.length){
33152             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33153             this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33154         }
33155     }
33156     
33157 });
33158
33159  
33160
33161  /*
33162  * - LGPL
33163  *
33164  * Number field 
33165  */
33166
33167 /**
33168  * @class Roo.bootstrap.NumberField
33169  * @extends Roo.bootstrap.Input
33170  * Bootstrap NumberField class
33171  * 
33172  * 
33173  * 
33174  * 
33175  * @constructor
33176  * Create a new NumberField
33177  * @param {Object} config The config object
33178  */
33179
33180 Roo.bootstrap.NumberField = function(config){
33181     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33182 };
33183
33184 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33185     
33186     /**
33187      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33188      */
33189     allowDecimals : true,
33190     /**
33191      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33192      */
33193     decimalSeparator : ".",
33194     /**
33195      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33196      */
33197     decimalPrecision : 2,
33198     /**
33199      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33200      */
33201     allowNegative : true,
33202     
33203     /**
33204      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33205      */
33206     allowZero: true,
33207     /**
33208      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33209      */
33210     minValue : Number.NEGATIVE_INFINITY,
33211     /**
33212      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33213      */
33214     maxValue : Number.MAX_VALUE,
33215     /**
33216      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33217      */
33218     minText : "The minimum value for this field is {0}",
33219     /**
33220      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33221      */
33222     maxText : "The maximum value for this field is {0}",
33223     /**
33224      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
33225      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33226      */
33227     nanText : "{0} is not a valid number",
33228     /**
33229      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33230      */
33231     castInt : true,
33232     /**
33233      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33234      */
33235     thousandsDelimiter : false,
33236     /**
33237      * @cfg {String} valueAlign alignment of value
33238      */
33239     valueAlign : "left",
33240
33241     getAutoCreate : function()
33242     {
33243         var hiddenInput = {
33244             tag: 'input',
33245             type: 'hidden',
33246             id: Roo.id(),
33247             cls: 'hidden-number-input'
33248         };
33249         
33250         if (this.name) {
33251             hiddenInput.name = this.name;
33252         }
33253         
33254         this.name = '';
33255         
33256         var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33257         
33258         this.name = hiddenInput.name;
33259         
33260         if(cfg.cn.length > 0) {
33261             cfg.cn.push(hiddenInput);
33262         }
33263         
33264         return cfg;
33265     },
33266
33267     // private
33268     initEvents : function()
33269     {   
33270         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33271         
33272         var allowed = "0123456789";
33273         
33274         if(this.allowDecimals){
33275             allowed += this.decimalSeparator;
33276         }
33277         
33278         if(this.allowNegative){
33279             allowed += "-";
33280         }
33281         
33282         if(this.thousandsDelimiter) {
33283             allowed += ",";
33284         }
33285         
33286         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33287         
33288         var keyPress = function(e){
33289             
33290             var k = e.getKey();
33291             
33292             var c = e.getCharCode();
33293             
33294             if(
33295                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33296                     allowed.indexOf(String.fromCharCode(c)) === -1
33297             ){
33298                 e.stopEvent();
33299                 return;
33300             }
33301             
33302             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33303                 return;
33304             }
33305             
33306             if(allowed.indexOf(String.fromCharCode(c)) === -1){
33307                 e.stopEvent();
33308             }
33309         };
33310         
33311         this.el.on("keypress", keyPress, this);
33312     },
33313     
33314     validateValue : function(value)
33315     {
33316         
33317         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33318             return false;
33319         }
33320         
33321         var num = this.parseValue(value);
33322         
33323         if(isNaN(num)){
33324             this.markInvalid(String.format(this.nanText, value));
33325             return false;
33326         }
33327         
33328         if(num < this.minValue){
33329             this.markInvalid(String.format(this.minText, this.minValue));
33330             return false;
33331         }
33332         
33333         if(num > this.maxValue){
33334             this.markInvalid(String.format(this.maxText, this.maxValue));
33335             return false;
33336         }
33337         
33338         return true;
33339     },
33340
33341     getValue : function()
33342     {
33343         var v = this.hiddenEl().getValue();
33344         
33345         return this.fixPrecision(this.parseValue(v));
33346     },
33347
33348     parseValue : function(value)
33349     {
33350         if(this.thousandsDelimiter) {
33351             value += "";
33352             r = new RegExp(",", "g");
33353             value = value.replace(r, "");
33354         }
33355         
33356         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33357         return isNaN(value) ? '' : value;
33358     },
33359
33360     fixPrecision : function(value)
33361     {
33362         if(this.thousandsDelimiter) {
33363             value += "";
33364             r = new RegExp(",", "g");
33365             value = value.replace(r, "");
33366         }
33367         
33368         var nan = isNaN(value);
33369         
33370         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33371             return nan ? '' : value;
33372         }
33373         return parseFloat(value).toFixed(this.decimalPrecision);
33374     },
33375
33376     setValue : function(v)
33377     {
33378         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33379         
33380         this.value = v;
33381         
33382         if(this.rendered){
33383             
33384             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33385             
33386             this.inputEl().dom.value = (v == '') ? '' :
33387                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33388             
33389             if(!this.allowZero && v === '0') {
33390                 this.hiddenEl().dom.value = '';
33391                 this.inputEl().dom.value = '';
33392             }
33393             
33394             this.validate();
33395         }
33396     },
33397
33398     decimalPrecisionFcn : function(v)
33399     {
33400         return Math.floor(v);
33401     },
33402
33403     beforeBlur : function()
33404     {
33405         if(!this.castInt){
33406             return;
33407         }
33408         
33409         var v = this.parseValue(this.getRawValue());
33410         
33411         if(v || v === 0){
33412             this.setValue(v);
33413         }
33414     },
33415     
33416     hiddenEl : function()
33417     {
33418         return this.el.select('input.hidden-number-input',true).first();
33419     }
33420     
33421 });
33422
33423  
33424
33425 /*
33426 * Licence: LGPL
33427 */
33428
33429 /**
33430  * @class Roo.bootstrap.DocumentSlider
33431  * @extends Roo.bootstrap.Component
33432  * Bootstrap DocumentSlider class
33433  * 
33434  * @constructor
33435  * Create a new DocumentViewer
33436  * @param {Object} config The config object
33437  */
33438
33439 Roo.bootstrap.DocumentSlider = function(config){
33440     Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33441     
33442     this.files = [];
33443     
33444     this.addEvents({
33445         /**
33446          * @event initial
33447          * Fire after initEvent
33448          * @param {Roo.bootstrap.DocumentSlider} this
33449          */
33450         "initial" : true,
33451         /**
33452          * @event update
33453          * Fire after update
33454          * @param {Roo.bootstrap.DocumentSlider} this
33455          */
33456         "update" : true,
33457         /**
33458          * @event click
33459          * Fire after click
33460          * @param {Roo.bootstrap.DocumentSlider} this
33461          */
33462         "click" : true
33463     });
33464 };
33465
33466 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
33467     
33468     files : false,
33469     
33470     indicator : 0,
33471     
33472     getAutoCreate : function()
33473     {
33474         var cfg = {
33475             tag : 'div',
33476             cls : 'roo-document-slider',
33477             cn : [
33478                 {
33479                     tag : 'div',
33480                     cls : 'roo-document-slider-header',
33481                     cn : [
33482                         {
33483                             tag : 'div',
33484                             cls : 'roo-document-slider-header-title'
33485                         }
33486                     ]
33487                 },
33488                 {
33489                     tag : 'div',
33490                     cls : 'roo-document-slider-body',
33491                     cn : [
33492                         {
33493                             tag : 'div',
33494                             cls : 'roo-document-slider-prev',
33495                             cn : [
33496                                 {
33497                                     tag : 'i',
33498                                     cls : 'fa fa-chevron-left'
33499                                 }
33500                             ]
33501                         },
33502                         {
33503                             tag : 'div',
33504                             cls : 'roo-document-slider-thumb',
33505                             cn : [
33506                                 {
33507                                     tag : 'img',
33508                                     cls : 'roo-document-slider-image'
33509                                 }
33510                             ]
33511                         },
33512                         {
33513                             tag : 'div',
33514                             cls : 'roo-document-slider-next',
33515                             cn : [
33516                                 {
33517                                     tag : 'i',
33518                                     cls : 'fa fa-chevron-right'
33519                                 }
33520                             ]
33521                         }
33522                     ]
33523                 }
33524             ]
33525         };
33526         
33527         return cfg;
33528     },
33529     
33530     initEvents : function()
33531     {
33532         this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33533         this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33534         
33535         this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33536         this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33537         
33538         this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33539         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33540         
33541         this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33542         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33543         
33544         this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33545         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33546         
33547         this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33548         this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33549         
33550         this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33551         this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33552         
33553         this.thumbEl.on('click', this.onClick, this);
33554         
33555         this.prevIndicator.on('click', this.prev, this);
33556         
33557         this.nextIndicator.on('click', this.next, this);
33558         
33559     },
33560     
33561     initial : function()
33562     {
33563         if(this.files.length){
33564             this.indicator = 1;
33565             this.update()
33566         }
33567         
33568         this.fireEvent('initial', this);
33569     },
33570     
33571     update : function()
33572     {
33573         this.imageEl.attr('src', this.files[this.indicator - 1]);
33574         
33575         this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33576         
33577         this.prevIndicator.show();
33578         
33579         if(this.indicator == 1){
33580             this.prevIndicator.hide();
33581         }
33582         
33583         this.nextIndicator.show();
33584         
33585         if(this.indicator == this.files.length){
33586             this.nextIndicator.hide();
33587         }
33588         
33589         this.thumbEl.scrollTo('top');
33590         
33591         this.fireEvent('update', this);
33592     },
33593     
33594     onClick : function(e)
33595     {
33596         e.preventDefault();
33597         
33598         this.fireEvent('click', this);
33599     },
33600     
33601     prev : function(e)
33602     {
33603         e.preventDefault();
33604         
33605         this.indicator = Math.max(1, this.indicator - 1);
33606         
33607         this.update();
33608     },
33609     
33610     next : function(e)
33611     {
33612         e.preventDefault();
33613         
33614         this.indicator = Math.min(this.files.length, this.indicator + 1);
33615         
33616         this.update();
33617     }
33618 });
33619 /*
33620  * - LGPL
33621  *
33622  * RadioSet
33623  *
33624  *
33625  */
33626
33627 /**
33628  * @class Roo.bootstrap.RadioSet
33629  * @extends Roo.bootstrap.Input
33630  * Bootstrap RadioSet class
33631  * @cfg {String} indicatorpos (left|right) default left
33632  * @cfg {Boolean} inline (true|false) inline the element (default true)
33633  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33634  * @constructor
33635  * Create a new RadioSet
33636  * @param {Object} config The config object
33637  */
33638
33639 Roo.bootstrap.RadioSet = function(config){
33640     
33641     Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33642     
33643     this.radioes = [];
33644     
33645     Roo.bootstrap.RadioSet.register(this);
33646     
33647     this.addEvents({
33648         /**
33649         * @event check
33650         * Fires when the element is checked or unchecked.
33651         * @param {Roo.bootstrap.RadioSet} this This radio
33652         * @param {Roo.bootstrap.Radio} item The checked item
33653         */
33654        check : true,
33655        /**
33656         * @event click
33657         * Fires when the element is click.
33658         * @param {Roo.bootstrap.RadioSet} this This radio set
33659         * @param {Roo.bootstrap.Radio} item The checked item
33660         * @param {Roo.EventObject} e The event object
33661         */
33662        click : true
33663     });
33664     
33665 };
33666
33667 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
33668
33669     radioes : false,
33670     
33671     inline : true,
33672     
33673     weight : '',
33674     
33675     indicatorpos : 'left',
33676     
33677     getAutoCreate : function()
33678     {
33679         var label = {
33680             tag : 'label',
33681             cls : 'roo-radio-set-label',
33682             cn : [
33683                 {
33684                     tag : 'span',
33685                     html : this.fieldLabel
33686                 }
33687             ]
33688         };
33689         
33690         if(this.indicatorpos == 'left'){
33691             label.cn.unshift({
33692                 tag : 'i',
33693                 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33694                 tooltip : 'This field is required'
33695             });
33696         } else {
33697             label.cn.push({
33698                 tag : 'i',
33699                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33700                 tooltip : 'This field is required'
33701             });
33702         }
33703         
33704         var items = {
33705             tag : 'div',
33706             cls : 'roo-radio-set-items'
33707         };
33708         
33709         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33710         
33711         if (align === 'left' && this.fieldLabel.length) {
33712             
33713             items = {
33714                 cls : "roo-radio-set-right", 
33715                 cn: [
33716                     items
33717                 ]
33718             };
33719             
33720             if(this.labelWidth > 12){
33721                 label.style = "width: " + this.labelWidth + 'px';
33722             }
33723             
33724             if(this.labelWidth < 13 && this.labelmd == 0){
33725                 this.labelmd = this.labelWidth;
33726             }
33727             
33728             if(this.labellg > 0){
33729                 label.cls += ' col-lg-' + this.labellg;
33730                 items.cls += ' col-lg-' + (12 - this.labellg);
33731             }
33732             
33733             if(this.labelmd > 0){
33734                 label.cls += ' col-md-' + this.labelmd;
33735                 items.cls += ' col-md-' + (12 - this.labelmd);
33736             }
33737             
33738             if(this.labelsm > 0){
33739                 label.cls += ' col-sm-' + this.labelsm;
33740                 items.cls += ' col-sm-' + (12 - this.labelsm);
33741             }
33742             
33743             if(this.labelxs > 0){
33744                 label.cls += ' col-xs-' + this.labelxs;
33745                 items.cls += ' col-xs-' + (12 - this.labelxs);
33746             }
33747         }
33748         
33749         var cfg = {
33750             tag : 'div',
33751             cls : 'roo-radio-set',
33752             cn : [
33753                 {
33754                     tag : 'input',
33755                     cls : 'roo-radio-set-input',
33756                     type : 'hidden',
33757                     name : this.name,
33758                     value : this.value ? this.value :  ''
33759                 },
33760                 label,
33761                 items
33762             ]
33763         };
33764         
33765         if(this.weight.length){
33766             cfg.cls += ' roo-radio-' + this.weight;
33767         }
33768         
33769         if(this.inline) {
33770             cfg.cls += ' roo-radio-set-inline';
33771         }
33772         
33773         var settings=this;
33774         ['xs','sm','md','lg'].map(function(size){
33775             if (settings[size]) {
33776                 cfg.cls += ' col-' + size + '-' + settings[size];
33777             }
33778         });
33779         
33780         return cfg;
33781         
33782     },
33783
33784     initEvents : function()
33785     {
33786         this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33787         this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33788         
33789         if(!this.fieldLabel.length){
33790             this.labelEl.hide();
33791         }
33792         
33793         this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33794         this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33795         
33796         this.indicator = this.indicatorEl();
33797         
33798         if(this.indicator){
33799             this.indicator.addClass('invisible');
33800         }
33801         
33802         this.originalValue = this.getValue();
33803         
33804     },
33805     
33806     inputEl: function ()
33807     {
33808         return this.el.select('.roo-radio-set-input', true).first();
33809     },
33810     
33811     getChildContainer : function()
33812     {
33813         return this.itemsEl;
33814     },
33815     
33816     register : function(item)
33817     {
33818         this.radioes.push(item);
33819         
33820     },
33821     
33822     validate : function()
33823     {   
33824         if(this.getVisibilityEl().hasClass('hidden')){
33825             return true;
33826         }
33827         
33828         var valid = false;
33829         
33830         Roo.each(this.radioes, function(i){
33831             if(!i.checked){
33832                 return;
33833             }
33834             
33835             valid = true;
33836             return false;
33837         });
33838         
33839         if(this.allowBlank) {
33840             return true;
33841         }
33842         
33843         if(this.disabled || valid){
33844             this.markValid();
33845             return true;
33846         }
33847         
33848         this.markInvalid();
33849         return false;
33850         
33851     },
33852     
33853     markValid : function()
33854     {
33855         if(this.labelEl.isVisible(true)){
33856             this.indicatorEl().removeClass('visible');
33857             this.indicatorEl().addClass('invisible');
33858         }
33859         
33860         this.el.removeClass([this.invalidClass, this.validClass]);
33861         this.el.addClass(this.validClass);
33862         
33863         this.fireEvent('valid', this);
33864     },
33865     
33866     markInvalid : function(msg)
33867     {
33868         if(this.allowBlank || this.disabled){
33869             return;
33870         }
33871         
33872         if(this.labelEl.isVisible(true)){
33873             this.indicatorEl().removeClass('invisible');
33874             this.indicatorEl().addClass('visible');
33875         }
33876         
33877         this.el.removeClass([this.invalidClass, this.validClass]);
33878         this.el.addClass(this.invalidClass);
33879         
33880         this.fireEvent('invalid', this, msg);
33881         
33882     },
33883     
33884     setValue : function(v, suppressEvent)
33885     {   
33886         if(this.value === v){
33887             return;
33888         }
33889         
33890         this.value = v;
33891         
33892         if(this.rendered){
33893             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33894         }
33895         
33896         Roo.each(this.radioes, function(i){
33897             i.checked = false;
33898             i.el.removeClass('checked');
33899         });
33900         
33901         Roo.each(this.radioes, function(i){
33902             
33903             if(i.value === v || i.value.toString() === v.toString()){
33904                 i.checked = true;
33905                 i.el.addClass('checked');
33906                 
33907                 if(suppressEvent !== true){
33908                     this.fireEvent('check', this, i);
33909                 }
33910                 
33911                 return false;
33912             }
33913             
33914         }, this);
33915         
33916         this.validate();
33917     },
33918     
33919     clearInvalid : function(){
33920         
33921         if(!this.el || this.preventMark){
33922             return;
33923         }
33924         
33925         this.el.removeClass([this.invalidClass]);
33926         
33927         this.fireEvent('valid', this);
33928     }
33929     
33930 });
33931
33932 Roo.apply(Roo.bootstrap.RadioSet, {
33933     
33934     groups: {},
33935     
33936     register : function(set)
33937     {
33938         this.groups[set.name] = set;
33939     },
33940     
33941     get: function(name) 
33942     {
33943         if (typeof(this.groups[name]) == 'undefined') {
33944             return false;
33945         }
33946         
33947         return this.groups[name] ;
33948     }
33949     
33950 });
33951 /*
33952  * Based on:
33953  * Ext JS Library 1.1.1
33954  * Copyright(c) 2006-2007, Ext JS, LLC.
33955  *
33956  * Originally Released Under LGPL - original licence link has changed is not relivant.
33957  *
33958  * Fork - LGPL
33959  * <script type="text/javascript">
33960  */
33961
33962
33963 /**
33964  * @class Roo.bootstrap.SplitBar
33965  * @extends Roo.util.Observable
33966  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33967  * <br><br>
33968  * Usage:
33969  * <pre><code>
33970 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33971                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33972 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33973 split.minSize = 100;
33974 split.maxSize = 600;
33975 split.animate = true;
33976 split.on('moved', splitterMoved);
33977 </code></pre>
33978  * @constructor
33979  * Create a new SplitBar
33980  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
33981  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
33982  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33983  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
33984                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33985                         position of the SplitBar).
33986  */
33987 Roo.bootstrap.SplitBar = function(cfg){
33988     
33989     /** @private */
33990     
33991     //{
33992     //  dragElement : elm
33993     //  resizingElement: el,
33994         // optional..
33995     //    orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33996     //    placement : Roo.bootstrap.SplitBar.LEFT  ,
33997         // existingProxy ???
33998     //}
33999     
34000     this.el = Roo.get(cfg.dragElement, true);
34001     this.el.dom.unselectable = "on";
34002     /** @private */
34003     this.resizingEl = Roo.get(cfg.resizingElement, true);
34004
34005     /**
34006      * @private
34007      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34008      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34009      * @type Number
34010      */
34011     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34012     
34013     /**
34014      * The minimum size of the resizing element. (Defaults to 0)
34015      * @type Number
34016      */
34017     this.minSize = 0;
34018     
34019     /**
34020      * The maximum size of the resizing element. (Defaults to 2000)
34021      * @type Number
34022      */
34023     this.maxSize = 2000;
34024     
34025     /**
34026      * Whether to animate the transition to the new size
34027      * @type Boolean
34028      */
34029     this.animate = false;
34030     
34031     /**
34032      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34033      * @type Boolean
34034      */
34035     this.useShim = false;
34036     
34037     /** @private */
34038     this.shim = null;
34039     
34040     if(!cfg.existingProxy){
34041         /** @private */
34042         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34043     }else{
34044         this.proxy = Roo.get(cfg.existingProxy).dom;
34045     }
34046     /** @private */
34047     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34048     
34049     /** @private */
34050     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34051     
34052     /** @private */
34053     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34054     
34055     /** @private */
34056     this.dragSpecs = {};
34057     
34058     /**
34059      * @private The adapter to use to positon and resize elements
34060      */
34061     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34062     this.adapter.init(this);
34063     
34064     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34065         /** @private */
34066         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34067         this.el.addClass("roo-splitbar-h");
34068     }else{
34069         /** @private */
34070         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34071         this.el.addClass("roo-splitbar-v");
34072     }
34073     
34074     this.addEvents({
34075         /**
34076          * @event resize
34077          * Fires when the splitter is moved (alias for {@link #event-moved})
34078          * @param {Roo.bootstrap.SplitBar} this
34079          * @param {Number} newSize the new width or height
34080          */
34081         "resize" : true,
34082         /**
34083          * @event moved
34084          * Fires when the splitter is moved
34085          * @param {Roo.bootstrap.SplitBar} this
34086          * @param {Number} newSize the new width or height
34087          */
34088         "moved" : true,
34089         /**
34090          * @event beforeresize
34091          * Fires before the splitter is dragged
34092          * @param {Roo.bootstrap.SplitBar} this
34093          */
34094         "beforeresize" : true,
34095
34096         "beforeapply" : true
34097     });
34098
34099     Roo.util.Observable.call(this);
34100 };
34101
34102 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34103     onStartProxyDrag : function(x, y){
34104         this.fireEvent("beforeresize", this);
34105         if(!this.overlay){
34106             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "roo-drag-overlay", html: "&#160;"}, true);
34107             o.unselectable();
34108             o.enableDisplayMode("block");
34109             // all splitbars share the same overlay
34110             Roo.bootstrap.SplitBar.prototype.overlay = o;
34111         }
34112         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34113         this.overlay.show();
34114         Roo.get(this.proxy).setDisplayed("block");
34115         var size = this.adapter.getElementSize(this);
34116         this.activeMinSize = this.getMinimumSize();;
34117         this.activeMaxSize = this.getMaximumSize();;
34118         var c1 = size - this.activeMinSize;
34119         var c2 = Math.max(this.activeMaxSize - size, 0);
34120         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34121             this.dd.resetConstraints();
34122             this.dd.setXConstraint(
34123                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
34124                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34125             );
34126             this.dd.setYConstraint(0, 0);
34127         }else{
34128             this.dd.resetConstraints();
34129             this.dd.setXConstraint(0, 0);
34130             this.dd.setYConstraint(
34131                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
34132                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34133             );
34134          }
34135         this.dragSpecs.startSize = size;
34136         this.dragSpecs.startPoint = [x, y];
34137         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34138     },
34139     
34140     /** 
34141      * @private Called after the drag operation by the DDProxy
34142      */
34143     onEndProxyDrag : function(e){
34144         Roo.get(this.proxy).setDisplayed(false);
34145         var endPoint = Roo.lib.Event.getXY(e);
34146         if(this.overlay){
34147             this.overlay.hide();
34148         }
34149         var newSize;
34150         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34151             newSize = this.dragSpecs.startSize + 
34152                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34153                     endPoint[0] - this.dragSpecs.startPoint[0] :
34154                     this.dragSpecs.startPoint[0] - endPoint[0]
34155                 );
34156         }else{
34157             newSize = this.dragSpecs.startSize + 
34158                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34159                     endPoint[1] - this.dragSpecs.startPoint[1] :
34160                     this.dragSpecs.startPoint[1] - endPoint[1]
34161                 );
34162         }
34163         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34164         if(newSize != this.dragSpecs.startSize){
34165             if(this.fireEvent('beforeapply', this, newSize) !== false){
34166                 this.adapter.setElementSize(this, newSize);
34167                 this.fireEvent("moved", this, newSize);
34168                 this.fireEvent("resize", this, newSize);
34169             }
34170         }
34171     },
34172     
34173     /**
34174      * Get the adapter this SplitBar uses
34175      * @return The adapter object
34176      */
34177     getAdapter : function(){
34178         return this.adapter;
34179     },
34180     
34181     /**
34182      * Set the adapter this SplitBar uses
34183      * @param {Object} adapter A SplitBar adapter object
34184      */
34185     setAdapter : function(adapter){
34186         this.adapter = adapter;
34187         this.adapter.init(this);
34188     },
34189     
34190     /**
34191      * Gets the minimum size for the resizing element
34192      * @return {Number} The minimum size
34193      */
34194     getMinimumSize : function(){
34195         return this.minSize;
34196     },
34197     
34198     /**
34199      * Sets the minimum size for the resizing element
34200      * @param {Number} minSize The minimum size
34201      */
34202     setMinimumSize : function(minSize){
34203         this.minSize = minSize;
34204     },
34205     
34206     /**
34207      * Gets the maximum size for the resizing element
34208      * @return {Number} The maximum size
34209      */
34210     getMaximumSize : function(){
34211         return this.maxSize;
34212     },
34213     
34214     /**
34215      * Sets the maximum size for the resizing element
34216      * @param {Number} maxSize The maximum size
34217      */
34218     setMaximumSize : function(maxSize){
34219         this.maxSize = maxSize;
34220     },
34221     
34222     /**
34223      * Sets the initialize size for the resizing element
34224      * @param {Number} size The initial size
34225      */
34226     setCurrentSize : function(size){
34227         var oldAnimate = this.animate;
34228         this.animate = false;
34229         this.adapter.setElementSize(this, size);
34230         this.animate = oldAnimate;
34231     },
34232     
34233     /**
34234      * Destroy this splitbar. 
34235      * @param {Boolean} removeEl True to remove the element
34236      */
34237     destroy : function(removeEl){
34238         if(this.shim){
34239             this.shim.remove();
34240         }
34241         this.dd.unreg();
34242         this.proxy.parentNode.removeChild(this.proxy);
34243         if(removeEl){
34244             this.el.remove();
34245         }
34246     }
34247 });
34248
34249 /**
34250  * @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.
34251  */
34252 Roo.bootstrap.SplitBar.createProxy = function(dir){
34253     var proxy = new Roo.Element(document.createElement("div"));
34254     proxy.unselectable();
34255     var cls = 'roo-splitbar-proxy';
34256     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34257     document.body.appendChild(proxy.dom);
34258     return proxy.dom;
34259 };
34260
34261 /** 
34262  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34263  * Default Adapter. It assumes the splitter and resizing element are not positioned
34264  * elements and only gets/sets the width of the element. Generally used for table based layouts.
34265  */
34266 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34267 };
34268
34269 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34270     // do nothing for now
34271     init : function(s){
34272     
34273     },
34274     /**
34275      * Called before drag operations to get the current size of the resizing element. 
34276      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34277      */
34278      getElementSize : function(s){
34279         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34280             return s.resizingEl.getWidth();
34281         }else{
34282             return s.resizingEl.getHeight();
34283         }
34284     },
34285     
34286     /**
34287      * Called after drag operations to set the size of the resizing element.
34288      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34289      * @param {Number} newSize The new size to set
34290      * @param {Function} onComplete A function to be invoked when resizing is complete
34291      */
34292     setElementSize : function(s, newSize, onComplete){
34293         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34294             if(!s.animate){
34295                 s.resizingEl.setWidth(newSize);
34296                 if(onComplete){
34297                     onComplete(s, newSize);
34298                 }
34299             }else{
34300                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34301             }
34302         }else{
34303             
34304             if(!s.animate){
34305                 s.resizingEl.setHeight(newSize);
34306                 if(onComplete){
34307                     onComplete(s, newSize);
34308                 }
34309             }else{
34310                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34311             }
34312         }
34313     }
34314 };
34315
34316 /** 
34317  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34318  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34319  * Adapter that  moves the splitter element to align with the resized sizing element. 
34320  * Used with an absolute positioned SplitBar.
34321  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34322  * document.body, make sure you assign an id to the body element.
34323  */
34324 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34325     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34326     this.container = Roo.get(container);
34327 };
34328
34329 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34330     init : function(s){
34331         this.basic.init(s);
34332     },
34333     
34334     getElementSize : function(s){
34335         return this.basic.getElementSize(s);
34336     },
34337     
34338     setElementSize : function(s, newSize, onComplete){
34339         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34340     },
34341     
34342     moveSplitter : function(s){
34343         var yes = Roo.bootstrap.SplitBar;
34344         switch(s.placement){
34345             case yes.LEFT:
34346                 s.el.setX(s.resizingEl.getRight());
34347                 break;
34348             case yes.RIGHT:
34349                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34350                 break;
34351             case yes.TOP:
34352                 s.el.setY(s.resizingEl.getBottom());
34353                 break;
34354             case yes.BOTTOM:
34355                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34356                 break;
34357         }
34358     }
34359 };
34360
34361 /**
34362  * Orientation constant - Create a vertical SplitBar
34363  * @static
34364  * @type Number
34365  */
34366 Roo.bootstrap.SplitBar.VERTICAL = 1;
34367
34368 /**
34369  * Orientation constant - Create a horizontal SplitBar
34370  * @static
34371  * @type Number
34372  */
34373 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34374
34375 /**
34376  * Placement constant - The resizing element is to the left of the splitter element
34377  * @static
34378  * @type Number
34379  */
34380 Roo.bootstrap.SplitBar.LEFT = 1;
34381
34382 /**
34383  * Placement constant - The resizing element is to the right of the splitter element
34384  * @static
34385  * @type Number
34386  */
34387 Roo.bootstrap.SplitBar.RIGHT = 2;
34388
34389 /**
34390  * Placement constant - The resizing element is positioned above the splitter element
34391  * @static
34392  * @type Number
34393  */
34394 Roo.bootstrap.SplitBar.TOP = 3;
34395
34396 /**
34397  * Placement constant - The resizing element is positioned under splitter element
34398  * @static
34399  * @type Number
34400  */
34401 Roo.bootstrap.SplitBar.BOTTOM = 4;
34402 Roo.namespace("Roo.bootstrap.layout");/*
34403  * Based on:
34404  * Ext JS Library 1.1.1
34405  * Copyright(c) 2006-2007, Ext JS, LLC.
34406  *
34407  * Originally Released Under LGPL - original licence link has changed is not relivant.
34408  *
34409  * Fork - LGPL
34410  * <script type="text/javascript">
34411  */
34412
34413 /**
34414  * @class Roo.bootstrap.layout.Manager
34415  * @extends Roo.bootstrap.Component
34416  * Base class for layout managers.
34417  */
34418 Roo.bootstrap.layout.Manager = function(config)
34419 {
34420     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34421
34422
34423
34424
34425
34426     /** false to disable window resize monitoring @type Boolean */
34427     this.monitorWindowResize = true;
34428     this.regions = {};
34429     this.addEvents({
34430         /**
34431          * @event layout
34432          * Fires when a layout is performed.
34433          * @param {Roo.LayoutManager} this
34434          */
34435         "layout" : true,
34436         /**
34437          * @event regionresized
34438          * Fires when the user resizes a region.
34439          * @param {Roo.LayoutRegion} region The resized region
34440          * @param {Number} newSize The new size (width for east/west, height for north/south)
34441          */
34442         "regionresized" : true,
34443         /**
34444          * @event regioncollapsed
34445          * Fires when a region is collapsed.
34446          * @param {Roo.LayoutRegion} region The collapsed region
34447          */
34448         "regioncollapsed" : true,
34449         /**
34450          * @event regionexpanded
34451          * Fires when a region is expanded.
34452          * @param {Roo.LayoutRegion} region The expanded region
34453          */
34454         "regionexpanded" : true
34455     });
34456     this.updating = false;
34457
34458     if (config.el) {
34459         this.el = Roo.get(config.el);
34460         this.initEvents();
34461     }
34462
34463 };
34464
34465 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34466
34467
34468     regions : null,
34469
34470     monitorWindowResize : true,
34471
34472
34473     updating : false,
34474
34475
34476     onRender : function(ct, position)
34477     {
34478         if(!this.el){
34479             this.el = Roo.get(ct);
34480             this.initEvents();
34481         }
34482         //this.fireEvent('render',this);
34483     },
34484
34485
34486     initEvents: function()
34487     {
34488
34489
34490         // ie scrollbar fix
34491         if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34492             document.body.scroll = "no";
34493         }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34494             this.el.position('relative');
34495         }
34496         this.id = this.el.id;
34497         this.el.addClass("roo-layout-container");
34498         Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34499         if(this.el.dom != document.body ) {
34500             this.el.on('resize', this.layout,this);
34501             this.el.on('show', this.layout,this);
34502         }
34503
34504     },
34505
34506     /**
34507      * Returns true if this layout is currently being updated
34508      * @return {Boolean}
34509      */
34510     isUpdating : function(){
34511         return this.updating;
34512     },
34513
34514     /**
34515      * Suspend the LayoutManager from doing auto-layouts while
34516      * making multiple add or remove calls
34517      */
34518     beginUpdate : function(){
34519         this.updating = true;
34520     },
34521
34522     /**
34523      * Restore auto-layouts and optionally disable the manager from performing a layout
34524      * @param {Boolean} noLayout true to disable a layout update
34525      */
34526     endUpdate : function(noLayout){
34527         this.updating = false;
34528         if(!noLayout){
34529             this.layout();
34530         }
34531     },
34532
34533     layout: function(){
34534         // abstract...
34535     },
34536
34537     onRegionResized : function(region, newSize){
34538         this.fireEvent("regionresized", region, newSize);
34539         this.layout();
34540     },
34541
34542     onRegionCollapsed : function(region){
34543         this.fireEvent("regioncollapsed", region);
34544     },
34545
34546     onRegionExpanded : function(region){
34547         this.fireEvent("regionexpanded", region);
34548     },
34549
34550     /**
34551      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34552      * performs box-model adjustments.
34553      * @return {Object} The size as an object {width: (the width), height: (the height)}
34554      */
34555     getViewSize : function()
34556     {
34557         var size;
34558         if(this.el.dom != document.body){
34559             size = this.el.getSize();
34560         }else{
34561             size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34562         }
34563         size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34564         size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34565         return size;
34566     },
34567
34568     /**
34569      * Returns the Element this layout is bound to.
34570      * @return {Roo.Element}
34571      */
34572     getEl : function(){
34573         return this.el;
34574     },
34575
34576     /**
34577      * Returns the specified region.
34578      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34579      * @return {Roo.LayoutRegion}
34580      */
34581     getRegion : function(target){
34582         return this.regions[target.toLowerCase()];
34583     },
34584
34585     onWindowResize : function(){
34586         if(this.monitorWindowResize){
34587             this.layout();
34588         }
34589     }
34590 });
34591 /*
34592  * Based on:
34593  * Ext JS Library 1.1.1
34594  * Copyright(c) 2006-2007, Ext JS, LLC.
34595  *
34596  * Originally Released Under LGPL - original licence link has changed is not relivant.
34597  *
34598  * Fork - LGPL
34599  * <script type="text/javascript">
34600  */
34601 /**
34602  * @class Roo.bootstrap.layout.Border
34603  * @extends Roo.bootstrap.layout.Manager
34604  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34605  * please see: examples/bootstrap/nested.html<br><br>
34606  
34607 <b>The container the layout is rendered into can be either the body element or any other element.
34608 If it is not the body element, the container needs to either be an absolute positioned element,
34609 or you will need to add "position:relative" to the css of the container.  You will also need to specify
34610 the container size if it is not the body element.</b>
34611
34612 * @constructor
34613 * Create a new Border
34614 * @param {Object} config Configuration options
34615  */
34616 Roo.bootstrap.layout.Border = function(config){
34617     config = config || {};
34618     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34619     
34620     
34621     
34622     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34623         if(config[region]){
34624             config[region].region = region;
34625             this.addRegion(config[region]);
34626         }
34627     },this);
34628     
34629 };
34630
34631 Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
34632
34633 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34634     /**
34635      * Creates and adds a new region if it doesn't already exist.
34636      * @param {String} target The target region key (north, south, east, west or center).
34637      * @param {Object} config The regions config object
34638      * @return {BorderLayoutRegion} The new region
34639      */
34640     addRegion : function(config)
34641     {
34642         if(!this.regions[config.region]){
34643             var r = this.factory(config);
34644             this.bindRegion(r);
34645         }
34646         return this.regions[config.region];
34647     },
34648
34649     // private (kinda)
34650     bindRegion : function(r){
34651         this.regions[r.config.region] = r;
34652         
34653         r.on("visibilitychange",    this.layout, this);
34654         r.on("paneladded",          this.layout, this);
34655         r.on("panelremoved",        this.layout, this);
34656         r.on("invalidated",         this.layout, this);
34657         r.on("resized",             this.onRegionResized, this);
34658         r.on("collapsed",           this.onRegionCollapsed, this);
34659         r.on("expanded",            this.onRegionExpanded, this);
34660     },
34661
34662     /**
34663      * Performs a layout update.
34664      */
34665     layout : function()
34666     {
34667         if(this.updating) {
34668             return;
34669         }
34670         
34671         // render all the rebions if they have not been done alreayd?
34672         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34673             if(this.regions[region] && !this.regions[region].bodyEl){
34674                 this.regions[region].onRender(this.el)
34675             }
34676         },this);
34677         
34678         var size = this.getViewSize();
34679         var w = size.width;
34680         var h = size.height;
34681         var centerW = w;
34682         var centerH = h;
34683         var centerY = 0;
34684         var centerX = 0;
34685         //var x = 0, y = 0;
34686
34687         var rs = this.regions;
34688         var north = rs["north"];
34689         var south = rs["south"]; 
34690         var west = rs["west"];
34691         var east = rs["east"];
34692         var center = rs["center"];
34693         //if(this.hideOnLayout){ // not supported anymore
34694             //c.el.setStyle("display", "none");
34695         //}
34696         if(north && north.isVisible()){
34697             var b = north.getBox();
34698             var m = north.getMargins();
34699             b.width = w - (m.left+m.right);
34700             b.x = m.left;
34701             b.y = m.top;
34702             centerY = b.height + b.y + m.bottom;
34703             centerH -= centerY;
34704             north.updateBox(this.safeBox(b));
34705         }
34706         if(south && south.isVisible()){
34707             var b = south.getBox();
34708             var m = south.getMargins();
34709             b.width = w - (m.left+m.right);
34710             b.x = m.left;
34711             var totalHeight = (b.height + m.top + m.bottom);
34712             b.y = h - totalHeight + m.top;
34713             centerH -= totalHeight;
34714             south.updateBox(this.safeBox(b));
34715         }
34716         if(west && west.isVisible()){
34717             var b = west.getBox();
34718             var m = west.getMargins();
34719             b.height = centerH - (m.top+m.bottom);
34720             b.x = m.left;
34721             b.y = centerY + m.top;
34722             var totalWidth = (b.width + m.left + m.right);
34723             centerX += totalWidth;
34724             centerW -= totalWidth;
34725             west.updateBox(this.safeBox(b));
34726         }
34727         if(east && east.isVisible()){
34728             var b = east.getBox();
34729             var m = east.getMargins();
34730             b.height = centerH - (m.top+m.bottom);
34731             var totalWidth = (b.width + m.left + m.right);
34732             b.x = w - totalWidth + m.left;
34733             b.y = centerY + m.top;
34734             centerW -= totalWidth;
34735             east.updateBox(this.safeBox(b));
34736         }
34737         if(center){
34738             var m = center.getMargins();
34739             var centerBox = {
34740                 x: centerX + m.left,
34741                 y: centerY + m.top,
34742                 width: centerW - (m.left+m.right),
34743                 height: centerH - (m.top+m.bottom)
34744             };
34745             //if(this.hideOnLayout){
34746                 //center.el.setStyle("display", "block");
34747             //}
34748             center.updateBox(this.safeBox(centerBox));
34749         }
34750         this.el.repaint();
34751         this.fireEvent("layout", this);
34752     },
34753
34754     // private
34755     safeBox : function(box){
34756         box.width = Math.max(0, box.width);
34757         box.height = Math.max(0, box.height);
34758         return box;
34759     },
34760
34761     /**
34762      * Adds a ContentPanel (or subclass) to this layout.
34763      * @param {String} target The target region key (north, south, east, west or center).
34764      * @param {Roo.ContentPanel} panel The panel to add
34765      * @return {Roo.ContentPanel} The added panel
34766      */
34767     add : function(target, panel){
34768          
34769         target = target.toLowerCase();
34770         return this.regions[target].add(panel);
34771     },
34772
34773     /**
34774      * Remove a ContentPanel (or subclass) to this layout.
34775      * @param {String} target The target region key (north, south, east, west or center).
34776      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34777      * @return {Roo.ContentPanel} The removed panel
34778      */
34779     remove : function(target, panel){
34780         target = target.toLowerCase();
34781         return this.regions[target].remove(panel);
34782     },
34783
34784     /**
34785      * Searches all regions for a panel with the specified id
34786      * @param {String} panelId
34787      * @return {Roo.ContentPanel} The panel or null if it wasn't found
34788      */
34789     findPanel : function(panelId){
34790         var rs = this.regions;
34791         for(var target in rs){
34792             if(typeof rs[target] != "function"){
34793                 var p = rs[target].getPanel(panelId);
34794                 if(p){
34795                     return p;
34796                 }
34797             }
34798         }
34799         return null;
34800     },
34801
34802     /**
34803      * Searches all regions for a panel with the specified id and activates (shows) it.
34804      * @param {String/ContentPanel} panelId The panels id or the panel itself
34805      * @return {Roo.ContentPanel} The shown panel or null
34806      */
34807     showPanel : function(panelId) {
34808       var rs = this.regions;
34809       for(var target in rs){
34810          var r = rs[target];
34811          if(typeof r != "function"){
34812             if(r.hasPanel(panelId)){
34813                return r.showPanel(panelId);
34814             }
34815          }
34816       }
34817       return null;
34818    },
34819
34820    /**
34821      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34822      * @param {Roo.state.Provider} provider (optional) An alternate state provider
34823      */
34824    /*
34825     restoreState : function(provider){
34826         if(!provider){
34827             provider = Roo.state.Manager;
34828         }
34829         var sm = new Roo.LayoutStateManager();
34830         sm.init(this, provider);
34831     },
34832 */
34833  
34834  
34835     /**
34836      * Adds a xtype elements to the layout.
34837      * <pre><code>
34838
34839 layout.addxtype({
34840        xtype : 'ContentPanel',
34841        region: 'west',
34842        items: [ .... ]
34843    }
34844 );
34845
34846 layout.addxtype({
34847         xtype : 'NestedLayoutPanel',
34848         region: 'west',
34849         layout: {
34850            center: { },
34851            west: { }   
34852         },
34853         items : [ ... list of content panels or nested layout panels.. ]
34854    }
34855 );
34856 </code></pre>
34857      * @param {Object} cfg Xtype definition of item to add.
34858      */
34859     addxtype : function(cfg)
34860     {
34861         // basically accepts a pannel...
34862         // can accept a layout region..!?!?
34863         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34864         
34865         
34866         // theory?  children can only be panels??
34867         
34868         //if (!cfg.xtype.match(/Panel$/)) {
34869         //    return false;
34870         //}
34871         var ret = false;
34872         
34873         if (typeof(cfg.region) == 'undefined') {
34874             Roo.log("Failed to add Panel, region was not set");
34875             Roo.log(cfg);
34876             return false;
34877         }
34878         var region = cfg.region;
34879         delete cfg.region;
34880         
34881           
34882         var xitems = [];
34883         if (cfg.items) {
34884             xitems = cfg.items;
34885             delete cfg.items;
34886         }
34887         var nb = false;
34888         
34889         switch(cfg.xtype) 
34890         {
34891             case 'Content':  // ContentPanel (el, cfg)
34892             case 'Scroll':  // ContentPanel (el, cfg)
34893             case 'View': 
34894                 cfg.autoCreate = true;
34895                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34896                 //} else {
34897                 //    var el = this.el.createChild();
34898                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34899                 //}
34900                 
34901                 this.add(region, ret);
34902                 break;
34903             
34904             /*
34905             case 'TreePanel': // our new panel!
34906                 cfg.el = this.el.createChild();
34907                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34908                 this.add(region, ret);
34909                 break;
34910             */
34911             
34912             case 'Nest': 
34913                 // create a new Layout (which is  a Border Layout...
34914                 
34915                 var clayout = cfg.layout;
34916                 clayout.el  = this.el.createChild();
34917                 clayout.items   = clayout.items  || [];
34918                 
34919                 delete cfg.layout;
34920                 
34921                 // replace this exitems with the clayout ones..
34922                 xitems = clayout.items;
34923                  
34924                 // force background off if it's in center...
34925                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34926                     cfg.background = false;
34927                 }
34928                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
34929                 
34930                 
34931                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34932                 //console.log('adding nested layout panel '  + cfg.toSource());
34933                 this.add(region, ret);
34934                 nb = {}; /// find first...
34935                 break;
34936             
34937             case 'Grid':
34938                 
34939                 // needs grid and region
34940                 
34941                 //var el = this.getRegion(region).el.createChild();
34942                 /*
34943                  *var el = this.el.createChild();
34944                 // create the grid first...
34945                 cfg.grid.container = el;
34946                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34947                 */
34948                 
34949                 if (region == 'center' && this.active ) {
34950                     cfg.background = false;
34951                 }
34952                 
34953                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34954                 
34955                 this.add(region, ret);
34956                 /*
34957                 if (cfg.background) {
34958                     // render grid on panel activation (if panel background)
34959                     ret.on('activate', function(gp) {
34960                         if (!gp.grid.rendered) {
34961                     //        gp.grid.render(el);
34962                         }
34963                     });
34964                 } else {
34965                   //  cfg.grid.render(el);
34966                 }
34967                 */
34968                 break;
34969            
34970            
34971             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34972                 // it was the old xcomponent building that caused this before.
34973                 // espeically if border is the top element in the tree.
34974                 ret = this;
34975                 break; 
34976                 
34977                     
34978                 
34979                 
34980                 
34981             default:
34982                 /*
34983                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34984                     
34985                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34986                     this.add(region, ret);
34987                 } else {
34988                 */
34989                     Roo.log(cfg);
34990                     throw "Can not add '" + cfg.xtype + "' to Border";
34991                     return null;
34992              
34993                                 
34994              
34995         }
34996         this.beginUpdate();
34997         // add children..
34998         var region = '';
34999         var abn = {};
35000         Roo.each(xitems, function(i)  {
35001             region = nb && i.region ? i.region : false;
35002             
35003             var add = ret.addxtype(i);
35004            
35005             if (region) {
35006                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35007                 if (!i.background) {
35008                     abn[region] = nb[region] ;
35009                 }
35010             }
35011             
35012         });
35013         this.endUpdate();
35014
35015         // make the last non-background panel active..
35016         //if (nb) { Roo.log(abn); }
35017         if (nb) {
35018             
35019             for(var r in abn) {
35020                 region = this.getRegion(r);
35021                 if (region) {
35022                     // tried using nb[r], but it does not work..
35023                      
35024                     region.showPanel(abn[r]);
35025                    
35026                 }
35027             }
35028         }
35029         return ret;
35030         
35031     },
35032     
35033     
35034 // private
35035     factory : function(cfg)
35036     {
35037         
35038         var validRegions = Roo.bootstrap.layout.Border.regions;
35039
35040         var target = cfg.region;
35041         cfg.mgr = this;
35042         
35043         var r = Roo.bootstrap.layout;
35044         Roo.log(target);
35045         switch(target){
35046             case "north":
35047                 return new r.North(cfg);
35048             case "south":
35049                 return new r.South(cfg);
35050             case "east":
35051                 return new r.East(cfg);
35052             case "west":
35053                 return new r.West(cfg);
35054             case "center":
35055                 return new r.Center(cfg);
35056         }
35057         throw 'Layout region "'+target+'" not supported.';
35058     }
35059     
35060     
35061 });
35062  /*
35063  * Based on:
35064  * Ext JS Library 1.1.1
35065  * Copyright(c) 2006-2007, Ext JS, LLC.
35066  *
35067  * Originally Released Under LGPL - original licence link has changed is not relivant.
35068  *
35069  * Fork - LGPL
35070  * <script type="text/javascript">
35071  */
35072  
35073 /**
35074  * @class Roo.bootstrap.layout.Basic
35075  * @extends Roo.util.Observable
35076  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35077  * and does not have a titlebar, tabs or any other features. All it does is size and position 
35078  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35079  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35080  * @cfg {string}   region  the region that it inhabits..
35081  * @cfg {bool}   skipConfig skip config?
35082  * 
35083
35084  */
35085 Roo.bootstrap.layout.Basic = function(config){
35086     
35087     this.mgr = config.mgr;
35088     
35089     this.position = config.region;
35090     
35091     var skipConfig = config.skipConfig;
35092     
35093     this.events = {
35094         /**
35095          * @scope Roo.BasicLayoutRegion
35096          */
35097         
35098         /**
35099          * @event beforeremove
35100          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35101          * @param {Roo.LayoutRegion} this
35102          * @param {Roo.ContentPanel} panel The panel
35103          * @param {Object} e The cancel event object
35104          */
35105         "beforeremove" : true,
35106         /**
35107          * @event invalidated
35108          * Fires when the layout for this region is changed.
35109          * @param {Roo.LayoutRegion} this
35110          */
35111         "invalidated" : true,
35112         /**
35113          * @event visibilitychange
35114          * Fires when this region is shown or hidden 
35115          * @param {Roo.LayoutRegion} this
35116          * @param {Boolean} visibility true or false
35117          */
35118         "visibilitychange" : true,
35119         /**
35120          * @event paneladded
35121          * Fires when a panel is added. 
35122          * @param {Roo.LayoutRegion} this
35123          * @param {Roo.ContentPanel} panel The panel
35124          */
35125         "paneladded" : true,
35126         /**
35127          * @event panelremoved
35128          * Fires when a panel is removed. 
35129          * @param {Roo.LayoutRegion} this
35130          * @param {Roo.ContentPanel} panel The panel
35131          */
35132         "panelremoved" : true,
35133         /**
35134          * @event beforecollapse
35135          * Fires when this region before collapse.
35136          * @param {Roo.LayoutRegion} this
35137          */
35138         "beforecollapse" : true,
35139         /**
35140          * @event collapsed
35141          * Fires when this region is collapsed.
35142          * @param {Roo.LayoutRegion} this
35143          */
35144         "collapsed" : true,
35145         /**
35146          * @event expanded
35147          * Fires when this region is expanded.
35148          * @param {Roo.LayoutRegion} this
35149          */
35150         "expanded" : true,
35151         /**
35152          * @event slideshow
35153          * Fires when this region is slid into view.
35154          * @param {Roo.LayoutRegion} this
35155          */
35156         "slideshow" : true,
35157         /**
35158          * @event slidehide
35159          * Fires when this region slides out of view. 
35160          * @param {Roo.LayoutRegion} this
35161          */
35162         "slidehide" : true,
35163         /**
35164          * @event panelactivated
35165          * Fires when a panel is activated. 
35166          * @param {Roo.LayoutRegion} this
35167          * @param {Roo.ContentPanel} panel The activated panel
35168          */
35169         "panelactivated" : true,
35170         /**
35171          * @event resized
35172          * Fires when the user resizes this region. 
35173          * @param {Roo.LayoutRegion} this
35174          * @param {Number} newSize The new size (width for east/west, height for north/south)
35175          */
35176         "resized" : true
35177     };
35178     /** A collection of panels in this region. @type Roo.util.MixedCollection */
35179     this.panels = new Roo.util.MixedCollection();
35180     this.panels.getKey = this.getPanelId.createDelegate(this);
35181     this.box = null;
35182     this.activePanel = null;
35183     // ensure listeners are added...
35184     
35185     if (config.listeners || config.events) {
35186         Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35187             listeners : config.listeners || {},
35188             events : config.events || {}
35189         });
35190     }
35191     
35192     if(skipConfig !== true){
35193         this.applyConfig(config);
35194     }
35195 };
35196
35197 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35198 {
35199     getPanelId : function(p){
35200         return p.getId();
35201     },
35202     
35203     applyConfig : function(config){
35204         this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35205         this.config = config;
35206         
35207     },
35208     
35209     /**
35210      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
35211      * the width, for horizontal (north, south) the height.
35212      * @param {Number} newSize The new width or height
35213      */
35214     resizeTo : function(newSize){
35215         var el = this.el ? this.el :
35216                  (this.activePanel ? this.activePanel.getEl() : null);
35217         if(el){
35218             switch(this.position){
35219                 case "east":
35220                 case "west":
35221                     el.setWidth(newSize);
35222                     this.fireEvent("resized", this, newSize);
35223                 break;
35224                 case "north":
35225                 case "south":
35226                     el.setHeight(newSize);
35227                     this.fireEvent("resized", this, newSize);
35228                 break;                
35229             }
35230         }
35231     },
35232     
35233     getBox : function(){
35234         return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35235     },
35236     
35237     getMargins : function(){
35238         return this.margins;
35239     },
35240     
35241     updateBox : function(box){
35242         this.box = box;
35243         var el = this.activePanel.getEl();
35244         el.dom.style.left = box.x + "px";
35245         el.dom.style.top = box.y + "px";
35246         this.activePanel.setSize(box.width, box.height);
35247     },
35248     
35249     /**
35250      * Returns the container element for this region.
35251      * @return {Roo.Element}
35252      */
35253     getEl : function(){
35254         return this.activePanel;
35255     },
35256     
35257     /**
35258      * Returns true if this region is currently visible.
35259      * @return {Boolean}
35260      */
35261     isVisible : function(){
35262         return this.activePanel ? true : false;
35263     },
35264     
35265     setActivePanel : function(panel){
35266         panel = this.getPanel(panel);
35267         if(this.activePanel && this.activePanel != panel){
35268             this.activePanel.setActiveState(false);
35269             this.activePanel.getEl().setLeftTop(-10000,-10000);
35270         }
35271         this.activePanel = panel;
35272         panel.setActiveState(true);
35273         if(this.box){
35274             panel.setSize(this.box.width, this.box.height);
35275         }
35276         this.fireEvent("panelactivated", this, panel);
35277         this.fireEvent("invalidated");
35278     },
35279     
35280     /**
35281      * Show the specified panel.
35282      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35283      * @return {Roo.ContentPanel} The shown panel or null
35284      */
35285     showPanel : function(panel){
35286         panel = this.getPanel(panel);
35287         if(panel){
35288             this.setActivePanel(panel);
35289         }
35290         return panel;
35291     },
35292     
35293     /**
35294      * Get the active panel for this region.
35295      * @return {Roo.ContentPanel} The active panel or null
35296      */
35297     getActivePanel : function(){
35298         return this.activePanel;
35299     },
35300     
35301     /**
35302      * Add the passed ContentPanel(s)
35303      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35304      * @return {Roo.ContentPanel} The panel added (if only one was added)
35305      */
35306     add : function(panel){
35307         if(arguments.length > 1){
35308             for(var i = 0, len = arguments.length; i < len; i++) {
35309                 this.add(arguments[i]);
35310             }
35311             return null;
35312         }
35313         if(this.hasPanel(panel)){
35314             this.showPanel(panel);
35315             return panel;
35316         }
35317         var el = panel.getEl();
35318         if(el.dom.parentNode != this.mgr.el.dom){
35319             this.mgr.el.dom.appendChild(el.dom);
35320         }
35321         if(panel.setRegion){
35322             panel.setRegion(this);
35323         }
35324         this.panels.add(panel);
35325         el.setStyle("position", "absolute");
35326         if(!panel.background){
35327             this.setActivePanel(panel);
35328             if(this.config.initialSize && this.panels.getCount()==1){
35329                 this.resizeTo(this.config.initialSize);
35330             }
35331         }
35332         this.fireEvent("paneladded", this, panel);
35333         return panel;
35334     },
35335     
35336     /**
35337      * Returns true if the panel is in this region.
35338      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35339      * @return {Boolean}
35340      */
35341     hasPanel : function(panel){
35342         if(typeof panel == "object"){ // must be panel obj
35343             panel = panel.getId();
35344         }
35345         return this.getPanel(panel) ? true : false;
35346     },
35347     
35348     /**
35349      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35350      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35351      * @param {Boolean} preservePanel Overrides the config preservePanel option
35352      * @return {Roo.ContentPanel} The panel that was removed
35353      */
35354     remove : function(panel, preservePanel){
35355         panel = this.getPanel(panel);
35356         if(!panel){
35357             return null;
35358         }
35359         var e = {};
35360         this.fireEvent("beforeremove", this, panel, e);
35361         if(e.cancel === true){
35362             return null;
35363         }
35364         var panelId = panel.getId();
35365         this.panels.removeKey(panelId);
35366         return panel;
35367     },
35368     
35369     /**
35370      * Returns the panel specified or null if it's not in this region.
35371      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35372      * @return {Roo.ContentPanel}
35373      */
35374     getPanel : function(id){
35375         if(typeof id == "object"){ // must be panel obj
35376             return id;
35377         }
35378         return this.panels.get(id);
35379     },
35380     
35381     /**
35382      * Returns this regions position (north/south/east/west/center).
35383      * @return {String} 
35384      */
35385     getPosition: function(){
35386         return this.position;    
35387     }
35388 });/*
35389  * Based on:
35390  * Ext JS Library 1.1.1
35391  * Copyright(c) 2006-2007, Ext JS, LLC.
35392  *
35393  * Originally Released Under LGPL - original licence link has changed is not relivant.
35394  *
35395  * Fork - LGPL
35396  * <script type="text/javascript">
35397  */
35398  
35399 /**
35400  * @class Roo.bootstrap.layout.Region
35401  * @extends Roo.bootstrap.layout.Basic
35402  * This class represents a region in a layout manager.
35403  
35404  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35405  * @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})
35406  * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
35407  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
35408  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
35409  * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
35410  * @cfg {String}    title           The title for the region (overrides panel titles)
35411  * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
35412  * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35413  * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
35414  * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35415  * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
35416  * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35417  *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
35418  * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
35419  * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
35420  * @cfg {String}    overflow       (hidden|visible) if you have menus in the region, then you need to set this to visible.
35421
35422  * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
35423  * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
35424  * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
35425  * @cfg {Number}    width           For East/West panels
35426  * @cfg {Number}    height          For North/South panels
35427  * @cfg {Boolean}   split           To show the splitter
35428  * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
35429  * 
35430  * @cfg {string}   cls             Extra CSS classes to add to region
35431  * 
35432  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35433  * @cfg {string}   region  the region that it inhabits..
35434  *
35435
35436  * @xxxcfg {Boolean}   collapsible     DISABLED False to disable collapsing (defaults to true)
35437  * @xxxcfg {Boolean}   collapsed       DISABLED True to set the initial display to collapsed (defaults to false)
35438
35439  * @xxxcfg {String}    collapsedTitle  DISABLED Optional string message to display in the collapsed block of a north or south region
35440  * @xxxxcfg {Boolean}   floatable       DISABLED False to disable floating (defaults to true)
35441  * @xxxxcfg {Boolean}   showPin         True to show a pin button NOT SUPPORTED YET
35442  */
35443 Roo.bootstrap.layout.Region = function(config)
35444 {
35445     this.applyConfig(config);
35446
35447     var mgr = config.mgr;
35448     var pos = config.region;
35449     config.skipConfig = true;
35450     Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35451     
35452     if (mgr.el) {
35453         this.onRender(mgr.el);   
35454     }
35455      
35456     this.visible = true;
35457     this.collapsed = false;
35458     this.unrendered_panels = [];
35459 };
35460
35461 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35462
35463     position: '', // set by wrapper (eg. north/south etc..)
35464     unrendered_panels : null,  // unrendered panels.
35465     createBody : function(){
35466         /** This region's body element 
35467         * @type Roo.Element */
35468         this.bodyEl = this.el.createChild({
35469                 tag: "div",
35470                 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35471         });
35472     },
35473
35474     onRender: function(ctr, pos)
35475     {
35476         var dh = Roo.DomHelper;
35477         /** This region's container element 
35478         * @type Roo.Element */
35479         this.el = dh.append(ctr.dom, {
35480                 tag: "div",
35481                 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35482             }, true);
35483         /** This region's title element 
35484         * @type Roo.Element */
35485     
35486         this.titleEl = dh.append(this.el.dom,
35487             {
35488                     tag: "div",
35489                     unselectable: "on",
35490                     cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35491                     children:[
35492                         {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
35493                         {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35494                     ]}, true);
35495         
35496         this.titleEl.enableDisplayMode();
35497         /** This region's title text element 
35498         * @type HTMLElement */
35499         this.titleTextEl = this.titleEl.dom.firstChild;
35500         this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35501         /*
35502         this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35503         this.closeBtn.enableDisplayMode();
35504         this.closeBtn.on("click", this.closeClicked, this);
35505         this.closeBtn.hide();
35506     */
35507         this.createBody(this.config);
35508         if(this.config.hideWhenEmpty){
35509             this.hide();
35510             this.on("paneladded", this.validateVisibility, this);
35511             this.on("panelremoved", this.validateVisibility, this);
35512         }
35513         if(this.autoScroll){
35514             this.bodyEl.setStyle("overflow", "auto");
35515         }else{
35516             this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35517         }
35518         //if(c.titlebar !== false){
35519             if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35520                 this.titleEl.hide();
35521             }else{
35522                 this.titleEl.show();
35523                 if(this.config.title){
35524                     this.titleTextEl.innerHTML = this.config.title;
35525                 }
35526             }
35527         //}
35528         if(this.config.collapsed){
35529             this.collapse(true);
35530         }
35531         if(this.config.hidden){
35532             this.hide();
35533         }
35534         
35535         if (this.unrendered_panels && this.unrendered_panels.length) {
35536             for (var i =0;i< this.unrendered_panels.length; i++) {
35537                 this.add(this.unrendered_panels[i]);
35538             }
35539             this.unrendered_panels = null;
35540             
35541         }
35542         
35543     },
35544     
35545     applyConfig : function(c)
35546     {
35547         /*
35548          *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35549             var dh = Roo.DomHelper;
35550             if(c.titlebar !== false){
35551                 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35552                 this.collapseBtn.on("click", this.collapse, this);
35553                 this.collapseBtn.enableDisplayMode();
35554                 /*
35555                 if(c.showPin === true || this.showPin){
35556                     this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35557                     this.stickBtn.enableDisplayMode();
35558                     this.stickBtn.on("click", this.expand, this);
35559                     this.stickBtn.hide();
35560                 }
35561                 
35562             }
35563             */
35564             /** This region's collapsed element
35565             * @type Roo.Element */
35566             /*
35567              *
35568             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35569                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35570             ]}, true);
35571             
35572             if(c.floatable !== false){
35573                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35574                this.collapsedEl.on("click", this.collapseClick, this);
35575             }
35576
35577             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35578                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35579                    id: "message", unselectable: "on", style:{"float":"left"}});
35580                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35581              }
35582             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35583             this.expandBtn.on("click", this.expand, this);
35584             
35585         }
35586         
35587         if(this.collapseBtn){
35588             this.collapseBtn.setVisible(c.collapsible == true);
35589         }
35590         
35591         this.cmargins = c.cmargins || this.cmargins ||
35592                          (this.position == "west" || this.position == "east" ?
35593                              {top: 0, left: 2, right:2, bottom: 0} :
35594                              {top: 2, left: 0, right:0, bottom: 2});
35595         */
35596         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35597         
35598         
35599         this.bottomTabs = c.tabPosition != "top";
35600         
35601         this.autoScroll = c.autoScroll || false;
35602         
35603         
35604        
35605         
35606         this.duration = c.duration || .30;
35607         this.slideDuration = c.slideDuration || .45;
35608         this.config = c;
35609        
35610     },
35611     /**
35612      * Returns true if this region is currently visible.
35613      * @return {Boolean}
35614      */
35615     isVisible : function(){
35616         return this.visible;
35617     },
35618
35619     /**
35620      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35621      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
35622      */
35623     //setCollapsedTitle : function(title){
35624     //    title = title || "&#160;";
35625      //   if(this.collapsedTitleTextEl){
35626       //      this.collapsedTitleTextEl.innerHTML = title;
35627        // }
35628     //},
35629
35630     getBox : function(){
35631         var b;
35632       //  if(!this.collapsed){
35633             b = this.el.getBox(false, true);
35634        // }else{
35635           //  b = this.collapsedEl.getBox(false, true);
35636         //}
35637         return b;
35638     },
35639
35640     getMargins : function(){
35641         return this.margins;
35642         //return this.collapsed ? this.cmargins : this.margins;
35643     },
35644 /*
35645     highlight : function(){
35646         this.el.addClass("x-layout-panel-dragover");
35647     },
35648
35649     unhighlight : function(){
35650         this.el.removeClass("x-layout-panel-dragover");
35651     },
35652 */
35653     updateBox : function(box)
35654     {
35655         if (!this.bodyEl) {
35656             return; // not rendered yet..
35657         }
35658         
35659         this.box = box;
35660         if(!this.collapsed){
35661             this.el.dom.style.left = box.x + "px";
35662             this.el.dom.style.top = box.y + "px";
35663             this.updateBody(box.width, box.height);
35664         }else{
35665             this.collapsedEl.dom.style.left = box.x + "px";
35666             this.collapsedEl.dom.style.top = box.y + "px";
35667             this.collapsedEl.setSize(box.width, box.height);
35668         }
35669         if(this.tabs){
35670             this.tabs.autoSizeTabs();
35671         }
35672     },
35673
35674     updateBody : function(w, h)
35675     {
35676         if(w !== null){
35677             this.el.setWidth(w);
35678             w -= this.el.getBorderWidth("rl");
35679             if(this.config.adjustments){
35680                 w += this.config.adjustments[0];
35681             }
35682         }
35683         if(h !== null && h > 0){
35684             this.el.setHeight(h);
35685             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35686             h -= this.el.getBorderWidth("tb");
35687             if(this.config.adjustments){
35688                 h += this.config.adjustments[1];
35689             }
35690             this.bodyEl.setHeight(h);
35691             if(this.tabs){
35692                 h = this.tabs.syncHeight(h);
35693             }
35694         }
35695         if(this.panelSize){
35696             w = w !== null ? w : this.panelSize.width;
35697             h = h !== null ? h : this.panelSize.height;
35698         }
35699         if(this.activePanel){
35700             var el = this.activePanel.getEl();
35701             w = w !== null ? w : el.getWidth();
35702             h = h !== null ? h : el.getHeight();
35703             this.panelSize = {width: w, height: h};
35704             this.activePanel.setSize(w, h);
35705         }
35706         if(Roo.isIE && this.tabs){
35707             this.tabs.el.repaint();
35708         }
35709     },
35710
35711     /**
35712      * Returns the container element for this region.
35713      * @return {Roo.Element}
35714      */
35715     getEl : function(){
35716         return this.el;
35717     },
35718
35719     /**
35720      * Hides this region.
35721      */
35722     hide : function(){
35723         //if(!this.collapsed){
35724             this.el.dom.style.left = "-2000px";
35725             this.el.hide();
35726         //}else{
35727          //   this.collapsedEl.dom.style.left = "-2000px";
35728          //   this.collapsedEl.hide();
35729        // }
35730         this.visible = false;
35731         this.fireEvent("visibilitychange", this, false);
35732     },
35733
35734     /**
35735      * Shows this region if it was previously hidden.
35736      */
35737     show : function(){
35738         //if(!this.collapsed){
35739             this.el.show();
35740         //}else{
35741         //    this.collapsedEl.show();
35742        // }
35743         this.visible = true;
35744         this.fireEvent("visibilitychange", this, true);
35745     },
35746 /*
35747     closeClicked : function(){
35748         if(this.activePanel){
35749             this.remove(this.activePanel);
35750         }
35751     },
35752
35753     collapseClick : function(e){
35754         if(this.isSlid){
35755            e.stopPropagation();
35756            this.slideIn();
35757         }else{
35758            e.stopPropagation();
35759            this.slideOut();
35760         }
35761     },
35762 */
35763     /**
35764      * Collapses this region.
35765      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35766      */
35767     /*
35768     collapse : function(skipAnim, skipCheck = false){
35769         if(this.collapsed) {
35770             return;
35771         }
35772         
35773         if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35774             
35775             this.collapsed = true;
35776             if(this.split){
35777                 this.split.el.hide();
35778             }
35779             if(this.config.animate && skipAnim !== true){
35780                 this.fireEvent("invalidated", this);
35781                 this.animateCollapse();
35782             }else{
35783                 this.el.setLocation(-20000,-20000);
35784                 this.el.hide();
35785                 this.collapsedEl.show();
35786                 this.fireEvent("collapsed", this);
35787                 this.fireEvent("invalidated", this);
35788             }
35789         }
35790         
35791     },
35792 */
35793     animateCollapse : function(){
35794         // overridden
35795     },
35796
35797     /**
35798      * Expands this region if it was previously collapsed.
35799      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35800      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35801      */
35802     /*
35803     expand : function(e, skipAnim){
35804         if(e) {
35805             e.stopPropagation();
35806         }
35807         if(!this.collapsed || this.el.hasActiveFx()) {
35808             return;
35809         }
35810         if(this.isSlid){
35811             this.afterSlideIn();
35812             skipAnim = true;
35813         }
35814         this.collapsed = false;
35815         if(this.config.animate && skipAnim !== true){
35816             this.animateExpand();
35817         }else{
35818             this.el.show();
35819             if(this.split){
35820                 this.split.el.show();
35821             }
35822             this.collapsedEl.setLocation(-2000,-2000);
35823             this.collapsedEl.hide();
35824             this.fireEvent("invalidated", this);
35825             this.fireEvent("expanded", this);
35826         }
35827     },
35828 */
35829     animateExpand : function(){
35830         // overridden
35831     },
35832
35833     initTabs : function()
35834     {
35835         //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35836         
35837         var ts = new Roo.bootstrap.panel.Tabs({
35838                 el: this.bodyEl.dom,
35839                 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35840                 disableTooltips: this.config.disableTabTips,
35841                 toolbar : this.config.toolbar
35842             });
35843         
35844         if(this.config.hideTabs){
35845             ts.stripWrap.setDisplayed(false);
35846         }
35847         this.tabs = ts;
35848         ts.resizeTabs = this.config.resizeTabs === true;
35849         ts.minTabWidth = this.config.minTabWidth || 40;
35850         ts.maxTabWidth = this.config.maxTabWidth || 250;
35851         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35852         ts.monitorResize = false;
35853         //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35854         ts.bodyEl.addClass('roo-layout-tabs-body');
35855         this.panels.each(this.initPanelAsTab, this);
35856     },
35857
35858     initPanelAsTab : function(panel){
35859         var ti = this.tabs.addTab(
35860             panel.getEl().id,
35861             panel.getTitle(),
35862             null,
35863             this.config.closeOnTab && panel.isClosable(),
35864             panel.tpl
35865         );
35866         if(panel.tabTip !== undefined){
35867             ti.setTooltip(panel.tabTip);
35868         }
35869         ti.on("activate", function(){
35870               this.setActivePanel(panel);
35871         }, this);
35872         
35873         if(this.config.closeOnTab){
35874             ti.on("beforeclose", function(t, e){
35875                 e.cancel = true;
35876                 this.remove(panel);
35877             }, this);
35878         }
35879         
35880         panel.tabItem = ti;
35881         
35882         return ti;
35883     },
35884
35885     updatePanelTitle : function(panel, title)
35886     {
35887         if(this.activePanel == panel){
35888             this.updateTitle(title);
35889         }
35890         if(this.tabs){
35891             var ti = this.tabs.getTab(panel.getEl().id);
35892             ti.setText(title);
35893             if(panel.tabTip !== undefined){
35894                 ti.setTooltip(panel.tabTip);
35895             }
35896         }
35897     },
35898
35899     updateTitle : function(title){
35900         if(this.titleTextEl && !this.config.title){
35901             this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
35902         }
35903     },
35904
35905     setActivePanel : function(panel)
35906     {
35907         panel = this.getPanel(panel);
35908         if(this.activePanel && this.activePanel != panel){
35909             if(this.activePanel.setActiveState(false) === false){
35910                 return;
35911             }
35912         }
35913         this.activePanel = panel;
35914         panel.setActiveState(true);
35915         if(this.panelSize){
35916             panel.setSize(this.panelSize.width, this.panelSize.height);
35917         }
35918         if(this.closeBtn){
35919             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35920         }
35921         this.updateTitle(panel.getTitle());
35922         if(this.tabs){
35923             this.fireEvent("invalidated", this);
35924         }
35925         this.fireEvent("panelactivated", this, panel);
35926     },
35927
35928     /**
35929      * Shows the specified panel.
35930      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35931      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35932      */
35933     showPanel : function(panel)
35934     {
35935         panel = this.getPanel(panel);
35936         if(panel){
35937             if(this.tabs){
35938                 var tab = this.tabs.getTab(panel.getEl().id);
35939                 if(tab.isHidden()){
35940                     this.tabs.unhideTab(tab.id);
35941                 }
35942                 tab.activate();
35943             }else{
35944                 this.setActivePanel(panel);
35945             }
35946         }
35947         return panel;
35948     },
35949
35950     /**
35951      * Get the active panel for this region.
35952      * @return {Roo.ContentPanel} The active panel or null
35953      */
35954     getActivePanel : function(){
35955         return this.activePanel;
35956     },
35957
35958     validateVisibility : function(){
35959         if(this.panels.getCount() < 1){
35960             this.updateTitle("&#160;");
35961             this.closeBtn.hide();
35962             this.hide();
35963         }else{
35964             if(!this.isVisible()){
35965                 this.show();
35966             }
35967         }
35968     },
35969
35970     /**
35971      * Adds the passed ContentPanel(s) to this region.
35972      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35973      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35974      */
35975     add : function(panel)
35976     {
35977         if(arguments.length > 1){
35978             for(var i = 0, len = arguments.length; i < len; i++) {
35979                 this.add(arguments[i]);
35980             }
35981             return null;
35982         }
35983         
35984         // if we have not been rendered yet, then we can not really do much of this..
35985         if (!this.bodyEl) {
35986             this.unrendered_panels.push(panel);
35987             return panel;
35988         }
35989         
35990         
35991         
35992         
35993         if(this.hasPanel(panel)){
35994             this.showPanel(panel);
35995             return panel;
35996         }
35997         panel.setRegion(this);
35998         this.panels.add(panel);
35999        /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36000             // sinle panel - no tab...?? would it not be better to render it with the tabs,
36001             // and hide them... ???
36002             this.bodyEl.dom.appendChild(panel.getEl().dom);
36003             if(panel.background !== true){
36004                 this.setActivePanel(panel);
36005             }
36006             this.fireEvent("paneladded", this, panel);
36007             return panel;
36008         }
36009         */
36010         if(!this.tabs){
36011             this.initTabs();
36012         }else{
36013             this.initPanelAsTab(panel);
36014         }
36015         
36016         
36017         if(panel.background !== true){
36018             this.tabs.activate(panel.getEl().id);
36019         }
36020         this.fireEvent("paneladded", this, panel);
36021         return panel;
36022     },
36023
36024     /**
36025      * Hides the tab for the specified panel.
36026      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36027      */
36028     hidePanel : function(panel){
36029         if(this.tabs && (panel = this.getPanel(panel))){
36030             this.tabs.hideTab(panel.getEl().id);
36031         }
36032     },
36033
36034     /**
36035      * Unhides the tab for a previously hidden panel.
36036      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36037      */
36038     unhidePanel : function(panel){
36039         if(this.tabs && (panel = this.getPanel(panel))){
36040             this.tabs.unhideTab(panel.getEl().id);
36041         }
36042     },
36043
36044     clearPanels : function(){
36045         while(this.panels.getCount() > 0){
36046              this.remove(this.panels.first());
36047         }
36048     },
36049
36050     /**
36051      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36052      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36053      * @param {Boolean} preservePanel Overrides the config preservePanel option
36054      * @return {Roo.ContentPanel} The panel that was removed
36055      */
36056     remove : function(panel, preservePanel)
36057     {
36058         panel = this.getPanel(panel);
36059         if(!panel){
36060             return null;
36061         }
36062         var e = {};
36063         this.fireEvent("beforeremove", this, panel, e);
36064         if(e.cancel === true){
36065             return null;
36066         }
36067         preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36068         var panelId = panel.getId();
36069         this.panels.removeKey(panelId);
36070         if(preservePanel){
36071             document.body.appendChild(panel.getEl().dom);
36072         }
36073         if(this.tabs){
36074             this.tabs.removeTab(panel.getEl().id);
36075         }else if (!preservePanel){
36076             this.bodyEl.dom.removeChild(panel.getEl().dom);
36077         }
36078         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36079             var p = this.panels.first();
36080             var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36081             tempEl.appendChild(p.getEl().dom);
36082             this.bodyEl.update("");
36083             this.bodyEl.dom.appendChild(p.getEl().dom);
36084             tempEl = null;
36085             this.updateTitle(p.getTitle());
36086             this.tabs = null;
36087             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36088             this.setActivePanel(p);
36089         }
36090         panel.setRegion(null);
36091         if(this.activePanel == panel){
36092             this.activePanel = null;
36093         }
36094         if(this.config.autoDestroy !== false && preservePanel !== true){
36095             try{panel.destroy();}catch(e){}
36096         }
36097         this.fireEvent("panelremoved", this, panel);
36098         return panel;
36099     },
36100
36101     /**
36102      * Returns the TabPanel component used by this region
36103      * @return {Roo.TabPanel}
36104      */
36105     getTabs : function(){
36106         return this.tabs;
36107     },
36108
36109     createTool : function(parentEl, className){
36110         var btn = Roo.DomHelper.append(parentEl, {
36111             tag: "div",
36112             cls: "x-layout-tools-button",
36113             children: [ {
36114                 tag: "div",
36115                 cls: "roo-layout-tools-button-inner " + className,
36116                 html: "&#160;"
36117             }]
36118         }, true);
36119         btn.addClassOnOver("roo-layout-tools-button-over");
36120         return btn;
36121     }
36122 });/*
36123  * Based on:
36124  * Ext JS Library 1.1.1
36125  * Copyright(c) 2006-2007, Ext JS, LLC.
36126  *
36127  * Originally Released Under LGPL - original licence link has changed is not relivant.
36128  *
36129  * Fork - LGPL
36130  * <script type="text/javascript">
36131  */
36132  
36133
36134
36135 /**
36136  * @class Roo.SplitLayoutRegion
36137  * @extends Roo.LayoutRegion
36138  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36139  */
36140 Roo.bootstrap.layout.Split = function(config){
36141     this.cursor = config.cursor;
36142     Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36143 };
36144
36145 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36146 {
36147     splitTip : "Drag to resize.",
36148     collapsibleSplitTip : "Drag to resize. Double click to hide.",
36149     useSplitTips : false,
36150
36151     applyConfig : function(config){
36152         Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36153     },
36154     
36155     onRender : function(ctr,pos) {
36156         
36157         Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36158         if(!this.config.split){
36159             return;
36160         }
36161         if(!this.split){
36162             
36163             var splitEl = Roo.DomHelper.append(ctr.dom,  {
36164                             tag: "div",
36165                             id: this.el.id + "-split",
36166                             cls: "roo-layout-split roo-layout-split-"+this.position,
36167                             html: "&#160;"
36168             });
36169             /** The SplitBar for this region 
36170             * @type Roo.SplitBar */
36171             // does not exist yet...
36172             Roo.log([this.position, this.orientation]);
36173             
36174             this.split = new Roo.bootstrap.SplitBar({
36175                 dragElement : splitEl,
36176                 resizingElement: this.el,
36177                 orientation : this.orientation
36178             });
36179             
36180             this.split.on("moved", this.onSplitMove, this);
36181             this.split.useShim = this.config.useShim === true;
36182             this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36183             if(this.useSplitTips){
36184                 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36185             }
36186             //if(config.collapsible){
36187             //    this.split.el.on("dblclick", this.collapse,  this);
36188             //}
36189         }
36190         if(typeof this.config.minSize != "undefined"){
36191             this.split.minSize = this.config.minSize;
36192         }
36193         if(typeof this.config.maxSize != "undefined"){
36194             this.split.maxSize = this.config.maxSize;
36195         }
36196         if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36197             this.hideSplitter();
36198         }
36199         
36200     },
36201
36202     getHMaxSize : function(){
36203          var cmax = this.config.maxSize || 10000;
36204          var center = this.mgr.getRegion("center");
36205          return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36206     },
36207
36208     getVMaxSize : function(){
36209          var cmax = this.config.maxSize || 10000;
36210          var center = this.mgr.getRegion("center");
36211          return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36212     },
36213
36214     onSplitMove : function(split, newSize){
36215         this.fireEvent("resized", this, newSize);
36216     },
36217     
36218     /** 
36219      * Returns the {@link Roo.SplitBar} for this region.
36220      * @return {Roo.SplitBar}
36221      */
36222     getSplitBar : function(){
36223         return this.split;
36224     },
36225     
36226     hide : function(){
36227         this.hideSplitter();
36228         Roo.bootstrap.layout.Split.superclass.hide.call(this);
36229     },
36230
36231     hideSplitter : function(){
36232         if(this.split){
36233             this.split.el.setLocation(-2000,-2000);
36234             this.split.el.hide();
36235         }
36236     },
36237
36238     show : function(){
36239         if(this.split){
36240             this.split.el.show();
36241         }
36242         Roo.bootstrap.layout.Split.superclass.show.call(this);
36243     },
36244     
36245     beforeSlide: function(){
36246         if(Roo.isGecko){// firefox overflow auto bug workaround
36247             this.bodyEl.clip();
36248             if(this.tabs) {
36249                 this.tabs.bodyEl.clip();
36250             }
36251             if(this.activePanel){
36252                 this.activePanel.getEl().clip();
36253                 
36254                 if(this.activePanel.beforeSlide){
36255                     this.activePanel.beforeSlide();
36256                 }
36257             }
36258         }
36259     },
36260     
36261     afterSlide : function(){
36262         if(Roo.isGecko){// firefox overflow auto bug workaround
36263             this.bodyEl.unclip();
36264             if(this.tabs) {
36265                 this.tabs.bodyEl.unclip();
36266             }
36267             if(this.activePanel){
36268                 this.activePanel.getEl().unclip();
36269                 if(this.activePanel.afterSlide){
36270                     this.activePanel.afterSlide();
36271                 }
36272             }
36273         }
36274     },
36275
36276     initAutoHide : function(){
36277         if(this.autoHide !== false){
36278             if(!this.autoHideHd){
36279                 var st = new Roo.util.DelayedTask(this.slideIn, this);
36280                 this.autoHideHd = {
36281                     "mouseout": function(e){
36282                         if(!e.within(this.el, true)){
36283                             st.delay(500);
36284                         }
36285                     },
36286                     "mouseover" : function(e){
36287                         st.cancel();
36288                     },
36289                     scope : this
36290                 };
36291             }
36292             this.el.on(this.autoHideHd);
36293         }
36294     },
36295
36296     clearAutoHide : function(){
36297         if(this.autoHide !== false){
36298             this.el.un("mouseout", this.autoHideHd.mouseout);
36299             this.el.un("mouseover", this.autoHideHd.mouseover);
36300         }
36301     },
36302
36303     clearMonitor : function(){
36304         Roo.get(document).un("click", this.slideInIf, this);
36305     },
36306
36307     // these names are backwards but not changed for compat
36308     slideOut : function(){
36309         if(this.isSlid || this.el.hasActiveFx()){
36310             return;
36311         }
36312         this.isSlid = true;
36313         if(this.collapseBtn){
36314             this.collapseBtn.hide();
36315         }
36316         this.closeBtnState = this.closeBtn.getStyle('display');
36317         this.closeBtn.hide();
36318         if(this.stickBtn){
36319             this.stickBtn.show();
36320         }
36321         this.el.show();
36322         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36323         this.beforeSlide();
36324         this.el.setStyle("z-index", 10001);
36325         this.el.slideIn(this.getSlideAnchor(), {
36326             callback: function(){
36327                 this.afterSlide();
36328                 this.initAutoHide();
36329                 Roo.get(document).on("click", this.slideInIf, this);
36330                 this.fireEvent("slideshow", this);
36331             },
36332             scope: this,
36333             block: true
36334         });
36335     },
36336
36337     afterSlideIn : function(){
36338         this.clearAutoHide();
36339         this.isSlid = false;
36340         this.clearMonitor();
36341         this.el.setStyle("z-index", "");
36342         if(this.collapseBtn){
36343             this.collapseBtn.show();
36344         }
36345         this.closeBtn.setStyle('display', this.closeBtnState);
36346         if(this.stickBtn){
36347             this.stickBtn.hide();
36348         }
36349         this.fireEvent("slidehide", this);
36350     },
36351
36352     slideIn : function(cb){
36353         if(!this.isSlid || this.el.hasActiveFx()){
36354             Roo.callback(cb);
36355             return;
36356         }
36357         this.isSlid = false;
36358         this.beforeSlide();
36359         this.el.slideOut(this.getSlideAnchor(), {
36360             callback: function(){
36361                 this.el.setLeftTop(-10000, -10000);
36362                 this.afterSlide();
36363                 this.afterSlideIn();
36364                 Roo.callback(cb);
36365             },
36366             scope: this,
36367             block: true
36368         });
36369     },
36370     
36371     slideInIf : function(e){
36372         if(!e.within(this.el)){
36373             this.slideIn();
36374         }
36375     },
36376
36377     animateCollapse : function(){
36378         this.beforeSlide();
36379         this.el.setStyle("z-index", 20000);
36380         var anchor = this.getSlideAnchor();
36381         this.el.slideOut(anchor, {
36382             callback : function(){
36383                 this.el.setStyle("z-index", "");
36384                 this.collapsedEl.slideIn(anchor, {duration:.3});
36385                 this.afterSlide();
36386                 this.el.setLocation(-10000,-10000);
36387                 this.el.hide();
36388                 this.fireEvent("collapsed", this);
36389             },
36390             scope: this,
36391             block: true
36392         });
36393     },
36394
36395     animateExpand : function(){
36396         this.beforeSlide();
36397         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36398         this.el.setStyle("z-index", 20000);
36399         this.collapsedEl.hide({
36400             duration:.1
36401         });
36402         this.el.slideIn(this.getSlideAnchor(), {
36403             callback : function(){
36404                 this.el.setStyle("z-index", "");
36405                 this.afterSlide();
36406                 if(this.split){
36407                     this.split.el.show();
36408                 }
36409                 this.fireEvent("invalidated", this);
36410                 this.fireEvent("expanded", this);
36411             },
36412             scope: this,
36413             block: true
36414         });
36415     },
36416
36417     anchors : {
36418         "west" : "left",
36419         "east" : "right",
36420         "north" : "top",
36421         "south" : "bottom"
36422     },
36423
36424     sanchors : {
36425         "west" : "l",
36426         "east" : "r",
36427         "north" : "t",
36428         "south" : "b"
36429     },
36430
36431     canchors : {
36432         "west" : "tl-tr",
36433         "east" : "tr-tl",
36434         "north" : "tl-bl",
36435         "south" : "bl-tl"
36436     },
36437
36438     getAnchor : function(){
36439         return this.anchors[this.position];
36440     },
36441
36442     getCollapseAnchor : function(){
36443         return this.canchors[this.position];
36444     },
36445
36446     getSlideAnchor : function(){
36447         return this.sanchors[this.position];
36448     },
36449
36450     getAlignAdj : function(){
36451         var cm = this.cmargins;
36452         switch(this.position){
36453             case "west":
36454                 return [0, 0];
36455             break;
36456             case "east":
36457                 return [0, 0];
36458             break;
36459             case "north":
36460                 return [0, 0];
36461             break;
36462             case "south":
36463                 return [0, 0];
36464             break;
36465         }
36466     },
36467
36468     getExpandAdj : function(){
36469         var c = this.collapsedEl, cm = this.cmargins;
36470         switch(this.position){
36471             case "west":
36472                 return [-(cm.right+c.getWidth()+cm.left), 0];
36473             break;
36474             case "east":
36475                 return [cm.right+c.getWidth()+cm.left, 0];
36476             break;
36477             case "north":
36478                 return [0, -(cm.top+cm.bottom+c.getHeight())];
36479             break;
36480             case "south":
36481                 return [0, cm.top+cm.bottom+c.getHeight()];
36482             break;
36483         }
36484     }
36485 });/*
36486  * Based on:
36487  * Ext JS Library 1.1.1
36488  * Copyright(c) 2006-2007, Ext JS, LLC.
36489  *
36490  * Originally Released Under LGPL - original licence link has changed is not relivant.
36491  *
36492  * Fork - LGPL
36493  * <script type="text/javascript">
36494  */
36495 /*
36496  * These classes are private internal classes
36497  */
36498 Roo.bootstrap.layout.Center = function(config){
36499     config.region = "center";
36500     Roo.bootstrap.layout.Region.call(this, config);
36501     this.visible = true;
36502     this.minWidth = config.minWidth || 20;
36503     this.minHeight = config.minHeight || 20;
36504 };
36505
36506 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36507     hide : function(){
36508         // center panel can't be hidden
36509     },
36510     
36511     show : function(){
36512         // center panel can't be hidden
36513     },
36514     
36515     getMinWidth: function(){
36516         return this.minWidth;
36517     },
36518     
36519     getMinHeight: function(){
36520         return this.minHeight;
36521     }
36522 });
36523
36524
36525
36526
36527  
36528
36529
36530
36531
36532
36533 Roo.bootstrap.layout.North = function(config)
36534 {
36535     config.region = 'north';
36536     config.cursor = 'n-resize';
36537     
36538     Roo.bootstrap.layout.Split.call(this, config);
36539     
36540     
36541     if(this.split){
36542         this.split.placement = Roo.bootstrap.SplitBar.TOP;
36543         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36544         this.split.el.addClass("roo-layout-split-v");
36545     }
36546     var size = config.initialSize || config.height;
36547     if(typeof size != "undefined"){
36548         this.el.setHeight(size);
36549     }
36550 };
36551 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36552 {
36553     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36554     
36555     
36556     
36557     getBox : function(){
36558         if(this.collapsed){
36559             return this.collapsedEl.getBox();
36560         }
36561         var box = this.el.getBox();
36562         if(this.split){
36563             box.height += this.split.el.getHeight();
36564         }
36565         return box;
36566     },
36567     
36568     updateBox : function(box){
36569         if(this.split && !this.collapsed){
36570             box.height -= this.split.el.getHeight();
36571             this.split.el.setLeft(box.x);
36572             this.split.el.setTop(box.y+box.height);
36573             this.split.el.setWidth(box.width);
36574         }
36575         if(this.collapsed){
36576             this.updateBody(box.width, null);
36577         }
36578         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36579     }
36580 });
36581
36582
36583
36584
36585
36586 Roo.bootstrap.layout.South = function(config){
36587     config.region = 'south';
36588     config.cursor = 's-resize';
36589     Roo.bootstrap.layout.Split.call(this, config);
36590     if(this.split){
36591         this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36592         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36593         this.split.el.addClass("roo-layout-split-v");
36594     }
36595     var size = config.initialSize || config.height;
36596     if(typeof size != "undefined"){
36597         this.el.setHeight(size);
36598     }
36599 };
36600
36601 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36602     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36603     getBox : function(){
36604         if(this.collapsed){
36605             return this.collapsedEl.getBox();
36606         }
36607         var box = this.el.getBox();
36608         if(this.split){
36609             var sh = this.split.el.getHeight();
36610             box.height += sh;
36611             box.y -= sh;
36612         }
36613         return box;
36614     },
36615     
36616     updateBox : function(box){
36617         if(this.split && !this.collapsed){
36618             var sh = this.split.el.getHeight();
36619             box.height -= sh;
36620             box.y += sh;
36621             this.split.el.setLeft(box.x);
36622             this.split.el.setTop(box.y-sh);
36623             this.split.el.setWidth(box.width);
36624         }
36625         if(this.collapsed){
36626             this.updateBody(box.width, null);
36627         }
36628         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36629     }
36630 });
36631
36632 Roo.bootstrap.layout.East = function(config){
36633     config.region = "east";
36634     config.cursor = "e-resize";
36635     Roo.bootstrap.layout.Split.call(this, config);
36636     if(this.split){
36637         this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36638         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36639         this.split.el.addClass("roo-layout-split-h");
36640     }
36641     var size = config.initialSize || config.width;
36642     if(typeof size != "undefined"){
36643         this.el.setWidth(size);
36644     }
36645 };
36646 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36647     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36648     getBox : function(){
36649         if(this.collapsed){
36650             return this.collapsedEl.getBox();
36651         }
36652         var box = this.el.getBox();
36653         if(this.split){
36654             var sw = this.split.el.getWidth();
36655             box.width += sw;
36656             box.x -= sw;
36657         }
36658         return box;
36659     },
36660
36661     updateBox : function(box){
36662         if(this.split && !this.collapsed){
36663             var sw = this.split.el.getWidth();
36664             box.width -= sw;
36665             this.split.el.setLeft(box.x);
36666             this.split.el.setTop(box.y);
36667             this.split.el.setHeight(box.height);
36668             box.x += sw;
36669         }
36670         if(this.collapsed){
36671             this.updateBody(null, box.height);
36672         }
36673         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36674     }
36675 });
36676
36677 Roo.bootstrap.layout.West = function(config){
36678     config.region = "west";
36679     config.cursor = "w-resize";
36680     
36681     Roo.bootstrap.layout.Split.call(this, config);
36682     if(this.split){
36683         this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36684         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36685         this.split.el.addClass("roo-layout-split-h");
36686     }
36687     
36688 };
36689 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36690     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36691     
36692     onRender: function(ctr, pos)
36693     {
36694         Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36695         var size = this.config.initialSize || this.config.width;
36696         if(typeof size != "undefined"){
36697             this.el.setWidth(size);
36698         }
36699     },
36700     
36701     getBox : function(){
36702         if(this.collapsed){
36703             return this.collapsedEl.getBox();
36704         }
36705         var box = this.el.getBox();
36706         if(this.split){
36707             box.width += this.split.el.getWidth();
36708         }
36709         return box;
36710     },
36711     
36712     updateBox : function(box){
36713         if(this.split && !this.collapsed){
36714             var sw = this.split.el.getWidth();
36715             box.width -= sw;
36716             this.split.el.setLeft(box.x+box.width);
36717             this.split.el.setTop(box.y);
36718             this.split.el.setHeight(box.height);
36719         }
36720         if(this.collapsed){
36721             this.updateBody(null, box.height);
36722         }
36723         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36724     }
36725 });
36726 Roo.namespace("Roo.bootstrap.panel");/*
36727  * Based on:
36728  * Ext JS Library 1.1.1
36729  * Copyright(c) 2006-2007, Ext JS, LLC.
36730  *
36731  * Originally Released Under LGPL - original licence link has changed is not relivant.
36732  *
36733  * Fork - LGPL
36734  * <script type="text/javascript">
36735  */
36736 /**
36737  * @class Roo.ContentPanel
36738  * @extends Roo.util.Observable
36739  * A basic ContentPanel element.
36740  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
36741  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
36742  * @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
36743  * @cfg {Boolean}   closable      True if the panel can be closed/removed
36744  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
36745  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36746  * @cfg {Toolbar}   toolbar       A toolbar for this panel
36747  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
36748  * @cfg {String} title          The title for this panel
36749  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36750  * @cfg {String} url            Calls {@link #setUrl} with this value
36751  * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36752  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
36753  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
36754  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
36755  * @cfg {Boolean} badges render the badges
36756
36757  * @constructor
36758  * Create a new ContentPanel.
36759  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36760  * @param {String/Object} config A string to set only the title or a config object
36761  * @param {String} content (optional) Set the HTML content for this panel
36762  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36763  */
36764 Roo.bootstrap.panel.Content = function( config){
36765     
36766     this.tpl = config.tpl || false;
36767     
36768     var el = config.el;
36769     var content = config.content;
36770
36771     if(config.autoCreate){ // xtype is available if this is called from factory
36772         el = Roo.id();
36773     }
36774     this.el = Roo.get(el);
36775     if(!this.el && config && config.autoCreate){
36776         if(typeof config.autoCreate == "object"){
36777             if(!config.autoCreate.id){
36778                 config.autoCreate.id = config.id||el;
36779             }
36780             this.el = Roo.DomHelper.append(document.body,
36781                         config.autoCreate, true);
36782         }else{
36783             var elcfg =  {   tag: "div",
36784                             cls: "roo-layout-inactive-content",
36785                             id: config.id||el
36786                             };
36787             if (config.html) {
36788                 elcfg.html = config.html;
36789                 
36790             }
36791                         
36792             this.el = Roo.DomHelper.append(document.body, elcfg , true);
36793         }
36794     } 
36795     this.closable = false;
36796     this.loaded = false;
36797     this.active = false;
36798    
36799       
36800     if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36801         
36802         this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36803         
36804         this.wrapEl = this.el; //this.el.wrap();
36805         var ti = [];
36806         if (config.toolbar.items) {
36807             ti = config.toolbar.items ;
36808             delete config.toolbar.items ;
36809         }
36810         
36811         var nitems = [];
36812         this.toolbar.render(this.wrapEl, 'before');
36813         for(var i =0;i < ti.length;i++) {
36814           //  Roo.log(['add child', items[i]]);
36815             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36816         }
36817         this.toolbar.items = nitems;
36818         this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36819         delete config.toolbar;
36820         
36821     }
36822     /*
36823     // xtype created footer. - not sure if will work as we normally have to render first..
36824     if (this.footer && !this.footer.el && this.footer.xtype) {
36825         if (!this.wrapEl) {
36826             this.wrapEl = this.el.wrap();
36827         }
36828     
36829         this.footer.container = this.wrapEl.createChild();
36830          
36831         this.footer = Roo.factory(this.footer, Roo);
36832         
36833     }
36834     */
36835     
36836      if(typeof config == "string"){
36837         this.title = config;
36838     }else{
36839         Roo.apply(this, config);
36840     }
36841     
36842     if(this.resizeEl){
36843         this.resizeEl = Roo.get(this.resizeEl, true);
36844     }else{
36845         this.resizeEl = this.el;
36846     }
36847     // handle view.xtype
36848     
36849  
36850     
36851     
36852     this.addEvents({
36853         /**
36854          * @event activate
36855          * Fires when this panel is activated. 
36856          * @param {Roo.ContentPanel} this
36857          */
36858         "activate" : true,
36859         /**
36860          * @event deactivate
36861          * Fires when this panel is activated. 
36862          * @param {Roo.ContentPanel} this
36863          */
36864         "deactivate" : true,
36865
36866         /**
36867          * @event resize
36868          * Fires when this panel is resized if fitToFrame is true.
36869          * @param {Roo.ContentPanel} this
36870          * @param {Number} width The width after any component adjustments
36871          * @param {Number} height The height after any component adjustments
36872          */
36873         "resize" : true,
36874         
36875          /**
36876          * @event render
36877          * Fires when this tab is created
36878          * @param {Roo.ContentPanel} this
36879          */
36880         "render" : true
36881         
36882         
36883         
36884     });
36885     
36886
36887     
36888     
36889     if(this.autoScroll){
36890         this.resizeEl.setStyle("overflow", "auto");
36891     } else {
36892         // fix randome scrolling
36893         //this.el.on('scroll', function() {
36894         //    Roo.log('fix random scolling');
36895         //    this.scrollTo('top',0); 
36896         //});
36897     }
36898     content = content || this.content;
36899     if(content){
36900         this.setContent(content);
36901     }
36902     if(config && config.url){
36903         this.setUrl(this.url, this.params, this.loadOnce);
36904     }
36905     
36906     
36907     
36908     Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36909     
36910     if (this.view && typeof(this.view.xtype) != 'undefined') {
36911         this.view.el = this.el.appendChild(document.createElement("div"));
36912         this.view = Roo.factory(this.view); 
36913         this.view.render  &&  this.view.render(false, '');  
36914     }
36915     
36916     
36917     this.fireEvent('render', this);
36918 };
36919
36920 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36921     
36922     tabTip : '',
36923     
36924     setRegion : function(region){
36925         this.region = region;
36926         this.setActiveClass(region && !this.background);
36927     },
36928     
36929     
36930     setActiveClass: function(state)
36931     {
36932         if(state){
36933            this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36934            this.el.setStyle('position','relative');
36935         }else{
36936            this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36937            this.el.setStyle('position', 'absolute');
36938         } 
36939     },
36940     
36941     /**
36942      * Returns the toolbar for this Panel if one was configured. 
36943      * @return {Roo.Toolbar} 
36944      */
36945     getToolbar : function(){
36946         return this.toolbar;
36947     },
36948     
36949     setActiveState : function(active)
36950     {
36951         this.active = active;
36952         this.setActiveClass(active);
36953         if(!active){
36954             if(this.fireEvent("deactivate", this) === false){
36955                 return false;
36956             }
36957             return true;
36958         }
36959         this.fireEvent("activate", this);
36960         return true;
36961     },
36962     /**
36963      * Updates this panel's element
36964      * @param {String} content The new content
36965      * @param {Boolean} loadScripts (optional) true to look for and process scripts
36966     */
36967     setContent : function(content, loadScripts){
36968         this.el.update(content, loadScripts);
36969     },
36970
36971     ignoreResize : function(w, h){
36972         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36973             return true;
36974         }else{
36975             this.lastSize = {width: w, height: h};
36976             return false;
36977         }
36978     },
36979     /**
36980      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36981      * @return {Roo.UpdateManager} The UpdateManager
36982      */
36983     getUpdateManager : function(){
36984         return this.el.getUpdateManager();
36985     },
36986      /**
36987      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36988      * @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:
36989 <pre><code>
36990 panel.load({
36991     url: "your-url.php",
36992     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36993     callback: yourFunction,
36994     scope: yourObject, //(optional scope)
36995     discardUrl: false,
36996     nocache: false,
36997     text: "Loading...",
36998     timeout: 30,
36999     scripts: false
37000 });
37001 </code></pre>
37002      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37003      * 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.
37004      * @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}
37005      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37006      * @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.
37007      * @return {Roo.ContentPanel} this
37008      */
37009     load : function(){
37010         var um = this.el.getUpdateManager();
37011         um.update.apply(um, arguments);
37012         return this;
37013     },
37014
37015
37016     /**
37017      * 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.
37018      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37019      * @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)
37020      * @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)
37021      * @return {Roo.UpdateManager} The UpdateManager
37022      */
37023     setUrl : function(url, params, loadOnce){
37024         if(this.refreshDelegate){
37025             this.removeListener("activate", this.refreshDelegate);
37026         }
37027         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37028         this.on("activate", this.refreshDelegate);
37029         return this.el.getUpdateManager();
37030     },
37031     
37032     _handleRefresh : function(url, params, loadOnce){
37033         if(!loadOnce || !this.loaded){
37034             var updater = this.el.getUpdateManager();
37035             updater.update(url, params, this._setLoaded.createDelegate(this));
37036         }
37037     },
37038     
37039     _setLoaded : function(){
37040         this.loaded = true;
37041     }, 
37042     
37043     /**
37044      * Returns this panel's id
37045      * @return {String} 
37046      */
37047     getId : function(){
37048         return this.el.id;
37049     },
37050     
37051     /** 
37052      * Returns this panel's element - used by regiosn to add.
37053      * @return {Roo.Element} 
37054      */
37055     getEl : function(){
37056         return this.wrapEl || this.el;
37057     },
37058     
37059    
37060     
37061     adjustForComponents : function(width, height)
37062     {
37063         //Roo.log('adjustForComponents ');
37064         if(this.resizeEl != this.el){
37065             width -= this.el.getFrameWidth('lr');
37066             height -= this.el.getFrameWidth('tb');
37067         }
37068         if(this.toolbar){
37069             var te = this.toolbar.getEl();
37070             te.setWidth(width);
37071             height -= te.getHeight();
37072         }
37073         if(this.footer){
37074             var te = this.footer.getEl();
37075             te.setWidth(width);
37076             height -= te.getHeight();
37077         }
37078         
37079         
37080         if(this.adjustments){
37081             width += this.adjustments[0];
37082             height += this.adjustments[1];
37083         }
37084         return {"width": width, "height": height};
37085     },
37086     
37087     setSize : function(width, height){
37088         if(this.fitToFrame && !this.ignoreResize(width, height)){
37089             if(this.fitContainer && this.resizeEl != this.el){
37090                 this.el.setSize(width, height);
37091             }
37092             var size = this.adjustForComponents(width, height);
37093             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37094             this.fireEvent('resize', this, size.width, size.height);
37095         }
37096     },
37097     
37098     /**
37099      * Returns this panel's title
37100      * @return {String} 
37101      */
37102     getTitle : function(){
37103         
37104         if (typeof(this.title) != 'object') {
37105             return this.title;
37106         }
37107         
37108         var t = '';
37109         for (var k in this.title) {
37110             if (!this.title.hasOwnProperty(k)) {
37111                 continue;
37112             }
37113             
37114             if (k.indexOf('-') >= 0) {
37115                 var s = k.split('-');
37116                 for (var i = 0; i<s.length; i++) {
37117                     t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37118                 }
37119             } else {
37120                 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37121             }
37122         }
37123         return t;
37124     },
37125     
37126     /**
37127      * Set this panel's title
37128      * @param {String} title
37129      */
37130     setTitle : function(title){
37131         this.title = title;
37132         if(this.region){
37133             this.region.updatePanelTitle(this, title);
37134         }
37135     },
37136     
37137     /**
37138      * Returns true is this panel was configured to be closable
37139      * @return {Boolean} 
37140      */
37141     isClosable : function(){
37142         return this.closable;
37143     },
37144     
37145     beforeSlide : function(){
37146         this.el.clip();
37147         this.resizeEl.clip();
37148     },
37149     
37150     afterSlide : function(){
37151         this.el.unclip();
37152         this.resizeEl.unclip();
37153     },
37154     
37155     /**
37156      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
37157      *   Will fail silently if the {@link #setUrl} method has not been called.
37158      *   This does not activate the panel, just updates its content.
37159      */
37160     refresh : function(){
37161         if(this.refreshDelegate){
37162            this.loaded = false;
37163            this.refreshDelegate();
37164         }
37165     },
37166     
37167     /**
37168      * Destroys this panel
37169      */
37170     destroy : function(){
37171         this.el.removeAllListeners();
37172         var tempEl = document.createElement("span");
37173         tempEl.appendChild(this.el.dom);
37174         tempEl.innerHTML = "";
37175         this.el.remove();
37176         this.el = null;
37177     },
37178     
37179     /**
37180      * form - if the content panel contains a form - this is a reference to it.
37181      * @type {Roo.form.Form}
37182      */
37183     form : false,
37184     /**
37185      * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37186      *    This contains a reference to it.
37187      * @type {Roo.View}
37188      */
37189     view : false,
37190     
37191       /**
37192      * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37193      * <pre><code>
37194
37195 layout.addxtype({
37196        xtype : 'Form',
37197        items: [ .... ]
37198    }
37199 );
37200
37201 </code></pre>
37202      * @param {Object} cfg Xtype definition of item to add.
37203      */
37204     
37205     
37206     getChildContainer: function () {
37207         return this.getEl();
37208     }
37209     
37210     
37211     /*
37212         var  ret = new Roo.factory(cfg);
37213         return ret;
37214         
37215         
37216         // add form..
37217         if (cfg.xtype.match(/^Form$/)) {
37218             
37219             var el;
37220             //if (this.footer) {
37221             //    el = this.footer.container.insertSibling(false, 'before');
37222             //} else {
37223                 el = this.el.createChild();
37224             //}
37225
37226             this.form = new  Roo.form.Form(cfg);
37227             
37228             
37229             if ( this.form.allItems.length) {
37230                 this.form.render(el.dom);
37231             }
37232             return this.form;
37233         }
37234         // should only have one of theses..
37235         if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37236             // views.. should not be just added - used named prop 'view''
37237             
37238             cfg.el = this.el.appendChild(document.createElement("div"));
37239             // factory?
37240             
37241             var ret = new Roo.factory(cfg);
37242              
37243              ret.render && ret.render(false, ''); // render blank..
37244             this.view = ret;
37245             return ret;
37246         }
37247         return false;
37248     }
37249     \*/
37250 });
37251  
37252 /**
37253  * @class Roo.bootstrap.panel.Grid
37254  * @extends Roo.bootstrap.panel.Content
37255  * @constructor
37256  * Create a new GridPanel.
37257  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37258  * @param {Object} config A the config object
37259   
37260  */
37261
37262
37263
37264 Roo.bootstrap.panel.Grid = function(config)
37265 {
37266     
37267       
37268     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37269         {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37270
37271     config.el = this.wrapper;
37272     //this.el = this.wrapper;
37273     
37274       if (config.container) {
37275         // ctor'ed from a Border/panel.grid
37276         
37277         
37278         this.wrapper.setStyle("overflow", "hidden");
37279         this.wrapper.addClass('roo-grid-container');
37280
37281     }
37282     
37283     
37284     if(config.toolbar){
37285         var tool_el = this.wrapper.createChild();    
37286         this.toolbar = Roo.factory(config.toolbar);
37287         var ti = [];
37288         if (config.toolbar.items) {
37289             ti = config.toolbar.items ;
37290             delete config.toolbar.items ;
37291         }
37292         
37293         var nitems = [];
37294         this.toolbar.render(tool_el);
37295         for(var i =0;i < ti.length;i++) {
37296           //  Roo.log(['add child', items[i]]);
37297             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37298         }
37299         this.toolbar.items = nitems;
37300         
37301         delete config.toolbar;
37302     }
37303     
37304     Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37305     config.grid.scrollBody = true;;
37306     config.grid.monitorWindowResize = false; // turn off autosizing
37307     config.grid.autoHeight = false;
37308     config.grid.autoWidth = false;
37309     
37310     this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37311     
37312     if (config.background) {
37313         // render grid on panel activation (if panel background)
37314         this.on('activate', function(gp) {
37315             if (!gp.grid.rendered) {
37316                 gp.grid.render(this.wrapper);
37317                 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");   
37318             }
37319         });
37320             
37321     } else {
37322         this.grid.render(this.wrapper);
37323         this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");               
37324
37325     }
37326     //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37327     // ??? needed ??? config.el = this.wrapper;
37328     
37329     
37330     
37331   
37332     // xtype created footer. - not sure if will work as we normally have to render first..
37333     if (this.footer && !this.footer.el && this.footer.xtype) {
37334         
37335         var ctr = this.grid.getView().getFooterPanel(true);
37336         this.footer.dataSource = this.grid.dataSource;
37337         this.footer = Roo.factory(this.footer, Roo);
37338         this.footer.render(ctr);
37339         
37340     }
37341     
37342     
37343     
37344     
37345      
37346 };
37347
37348 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37349     getId : function(){
37350         return this.grid.id;
37351     },
37352     
37353     /**
37354      * Returns the grid for this panel
37355      * @return {Roo.bootstrap.Table} 
37356      */
37357     getGrid : function(){
37358         return this.grid;    
37359     },
37360     
37361     setSize : function(width, height){
37362         if(!this.ignoreResize(width, height)){
37363             var grid = this.grid;
37364             var size = this.adjustForComponents(width, height);
37365             var gridel = grid.getGridEl();
37366             gridel.setSize(size.width, size.height);
37367             /*
37368             var thd = grid.getGridEl().select('thead',true).first();
37369             var tbd = grid.getGridEl().select('tbody', true).first();
37370             if (tbd) {
37371                 tbd.setSize(width, height - thd.getHeight());
37372             }
37373             */
37374             grid.autoSize();
37375         }
37376     },
37377      
37378     
37379     
37380     beforeSlide : function(){
37381         this.grid.getView().scroller.clip();
37382     },
37383     
37384     afterSlide : function(){
37385         this.grid.getView().scroller.unclip();
37386     },
37387     
37388     destroy : function(){
37389         this.grid.destroy();
37390         delete this.grid;
37391         Roo.bootstrap.panel.Grid.superclass.destroy.call(this); 
37392     }
37393 });
37394
37395 /**
37396  * @class Roo.bootstrap.panel.Nest
37397  * @extends Roo.bootstrap.panel.Content
37398  * @constructor
37399  * Create a new Panel, that can contain a layout.Border.
37400  * 
37401  * 
37402  * @param {Roo.BorderLayout} layout The layout for this panel
37403  * @param {String/Object} config A string to set only the title or a config object
37404  */
37405 Roo.bootstrap.panel.Nest = function(config)
37406 {
37407     // construct with only one argument..
37408     /* FIXME - implement nicer consturctors
37409     if (layout.layout) {
37410         config = layout;
37411         layout = config.layout;
37412         delete config.layout;
37413     }
37414     if (layout.xtype && !layout.getEl) {
37415         // then layout needs constructing..
37416         layout = Roo.factory(layout, Roo);
37417     }
37418     */
37419     
37420     config.el =  config.layout.getEl();
37421     
37422     Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37423     
37424     config.layout.monitorWindowResize = false; // turn off autosizing
37425     this.layout = config.layout;
37426     this.layout.getEl().addClass("roo-layout-nested-layout");
37427     
37428     
37429     
37430     
37431 };
37432
37433 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37434
37435     setSize : function(width, height){
37436         if(!this.ignoreResize(width, height)){
37437             var size = this.adjustForComponents(width, height);
37438             var el = this.layout.getEl();
37439             if (size.height < 1) {
37440                 el.setWidth(size.width);   
37441             } else {
37442                 el.setSize(size.width, size.height);
37443             }
37444             var touch = el.dom.offsetWidth;
37445             this.layout.layout();
37446             // ie requires a double layout on the first pass
37447             if(Roo.isIE && !this.initialized){
37448                 this.initialized = true;
37449                 this.layout.layout();
37450             }
37451         }
37452     },
37453     
37454     // activate all subpanels if not currently active..
37455     
37456     setActiveState : function(active){
37457         this.active = active;
37458         this.setActiveClass(active);
37459         
37460         if(!active){
37461             this.fireEvent("deactivate", this);
37462             return;
37463         }
37464         
37465         this.fireEvent("activate", this);
37466         // not sure if this should happen before or after..
37467         if (!this.layout) {
37468             return; // should not happen..
37469         }
37470         var reg = false;
37471         for (var r in this.layout.regions) {
37472             reg = this.layout.getRegion(r);
37473             if (reg.getActivePanel()) {
37474                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
37475                 reg.setActivePanel(reg.getActivePanel());
37476                 continue;
37477             }
37478             if (!reg.panels.length) {
37479                 continue;
37480             }
37481             reg.showPanel(reg.getPanel(0));
37482         }
37483         
37484         
37485         
37486         
37487     },
37488     
37489     /**
37490      * Returns the nested BorderLayout for this panel
37491      * @return {Roo.BorderLayout} 
37492      */
37493     getLayout : function(){
37494         return this.layout;
37495     },
37496     
37497      /**
37498      * Adds a xtype elements to the layout of the nested panel
37499      * <pre><code>
37500
37501 panel.addxtype({
37502        xtype : 'ContentPanel',
37503        region: 'west',
37504        items: [ .... ]
37505    }
37506 );
37507
37508 panel.addxtype({
37509         xtype : 'NestedLayoutPanel',
37510         region: 'west',
37511         layout: {
37512            center: { },
37513            west: { }   
37514         },
37515         items : [ ... list of content panels or nested layout panels.. ]
37516    }
37517 );
37518 </code></pre>
37519      * @param {Object} cfg Xtype definition of item to add.
37520      */
37521     addxtype : function(cfg) {
37522         return this.layout.addxtype(cfg);
37523     
37524     }
37525 });        /*
37526  * Based on:
37527  * Ext JS Library 1.1.1
37528  * Copyright(c) 2006-2007, Ext JS, LLC.
37529  *
37530  * Originally Released Under LGPL - original licence link has changed is not relivant.
37531  *
37532  * Fork - LGPL
37533  * <script type="text/javascript">
37534  */
37535 /**
37536  * @class Roo.TabPanel
37537  * @extends Roo.util.Observable
37538  * A lightweight tab container.
37539  * <br><br>
37540  * Usage:
37541  * <pre><code>
37542 // basic tabs 1, built from existing content
37543 var tabs = new Roo.TabPanel("tabs1");
37544 tabs.addTab("script", "View Script");
37545 tabs.addTab("markup", "View Markup");
37546 tabs.activate("script");
37547
37548 // more advanced tabs, built from javascript
37549 var jtabs = new Roo.TabPanel("jtabs");
37550 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37551
37552 // set up the UpdateManager
37553 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37554 var updater = tab2.getUpdateManager();
37555 updater.setDefaultUrl("ajax1.htm");
37556 tab2.on('activate', updater.refresh, updater, true);
37557
37558 // Use setUrl for Ajax loading
37559 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37560 tab3.setUrl("ajax2.htm", null, true);
37561
37562 // Disabled tab
37563 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37564 tab4.disable();
37565
37566 jtabs.activate("jtabs-1");
37567  * </code></pre>
37568  * @constructor
37569  * Create a new TabPanel.
37570  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37571  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37572  */
37573 Roo.bootstrap.panel.Tabs = function(config){
37574     /**
37575     * The container element for this TabPanel.
37576     * @type Roo.Element
37577     */
37578     this.el = Roo.get(config.el);
37579     delete config.el;
37580     if(config){
37581         if(typeof config == "boolean"){
37582             this.tabPosition = config ? "bottom" : "top";
37583         }else{
37584             Roo.apply(this, config);
37585         }
37586     }
37587     
37588     if(this.tabPosition == "bottom"){
37589         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37590         this.el.addClass("roo-tabs-bottom");
37591     }
37592     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37593     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37594     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37595     if(Roo.isIE){
37596         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37597     }
37598     if(this.tabPosition != "bottom"){
37599         /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37600          * @type Roo.Element
37601          */
37602         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37603         this.el.addClass("roo-tabs-top");
37604     }
37605     this.items = [];
37606
37607     this.bodyEl.setStyle("position", "relative");
37608
37609     this.active = null;
37610     this.activateDelegate = this.activate.createDelegate(this);
37611
37612     this.addEvents({
37613         /**
37614          * @event tabchange
37615          * Fires when the active tab changes
37616          * @param {Roo.TabPanel} this
37617          * @param {Roo.TabPanelItem} activePanel The new active tab
37618          */
37619         "tabchange": true,
37620         /**
37621          * @event beforetabchange
37622          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37623          * @param {Roo.TabPanel} this
37624          * @param {Object} e Set cancel to true on this object to cancel the tab change
37625          * @param {Roo.TabPanelItem} tab The tab being changed to
37626          */
37627         "beforetabchange" : true
37628     });
37629
37630     Roo.EventManager.onWindowResize(this.onResize, this);
37631     this.cpad = this.el.getPadding("lr");
37632     this.hiddenCount = 0;
37633
37634
37635     // toolbar on the tabbar support...
37636     if (this.toolbar) {
37637         alert("no toolbar support yet");
37638         this.toolbar  = false;
37639         /*
37640         var tcfg = this.toolbar;
37641         tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
37642         this.toolbar = new Roo.Toolbar(tcfg);
37643         if (Roo.isSafari) {
37644             var tbl = tcfg.container.child('table', true);
37645             tbl.setAttribute('width', '100%');
37646         }
37647         */
37648         
37649     }
37650    
37651
37652
37653     Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37654 };
37655
37656 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37657     /*
37658      *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37659      */
37660     tabPosition : "top",
37661     /*
37662      *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37663      */
37664     currentTabWidth : 0,
37665     /*
37666      *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37667      */
37668     minTabWidth : 40,
37669     /*
37670      *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37671      */
37672     maxTabWidth : 250,
37673     /*
37674      *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37675      */
37676     preferredTabWidth : 175,
37677     /*
37678      *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37679      */
37680     resizeTabs : false,
37681     /*
37682      *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37683      */
37684     monitorResize : true,
37685     /*
37686      *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
37687      */
37688     toolbar : false,
37689
37690     /**
37691      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37692      * @param {String} id The id of the div to use <b>or create</b>
37693      * @param {String} text The text for the tab
37694      * @param {String} content (optional) Content to put in the TabPanelItem body
37695      * @param {Boolean} closable (optional) True to create a close icon on the tab
37696      * @return {Roo.TabPanelItem} The created TabPanelItem
37697      */
37698     addTab : function(id, text, content, closable, tpl)
37699     {
37700         var item = new Roo.bootstrap.panel.TabItem({
37701             panel: this,
37702             id : id,
37703             text : text,
37704             closable : closable,
37705             tpl : tpl
37706         });
37707         this.addTabItem(item);
37708         if(content){
37709             item.setContent(content);
37710         }
37711         return item;
37712     },
37713
37714     /**
37715      * Returns the {@link Roo.TabPanelItem} with the specified id/index
37716      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37717      * @return {Roo.TabPanelItem}
37718      */
37719     getTab : function(id){
37720         return this.items[id];
37721     },
37722
37723     /**
37724      * Hides the {@link Roo.TabPanelItem} with the specified id/index
37725      * @param {String/Number} id The id or index of the TabPanelItem to hide.
37726      */
37727     hideTab : function(id){
37728         var t = this.items[id];
37729         if(!t.isHidden()){
37730            t.setHidden(true);
37731            this.hiddenCount++;
37732            this.autoSizeTabs();
37733         }
37734     },
37735
37736     /**
37737      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37738      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37739      */
37740     unhideTab : function(id){
37741         var t = this.items[id];
37742         if(t.isHidden()){
37743            t.setHidden(false);
37744            this.hiddenCount--;
37745            this.autoSizeTabs();
37746         }
37747     },
37748
37749     /**
37750      * Adds an existing {@link Roo.TabPanelItem}.
37751      * @param {Roo.TabPanelItem} item The TabPanelItem to add
37752      */
37753     addTabItem : function(item){
37754         this.items[item.id] = item;
37755         this.items.push(item);
37756       //  if(this.resizeTabs){
37757     //       item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37758   //         this.autoSizeTabs();
37759 //        }else{
37760 //            item.autoSize();
37761        // }
37762     },
37763
37764     /**
37765      * Removes a {@link Roo.TabPanelItem}.
37766      * @param {String/Number} id The id or index of the TabPanelItem to remove.
37767      */
37768     removeTab : function(id){
37769         var items = this.items;
37770         var tab = items[id];
37771         if(!tab) { return; }
37772         var index = items.indexOf(tab);
37773         if(this.active == tab && items.length > 1){
37774             var newTab = this.getNextAvailable(index);
37775             if(newTab) {
37776                 newTab.activate();
37777             }
37778         }
37779         this.stripEl.dom.removeChild(tab.pnode.dom);
37780         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37781             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37782         }
37783         items.splice(index, 1);
37784         delete this.items[tab.id];
37785         tab.fireEvent("close", tab);
37786         tab.purgeListeners();
37787         this.autoSizeTabs();
37788     },
37789
37790     getNextAvailable : function(start){
37791         var items = this.items;
37792         var index = start;
37793         // look for a next tab that will slide over to
37794         // replace the one being removed
37795         while(index < items.length){
37796             var item = items[++index];
37797             if(item && !item.isHidden()){
37798                 return item;
37799             }
37800         }
37801         // if one isn't found select the previous tab (on the left)
37802         index = start;
37803         while(index >= 0){
37804             var item = items[--index];
37805             if(item && !item.isHidden()){
37806                 return item;
37807             }
37808         }
37809         return null;
37810     },
37811
37812     /**
37813      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37814      * @param {String/Number} id The id or index of the TabPanelItem to disable.
37815      */
37816     disableTab : function(id){
37817         var tab = this.items[id];
37818         if(tab && this.active != tab){
37819             tab.disable();
37820         }
37821     },
37822
37823     /**
37824      * Enables a {@link Roo.TabPanelItem} that is disabled.
37825      * @param {String/Number} id The id or index of the TabPanelItem to enable.
37826      */
37827     enableTab : function(id){
37828         var tab = this.items[id];
37829         tab.enable();
37830     },
37831
37832     /**
37833      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37834      * @param {String/Number} id The id or index of the TabPanelItem to activate.
37835      * @return {Roo.TabPanelItem} The TabPanelItem.
37836      */
37837     activate : function(id){
37838         var tab = this.items[id];
37839         if(!tab){
37840             return null;
37841         }
37842         if(tab == this.active || tab.disabled){
37843             return tab;
37844         }
37845         var e = {};
37846         this.fireEvent("beforetabchange", this, e, tab);
37847         if(e.cancel !== true && !tab.disabled){
37848             if(this.active){
37849                 this.active.hide();
37850             }
37851             this.active = this.items[id];
37852             this.active.show();
37853             this.fireEvent("tabchange", this, this.active);
37854         }
37855         return tab;
37856     },
37857
37858     /**
37859      * Gets the active {@link Roo.TabPanelItem}.
37860      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37861      */
37862     getActiveTab : function(){
37863         return this.active;
37864     },
37865
37866     /**
37867      * Updates the tab body element to fit the height of the container element
37868      * for overflow scrolling
37869      * @param {Number} targetHeight (optional) Override the starting height from the elements height
37870      */
37871     syncHeight : function(targetHeight){
37872         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37873         var bm = this.bodyEl.getMargins();
37874         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37875         this.bodyEl.setHeight(newHeight);
37876         return newHeight;
37877     },
37878
37879     onResize : function(){
37880         if(this.monitorResize){
37881             this.autoSizeTabs();
37882         }
37883     },
37884
37885     /**
37886      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37887      */
37888     beginUpdate : function(){
37889         this.updating = true;
37890     },
37891
37892     /**
37893      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37894      */
37895     endUpdate : function(){
37896         this.updating = false;
37897         this.autoSizeTabs();
37898     },
37899
37900     /**
37901      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37902      */
37903     autoSizeTabs : function(){
37904         var count = this.items.length;
37905         var vcount = count - this.hiddenCount;
37906         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37907             return;
37908         }
37909         var w = Math.max(this.el.getWidth() - this.cpad, 10);
37910         var availWidth = Math.floor(w / vcount);
37911         var b = this.stripBody;
37912         if(b.getWidth() > w){
37913             var tabs = this.items;
37914             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37915             if(availWidth < this.minTabWidth){
37916                 /*if(!this.sleft){    // incomplete scrolling code
37917                     this.createScrollButtons();
37918                 }
37919                 this.showScroll();
37920                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37921             }
37922         }else{
37923             if(this.currentTabWidth < this.preferredTabWidth){
37924                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37925             }
37926         }
37927     },
37928
37929     /**
37930      * Returns the number of tabs in this TabPanel.
37931      * @return {Number}
37932      */
37933      getCount : function(){
37934          return this.items.length;
37935      },
37936
37937     /**
37938      * Resizes all the tabs to the passed width
37939      * @param {Number} The new width
37940      */
37941     setTabWidth : function(width){
37942         this.currentTabWidth = width;
37943         for(var i = 0, len = this.items.length; i < len; i++) {
37944                 if(!this.items[i].isHidden()) {
37945                 this.items[i].setWidth(width);
37946             }
37947         }
37948     },
37949
37950     /**
37951      * Destroys this TabPanel
37952      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37953      */
37954     destroy : function(removeEl){
37955         Roo.EventManager.removeResizeListener(this.onResize, this);
37956         for(var i = 0, len = this.items.length; i < len; i++){
37957             this.items[i].purgeListeners();
37958         }
37959         if(removeEl === true){
37960             this.el.update("");
37961             this.el.remove();
37962         }
37963     },
37964     
37965     createStrip : function(container)
37966     {
37967         var strip = document.createElement("nav");
37968         strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37969         container.appendChild(strip);
37970         return strip;
37971     },
37972     
37973     createStripList : function(strip)
37974     {
37975         // div wrapper for retard IE
37976         // returns the "tr" element.
37977         strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37978         //'<div class="x-tabs-strip-wrap">'+
37979           //  '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37980           //  '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37981         return strip.firstChild; //.firstChild.firstChild.firstChild;
37982     },
37983     createBody : function(container)
37984     {
37985         var body = document.createElement("div");
37986         Roo.id(body, "tab-body");
37987         //Roo.fly(body).addClass("x-tabs-body");
37988         Roo.fly(body).addClass("tab-content");
37989         container.appendChild(body);
37990         return body;
37991     },
37992     createItemBody :function(bodyEl, id){
37993         var body = Roo.getDom(id);
37994         if(!body){
37995             body = document.createElement("div");
37996             body.id = id;
37997         }
37998         //Roo.fly(body).addClass("x-tabs-item-body");
37999         Roo.fly(body).addClass("tab-pane");
38000          bodyEl.insertBefore(body, bodyEl.firstChild);
38001         return body;
38002     },
38003     /** @private */
38004     createStripElements :  function(stripEl, text, closable, tpl)
38005     {
38006         var td = document.createElement("li"); // was td..
38007         
38008         
38009         //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38010         
38011         
38012         stripEl.appendChild(td);
38013         /*if(closable){
38014             td.className = "x-tabs-closable";
38015             if(!this.closeTpl){
38016                 this.closeTpl = new Roo.Template(
38017                    '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38018                    '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38019                    '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
38020                 );
38021             }
38022             var el = this.closeTpl.overwrite(td, {"text": text});
38023             var close = el.getElementsByTagName("div")[0];
38024             var inner = el.getElementsByTagName("em")[0];
38025             return {"el": el, "close": close, "inner": inner};
38026         } else {
38027         */
38028         // not sure what this is..
38029 //            if(!this.tabTpl){
38030                 //this.tabTpl = new Roo.Template(
38031                 //   '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38032                 //   '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38033                 //);
38034 //                this.tabTpl = new Roo.Template(
38035 //                   '<a href="#">' +
38036 //                   '<span unselectable="on"' +
38037 //                            (this.disableTooltips ? '' : ' title="{text}"') +
38038 //                            ' >{text}</span></a>'
38039 //                );
38040 //                
38041 //            }
38042
38043
38044             var template = tpl || this.tabTpl || false;
38045             
38046             if(!template){
38047                 
38048                 template = new Roo.Template(
38049                    '<a href="#">' +
38050                    '<span unselectable="on"' +
38051                             (this.disableTooltips ? '' : ' title="{text}"') +
38052                             ' >{text}</span></a>'
38053                 );
38054             }
38055             
38056             switch (typeof(template)) {
38057                 case 'object' :
38058                     break;
38059                 case 'string' :
38060                     template = new Roo.Template(template);
38061                     break;
38062                 default :
38063                     break;
38064             }
38065             
38066             var el = template.overwrite(td, {"text": text});
38067             
38068             var inner = el.getElementsByTagName("span")[0];
38069             
38070             return {"el": el, "inner": inner};
38071             
38072     }
38073         
38074     
38075 });
38076
38077 /**
38078  * @class Roo.TabPanelItem
38079  * @extends Roo.util.Observable
38080  * Represents an individual item (tab plus body) in a TabPanel.
38081  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38082  * @param {String} id The id of this TabPanelItem
38083  * @param {String} text The text for the tab of this TabPanelItem
38084  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38085  */
38086 Roo.bootstrap.panel.TabItem = function(config){
38087     /**
38088      * The {@link Roo.TabPanel} this TabPanelItem belongs to
38089      * @type Roo.TabPanel
38090      */
38091     this.tabPanel = config.panel;
38092     /**
38093      * The id for this TabPanelItem
38094      * @type String
38095      */
38096     this.id = config.id;
38097     /** @private */
38098     this.disabled = false;
38099     /** @private */
38100     this.text = config.text;
38101     /** @private */
38102     this.loaded = false;
38103     this.closable = config.closable;
38104
38105     /**
38106      * The body element for this TabPanelItem.
38107      * @type Roo.Element
38108      */
38109     this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38110     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38111     this.bodyEl.setStyle("display", "block");
38112     this.bodyEl.setStyle("zoom", "1");
38113     //this.hideAction();
38114
38115     var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38116     /** @private */
38117     this.el = Roo.get(els.el);
38118     this.inner = Roo.get(els.inner, true);
38119     this.textEl = Roo.get(this.el.dom.firstChild, true);
38120     this.pnode = Roo.get(els.el.parentNode, true);
38121 //    this.el.on("mousedown", this.onTabMouseDown, this);
38122     this.el.on("click", this.onTabClick, this);
38123     /** @private */
38124     if(config.closable){
38125         var c = Roo.get(els.close, true);
38126         c.dom.title = this.closeText;
38127         c.addClassOnOver("close-over");
38128         c.on("click", this.closeClick, this);
38129      }
38130
38131     this.addEvents({
38132          /**
38133          * @event activate
38134          * Fires when this tab becomes the active tab.
38135          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38136          * @param {Roo.TabPanelItem} this
38137          */
38138         "activate": true,
38139         /**
38140          * @event beforeclose
38141          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38142          * @param {Roo.TabPanelItem} this
38143          * @param {Object} e Set cancel to true on this object to cancel the close.
38144          */
38145         "beforeclose": true,
38146         /**
38147          * @event close
38148          * Fires when this tab is closed.
38149          * @param {Roo.TabPanelItem} this
38150          */
38151          "close": true,
38152         /**
38153          * @event deactivate
38154          * Fires when this tab is no longer the active tab.
38155          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38156          * @param {Roo.TabPanelItem} this
38157          */
38158          "deactivate" : true
38159     });
38160     this.hidden = false;
38161
38162     Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38163 };
38164
38165 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38166            {
38167     purgeListeners : function(){
38168        Roo.util.Observable.prototype.purgeListeners.call(this);
38169        this.el.removeAllListeners();
38170     },
38171     /**
38172      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38173      */
38174     show : function(){
38175         this.pnode.addClass("active");
38176         this.showAction();
38177         if(Roo.isOpera){
38178             this.tabPanel.stripWrap.repaint();
38179         }
38180         this.fireEvent("activate", this.tabPanel, this);
38181     },
38182
38183     /**
38184      * Returns true if this tab is the active tab.
38185      * @return {Boolean}
38186      */
38187     isActive : function(){
38188         return this.tabPanel.getActiveTab() == this;
38189     },
38190
38191     /**
38192      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38193      */
38194     hide : function(){
38195         this.pnode.removeClass("active");
38196         this.hideAction();
38197         this.fireEvent("deactivate", this.tabPanel, this);
38198     },
38199
38200     hideAction : function(){
38201         this.bodyEl.hide();
38202         this.bodyEl.setStyle("position", "absolute");
38203         this.bodyEl.setLeft("-20000px");
38204         this.bodyEl.setTop("-20000px");
38205     },
38206
38207     showAction : function(){
38208         this.bodyEl.setStyle("position", "relative");
38209         this.bodyEl.setTop("");
38210         this.bodyEl.setLeft("");
38211         this.bodyEl.show();
38212     },
38213
38214     /**
38215      * Set the tooltip for the tab.
38216      * @param {String} tooltip The tab's tooltip
38217      */
38218     setTooltip : function(text){
38219         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38220             this.textEl.dom.qtip = text;
38221             this.textEl.dom.removeAttribute('title');
38222         }else{
38223             this.textEl.dom.title = text;
38224         }
38225     },
38226
38227     onTabClick : function(e){
38228         e.preventDefault();
38229         this.tabPanel.activate(this.id);
38230     },
38231
38232     onTabMouseDown : function(e){
38233         e.preventDefault();
38234         this.tabPanel.activate(this.id);
38235     },
38236 /*
38237     getWidth : function(){
38238         return this.inner.getWidth();
38239     },
38240
38241     setWidth : function(width){
38242         var iwidth = width - this.pnode.getPadding("lr");
38243         this.inner.setWidth(iwidth);
38244         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38245         this.pnode.setWidth(width);
38246     },
38247 */
38248     /**
38249      * Show or hide the tab
38250      * @param {Boolean} hidden True to hide or false to show.
38251      */
38252     setHidden : function(hidden){
38253         this.hidden = hidden;
38254         this.pnode.setStyle("display", hidden ? "none" : "");
38255     },
38256
38257     /**
38258      * Returns true if this tab is "hidden"
38259      * @return {Boolean}
38260      */
38261     isHidden : function(){
38262         return this.hidden;
38263     },
38264
38265     /**
38266      * Returns the text for this tab
38267      * @return {String}
38268      */
38269     getText : function(){
38270         return this.text;
38271     },
38272     /*
38273     autoSize : function(){
38274         //this.el.beginMeasure();
38275         this.textEl.setWidth(1);
38276         /*
38277          *  #2804 [new] Tabs in Roojs
38278          *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38279          */
38280         //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38281         //this.el.endMeasure();
38282     //},
38283
38284     /**
38285      * Sets the text for the tab (Note: this also sets the tooltip text)
38286      * @param {String} text The tab's text and tooltip
38287      */
38288     setText : function(text){
38289         this.text = text;
38290         this.textEl.update(text);
38291         this.setTooltip(text);
38292         //if(!this.tabPanel.resizeTabs){
38293         //    this.autoSize();
38294         //}
38295     },
38296     /**
38297      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38298      */
38299     activate : function(){
38300         this.tabPanel.activate(this.id);
38301     },
38302
38303     /**
38304      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38305      */
38306     disable : function(){
38307         if(this.tabPanel.active != this){
38308             this.disabled = true;
38309             this.pnode.addClass("disabled");
38310         }
38311     },
38312
38313     /**
38314      * Enables this TabPanelItem if it was previously disabled.
38315      */
38316     enable : function(){
38317         this.disabled = false;
38318         this.pnode.removeClass("disabled");
38319     },
38320
38321     /**
38322      * Sets the content for this TabPanelItem.
38323      * @param {String} content The content
38324      * @param {Boolean} loadScripts true to look for and load scripts
38325      */
38326     setContent : function(content, loadScripts){
38327         this.bodyEl.update(content, loadScripts);
38328     },
38329
38330     /**
38331      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38332      * @return {Roo.UpdateManager} The UpdateManager
38333      */
38334     getUpdateManager : function(){
38335         return this.bodyEl.getUpdateManager();
38336     },
38337
38338     /**
38339      * Set a URL to be used to load the content for this TabPanelItem.
38340      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38341      * @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)
38342      * @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)
38343      * @return {Roo.UpdateManager} The UpdateManager
38344      */
38345     setUrl : function(url, params, loadOnce){
38346         if(this.refreshDelegate){
38347             this.un('activate', this.refreshDelegate);
38348         }
38349         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38350         this.on("activate", this.refreshDelegate);
38351         return this.bodyEl.getUpdateManager();
38352     },
38353
38354     /** @private */
38355     _handleRefresh : function(url, params, loadOnce){
38356         if(!loadOnce || !this.loaded){
38357             var updater = this.bodyEl.getUpdateManager();
38358             updater.update(url, params, this._setLoaded.createDelegate(this));
38359         }
38360     },
38361
38362     /**
38363      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
38364      *   Will fail silently if the setUrl method has not been called.
38365      *   This does not activate the panel, just updates its content.
38366      */
38367     refresh : function(){
38368         if(this.refreshDelegate){
38369            this.loaded = false;
38370            this.refreshDelegate();
38371         }
38372     },
38373
38374     /** @private */
38375     _setLoaded : function(){
38376         this.loaded = true;
38377     },
38378
38379     /** @private */
38380     closeClick : function(e){
38381         var o = {};
38382         e.stopEvent();
38383         this.fireEvent("beforeclose", this, o);
38384         if(o.cancel !== true){
38385             this.tabPanel.removeTab(this.id);
38386         }
38387     },
38388     /**
38389      * The text displayed in the tooltip for the close icon.
38390      * @type String
38391      */
38392     closeText : "Close this tab"
38393 });
38394 /**
38395 *    This script refer to:
38396 *    Title: International Telephone Input
38397 *    Author: Jack O'Connor
38398 *    Code version:  v12.1.12
38399 *    Availability: https://github.com/jackocnr/intl-tel-input.git
38400 **/
38401
38402 Roo.bootstrap.PhoneInputData = function() {
38403     var d = [
38404       [
38405         "Afghanistan (‫افغانستان‬‎)",
38406         "af",
38407         "93"
38408       ],
38409       [
38410         "Albania (Shqipëri)",
38411         "al",
38412         "355"
38413       ],
38414       [
38415         "Algeria (‫الجزائر‬‎)",
38416         "dz",
38417         "213"
38418       ],
38419       [
38420         "American Samoa",
38421         "as",
38422         "1684"
38423       ],
38424       [
38425         "Andorra",
38426         "ad",
38427         "376"
38428       ],
38429       [
38430         "Angola",
38431         "ao",
38432         "244"
38433       ],
38434       [
38435         "Anguilla",
38436         "ai",
38437         "1264"
38438       ],
38439       [
38440         "Antigua and Barbuda",
38441         "ag",
38442         "1268"
38443       ],
38444       [
38445         "Argentina",
38446         "ar",
38447         "54"
38448       ],
38449       [
38450         "Armenia (Հայաստան)",
38451         "am",
38452         "374"
38453       ],
38454       [
38455         "Aruba",
38456         "aw",
38457         "297"
38458       ],
38459       [
38460         "Australia",
38461         "au",
38462         "61",
38463         0
38464       ],
38465       [
38466         "Austria (Österreich)",
38467         "at",
38468         "43"
38469       ],
38470       [
38471         "Azerbaijan (Azərbaycan)",
38472         "az",
38473         "994"
38474       ],
38475       [
38476         "Bahamas",
38477         "bs",
38478         "1242"
38479       ],
38480       [
38481         "Bahrain (‫البحرين‬‎)",
38482         "bh",
38483         "973"
38484       ],
38485       [
38486         "Bangladesh (বাংলাদেশ)",
38487         "bd",
38488         "880"
38489       ],
38490       [
38491         "Barbados",
38492         "bb",
38493         "1246"
38494       ],
38495       [
38496         "Belarus (Беларусь)",
38497         "by",
38498         "375"
38499       ],
38500       [
38501         "Belgium (België)",
38502         "be",
38503         "32"
38504       ],
38505       [
38506         "Belize",
38507         "bz",
38508         "501"
38509       ],
38510       [
38511         "Benin (Bénin)",
38512         "bj",
38513         "229"
38514       ],
38515       [
38516         "Bermuda",
38517         "bm",
38518         "1441"
38519       ],
38520       [
38521         "Bhutan (འབྲུག)",
38522         "bt",
38523         "975"
38524       ],
38525       [
38526         "Bolivia",
38527         "bo",
38528         "591"
38529       ],
38530       [
38531         "Bosnia and Herzegovina (Босна и Херцеговина)",
38532         "ba",
38533         "387"
38534       ],
38535       [
38536         "Botswana",
38537         "bw",
38538         "267"
38539       ],
38540       [
38541         "Brazil (Brasil)",
38542         "br",
38543         "55"
38544       ],
38545       [
38546         "British Indian Ocean Territory",
38547         "io",
38548         "246"
38549       ],
38550       [
38551         "British Virgin Islands",
38552         "vg",
38553         "1284"
38554       ],
38555       [
38556         "Brunei",
38557         "bn",
38558         "673"
38559       ],
38560       [
38561         "Bulgaria (България)",
38562         "bg",
38563         "359"
38564       ],
38565       [
38566         "Burkina Faso",
38567         "bf",
38568         "226"
38569       ],
38570       [
38571         "Burundi (Uburundi)",
38572         "bi",
38573         "257"
38574       ],
38575       [
38576         "Cambodia (កម្ពុជា)",
38577         "kh",
38578         "855"
38579       ],
38580       [
38581         "Cameroon (Cameroun)",
38582         "cm",
38583         "237"
38584       ],
38585       [
38586         "Canada",
38587         "ca",
38588         "1",
38589         1,
38590         ["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"]
38591       ],
38592       [
38593         "Cape Verde (Kabu Verdi)",
38594         "cv",
38595         "238"
38596       ],
38597       [
38598         "Caribbean Netherlands",
38599         "bq",
38600         "599",
38601         1
38602       ],
38603       [
38604         "Cayman Islands",
38605         "ky",
38606         "1345"
38607       ],
38608       [
38609         "Central African Republic (République centrafricaine)",
38610         "cf",
38611         "236"
38612       ],
38613       [
38614         "Chad (Tchad)",
38615         "td",
38616         "235"
38617       ],
38618       [
38619         "Chile",
38620         "cl",
38621         "56"
38622       ],
38623       [
38624         "China (中国)",
38625         "cn",
38626         "86"
38627       ],
38628       [
38629         "Christmas Island",
38630         "cx",
38631         "61",
38632         2
38633       ],
38634       [
38635         "Cocos (Keeling) Islands",
38636         "cc",
38637         "61",
38638         1
38639       ],
38640       [
38641         "Colombia",
38642         "co",
38643         "57"
38644       ],
38645       [
38646         "Comoros (‫جزر القمر‬‎)",
38647         "km",
38648         "269"
38649       ],
38650       [
38651         "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38652         "cd",
38653         "243"
38654       ],
38655       [
38656         "Congo (Republic) (Congo-Brazzaville)",
38657         "cg",
38658         "242"
38659       ],
38660       [
38661         "Cook Islands",
38662         "ck",
38663         "682"
38664       ],
38665       [
38666         "Costa Rica",
38667         "cr",
38668         "506"
38669       ],
38670       [
38671         "Côte d’Ivoire",
38672         "ci",
38673         "225"
38674       ],
38675       [
38676         "Croatia (Hrvatska)",
38677         "hr",
38678         "385"
38679       ],
38680       [
38681         "Cuba",
38682         "cu",
38683         "53"
38684       ],
38685       [
38686         "Curaçao",
38687         "cw",
38688         "599",
38689         0
38690       ],
38691       [
38692         "Cyprus (Κύπρος)",
38693         "cy",
38694         "357"
38695       ],
38696       [
38697         "Czech Republic (Česká republika)",
38698         "cz",
38699         "420"
38700       ],
38701       [
38702         "Denmark (Danmark)",
38703         "dk",
38704         "45"
38705       ],
38706       [
38707         "Djibouti",
38708         "dj",
38709         "253"
38710       ],
38711       [
38712         "Dominica",
38713         "dm",
38714         "1767"
38715       ],
38716       [
38717         "Dominican Republic (República Dominicana)",
38718         "do",
38719         "1",
38720         2,
38721         ["809", "829", "849"]
38722       ],
38723       [
38724         "Ecuador",
38725         "ec",
38726         "593"
38727       ],
38728       [
38729         "Egypt (‫مصر‬‎)",
38730         "eg",
38731         "20"
38732       ],
38733       [
38734         "El Salvador",
38735         "sv",
38736         "503"
38737       ],
38738       [
38739         "Equatorial Guinea (Guinea Ecuatorial)",
38740         "gq",
38741         "240"
38742       ],
38743       [
38744         "Eritrea",
38745         "er",
38746         "291"
38747       ],
38748       [
38749         "Estonia (Eesti)",
38750         "ee",
38751         "372"
38752       ],
38753       [
38754         "Ethiopia",
38755         "et",
38756         "251"
38757       ],
38758       [
38759         "Falkland Islands (Islas Malvinas)",
38760         "fk",
38761         "500"
38762       ],
38763       [
38764         "Faroe Islands (Føroyar)",
38765         "fo",
38766         "298"
38767       ],
38768       [
38769         "Fiji",
38770         "fj",
38771         "679"
38772       ],
38773       [
38774         "Finland (Suomi)",
38775         "fi",
38776         "358",
38777         0
38778       ],
38779       [
38780         "France",
38781         "fr",
38782         "33"
38783       ],
38784       [
38785         "French Guiana (Guyane française)",
38786         "gf",
38787         "594"
38788       ],
38789       [
38790         "French Polynesia (Polynésie française)",
38791         "pf",
38792         "689"
38793       ],
38794       [
38795         "Gabon",
38796         "ga",
38797         "241"
38798       ],
38799       [
38800         "Gambia",
38801         "gm",
38802         "220"
38803       ],
38804       [
38805         "Georgia (საქართველო)",
38806         "ge",
38807         "995"
38808       ],
38809       [
38810         "Germany (Deutschland)",
38811         "de",
38812         "49"
38813       ],
38814       [
38815         "Ghana (Gaana)",
38816         "gh",
38817         "233"
38818       ],
38819       [
38820         "Gibraltar",
38821         "gi",
38822         "350"
38823       ],
38824       [
38825         "Greece (Ελλάδα)",
38826         "gr",
38827         "30"
38828       ],
38829       [
38830         "Greenland (Kalaallit Nunaat)",
38831         "gl",
38832         "299"
38833       ],
38834       [
38835         "Grenada",
38836         "gd",
38837         "1473"
38838       ],
38839       [
38840         "Guadeloupe",
38841         "gp",
38842         "590",
38843         0
38844       ],
38845       [
38846         "Guam",
38847         "gu",
38848         "1671"
38849       ],
38850       [
38851         "Guatemala",
38852         "gt",
38853         "502"
38854       ],
38855       [
38856         "Guernsey",
38857         "gg",
38858         "44",
38859         1
38860       ],
38861       [
38862         "Guinea (Guinée)",
38863         "gn",
38864         "224"
38865       ],
38866       [
38867         "Guinea-Bissau (Guiné Bissau)",
38868         "gw",
38869         "245"
38870       ],
38871       [
38872         "Guyana",
38873         "gy",
38874         "592"
38875       ],
38876       [
38877         "Haiti",
38878         "ht",
38879         "509"
38880       ],
38881       [
38882         "Honduras",
38883         "hn",
38884         "504"
38885       ],
38886       [
38887         "Hong Kong (香港)",
38888         "hk",
38889         "852"
38890       ],
38891       [
38892         "Hungary (Magyarország)",
38893         "hu",
38894         "36"
38895       ],
38896       [
38897         "Iceland (Ísland)",
38898         "is",
38899         "354"
38900       ],
38901       [
38902         "India (भारत)",
38903         "in",
38904         "91"
38905       ],
38906       [
38907         "Indonesia",
38908         "id",
38909         "62"
38910       ],
38911       [
38912         "Iran (‫ایران‬‎)",
38913         "ir",
38914         "98"
38915       ],
38916       [
38917         "Iraq (‫العراق‬‎)",
38918         "iq",
38919         "964"
38920       ],
38921       [
38922         "Ireland",
38923         "ie",
38924         "353"
38925       ],
38926       [
38927         "Isle of Man",
38928         "im",
38929         "44",
38930         2
38931       ],
38932       [
38933         "Israel (‫ישראל‬‎)",
38934         "il",
38935         "972"
38936       ],
38937       [
38938         "Italy (Italia)",
38939         "it",
38940         "39",
38941         0
38942       ],
38943       [
38944         "Jamaica",
38945         "jm",
38946         "1876"
38947       ],
38948       [
38949         "Japan (日本)",
38950         "jp",
38951         "81"
38952       ],
38953       [
38954         "Jersey",
38955         "je",
38956         "44",
38957         3
38958       ],
38959       [
38960         "Jordan (‫الأردن‬‎)",
38961         "jo",
38962         "962"
38963       ],
38964       [
38965         "Kazakhstan (Казахстан)",
38966         "kz",
38967         "7",
38968         1
38969       ],
38970       [
38971         "Kenya",
38972         "ke",
38973         "254"
38974       ],
38975       [
38976         "Kiribati",
38977         "ki",
38978         "686"
38979       ],
38980       [
38981         "Kosovo",
38982         "xk",
38983         "383"
38984       ],
38985       [
38986         "Kuwait (‫الكويت‬‎)",
38987         "kw",
38988         "965"
38989       ],
38990       [
38991         "Kyrgyzstan (Кыргызстан)",
38992         "kg",
38993         "996"
38994       ],
38995       [
38996         "Laos (ລາວ)",
38997         "la",
38998         "856"
38999       ],
39000       [
39001         "Latvia (Latvija)",
39002         "lv",
39003         "371"
39004       ],
39005       [
39006         "Lebanon (‫لبنان‬‎)",
39007         "lb",
39008         "961"
39009       ],
39010       [
39011         "Lesotho",
39012         "ls",
39013         "266"
39014       ],
39015       [
39016         "Liberia",
39017         "lr",
39018         "231"
39019       ],
39020       [
39021         "Libya (‫ليبيا‬‎)",
39022         "ly",
39023         "218"
39024       ],
39025       [
39026         "Liechtenstein",
39027         "li",
39028         "423"
39029       ],
39030       [
39031         "Lithuania (Lietuva)",
39032         "lt",
39033         "370"
39034       ],
39035       [
39036         "Luxembourg",
39037         "lu",
39038         "352"
39039       ],
39040       [
39041         "Macau (澳門)",
39042         "mo",
39043         "853"
39044       ],
39045       [
39046         "Macedonia (FYROM) (Македонија)",
39047         "mk",
39048         "389"
39049       ],
39050       [
39051         "Madagascar (Madagasikara)",
39052         "mg",
39053         "261"
39054       ],
39055       [
39056         "Malawi",
39057         "mw",
39058         "265"
39059       ],
39060       [
39061         "Malaysia",
39062         "my",
39063         "60"
39064       ],
39065       [
39066         "Maldives",
39067         "mv",
39068         "960"
39069       ],
39070       [
39071         "Mali",
39072         "ml",
39073         "223"
39074       ],
39075       [
39076         "Malta",
39077         "mt",
39078         "356"
39079       ],
39080       [
39081         "Marshall Islands",
39082         "mh",
39083         "692"
39084       ],
39085       [
39086         "Martinique",
39087         "mq",
39088         "596"
39089       ],
39090       [
39091         "Mauritania (‫موريتانيا‬‎)",
39092         "mr",
39093         "222"
39094       ],
39095       [
39096         "Mauritius (Moris)",
39097         "mu",
39098         "230"
39099       ],
39100       [
39101         "Mayotte",
39102         "yt",
39103         "262",
39104         1
39105       ],
39106       [
39107         "Mexico (México)",
39108         "mx",
39109         "52"
39110       ],
39111       [
39112         "Micronesia",
39113         "fm",
39114         "691"
39115       ],
39116       [
39117         "Moldova (Republica Moldova)",
39118         "md",
39119         "373"
39120       ],
39121       [
39122         "Monaco",
39123         "mc",
39124         "377"
39125       ],
39126       [
39127         "Mongolia (Монгол)",
39128         "mn",
39129         "976"
39130       ],
39131       [
39132         "Montenegro (Crna Gora)",
39133         "me",
39134         "382"
39135       ],
39136       [
39137         "Montserrat",
39138         "ms",
39139         "1664"
39140       ],
39141       [
39142         "Morocco (‫المغرب‬‎)",
39143         "ma",
39144         "212",
39145         0
39146       ],
39147       [
39148         "Mozambique (Moçambique)",
39149         "mz",
39150         "258"
39151       ],
39152       [
39153         "Myanmar (Burma) (မြန်မာ)",
39154         "mm",
39155         "95"
39156       ],
39157       [
39158         "Namibia (Namibië)",
39159         "na",
39160         "264"
39161       ],
39162       [
39163         "Nauru",
39164         "nr",
39165         "674"
39166       ],
39167       [
39168         "Nepal (नेपाल)",
39169         "np",
39170         "977"
39171       ],
39172       [
39173         "Netherlands (Nederland)",
39174         "nl",
39175         "31"
39176       ],
39177       [
39178         "New Caledonia (Nouvelle-Calédonie)",
39179         "nc",
39180         "687"
39181       ],
39182       [
39183         "New Zealand",
39184         "nz",
39185         "64"
39186       ],
39187       [
39188         "Nicaragua",
39189         "ni",
39190         "505"
39191       ],
39192       [
39193         "Niger (Nijar)",
39194         "ne",
39195         "227"
39196       ],
39197       [
39198         "Nigeria",
39199         "ng",
39200         "234"
39201       ],
39202       [
39203         "Niue",
39204         "nu",
39205         "683"
39206       ],
39207       [
39208         "Norfolk Island",
39209         "nf",
39210         "672"
39211       ],
39212       [
39213         "North Korea (조선 민주주의 인민 공화국)",
39214         "kp",
39215         "850"
39216       ],
39217       [
39218         "Northern Mariana Islands",
39219         "mp",
39220         "1670"
39221       ],
39222       [
39223         "Norway (Norge)",
39224         "no",
39225         "47",
39226         0
39227       ],
39228       [
39229         "Oman (‫عُمان‬‎)",
39230         "om",
39231         "968"
39232       ],
39233       [
39234         "Pakistan (‫پاکستان‬‎)",
39235         "pk",
39236         "92"
39237       ],
39238       [
39239         "Palau",
39240         "pw",
39241         "680"
39242       ],
39243       [
39244         "Palestine (‫فلسطين‬‎)",
39245         "ps",
39246         "970"
39247       ],
39248       [
39249         "Panama (Panamá)",
39250         "pa",
39251         "507"
39252       ],
39253       [
39254         "Papua New Guinea",
39255         "pg",
39256         "675"
39257       ],
39258       [
39259         "Paraguay",
39260         "py",
39261         "595"
39262       ],
39263       [
39264         "Peru (Perú)",
39265         "pe",
39266         "51"
39267       ],
39268       [
39269         "Philippines",
39270         "ph",
39271         "63"
39272       ],
39273       [
39274         "Poland (Polska)",
39275         "pl",
39276         "48"
39277       ],
39278       [
39279         "Portugal",
39280         "pt",
39281         "351"
39282       ],
39283       [
39284         "Puerto Rico",
39285         "pr",
39286         "1",
39287         3,
39288         ["787", "939"]
39289       ],
39290       [
39291         "Qatar (‫قطر‬‎)",
39292         "qa",
39293         "974"
39294       ],
39295       [
39296         "Réunion (La Réunion)",
39297         "re",
39298         "262",
39299         0
39300       ],
39301       [
39302         "Romania (România)",
39303         "ro",
39304         "40"
39305       ],
39306       [
39307         "Russia (Россия)",
39308         "ru",
39309         "7",
39310         0
39311       ],
39312       [
39313         "Rwanda",
39314         "rw",
39315         "250"
39316       ],
39317       [
39318         "Saint Barthélemy",
39319         "bl",
39320         "590",
39321         1
39322       ],
39323       [
39324         "Saint Helena",
39325         "sh",
39326         "290"
39327       ],
39328       [
39329         "Saint Kitts and Nevis",
39330         "kn",
39331         "1869"
39332       ],
39333       [
39334         "Saint Lucia",
39335         "lc",
39336         "1758"
39337       ],
39338       [
39339         "Saint Martin (Saint-Martin (partie française))",
39340         "mf",
39341         "590",
39342         2
39343       ],
39344       [
39345         "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39346         "pm",
39347         "508"
39348       ],
39349       [
39350         "Saint Vincent and the Grenadines",
39351         "vc",
39352         "1784"
39353       ],
39354       [
39355         "Samoa",
39356         "ws",
39357         "685"
39358       ],
39359       [
39360         "San Marino",
39361         "sm",
39362         "378"
39363       ],
39364       [
39365         "São Tomé and Príncipe (São Tomé e Príncipe)",
39366         "st",
39367         "239"
39368       ],
39369       [
39370         "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
39371         "sa",
39372         "966"
39373       ],
39374       [
39375         "Senegal (Sénégal)",
39376         "sn",
39377         "221"
39378       ],
39379       [
39380         "Serbia (Србија)",
39381         "rs",
39382         "381"
39383       ],
39384       [
39385         "Seychelles",
39386         "sc",
39387         "248"
39388       ],
39389       [
39390         "Sierra Leone",
39391         "sl",
39392         "232"
39393       ],
39394       [
39395         "Singapore",
39396         "sg",
39397         "65"
39398       ],
39399       [
39400         "Sint Maarten",
39401         "sx",
39402         "1721"
39403       ],
39404       [
39405         "Slovakia (Slovensko)",
39406         "sk",
39407         "421"
39408       ],
39409       [
39410         "Slovenia (Slovenija)",
39411         "si",
39412         "386"
39413       ],
39414       [
39415         "Solomon Islands",
39416         "sb",
39417         "677"
39418       ],
39419       [
39420         "Somalia (Soomaaliya)",
39421         "so",
39422         "252"
39423       ],
39424       [
39425         "South Africa",
39426         "za",
39427         "27"
39428       ],
39429       [
39430         "South Korea (대한민국)",
39431         "kr",
39432         "82"
39433       ],
39434       [
39435         "South Sudan (‫جنوب السودان‬‎)",
39436         "ss",
39437         "211"
39438       ],
39439       [
39440         "Spain (España)",
39441         "es",
39442         "34"
39443       ],
39444       [
39445         "Sri Lanka (ශ්‍රී ලංකාව)",
39446         "lk",
39447         "94"
39448       ],
39449       [
39450         "Sudan (‫السودان‬‎)",
39451         "sd",
39452         "249"
39453       ],
39454       [
39455         "Suriname",
39456         "sr",
39457         "597"
39458       ],
39459       [
39460         "Svalbard and Jan Mayen",
39461         "sj",
39462         "47",
39463         1
39464       ],
39465       [
39466         "Swaziland",
39467         "sz",
39468         "268"
39469       ],
39470       [
39471         "Sweden (Sverige)",
39472         "se",
39473         "46"
39474       ],
39475       [
39476         "Switzerland (Schweiz)",
39477         "ch",
39478         "41"
39479       ],
39480       [
39481         "Syria (‫سوريا‬‎)",
39482         "sy",
39483         "963"
39484       ],
39485       [
39486         "Taiwan (台灣)",
39487         "tw",
39488         "886"
39489       ],
39490       [
39491         "Tajikistan",
39492         "tj",
39493         "992"
39494       ],
39495       [
39496         "Tanzania",
39497         "tz",
39498         "255"
39499       ],
39500       [
39501         "Thailand (ไทย)",
39502         "th",
39503         "66"
39504       ],
39505       [
39506         "Timor-Leste",
39507         "tl",
39508         "670"
39509       ],
39510       [
39511         "Togo",
39512         "tg",
39513         "228"
39514       ],
39515       [
39516         "Tokelau",
39517         "tk",
39518         "690"
39519       ],
39520       [
39521         "Tonga",
39522         "to",
39523         "676"
39524       ],
39525       [
39526         "Trinidad and Tobago",
39527         "tt",
39528         "1868"
39529       ],
39530       [
39531         "Tunisia (‫تونس‬‎)",
39532         "tn",
39533         "216"
39534       ],
39535       [
39536         "Turkey (Türkiye)",
39537         "tr",
39538         "90"
39539       ],
39540       [
39541         "Turkmenistan",
39542         "tm",
39543         "993"
39544       ],
39545       [
39546         "Turks and Caicos Islands",
39547         "tc",
39548         "1649"
39549       ],
39550       [
39551         "Tuvalu",
39552         "tv",
39553         "688"
39554       ],
39555       [
39556         "U.S. Virgin Islands",
39557         "vi",
39558         "1340"
39559       ],
39560       [
39561         "Uganda",
39562         "ug",
39563         "256"
39564       ],
39565       [
39566         "Ukraine (Україна)",
39567         "ua",
39568         "380"
39569       ],
39570       [
39571         "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
39572         "ae",
39573         "971"
39574       ],
39575       [
39576         "United Kingdom",
39577         "gb",
39578         "44",
39579         0
39580       ],
39581       [
39582         "United States",
39583         "us",
39584         "1",
39585         0
39586       ],
39587       [
39588         "Uruguay",
39589         "uy",
39590         "598"
39591       ],
39592       [
39593         "Uzbekistan (Oʻzbekiston)",
39594         "uz",
39595         "998"
39596       ],
39597       [
39598         "Vanuatu",
39599         "vu",
39600         "678"
39601       ],
39602       [
39603         "Vatican City (Città del Vaticano)",
39604         "va",
39605         "39",
39606         1
39607       ],
39608       [
39609         "Venezuela",
39610         "ve",
39611         "58"
39612       ],
39613       [
39614         "Vietnam (Việt Nam)",
39615         "vn",
39616         "84"
39617       ],
39618       [
39619         "Wallis and Futuna (Wallis-et-Futuna)",
39620         "wf",
39621         "681"
39622       ],
39623       [
39624         "Western Sahara (‫الصحراء الغربية‬‎)",
39625         "eh",
39626         "212",
39627         1
39628       ],
39629       [
39630         "Yemen (‫اليمن‬‎)",
39631         "ye",
39632         "967"
39633       ],
39634       [
39635         "Zambia",
39636         "zm",
39637         "260"
39638       ],
39639       [
39640         "Zimbabwe",
39641         "zw",
39642         "263"
39643       ],
39644       [
39645         "Åland Islands",
39646         "ax",
39647         "358",
39648         1
39649       ]
39650   ];
39651   
39652   return d;
39653 }/**
39654 *    This script refer to:
39655 *    Title: International Telephone Input
39656 *    Author: Jack O'Connor
39657 *    Code version:  v12.1.12
39658 *    Availability: https://github.com/jackocnr/intl-tel-input.git
39659 **/
39660
39661 /**
39662  * @class Roo.bootstrap.PhoneInput
39663  * @extends Roo.bootstrap.TriggerField
39664  * An input with International dial-code selection
39665  
39666  * @cfg {String} defaultDialCode default '+852'
39667  * @cfg {Array} preferedCountries default []
39668   
39669  * @constructor
39670  * Create a new PhoneInput.
39671  * @param {Object} config Configuration options
39672  */
39673
39674 Roo.bootstrap.PhoneInput = function(config) {
39675     Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39676 };
39677
39678 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39679         
39680         listWidth: undefined,
39681         
39682         selectedClass: 'active',
39683         
39684         invalidClass : "has-warning",
39685         
39686         validClass: 'has-success',
39687         
39688         allowed: '0123456789',
39689         
39690         /**
39691          * @cfg {String} defaultDialCode The default dial code when initializing the input
39692          */
39693         defaultDialCode: '+852',
39694         
39695         /**
39696          * @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
39697          */
39698         preferedCountries: false,
39699         
39700         getAutoCreate : function()
39701         {
39702             var data = Roo.bootstrap.PhoneInputData();
39703             var align = this.labelAlign || this.parentLabelAlign();
39704             var id = Roo.id();
39705             
39706             this.allCountries = [];
39707             this.dialCodeMapping = [];
39708             
39709             for (var i = 0; i < data.length; i++) {
39710               var c = data[i];
39711               this.allCountries[i] = {
39712                 name: c[0],
39713                 iso2: c[1],
39714                 dialCode: c[2],
39715                 priority: c[3] || 0,
39716                 areaCodes: c[4] || null
39717               };
39718               this.dialCodeMapping[c[2]] = {
39719                   name: c[0],
39720                   iso2: c[1],
39721                   priority: c[3] || 0,
39722                   areaCodes: c[4] || null
39723               };
39724             }
39725             
39726             var cfg = {
39727                 cls: 'form-group',
39728                 cn: []
39729             };
39730             
39731             var input =  {
39732                 tag: 'input',
39733                 id : id,
39734                 cls : 'form-control tel-input',
39735                 autocomplete: 'new-password'
39736             };
39737             
39738             var hiddenInput = {
39739                 tag: 'input',
39740                 type: 'hidden',
39741                 cls: 'hidden-tel-input'
39742             };
39743             
39744             if (this.name) {
39745                 hiddenInput.name = this.name;
39746             }
39747             
39748             if (this.disabled) {
39749                 input.disabled = true;
39750             }
39751             
39752             var flag_container = {
39753                 tag: 'div',
39754                 cls: 'flag-box',
39755                 cn: [
39756                     {
39757                         tag: 'div',
39758                         cls: 'flag'
39759                     },
39760                     {
39761                         tag: 'div',
39762                         cls: 'caret'
39763                     }
39764                 ]
39765             };
39766             
39767             var box = {
39768                 tag: 'div',
39769                 cls: this.hasFeedback ? 'has-feedback' : '',
39770                 cn: [
39771                     hiddenInput,
39772                     input,
39773                     {
39774                         tag: 'input',
39775                         cls: 'dial-code-holder',
39776                         disabled: true
39777                     }
39778                 ]
39779             };
39780             
39781             var container = {
39782                 cls: 'roo-select2-container input-group',
39783                 cn: [
39784                     flag_container,
39785                     box
39786                 ]
39787             };
39788             
39789             if (this.fieldLabel.length) {
39790                 var indicator = {
39791                     tag: 'i',
39792                     tooltip: 'This field is required'
39793                 };
39794                 
39795                 var label = {
39796                     tag: 'label',
39797                     'for':  id,
39798                     cls: 'control-label',
39799                     cn: []
39800                 };
39801                 
39802                 var label_text = {
39803                     tag: 'span',
39804                     html: this.fieldLabel
39805                 };
39806                 
39807                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39808                 label.cn = [
39809                     indicator,
39810                     label_text
39811                 ];
39812                 
39813                 if(this.indicatorpos == 'right') {
39814                     indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39815                     label.cn = [
39816                         label_text,
39817                         indicator
39818                     ];
39819                 }
39820                 
39821                 if(align == 'left') {
39822                     container = {
39823                         tag: 'div',
39824                         cn: [
39825                             container
39826                         ]
39827                     };
39828                     
39829                     if(this.labelWidth > 12){
39830                         label.style = "width: " + this.labelWidth + 'px';
39831                     }
39832                     if(this.labelWidth < 13 && this.labelmd == 0){
39833                         this.labelmd = this.labelWidth;
39834                     }
39835                     if(this.labellg > 0){
39836                         label.cls += ' col-lg-' + this.labellg;
39837                         input.cls += ' col-lg-' + (12 - this.labellg);
39838                     }
39839                     if(this.labelmd > 0){
39840                         label.cls += ' col-md-' + this.labelmd;
39841                         container.cls += ' col-md-' + (12 - this.labelmd);
39842                     }
39843                     if(this.labelsm > 0){
39844                         label.cls += ' col-sm-' + this.labelsm;
39845                         container.cls += ' col-sm-' + (12 - this.labelsm);
39846                     }
39847                     if(this.labelxs > 0){
39848                         label.cls += ' col-xs-' + this.labelxs;
39849                         container.cls += ' col-xs-' + (12 - this.labelxs);
39850                     }
39851                 }
39852             }
39853             
39854             cfg.cn = [
39855                 label,
39856                 container
39857             ];
39858             
39859             var settings = this;
39860             
39861             ['xs','sm','md','lg'].map(function(size){
39862                 if (settings[size]) {
39863                     cfg.cls += ' col-' + size + '-' + settings[size];
39864                 }
39865             });
39866             
39867             this.store = new Roo.data.Store({
39868                 proxy : new Roo.data.MemoryProxy({}),
39869                 reader : new Roo.data.JsonReader({
39870                     fields : [
39871                         {
39872                             'name' : 'name',
39873                             'type' : 'string'
39874                         },
39875                         {
39876                             'name' : 'iso2',
39877                             'type' : 'string'
39878                         },
39879                         {
39880                             'name' : 'dialCode',
39881                             'type' : 'string'
39882                         },
39883                         {
39884                             'name' : 'priority',
39885                             'type' : 'string'
39886                         },
39887                         {
39888                             'name' : 'areaCodes',
39889                             'type' : 'string'
39890                         }
39891                     ]
39892                 })
39893             });
39894             
39895             if(!this.preferedCountries) {
39896                 this.preferedCountries = [
39897                     'hk',
39898                     'gb',
39899                     'us'
39900                 ];
39901             }
39902             
39903             var p = this.preferedCountries.reverse();
39904             
39905             if(p) {
39906                 for (var i = 0; i < p.length; i++) {
39907                     for (var j = 0; j < this.allCountries.length; j++) {
39908                         if(this.allCountries[j].iso2 == p[i]) {
39909                             var t = this.allCountries[j];
39910                             this.allCountries.splice(j,1);
39911                             this.allCountries.unshift(t);
39912                         }
39913                     } 
39914                 }
39915             }
39916             
39917             this.store.proxy.data = {
39918                 success: true,
39919                 data: this.allCountries
39920             };
39921             
39922             return cfg;
39923         },
39924         
39925         initEvents : function()
39926         {
39927             this.createList();
39928             Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39929             
39930             this.indicator = this.indicatorEl();
39931             this.flag = this.flagEl();
39932             this.dialCodeHolder = this.dialCodeHolderEl();
39933             
39934             this.trigger = this.el.select('div.flag-box',true).first();
39935             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39936             
39937             var _this = this;
39938             
39939             (function(){
39940                 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39941                 _this.list.setWidth(lw);
39942             }).defer(100);
39943             
39944             this.list.on('mouseover', this.onViewOver, this);
39945             this.list.on('mousemove', this.onViewMove, this);
39946             this.inputEl().on("keyup", this.onKeyUp, this);
39947             
39948             this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39949
39950             this.view = new Roo.View(this.list, this.tpl, {
39951                 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39952             });
39953             
39954             this.view.on('click', this.onViewClick, this);
39955             this.setValue(this.defaultDialCode);
39956         },
39957         
39958         onTriggerClick : function(e)
39959         {
39960             Roo.log('trigger click');
39961             if(this.disabled){
39962                 return;
39963             }
39964             
39965             if(this.isExpanded()){
39966                 this.collapse();
39967                 this.hasFocus = false;
39968             }else {
39969                 this.store.load({});
39970                 this.hasFocus = true;
39971                 this.expand();
39972             }
39973         },
39974         
39975         isExpanded : function()
39976         {
39977             return this.list.isVisible();
39978         },
39979         
39980         collapse : function()
39981         {
39982             if(!this.isExpanded()){
39983                 return;
39984             }
39985             this.list.hide();
39986             Roo.get(document).un('mousedown', this.collapseIf, this);
39987             Roo.get(document).un('mousewheel', this.collapseIf, this);
39988             this.fireEvent('collapse', this);
39989             this.validate();
39990         },
39991         
39992         expand : function()
39993         {
39994             Roo.log('expand');
39995
39996             if(this.isExpanded() || !this.hasFocus){
39997                 return;
39998             }
39999             
40000             var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40001             this.list.setWidth(lw);
40002             
40003             this.list.show();
40004             this.restrictHeight();
40005             
40006             Roo.get(document).on('mousedown', this.collapseIf, this);
40007             Roo.get(document).on('mousewheel', this.collapseIf, this);
40008             
40009             this.fireEvent('expand', this);
40010         },
40011         
40012         restrictHeight : function()
40013         {
40014             this.list.alignTo(this.inputEl(), this.listAlign);
40015             this.list.alignTo(this.inputEl(), this.listAlign);
40016         },
40017         
40018         onViewOver : function(e, t)
40019         {
40020             if(this.inKeyMode){
40021                 return;
40022             }
40023             var item = this.view.findItemFromChild(t);
40024             
40025             if(item){
40026                 var index = this.view.indexOf(item);
40027                 this.select(index, false);
40028             }
40029         },
40030
40031         // private
40032         onViewClick : function(view, doFocus, el, e)
40033         {
40034             var index = this.view.getSelectedIndexes()[0];
40035             
40036             var r = this.store.getAt(index);
40037             
40038             if(r){
40039                 this.onSelect(r, index);
40040             }
40041             if(doFocus !== false && !this.blockFocus){
40042                 this.inputEl().focus();
40043             }
40044         },
40045         
40046         onViewMove : function(e, t)
40047         {
40048             this.inKeyMode = false;
40049         },
40050         
40051         select : function(index, scrollIntoView)
40052         {
40053             this.selectedIndex = index;
40054             this.view.select(index);
40055             if(scrollIntoView !== false){
40056                 var el = this.view.getNode(index);
40057                 if(el){
40058                     this.list.scrollChildIntoView(el, false);
40059                 }
40060             }
40061         },
40062         
40063         createList : function()
40064         {
40065             this.list = Roo.get(document.body).createChild({
40066                 tag: 'ul',
40067                 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40068                 style: 'display:none'
40069             });
40070             
40071             this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40072         },
40073         
40074         collapseIf : function(e)
40075         {
40076             var in_combo  = e.within(this.el);
40077             var in_list =  e.within(this.list);
40078             var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40079             
40080             if (in_combo || in_list || is_list) {
40081                 return;
40082             }
40083             this.collapse();
40084         },
40085         
40086         onSelect : function(record, index)
40087         {
40088             if(this.fireEvent('beforeselect', this, record, index) !== false){
40089                 
40090                 this.setFlagClass(record.data.iso2);
40091                 this.setDialCode(record.data.dialCode);
40092                 this.hasFocus = false;
40093                 this.collapse();
40094                 this.fireEvent('select', this, record, index);
40095             }
40096         },
40097         
40098         flagEl : function()
40099         {
40100             var flag = this.el.select('div.flag',true).first();
40101             if(!flag){
40102                 return false;
40103             }
40104             return flag;
40105         },
40106         
40107         dialCodeHolderEl : function()
40108         {
40109             var d = this.el.select('input.dial-code-holder',true).first();
40110             if(!d){
40111                 return false;
40112             }
40113             return d;
40114         },
40115         
40116         setDialCode : function(v)
40117         {
40118             this.dialCodeHolder.dom.value = '+'+v;
40119         },
40120         
40121         setFlagClass : function(n)
40122         {
40123             this.flag.dom.className = 'flag '+n;
40124         },
40125         
40126         getValue : function()
40127         {
40128             var v = this.inputEl().getValue();
40129             if(this.dialCodeHolder) {
40130                 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40131             }
40132             return v;
40133         },
40134         
40135         setValue : function(v)
40136         {
40137             var d = this.getDialCode(v);
40138             
40139             //invalid dial code
40140             if(v.length == 0 || !d || d.length == 0) {
40141                 if(this.rendered){
40142                     this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40143                     this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40144                 }
40145                 return;
40146             }
40147             
40148             //valid dial code
40149             this.setFlagClass(this.dialCodeMapping[d].iso2);
40150             this.setDialCode(d);
40151             this.inputEl().dom.value = v.replace('+'+d,'');
40152             this.hiddenEl().dom.value = this.getValue();
40153             
40154             this.validate();
40155         },
40156         
40157         getDialCode : function(v)
40158         {
40159             v = v ||  '';
40160             
40161             if (v.length == 0) {
40162                 return this.dialCodeHolder.dom.value;
40163             }
40164             
40165             var dialCode = "";
40166             if (v.charAt(0) != "+") {
40167                 return false;
40168             }
40169             var numericChars = "";
40170             for (var i = 1; i < v.length; i++) {
40171               var c = v.charAt(i);
40172               if (!isNaN(c)) {
40173                 numericChars += c;
40174                 if (this.dialCodeMapping[numericChars]) {
40175                   dialCode = v.substr(1, i);
40176                 }
40177                 if (numericChars.length == 4) {
40178                   break;
40179                 }
40180               }
40181             }
40182             return dialCode;
40183         },
40184         
40185         reset : function()
40186         {
40187             this.setValue(this.defaultDialCode);
40188             this.validate();
40189         },
40190         
40191         hiddenEl : function()
40192         {
40193             return this.el.select('input.hidden-tel-input',true).first();
40194         },
40195         
40196         onKeyUp : function(e){
40197             
40198             var k = e.getKey();
40199             var c = e.getCharCode();
40200             
40201             if(
40202                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40203                     this.allowed.indexOf(String.fromCharCode(c)) === -1
40204             ){
40205                 e.stopEvent();
40206             }
40207             
40208             // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40209             //     return;
40210             // }
40211             if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40212                 e.stopEvent();
40213             }
40214             
40215             this.setValue(this.getValue());
40216         }
40217         
40218 });
40219 /**
40220  * @class Roo.bootstrap.MoneyField
40221  * @extends Roo.bootstrap.ComboBox
40222  * Bootstrap MoneyField class
40223  * 
40224  * @constructor
40225  * Create a new MoneyField.
40226  * @param {Object} config Configuration options
40227  */
40228
40229 Roo.bootstrap.MoneyField = function(config) {
40230     
40231     Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40232     
40233 };
40234
40235 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40236     
40237     /**
40238      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40239      */
40240     allowDecimals : true,
40241     /**
40242      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40243      */
40244     decimalSeparator : ".",
40245     /**
40246      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40247      */
40248     decimalPrecision : 0,
40249     /**
40250      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40251      */
40252     allowNegative : true,
40253     /**
40254      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40255      */
40256     allowZero: true,
40257     /**
40258      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40259      */
40260     minValue : Number.NEGATIVE_INFINITY,
40261     /**
40262      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40263      */
40264     maxValue : Number.MAX_VALUE,
40265     /**
40266      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40267      */
40268     minText : "The minimum value for this field is {0}",
40269     /**
40270      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40271      */
40272     maxText : "The maximum value for this field is {0}",
40273     /**
40274      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
40275      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40276      */
40277     nanText : "{0} is not a valid number",
40278     /**
40279      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40280      */
40281     castInt : true,
40282     /**
40283      * @cfg {String} defaults currency of the MoneyField
40284      * value should be in lkey
40285      */
40286     defaultCurrency : false,
40287     /**
40288      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40289      */
40290     thousandsDelimiter : false,
40291     
40292     
40293     inputlg : 9,
40294     inputmd : 9,
40295     inputsm : 9,
40296     inputxs : 6,
40297     
40298     store : false,
40299     
40300     getAutoCreate : function()
40301     {
40302         var align = this.labelAlign || this.parentLabelAlign();
40303         
40304         var id = Roo.id();
40305
40306         var cfg = {
40307             cls: 'form-group',
40308             cn: []
40309         };
40310
40311         var input =  {
40312             tag: 'input',
40313             id : id,
40314             cls : 'form-control roo-money-amount-input',
40315             autocomplete: 'new-password'
40316         };
40317         
40318         var hiddenInput = {
40319             tag: 'input',
40320             type: 'hidden',
40321             id: Roo.id(),
40322             cls: 'hidden-number-input'
40323         };
40324         
40325         if (this.name) {
40326             hiddenInput.name = this.name;
40327         }
40328
40329         if (this.disabled) {
40330             input.disabled = true;
40331         }
40332
40333         var clg = 12 - this.inputlg;
40334         var cmd = 12 - this.inputmd;
40335         var csm = 12 - this.inputsm;
40336         var cxs = 12 - this.inputxs;
40337         
40338         var container = {
40339             tag : 'div',
40340             cls : 'row roo-money-field',
40341             cn : [
40342                 {
40343                     tag : 'div',
40344                     cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40345                     cn : [
40346                         {
40347                             tag : 'div',
40348                             cls: 'roo-select2-container input-group',
40349                             cn: [
40350                                 {
40351                                     tag : 'input',
40352                                     cls : 'form-control roo-money-currency-input',
40353                                     autocomplete: 'new-password',
40354                                     readOnly : 1,
40355                                     name : this.currencyName
40356                                 },
40357                                 {
40358                                     tag :'span',
40359                                     cls : 'input-group-addon',
40360                                     cn : [
40361                                         {
40362                                             tag: 'span',
40363                                             cls: 'caret'
40364                                         }
40365                                     ]
40366                                 }
40367                             ]
40368                         }
40369                     ]
40370                 },
40371                 {
40372                     tag : 'div',
40373                     cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40374                     cn : [
40375                         {
40376                             tag: 'div',
40377                             cls: this.hasFeedback ? 'has-feedback' : '',
40378                             cn: [
40379                                 input
40380                             ]
40381                         }
40382                     ]
40383                 }
40384             ]
40385             
40386         };
40387         
40388         if (this.fieldLabel.length) {
40389             var indicator = {
40390                 tag: 'i',
40391                 tooltip: 'This field is required'
40392             };
40393
40394             var label = {
40395                 tag: 'label',
40396                 'for':  id,
40397                 cls: 'control-label',
40398                 cn: []
40399             };
40400
40401             var label_text = {
40402                 tag: 'span',
40403                 html: this.fieldLabel
40404             };
40405
40406             indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40407             label.cn = [
40408                 indicator,
40409                 label_text
40410             ];
40411
40412             if(this.indicatorpos == 'right') {
40413                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40414                 label.cn = [
40415                     label_text,
40416                     indicator
40417                 ];
40418             }
40419
40420             if(align == 'left') {
40421                 container = {
40422                     tag: 'div',
40423                     cn: [
40424                         container
40425                     ]
40426                 };
40427
40428                 if(this.labelWidth > 12){
40429                     label.style = "width: " + this.labelWidth + 'px';
40430                 }
40431                 if(this.labelWidth < 13 && this.labelmd == 0){
40432                     this.labelmd = this.labelWidth;
40433                 }
40434                 if(this.labellg > 0){
40435                     label.cls += ' col-lg-' + this.labellg;
40436                     input.cls += ' col-lg-' + (12 - this.labellg);
40437                 }
40438                 if(this.labelmd > 0){
40439                     label.cls += ' col-md-' + this.labelmd;
40440                     container.cls += ' col-md-' + (12 - this.labelmd);
40441                 }
40442                 if(this.labelsm > 0){
40443                     label.cls += ' col-sm-' + this.labelsm;
40444                     container.cls += ' col-sm-' + (12 - this.labelsm);
40445                 }
40446                 if(this.labelxs > 0){
40447                     label.cls += ' col-xs-' + this.labelxs;
40448                     container.cls += ' col-xs-' + (12 - this.labelxs);
40449                 }
40450             }
40451         }
40452
40453         cfg.cn = [
40454             label,
40455             container,
40456             hiddenInput
40457         ];
40458         
40459         var settings = this;
40460
40461         ['xs','sm','md','lg'].map(function(size){
40462             if (settings[size]) {
40463                 cfg.cls += ' col-' + size + '-' + settings[size];
40464             }
40465         });
40466         
40467         return cfg;
40468     },
40469     
40470     initEvents : function()
40471     {
40472         this.indicator = this.indicatorEl();
40473         
40474         this.initCurrencyEvent();
40475         
40476         this.initNumberEvent();
40477     },
40478     
40479     initCurrencyEvent : function()
40480     {
40481         if (!this.store) {
40482             throw "can not find store for combo";
40483         }
40484         
40485         this.store = Roo.factory(this.store, Roo.data);
40486         this.store.parent = this;
40487         
40488         this.createList();
40489         
40490         this.triggerEl = this.el.select('.input-group-addon', true).first();
40491         
40492         this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40493         
40494         var _this = this;
40495         
40496         (function(){
40497             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40498             _this.list.setWidth(lw);
40499         }).defer(100);
40500         
40501         this.list.on('mouseover', this.onViewOver, this);
40502         this.list.on('mousemove', this.onViewMove, this);
40503         this.list.on('scroll', this.onViewScroll, this);
40504         
40505         if(!this.tpl){
40506             this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40507         }
40508         
40509         this.view = new Roo.View(this.list, this.tpl, {
40510             singleSelect:true, store: this.store, selectedClass: this.selectedClass
40511         });
40512         
40513         this.view.on('click', this.onViewClick, this);
40514         
40515         this.store.on('beforeload', this.onBeforeLoad, this);
40516         this.store.on('load', this.onLoad, this);
40517         this.store.on('loadexception', this.onLoadException, this);
40518         
40519         this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40520             "up" : function(e){
40521                 this.inKeyMode = true;
40522                 this.selectPrev();
40523             },
40524
40525             "down" : function(e){
40526                 if(!this.isExpanded()){
40527                     this.onTriggerClick();
40528                 }else{
40529                     this.inKeyMode = true;
40530                     this.selectNext();
40531                 }
40532             },
40533
40534             "enter" : function(e){
40535                 this.collapse();
40536                 
40537                 if(this.fireEvent("specialkey", this, e)){
40538                     this.onViewClick(false);
40539                 }
40540                 
40541                 return true;
40542             },
40543
40544             "esc" : function(e){
40545                 this.collapse();
40546             },
40547
40548             "tab" : function(e){
40549                 this.collapse();
40550                 
40551                 if(this.fireEvent("specialkey", this, e)){
40552                     this.onViewClick(false);
40553                 }
40554                 
40555                 return true;
40556             },
40557
40558             scope : this,
40559
40560             doRelay : function(foo, bar, hname){
40561                 if(hname == 'down' || this.scope.isExpanded()){
40562                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40563                 }
40564                 return true;
40565             },
40566
40567             forceKeyDown: true
40568         });
40569         
40570         this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40571         
40572     },
40573     
40574     initNumberEvent : function(e)
40575     {
40576         this.inputEl().on("keydown" , this.fireKey,  this);
40577         this.inputEl().on("focus", this.onFocus,  this);
40578         this.inputEl().on("blur", this.onBlur,  this);
40579         
40580         this.inputEl().relayEvent('keyup', this);
40581         
40582         if(this.indicator){
40583             this.indicator.addClass('invisible');
40584         }
40585  
40586         this.originalValue = this.getValue();
40587         
40588         if(this.validationEvent == 'keyup'){
40589             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40590             this.inputEl().on('keyup', this.filterValidation, this);
40591         }
40592         else if(this.validationEvent !== false){
40593             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40594         }
40595         
40596         if(this.selectOnFocus){
40597             this.on("focus", this.preFocus, this);
40598             
40599         }
40600         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40601             this.inputEl().on("keypress", this.filterKeys, this);
40602         } else {
40603             this.inputEl().relayEvent('keypress', this);
40604         }
40605         
40606         var allowed = "0123456789";
40607         
40608         if(this.allowDecimals){
40609             allowed += this.decimalSeparator;
40610         }
40611         
40612         if(this.allowNegative){
40613             allowed += "-";
40614         }
40615         
40616         if(this.thousandsDelimiter) {
40617             allowed += ",";
40618         }
40619         
40620         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40621         
40622         var keyPress = function(e){
40623             
40624             var k = e.getKey();
40625             
40626             var c = e.getCharCode();
40627             
40628             if(
40629                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40630                     allowed.indexOf(String.fromCharCode(c)) === -1
40631             ){
40632                 e.stopEvent();
40633                 return;
40634             }
40635             
40636             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40637                 return;
40638             }
40639             
40640             if(allowed.indexOf(String.fromCharCode(c)) === -1){
40641                 e.stopEvent();
40642             }
40643         };
40644         
40645         this.inputEl().on("keypress", keyPress, this);
40646         
40647     },
40648     
40649     onTriggerClick : function(e)
40650     {   
40651         if(this.disabled){
40652             return;
40653         }
40654         
40655         this.page = 0;
40656         this.loadNext = false;
40657         
40658         if(this.isExpanded()){
40659             this.collapse();
40660             return;
40661         }
40662         
40663         this.hasFocus = true;
40664         
40665         if(this.triggerAction == 'all') {
40666             this.doQuery(this.allQuery, true);
40667             return;
40668         }
40669         
40670         this.doQuery(this.getRawValue());
40671     },
40672     
40673     getCurrency : function()
40674     {   
40675         var v = this.currencyEl().getValue();
40676         
40677         return v;
40678     },
40679     
40680     restrictHeight : function()
40681     {
40682         this.list.alignTo(this.currencyEl(), this.listAlign);
40683         this.list.alignTo(this.currencyEl(), this.listAlign);
40684     },
40685     
40686     onViewClick : function(view, doFocus, el, e)
40687     {
40688         var index = this.view.getSelectedIndexes()[0];
40689         
40690         var r = this.store.getAt(index);
40691         
40692         if(r){
40693             this.onSelect(r, index);
40694         }
40695     },
40696     
40697     onSelect : function(record, index){
40698         
40699         if(this.fireEvent('beforeselect', this, record, index) !== false){
40700         
40701             this.setFromCurrencyData(index > -1 ? record.data : false);
40702             
40703             this.collapse();
40704             
40705             this.fireEvent('select', this, record, index);
40706         }
40707     },
40708     
40709     setFromCurrencyData : function(o)
40710     {
40711         var currency = '';
40712         
40713         this.lastCurrency = o;
40714         
40715         if (this.currencyField) {
40716             currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40717         } else {
40718             Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
40719         }
40720         
40721         this.lastSelectionText = currency;
40722         
40723         //setting default currency
40724         if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40725             this.setCurrency(this.defaultCurrency);
40726             return;
40727         }
40728         
40729         this.setCurrency(currency);
40730     },
40731     
40732     setFromData : function(o)
40733     {
40734         var c = {};
40735         
40736         c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40737         
40738         this.setFromCurrencyData(c);
40739         
40740         var value = '';
40741         
40742         if (this.name) {
40743             value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40744         } else {
40745             Roo.log('no value set for '+ (this.name ? this.name : this.id));
40746         }
40747         
40748         this.setValue(value);
40749         
40750     },
40751     
40752     setCurrency : function(v)
40753     {   
40754         this.currencyValue = v;
40755         
40756         if(this.rendered){
40757             this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40758             this.validate();
40759         }
40760     },
40761     
40762     setValue : function(v)
40763     {
40764         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40765         
40766         this.value = v;
40767         
40768         if(this.rendered){
40769             
40770             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40771             
40772             this.inputEl().dom.value = (v == '') ? '' :
40773                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40774             
40775             if(!this.allowZero && v === '0') {
40776                 this.hiddenEl().dom.value = '';
40777                 this.inputEl().dom.value = '';
40778             }
40779             
40780             this.validate();
40781         }
40782     },
40783     
40784     getRawValue : function()
40785     {
40786         var v = this.inputEl().getValue();
40787         
40788         return v;
40789     },
40790     
40791     getValue : function()
40792     {
40793         return this.fixPrecision(this.parseValue(this.getRawValue()));
40794     },
40795     
40796     parseValue : function(value)
40797     {
40798         if(this.thousandsDelimiter) {
40799             value += "";
40800             r = new RegExp(",", "g");
40801             value = value.replace(r, "");
40802         }
40803         
40804         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40805         return isNaN(value) ? '' : value;
40806         
40807     },
40808     
40809     fixPrecision : function(value)
40810     {
40811         if(this.thousandsDelimiter) {
40812             value += "";
40813             r = new RegExp(",", "g");
40814             value = value.replace(r, "");
40815         }
40816         
40817         var nan = isNaN(value);
40818         
40819         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40820             return nan ? '' : value;
40821         }
40822         return parseFloat(value).toFixed(this.decimalPrecision);
40823     },
40824     
40825     decimalPrecisionFcn : function(v)
40826     {
40827         return Math.floor(v);
40828     },
40829     
40830     validateValue : function(value)
40831     {
40832         if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40833             return false;
40834         }
40835         
40836         var num = this.parseValue(value);
40837         
40838         if(isNaN(num)){
40839             this.markInvalid(String.format(this.nanText, value));
40840             return false;
40841         }
40842         
40843         if(num < this.minValue){
40844             this.markInvalid(String.format(this.minText, this.minValue));
40845             return false;
40846         }
40847         
40848         if(num > this.maxValue){
40849             this.markInvalid(String.format(this.maxText, this.maxValue));
40850             return false;
40851         }
40852         
40853         return true;
40854     },
40855     
40856     validate : function()
40857     {
40858         if(this.disabled || this.allowBlank){
40859             this.markValid();
40860             return true;
40861         }
40862         
40863         var currency = this.getCurrency();
40864         
40865         if(this.validateValue(this.getRawValue()) && currency.length){
40866             this.markValid();
40867             return true;
40868         }
40869         
40870         this.markInvalid();
40871         return false;
40872     },
40873     
40874     getName: function()
40875     {
40876         return this.name;
40877     },
40878     
40879     beforeBlur : function()
40880     {
40881         if(!this.castInt){
40882             return;
40883         }
40884         
40885         var v = this.parseValue(this.getRawValue());
40886         
40887         if(v || v == 0){
40888             this.setValue(v);
40889         }
40890     },
40891     
40892     onBlur : function()
40893     {
40894         this.beforeBlur();
40895         
40896         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40897             //this.el.removeClass(this.focusClass);
40898         }
40899         
40900         this.hasFocus = false;
40901         
40902         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40903             this.validate();
40904         }
40905         
40906         var v = this.getValue();
40907         
40908         if(String(v) !== String(this.startValue)){
40909             this.fireEvent('change', this, v, this.startValue);
40910         }
40911         
40912         this.fireEvent("blur", this);
40913     },
40914     
40915     inputEl : function()
40916     {
40917         return this.el.select('.roo-money-amount-input', true).first();
40918     },
40919     
40920     currencyEl : function()
40921     {
40922         return this.el.select('.roo-money-currency-input', true).first();
40923     },
40924     
40925     hiddenEl : function()
40926     {
40927         return this.el.select('input.hidden-number-input',true).first();
40928     }
40929     
40930 });