Roo/bootstrap/ComboBox.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  * 
22  * @constructor
23  * Do not use directly - it does not do anything..
24  * @param {Object} config The config object
25  */
26
27
28
29 Roo.bootstrap.Component = function(config){
30     Roo.bootstrap.Component.superclass.constructor.call(this, config);
31        
32     this.addEvents({
33         /**
34          * @event childrenrendered
35          * Fires when the children have been rendered..
36          * @param {Roo.bootstrap.Component} this
37          */
38         "childrenrendered" : true
39         
40         
41         
42     });
43     
44     
45 };
46
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
48     
49     
50     allowDomMove : false, // to stop relocations in parent onRender...
51     
52     cls : false,
53     
54     style : false,
55     
56     autoCreate : false,
57     
58     tooltip : null,
59     /**
60      * Initialize Events for the element
61      */
62     initEvents : function() { },
63     
64     xattr : false,
65     
66     parentId : false,
67     
68     can_build_overlaid : true,
69     
70     container_method : false,
71     
72     dataId : false,
73     
74     name : false,
75     
76     parent: function() {
77         // returns the parent component..
78         return Roo.ComponentMgr.get(this.parentId)
79         
80         
81     },
82     
83     // private
84     onRender : function(ct, position)
85     {
86        // Roo.log("Call onRender: " + this.xtype);
87         
88         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
89         
90         if(this.el){
91             if (this.el.attr('xtype')) {
92                 this.el.attr('xtypex', this.el.attr('xtype'));
93                 this.el.dom.removeAttribute('xtype');
94                 
95                 this.initEvents();
96             }
97             
98             return;
99         }
100         
101          
102         
103         var cfg = Roo.apply({},  this.getAutoCreate());
104         
105         cfg.id = this.id || Roo.id();
106         
107         // fill in the extra attributes 
108         if (this.xattr && typeof(this.xattr) =='object') {
109             for (var i in this.xattr) {
110                 cfg[i] = this.xattr[i];
111             }
112         }
113         
114         if(this.dataId){
115             cfg.dataId = this.dataId;
116         }
117         
118         if (this.cls) {
119             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
120         }
121         
122         if (this.style) { // fixme needs to support more complex style data.
123             cfg.style = this.style;
124         }
125         
126         if(this.name){
127             cfg.name = this.name;
128         }
129         
130         this.el = ct.createChild(cfg, position);
131         
132         if (this.tooltip) {
133             this.tooltipEl().attr('tooltip', this.tooltip);
134         }
135         
136         if(this.tabIndex !== undefined){
137             this.el.dom.setAttribute('tabIndex', this.tabIndex);
138         }
139         
140         this.initEvents();
141         
142     },
143     /**
144      * Fetch the element to add children to
145      * @return {Roo.Element} defaults to this.el
146      */
147     getChildContainer : function()
148     {
149         return this.el;
150     },
151     /**
152      * Fetch the element to display the tooltip on.
153      * @return {Roo.Element} defaults to this.el
154      */
155     tooltipEl : function()
156     {
157         return this.el;
158     },
159         
160     addxtype  : function(tree,cntr)
161     {
162         var cn = this;
163         
164         cn = Roo.factory(tree);
165         //Roo.log(['addxtype', cn]);
166            
167         cn.parentType = this.xtype; //??
168         cn.parentId = this.id;
169         
170         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171         if (typeof(cn.container_method) == 'string') {
172             cntr = cn.container_method;
173         }
174         
175         
176         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
177         
178         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
179         
180         var build_from_html =  Roo.XComponent.build_from_html;
181           
182         var is_body  = (tree.xtype == 'Body') ;
183           
184         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
185           
186         var self_cntr_el = Roo.get(this[cntr](false));
187         
188         // do not try and build conditional elements 
189         if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
190             return false;
191         }
192         
193         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195                 return this.addxtypeChild(tree,cntr, is_body);
196             }
197             
198             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
199                 
200             if(echild){
201                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
202             }
203             
204             Roo.log('skipping render');
205             return cn;
206             
207         }
208         
209         var ret = false;
210         if (!build_from_html) {
211             return false;
212         }
213         
214         // this i think handles overlaying multiple children of the same type
215         // with the sam eelement.. - which might be buggy..
216         while (true) {
217             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
218             
219             if (!echild) {
220                 break;
221             }
222             
223             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
224                 break;
225             }
226             
227             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
228         }
229        
230         return ret;
231     },
232     
233     
234     addxtypeChild : function (tree, cntr, is_body)
235     {
236         Roo.debug && Roo.log('addxtypeChild:' + cntr);
237         var cn = this;
238         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
239         
240         
241         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242                     (typeof(tree['flexy:foreach']) != 'undefined');
243           
244     
245         
246         skip_children = false;
247         // render the element if it's not BODY.
248         if (!is_body) {
249             
250             // if parent was disabled, then do not try and create the children..
251             if(!this[cntr](true)){
252                 tree.items = [];
253                 return tree;
254             }
255            
256             cn = Roo.factory(tree);
257            
258             cn.parentType = this.xtype; //??
259             cn.parentId = this.id;
260             
261             var build_from_html =  Roo.XComponent.build_from_html;
262             
263             
264             // does the container contain child eleemnts with 'xtype' attributes.
265             // that match this xtype..
266             // note - when we render we create these as well..
267             // so we should check to see if body has xtype set.
268             if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
269                
270                 var self_cntr_el = Roo.get(this[cntr](false));
271                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
272                 if (echild) { 
273                     //Roo.log(Roo.XComponent.build_from_html);
274                     //Roo.log("got echild:");
275                     //Roo.log(echild);
276                 }
277                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
278                 // and are not displayed -this causes this to use up the wrong element when matching.
279                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
280                 
281                 
282                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
283                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
284                   
285                   
286                   
287                     cn.el = echild;
288                   //  Roo.log("GOT");
289                     //echild.dom.removeAttribute('xtype');
290                 } else {
291                     Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
292                     Roo.debug && Roo.log(self_cntr_el);
293                     Roo.debug && Roo.log(echild);
294                     Roo.debug && Roo.log(cn);
295                 }
296             }
297            
298             
299            
300             // if object has flexy:if - then it may or may not be rendered.
301             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
302                 // skip a flexy if element.
303                 Roo.debug && Roo.log('skipping render');
304                 Roo.debug && Roo.log(tree);
305                 if (!cn.el) {
306                     Roo.debug && Roo.log('skipping all children');
307                     skip_children = true;
308                 }
309                 
310              } else {
311                  
312                 // actually if flexy:foreach is found, we really want to create 
313                 // multiple copies here...
314                 //Roo.log('render');
315                 //Roo.log(this[cntr]());
316                 // some elements do not have render methods.. like the layouts...
317                 /*
318                 if(this[cntr](true) === false){
319                     cn.items = [];
320                     return cn;
321                 }
322                 */
323                 cn.render && cn.render(this[cntr](true));
324                 
325              }
326             // then add the element..
327         }
328          
329         // handle the kids..
330         
331         var nitems = [];
332         /*
333         if (typeof (tree.menu) != 'undefined') {
334             tree.menu.parentType = cn.xtype;
335             tree.menu.triggerEl = cn.el;
336             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
337             
338         }
339         */
340         if (!tree.items || !tree.items.length) {
341             cn.items = nitems;
342             //Roo.log(["no children", this]);
343             
344             return cn;
345         }
346          
347         var items = tree.items;
348         delete tree.items;
349         
350         //Roo.log(items.length);
351             // add the items..
352         if (!skip_children) {    
353             for(var i =0;i < items.length;i++) {
354               //  Roo.log(['add child', items[i]]);
355                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
356             }
357         }
358         
359         cn.items = nitems;
360         
361         //Roo.log("fire childrenrendered");
362         
363         cn.fireEvent('childrenrendered', this);
364         
365         return cn;
366     },
367     /**
368      * Show a component - removes 'hidden' class
369      */
370     show : function()
371     {
372         if(!this.getEl()){
373             return;
374         }
375         
376         this.getEl().removeClass('hidden');
377         
378     },
379     /**
380      * Hide a component - adds 'hidden' class
381      */
382     hide: function()
383     {
384         if(!this.getEl() || this.getEl().hasClass('hidden')){
385             return;
386         }
387         
388         this.getEl().addClass('hidden');
389         
390     }
391 });
392
393  /*
394  * - LGPL
395  *
396  * Body
397  *
398  */
399
400 /**
401  * @class Roo.bootstrap.Body
402  * @extends Roo.bootstrap.Component
403  * Bootstrap Body class
404  *
405  * @constructor
406  * Create a new body
407  * @param {Object} config The config object
408  */
409
410 Roo.bootstrap.Body = function(config){
411
412     config = config || {};
413
414     Roo.bootstrap.Body.superclass.constructor.call(this, config);
415     this.el = Roo.get(config.el ? config.el : document.body );
416     if (this.cls && this.cls.length) {
417         Roo.get(document.body).addClass(this.cls);
418     }
419 };
420
421 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
422
423     is_body : true,// just to make sure it's constructed?
424
425         autoCreate : {
426         cls: 'container'
427     },
428     onRender : function(ct, position)
429     {
430        /* Roo.log("Roo.bootstrap.Body - onRender");
431         if (this.cls && this.cls.length) {
432             Roo.get(document.body).addClass(this.cls);
433         }
434         // style??? xttr???
435         */
436     }
437
438
439
440
441 });
442 /*
443  * - LGPL
444  *
445  * button group
446  * 
447  */
448
449
450 /**
451  * @class Roo.bootstrap.ButtonGroup
452  * @extends Roo.bootstrap.Component
453  * Bootstrap ButtonGroup class
454  * @cfg {String} size lg | sm | xs (default empty normal)
455  * @cfg {String} align vertical | justified  (default none)
456  * @cfg {String} direction up | down (default down)
457  * @cfg {Boolean} toolbar false | true
458  * @cfg {Boolean} btn true | false
459  * 
460  * 
461  * @constructor
462  * Create a new Input
463  * @param {Object} config The config object
464  */
465
466 Roo.bootstrap.ButtonGroup = function(config){
467     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
468 };
469
470 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
471     
472     size: '',
473     align: '',
474     direction: '',
475     toolbar: false,
476     btn: true,
477
478     getAutoCreate : function(){
479         var cfg = {
480             cls: 'btn-group',
481             html : null
482         };
483         
484         cfg.html = this.html || cfg.html;
485         
486         if (this.toolbar) {
487             cfg = {
488                 cls: 'btn-toolbar',
489                 html: null
490             };
491             
492             return cfg;
493         }
494         
495         if (['vertical','justified'].indexOf(this.align)!==-1) {
496             cfg.cls = 'btn-group-' + this.align;
497             
498             if (this.align == 'justified') {
499                 console.log(this.items);
500             }
501         }
502         
503         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
504             cfg.cls += ' btn-group-' + this.size;
505         }
506         
507         if (this.direction == 'up') {
508             cfg.cls += ' dropup' ;
509         }
510         
511         return cfg;
512     }
513    
514 });
515
516  /*
517  * - LGPL
518  *
519  * button
520  * 
521  */
522
523 /**
524  * @class Roo.bootstrap.Button
525  * @extends Roo.bootstrap.Component
526  * Bootstrap Button class
527  * @cfg {String} html The button content
528  * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default 
529  * @cfg {String} size ( lg | sm | xs)
530  * @cfg {String} tag ( a | input | submit)
531  * @cfg {String} href empty or href
532  * @cfg {Boolean} disabled default false;
533  * @cfg {Boolean} isClose default false;
534  * @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)
535  * @cfg {String} badge text for badge
536  * @cfg {String} theme default 
537  * @cfg {Boolean} inverse 
538  * @cfg {Boolean} toggle 
539  * @cfg {String} ontext text for on toggle state
540  * @cfg {String} offtext text for off toggle state
541  * @cfg {Boolean} defaulton 
542  * @cfg {Boolean} preventDefault  default true
543  * @cfg {Boolean} removeClass remove the standard class..
544  * @cfg {String} target  target for a href. (_self|_blank|_parent|_top| other)
545  * 
546  * @constructor
547  * Create a new button
548  * @param {Object} config The config object
549  */
550
551
552 Roo.bootstrap.Button = function(config){
553     Roo.bootstrap.Button.superclass.constructor.call(this, config);
554     this.weightClass = ["btn-default", 
555                        "btn-primary", 
556                        "btn-success", 
557                        "btn-info", 
558                        "btn-warning",
559                        "btn-danger",
560                        "btn-link"
561                       ],  
562     this.addEvents({
563         // raw events
564         /**
565          * @event click
566          * When a butotn is pressed
567          * @param {Roo.bootstrap.Button} this
568          * @param {Roo.EventObject} e
569          */
570         "click" : true,
571          /**
572          * @event toggle
573          * After the button has been toggles
574          * @param {Roo.EventObject} e
575          * @param {boolean} pressed (also available as button.pressed)
576          */
577         "toggle" : true
578     });
579 };
580
581 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
582     html: false,
583     active: false,
584     weight: '',
585     size: '',
586     tag: 'button',
587     href: '',
588     disabled: false,
589     isClose: false,
590     glyphicon: '',
591     badge: '',
592     theme: 'default',
593     inverse: false,
594     
595     toggle: false,
596     ontext: 'ON',
597     offtext: 'OFF',
598     defaulton: true,
599     preventDefault: true,
600     removeClass: false,
601     name: false,
602     target: false,
603     
604     
605     pressed : null,
606      
607     
608     getAutoCreate : function(){
609         
610         var cfg = {
611             tag : 'button',
612             cls : 'roo-button',
613             html: ''
614         };
615         
616         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
617             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
618             this.tag = 'button';
619         } else {
620             cfg.tag = this.tag;
621         }
622         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
623         
624         if (this.toggle == true) {
625             cfg={
626                 tag: 'div',
627                 cls: 'slider-frame roo-button',
628                 cn: [
629                     {
630                         tag: 'span',
631                         'data-on-text':'ON',
632                         'data-off-text':'OFF',
633                         cls: 'slider-button',
634                         html: this.offtext
635                     }
636                 ]
637             };
638             
639             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
640                 cfg.cls += ' '+this.weight;
641             }
642             
643             return cfg;
644         }
645         
646         if (this.isClose) {
647             cfg.cls += ' close';
648             
649             cfg["aria-hidden"] = true;
650             
651             cfg.html = "&times;";
652             
653             return cfg;
654         }
655         
656          
657         if (this.theme==='default') {
658             cfg.cls = 'btn roo-button';
659             
660             //if (this.parentType != 'Navbar') {
661             this.weight = this.weight.length ?  this.weight : 'default';
662             //}
663             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
664                 
665                 cfg.cls += ' btn-' + this.weight;
666             }
667         } else if (this.theme==='glow') {
668             
669             cfg.tag = 'a';
670             cfg.cls = 'btn-glow roo-button';
671             
672             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
673                 
674                 cfg.cls += ' ' + this.weight;
675             }
676         }
677    
678         
679         if (this.inverse) {
680             this.cls += ' inverse';
681         }
682         
683         
684         if (this.active) {
685             cfg.cls += ' active';
686         }
687         
688         if (this.disabled) {
689             cfg.disabled = 'disabled';
690         }
691         
692         if (this.items) {
693             Roo.log('changing to ul' );
694             cfg.tag = 'ul';
695             this.glyphicon = 'caret';
696         }
697         
698         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
699          
700         //gsRoo.log(this.parentType);
701         if (this.parentType === 'Navbar' && !this.parent().bar) {
702             Roo.log('changing to li?');
703             
704             cfg.tag = 'li';
705             
706             cfg.cls = '';
707             cfg.cn =  [{
708                 tag : 'a',
709                 cls : 'roo-button',
710                 html : this.html,
711                 href : this.href || '#'
712             }];
713             if (this.menu) {
714                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
715                 cfg.cls += ' dropdown';
716             }   
717             
718             delete cfg.html;
719             
720         }
721         
722        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
723         
724         if (this.glyphicon) {
725             cfg.html = ' ' + cfg.html;
726             
727             cfg.cn = [
728                 {
729                     tag: 'span',
730                     cls: 'glyphicon glyphicon-' + this.glyphicon
731                 }
732             ];
733         }
734         
735         if (this.badge) {
736             cfg.html += ' ';
737             
738             cfg.tag = 'a';
739             
740 //            cfg.cls='btn roo-button';
741             
742             cfg.href=this.href;
743             
744             var value = cfg.html;
745             
746             if(this.glyphicon){
747                 value = {
748                             tag: 'span',
749                             cls: 'glyphicon glyphicon-' + this.glyphicon,
750                             html: this.html
751                         };
752                 
753             }
754             
755             cfg.cn = [
756                 value,
757                 {
758                     tag: 'span',
759                     cls: 'badge',
760                     html: this.badge
761                 }
762             ];
763             
764             cfg.html='';
765         }
766         
767         if (this.menu) {
768             cfg.cls += ' dropdown';
769             cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
770         }
771         
772         if (cfg.tag !== 'a' && this.href !== '') {
773             throw "Tag must be a to set href.";
774         } else if (this.href.length > 0) {
775             cfg.href = this.href;
776         }
777         
778         if(this.removeClass){
779             cfg.cls = '';
780         }
781         
782         if(this.target){
783             cfg.target = this.target;
784         }
785         
786         return cfg;
787     },
788     initEvents: function() {
789        // Roo.log('init events?');
790 //        Roo.log(this.el.dom);
791         // add the menu...
792         
793         if (typeof (this.menu) != 'undefined') {
794             this.menu.parentType = this.xtype;
795             this.menu.triggerEl = this.el;
796             this.addxtype(Roo.apply({}, this.menu));
797         }
798
799
800        if (this.el.hasClass('roo-button')) {
801             this.el.on('click', this.onClick, this);
802        } else {
803             this.el.select('.roo-button').on('click', this.onClick, this);
804        }
805        
806        if(this.removeClass){
807            this.el.on('click', this.onClick, this);
808        }
809        
810        this.el.enableDisplayMode();
811         
812     },
813     onClick : function(e)
814     {
815         if (this.disabled) {
816             return;
817         }
818         
819         
820         Roo.log('button on click ');
821         if(this.preventDefault){
822             e.preventDefault();
823         }
824         if (this.pressed === true || this.pressed === false) {
825             this.pressed = !this.pressed;
826             this.el[this.pressed ? 'addClass' : 'removeClass']('active');
827             this.fireEvent('toggle', this, e, this.pressed);
828         }
829         
830         
831         this.fireEvent('click', this, e);
832     },
833     
834     /**
835      * Enables this button
836      */
837     enable : function()
838     {
839         this.disabled = false;
840         this.el.removeClass('disabled');
841     },
842     
843     /**
844      * Disable this button
845      */
846     disable : function()
847     {
848         this.disabled = true;
849         this.el.addClass('disabled');
850     },
851      /**
852      * sets the active state on/off, 
853      * @param {Boolean} state (optional) Force a particular state
854      */
855     setActive : function(v) {
856         
857         this.el[v ? 'addClass' : 'removeClass']('active');
858     },
859      /**
860      * toggles the current active state 
861      */
862     toggleActive : function()
863     {
864        var active = this.el.hasClass('active');
865        this.setActive(!active);
866        
867         
868     },
869     setText : function(str)
870     {
871         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
872     },
873     getText : function()
874     {
875         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
876     },
877     hide: function() {
878        
879      
880         this.el.hide();   
881     },
882     show: function() {
883        
884         this.el.show();   
885     },
886     setWeight : function(str)
887     {
888           this.el.removeClass(this.weightClass);
889         this.el.addClass('btn-' + str);        
890     }
891     
892     
893 });
894
895  /*
896  * - LGPL
897  *
898  * column
899  * 
900  */
901
902 /**
903  * @class Roo.bootstrap.Column
904  * @extends Roo.bootstrap.Component
905  * Bootstrap Column class
906  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
907  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
908  * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
909  * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
910  * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
911  * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
912  * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
913  * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
914  *
915  * 
916  * @cfg {Boolean} hidden (true|false) hide the element
917  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
918  * @cfg {String} fa (ban|check|...) font awesome icon
919  * @cfg {Number} fasize (1|2|....) font awsome size
920
921  * @cfg {String} icon (info-sign|check|...) glyphicon name
922
923  * @cfg {String} html content of column.
924  * 
925  * @constructor
926  * Create a new Column
927  * @param {Object} config The config object
928  */
929
930 Roo.bootstrap.Column = function(config){
931     Roo.bootstrap.Column.superclass.constructor.call(this, config);
932 };
933
934 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
935     
936     xs: false,
937     sm: false,
938     md: false,
939     lg: false,
940     xsoff: false,
941     smoff: false,
942     mdoff: false,
943     lgoff: false,
944     html: '',
945     offset: 0,
946     alert: false,
947     fa: false,
948     icon : false,
949     hidden : false,
950     fasize : 1,
951     
952     getAutoCreate : function(){
953         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
954         
955         cfg = {
956             tag: 'div',
957             cls: 'column'
958         };
959         
960         var settings=this;
961         ['xs','sm','md','lg'].map(function(size){
962             //Roo.log( size + ':' + settings[size]);
963             
964             if (settings[size+'off'] !== false) {
965                 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
966             }
967             
968             if (settings[size] === false) {
969                 return;
970             }
971             
972             if (!settings[size]) { // 0 = hidden
973                 cfg.cls += ' hidden-' + size;
974                 return;
975             }
976             cfg.cls += ' col-' + size + '-' + settings[size];
977             
978         });
979         
980         if (this.hidden) {
981             cfg.cls += ' hidden';
982         }
983         
984         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
985             cfg.cls +=' alert alert-' + this.alert;
986         }
987         
988         
989         if (this.html.length) {
990             cfg.html = this.html;
991         }
992         if (this.fa) {
993             var fasize = '';
994             if (this.fasize > 1) {
995                 fasize = ' fa-' + this.fasize + 'x';
996             }
997             cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
998             
999             
1000         }
1001         if (this.icon) {
1002             cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' +  (cfg.html || '');
1003         }
1004         
1005         return cfg;
1006     }
1007    
1008 });
1009
1010  
1011
1012  /*
1013  * - LGPL
1014  *
1015  * page container.
1016  * 
1017  */
1018
1019
1020 /**
1021  * @class Roo.bootstrap.Container
1022  * @extends Roo.bootstrap.Component
1023  * Bootstrap Container class
1024  * @cfg {Boolean} jumbotron is it a jumbotron element
1025  * @cfg {String} html content of element
1026  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1027  * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel  - type - primary/success.....
1028  * @cfg {String} header content of header (for panel)
1029  * @cfg {String} footer content of footer (for panel)
1030  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1031  * @cfg {String} tag (header|aside|section) type of HTML tag.
1032  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1033  * @cfg {String} fa font awesome icon
1034  * @cfg {String} icon (info-sign|check|...) glyphicon name
1035  * @cfg {Boolean} hidden (true|false) hide the element
1036  * @cfg {Boolean} expandable (true|false) default false
1037  * @cfg {Boolean} expanded (true|false) default true
1038  * @cfg {String} rheader contet on the right of header
1039  * @cfg {Boolean} clickable (true|false) default false
1040
1041  *     
1042  * @constructor
1043  * Create a new Container
1044  * @param {Object} config The config object
1045  */
1046
1047 Roo.bootstrap.Container = function(config){
1048     Roo.bootstrap.Container.superclass.constructor.call(this, config);
1049     
1050     this.addEvents({
1051         // raw events
1052          /**
1053          * @event expand
1054          * After the panel has been expand
1055          * 
1056          * @param {Roo.bootstrap.Container} this
1057          */
1058         "expand" : true,
1059         /**
1060          * @event collapse
1061          * After the panel has been collapsed
1062          * 
1063          * @param {Roo.bootstrap.Container} this
1064          */
1065         "collapse" : true,
1066         /**
1067          * @event click
1068          * When a element is chick
1069          * @param {Roo.bootstrap.Container} this
1070          * @param {Roo.EventObject} e
1071          */
1072         "click" : true
1073     });
1074 };
1075
1076 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
1077     
1078     jumbotron : false,
1079     well: '',
1080     panel : '',
1081     header: '',
1082     footer : '',
1083     sticky: '',
1084     tag : false,
1085     alert : false,
1086     fa: false,
1087     icon : false,
1088     expandable : false,
1089     rheader : '',
1090     expanded : true,
1091     clickable: false,
1092   
1093      
1094     getChildContainer : function() {
1095         
1096         if(!this.el){
1097             return false;
1098         }
1099         
1100         if (this.panel.length) {
1101             return this.el.select('.panel-body',true).first();
1102         }
1103         
1104         return this.el;
1105     },
1106     
1107     
1108     getAutoCreate : function(){
1109         
1110         var cfg = {
1111             tag : this.tag || 'div',
1112             html : '',
1113             cls : ''
1114         };
1115         if (this.jumbotron) {
1116             cfg.cls = 'jumbotron';
1117         }
1118         
1119         
1120         
1121         // - this is applied by the parent..
1122         //if (this.cls) {
1123         //    cfg.cls = this.cls + '';
1124         //}
1125         
1126         if (this.sticky.length) {
1127             
1128             var bd = Roo.get(document.body);
1129             if (!bd.hasClass('bootstrap-sticky')) {
1130                 bd.addClass('bootstrap-sticky');
1131                 Roo.select('html',true).setStyle('height', '100%');
1132             }
1133              
1134             cfg.cls += 'bootstrap-sticky-' + this.sticky;
1135         }
1136         
1137         
1138         if (this.well.length) {
1139             switch (this.well) {
1140                 case 'lg':
1141                 case 'sm':
1142                     cfg.cls +=' well well-' +this.well;
1143                     break;
1144                 default:
1145                     cfg.cls +=' well';
1146                     break;
1147             }
1148         }
1149         
1150         if (this.hidden) {
1151             cfg.cls += ' hidden';
1152         }
1153         
1154         
1155         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1156             cfg.cls +=' alert alert-' + this.alert;
1157         }
1158         
1159         var body = cfg;
1160         
1161         if (this.panel.length) {
1162             cfg.cls += ' panel panel-' + this.panel;
1163             cfg.cn = [];
1164             if (this.header.length) {
1165                 
1166                 var h = [];
1167                 
1168                 if(this.expandable){
1169                     
1170                     cfg.cls = cfg.cls + ' expandable';
1171                     
1172                     h.push({
1173                         tag: 'i',
1174                         cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus') 
1175                     });
1176                     
1177                 }
1178                 
1179                 h.push(
1180                     {
1181                         tag: 'span',
1182                         cls : 'panel-title',
1183                         html : (this.expandable ? '&nbsp;' : '') + this.header
1184                     },
1185                     {
1186                         tag: 'span',
1187                         cls: 'panel-header-right',
1188                         html: this.rheader
1189                     }
1190                 );
1191                 
1192                 cfg.cn.push({
1193                     cls : 'panel-heading',
1194                     style : this.expandable ? 'cursor: pointer' : '',
1195                     cn : h
1196                 });
1197                 
1198             }
1199             
1200             body = false;
1201             cfg.cn.push({
1202                 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1203                 html : this.html
1204             });
1205             
1206             
1207             if (this.footer.length) {
1208                 cfg.cn.push({
1209                     cls : 'panel-footer',
1210                     html : this.footer
1211                     
1212                 });
1213             }
1214             
1215         }
1216         
1217         if (body) {
1218             body.html = this.html || cfg.html;
1219             // prefix with the icons..
1220             if (this.fa) {
1221                 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1222             }
1223             if (this.icon) {
1224                 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1225             }
1226             
1227             
1228         }
1229         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1230             cfg.cls =  'container';
1231         }
1232         
1233         return cfg;
1234     },
1235     
1236     initEvents: function() 
1237     {
1238         if(this.expandable){
1239             var headerEl = this.headerEl();
1240         
1241             if(headerEl){
1242                 headerEl.on('click', this.onToggleClick, this);
1243             }
1244         }
1245         
1246         if(this.clickable){
1247             this.el.on('click', this.onClick, this);
1248         }
1249         
1250     },
1251     
1252     onToggleClick : function()
1253     {
1254         var headerEl = this.headerEl();
1255         
1256         if(!headerEl){
1257             return;
1258         }
1259         
1260         if(this.expanded){
1261             this.collapse();
1262             return;
1263         }
1264         
1265         this.expand();
1266     },
1267     
1268     expand : function()
1269     {
1270         if(this.fireEvent('expand', this)) {
1271             
1272             this.expanded = true;
1273             
1274             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1275             
1276             this.el.select('.panel-body',true).first().removeClass('hide');
1277             
1278             var toggleEl = this.toggleEl();
1279
1280             if(!toggleEl){
1281                 return;
1282             }
1283
1284             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1285         }
1286         
1287     },
1288     
1289     collapse : function()
1290     {
1291         if(this.fireEvent('collapse', this)) {
1292             
1293             this.expanded = false;
1294             
1295             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1296             this.el.select('.panel-body',true).first().addClass('hide');
1297         
1298             var toggleEl = this.toggleEl();
1299
1300             if(!toggleEl){
1301                 return;
1302             }
1303
1304             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1305         }
1306     },
1307     
1308     toggleEl : function()
1309     {
1310         if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1311             return;
1312         }
1313         
1314         return this.el.select('.panel-heading .fa',true).first();
1315     },
1316     
1317     headerEl : function()
1318     {
1319         if(!this.el || !this.panel.length || !this.header.length){
1320             return;
1321         }
1322         
1323         return this.el.select('.panel-heading',true).first()
1324     },
1325     
1326     bodyEl : function()
1327     {
1328         if(!this.el || !this.panel.length){
1329             return;
1330         }
1331         
1332         return this.el.select('.panel-body',true).first()
1333     },
1334     
1335     titleEl : function()
1336     {
1337         if(!this.el || !this.panel.length || !this.header.length){
1338             return;
1339         }
1340         
1341         return this.el.select('.panel-title',true).first();
1342     },
1343     
1344     setTitle : function(v)
1345     {
1346         var titleEl = this.titleEl();
1347         
1348         if(!titleEl){
1349             return;
1350         }
1351         
1352         titleEl.dom.innerHTML = v;
1353     },
1354     
1355     getTitle : function()
1356     {
1357         
1358         var titleEl = this.titleEl();
1359         
1360         if(!titleEl){
1361             return '';
1362         }
1363         
1364         return titleEl.dom.innerHTML;
1365     },
1366     
1367     setRightTitle : function(v)
1368     {
1369         var t = this.el.select('.panel-header-right',true).first();
1370         
1371         if(!t){
1372             return;
1373         }
1374         
1375         t.dom.innerHTML = v;
1376     },
1377     
1378     onClick : function(e)
1379     {
1380         e.preventDefault();
1381         
1382         this.fireEvent('click', this, e);
1383     },
1384     
1385     allChildren : function()
1386     {
1387         var r=new Roo.util.MixedCollection(false, function(o){
1388             return o.id || (o.id = Roo.id());
1389         });
1390         var iter = function(el) {
1391             if (el.inputEl) {
1392                 r.add(el);
1393             }
1394             if (!el.items) {
1395                 return;
1396             }
1397             Roo.each(el.items,function(e) {
1398                 iter(e);
1399             });
1400         };
1401
1402         iter(this);
1403         return r;
1404     },
1405     
1406     checkEmpty : function()
1407     {
1408         var items = this.allChildren();
1409         var isEmpty = true;
1410         
1411         items.each(function(f){
1412             if(f.el.isVisible()) {
1413                 isEmpty = false;
1414             }
1415         });
1416         
1417         return isEmpty;
1418     }
1419    
1420 });
1421
1422  /*
1423  * - LGPL
1424  *
1425  * image
1426  * 
1427  */
1428
1429
1430 /**
1431  * @class Roo.bootstrap.Img
1432  * @extends Roo.bootstrap.Component
1433  * Bootstrap Img class
1434  * @cfg {Boolean} imgResponsive false | true
1435  * @cfg {String} border rounded | circle | thumbnail
1436  * @cfg {String} src image source
1437  * @cfg {String} alt image alternative text
1438  * @cfg {String} href a tag href
1439  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1440  * @cfg {String} xsUrl xs image source
1441  * @cfg {String} smUrl sm image source
1442  * @cfg {String} mdUrl md image source
1443  * @cfg {String} lgUrl lg image source
1444  * 
1445  * @constructor
1446  * Create a new Input
1447  * @param {Object} config The config object
1448  */
1449
1450 Roo.bootstrap.Img = function(config){
1451     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1452     
1453     this.addEvents({
1454         // img events
1455         /**
1456          * @event click
1457          * The img click event for the img.
1458          * @param {Roo.EventObject} e
1459          */
1460         "click" : true
1461     });
1462 };
1463
1464 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1465     
1466     imgResponsive: true,
1467     border: '',
1468     src: 'about:blank',
1469     href: false,
1470     target: false,
1471     xsUrl: '',
1472     smUrl: '',
1473     mdUrl: '',
1474     lgUrl: '',
1475
1476     getAutoCreate : function()
1477     {   
1478         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1479             return this.createSingleImg();
1480         }
1481         
1482         var cfg = {
1483             tag: 'div',
1484             cls: 'roo-image-responsive-group',
1485             cn: []
1486         };
1487         var _this = this;
1488         
1489         Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1490             
1491             if(!_this[size + 'Url']){
1492                 return;
1493             }
1494             
1495             var img = {
1496                 tag: 'img',
1497                 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1498                 html: _this.html || cfg.html,
1499                 src: _this[size + 'Url']
1500             };
1501             
1502             img.cls += ' roo-image-responsive-' + size;
1503             
1504             var s = ['xs', 'sm', 'md', 'lg'];
1505             
1506             s.splice(s.indexOf(size), 1);
1507             
1508             Roo.each(s, function(ss){
1509                 img.cls += ' hidden-' + ss;
1510             });
1511             
1512             if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1513                 cfg.cls += ' img-' + _this.border;
1514             }
1515             
1516             if(_this.alt){
1517                 cfg.alt = _this.alt;
1518             }
1519             
1520             if(_this.href){
1521                 var a = {
1522                     tag: 'a',
1523                     href: _this.href,
1524                     cn: [
1525                         img
1526                     ]
1527                 };
1528
1529                 if(this.target){
1530                     a.target = _this.target;
1531                 }
1532             }
1533             
1534             cfg.cn.push((_this.href) ? a : img);
1535             
1536         });
1537         
1538         return cfg;
1539     },
1540     
1541     createSingleImg : function()
1542     {
1543         var cfg = {
1544             tag: 'img',
1545             cls: (this.imgResponsive) ? 'img-responsive' : '',
1546             html : null,
1547             src : 'about:blank'  // just incase src get's set to undefined?!?
1548         };
1549         
1550         cfg.html = this.html || cfg.html;
1551         
1552         cfg.src = this.src || cfg.src;
1553         
1554         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1555             cfg.cls += ' img-' + this.border;
1556         }
1557         
1558         if(this.alt){
1559             cfg.alt = this.alt;
1560         }
1561         
1562         if(this.href){
1563             var a = {
1564                 tag: 'a',
1565                 href: this.href,
1566                 cn: [
1567                     cfg
1568                 ]
1569             };
1570             
1571             if(this.target){
1572                 a.target = this.target;
1573             }
1574             
1575         }
1576         
1577         return (this.href) ? a : cfg;
1578     },
1579     
1580     initEvents: function() 
1581     {
1582         if(!this.href){
1583             this.el.on('click', this.onClick, this);
1584         }
1585         
1586     },
1587     
1588     onClick : function(e)
1589     {
1590         Roo.log('img onclick');
1591         this.fireEvent('click', this, e);
1592     },
1593     /**
1594      * Sets the url of the image - used to update it
1595      * @param {String} url the url of the image
1596      */
1597     
1598     setSrc : function(url)
1599     {
1600         this.src =  url;
1601         
1602         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1603             this.el.dom.src =  url;
1604             return;
1605         }
1606         
1607         this.el.select('img', true).first().dom.src =  url;
1608     }
1609     
1610     
1611    
1612 });
1613
1614  /*
1615  * - LGPL
1616  *
1617  * image
1618  * 
1619  */
1620
1621
1622 /**
1623  * @class Roo.bootstrap.Link
1624  * @extends Roo.bootstrap.Component
1625  * Bootstrap Link Class
1626  * @cfg {String} alt image alternative text
1627  * @cfg {String} href a tag href
1628  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1629  * @cfg {String} html the content of the link.
1630  * @cfg {String} anchor name for the anchor link
1631  * @cfg {String} fa - favicon
1632
1633  * @cfg {Boolean} preventDefault (true | false) default false
1634
1635  * 
1636  * @constructor
1637  * Create a new Input
1638  * @param {Object} config The config object
1639  */
1640
1641 Roo.bootstrap.Link = function(config){
1642     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1643     
1644     this.addEvents({
1645         // img events
1646         /**
1647          * @event click
1648          * The img click event for the img.
1649          * @param {Roo.EventObject} e
1650          */
1651         "click" : true
1652     });
1653 };
1654
1655 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1656     
1657     href: false,
1658     target: false,
1659     preventDefault: false,
1660     anchor : false,
1661     alt : false,
1662     fa: false,
1663
1664
1665     getAutoCreate : function()
1666     {
1667         var html = this.html || '';
1668         
1669         if (this.fa !== false) {
1670             html = '<i class="fa fa-' + this.fa + '"></i>';
1671         }
1672         var cfg = {
1673             tag: 'a'
1674         };
1675         // anchor's do not require html/href...
1676         if (this.anchor === false) {
1677             cfg.html = html;
1678             cfg.href = this.href || '#';
1679         } else {
1680             cfg.name = this.anchor;
1681             if (this.html !== false || this.fa !== false) {
1682                 cfg.html = html;
1683             }
1684             if (this.href !== false) {
1685                 cfg.href = this.href;
1686             }
1687         }
1688         
1689         if(this.alt !== false){
1690             cfg.alt = this.alt;
1691         }
1692         
1693         
1694         if(this.target !== false) {
1695             cfg.target = this.target;
1696         }
1697         
1698         return cfg;
1699     },
1700     
1701     initEvents: function() {
1702         
1703         if(!this.href || this.preventDefault){
1704             this.el.on('click', this.onClick, this);
1705         }
1706     },
1707     
1708     onClick : function(e)
1709     {
1710         if(this.preventDefault){
1711             e.preventDefault();
1712         }
1713         //Roo.log('img onclick');
1714         this.fireEvent('click', this, e);
1715     }
1716    
1717 });
1718
1719  /*
1720  * - LGPL
1721  *
1722  * header
1723  * 
1724  */
1725
1726 /**
1727  * @class Roo.bootstrap.Header
1728  * @extends Roo.bootstrap.Component
1729  * Bootstrap Header class
1730  * @cfg {String} html content of header
1731  * @cfg {Number} level (1|2|3|4|5|6) default 1
1732  * 
1733  * @constructor
1734  * Create a new Header
1735  * @param {Object} config The config object
1736  */
1737
1738
1739 Roo.bootstrap.Header  = function(config){
1740     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1741 };
1742
1743 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1744     
1745     //href : false,
1746     html : false,
1747     level : 1,
1748     
1749     
1750     
1751     getAutoCreate : function(){
1752         
1753         
1754         
1755         var cfg = {
1756             tag: 'h' + (1 *this.level),
1757             html: this.html || ''
1758         } ;
1759         
1760         return cfg;
1761     }
1762    
1763 });
1764
1765  
1766
1767  /*
1768  * Based on:
1769  * Ext JS Library 1.1.1
1770  * Copyright(c) 2006-2007, Ext JS, LLC.
1771  *
1772  * Originally Released Under LGPL - original licence link has changed is not relivant.
1773  *
1774  * Fork - LGPL
1775  * <script type="text/javascript">
1776  */
1777  
1778 /**
1779  * @class Roo.bootstrap.MenuMgr
1780  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1781  * @singleton
1782  */
1783 Roo.bootstrap.MenuMgr = function(){
1784    var menus, active, groups = {}, attached = false, lastShow = new Date();
1785
1786    // private - called when first menu is created
1787    function init(){
1788        menus = {};
1789        active = new Roo.util.MixedCollection();
1790        Roo.get(document).addKeyListener(27, function(){
1791            if(active.length > 0){
1792                hideAll();
1793            }
1794        });
1795    }
1796
1797    // private
1798    function hideAll(){
1799        if(active && active.length > 0){
1800            var c = active.clone();
1801            c.each(function(m){
1802                m.hide();
1803            });
1804        }
1805    }
1806
1807    // private
1808    function onHide(m){
1809        active.remove(m);
1810        if(active.length < 1){
1811            Roo.get(document).un("mouseup", onMouseDown);
1812             
1813            attached = false;
1814        }
1815    }
1816
1817    // private
1818    function onShow(m){
1819        var last = active.last();
1820        lastShow = new Date();
1821        active.add(m);
1822        if(!attached){
1823           Roo.get(document).on("mouseup", onMouseDown);
1824            
1825            attached = true;
1826        }
1827        if(m.parentMenu){
1828           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1829           m.parentMenu.activeChild = m;
1830        }else if(last && last.isVisible()){
1831           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1832        }
1833    }
1834
1835    // private
1836    function onBeforeHide(m){
1837        if(m.activeChild){
1838            m.activeChild.hide();
1839        }
1840        if(m.autoHideTimer){
1841            clearTimeout(m.autoHideTimer);
1842            delete m.autoHideTimer;
1843        }
1844    }
1845
1846    // private
1847    function onBeforeShow(m){
1848        var pm = m.parentMenu;
1849        if(!pm && !m.allowOtherMenus){
1850            hideAll();
1851        }else if(pm && pm.activeChild && active != m){
1852            pm.activeChild.hide();
1853        }
1854    }
1855
1856    // private this should really trigger on mouseup..
1857    function onMouseDown(e){
1858         Roo.log("on Mouse Up");
1859         
1860         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1861             Roo.log("MenuManager hideAll");
1862             hideAll();
1863             e.stopEvent();
1864         }
1865         
1866         
1867    }
1868
1869    // private
1870    function onBeforeCheck(mi, state){
1871        if(state){
1872            var g = groups[mi.group];
1873            for(var i = 0, l = g.length; i < l; i++){
1874                if(g[i] != mi){
1875                    g[i].setChecked(false);
1876                }
1877            }
1878        }
1879    }
1880
1881    return {
1882
1883        /**
1884         * Hides all menus that are currently visible
1885         */
1886        hideAll : function(){
1887             hideAll();  
1888        },
1889
1890        // private
1891        register : function(menu){
1892            if(!menus){
1893                init();
1894            }
1895            menus[menu.id] = menu;
1896            menu.on("beforehide", onBeforeHide);
1897            menu.on("hide", onHide);
1898            menu.on("beforeshow", onBeforeShow);
1899            menu.on("show", onShow);
1900            var g = menu.group;
1901            if(g && menu.events["checkchange"]){
1902                if(!groups[g]){
1903                    groups[g] = [];
1904                }
1905                groups[g].push(menu);
1906                menu.on("checkchange", onCheck);
1907            }
1908        },
1909
1910         /**
1911          * Returns a {@link Roo.menu.Menu} object
1912          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1913          * be used to generate and return a new Menu instance.
1914          */
1915        get : function(menu){
1916            if(typeof menu == "string"){ // menu id
1917                return menus[menu];
1918            }else if(menu.events){  // menu instance
1919                return menu;
1920            }
1921            /*else if(typeof menu.length == 'number'){ // array of menu items?
1922                return new Roo.bootstrap.Menu({items:menu});
1923            }else{ // otherwise, must be a config
1924                return new Roo.bootstrap.Menu(menu);
1925            }
1926            */
1927            return false;
1928        },
1929
1930        // private
1931        unregister : function(menu){
1932            delete menus[menu.id];
1933            menu.un("beforehide", onBeforeHide);
1934            menu.un("hide", onHide);
1935            menu.un("beforeshow", onBeforeShow);
1936            menu.un("show", onShow);
1937            var g = menu.group;
1938            if(g && menu.events["checkchange"]){
1939                groups[g].remove(menu);
1940                menu.un("checkchange", onCheck);
1941            }
1942        },
1943
1944        // private
1945        registerCheckable : function(menuItem){
1946            var g = menuItem.group;
1947            if(g){
1948                if(!groups[g]){
1949                    groups[g] = [];
1950                }
1951                groups[g].push(menuItem);
1952                menuItem.on("beforecheckchange", onBeforeCheck);
1953            }
1954        },
1955
1956        // private
1957        unregisterCheckable : function(menuItem){
1958            var g = menuItem.group;
1959            if(g){
1960                groups[g].remove(menuItem);
1961                menuItem.un("beforecheckchange", onBeforeCheck);
1962            }
1963        }
1964    };
1965 }();/*
1966  * - LGPL
1967  *
1968  * menu
1969  * 
1970  */
1971
1972 /**
1973  * @class Roo.bootstrap.Menu
1974  * @extends Roo.bootstrap.Component
1975  * Bootstrap Menu class - container for MenuItems
1976  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1977  * @cfg {bool} hidden  if the menu should be hidden when rendered.
1978  * @cfg {bool} stopEvent (true|false)  Stop event after trigger press (default true)
1979  * @cfg {bool} isLink (true|false)  the menu has link disable auto expand and collaspe (default false)
1980  * 
1981  * @constructor
1982  * Create a new Menu
1983  * @param {Object} config The config object
1984  */
1985
1986
1987 Roo.bootstrap.Menu = function(config){
1988     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1989     if (this.registerMenu && this.type != 'treeview')  {
1990         Roo.bootstrap.MenuMgr.register(this);
1991     }
1992     this.addEvents({
1993         /**
1994          * @event beforeshow
1995          * Fires before this menu is displayed
1996          * @param {Roo.menu.Menu} this
1997          */
1998         beforeshow : true,
1999         /**
2000          * @event beforehide
2001          * Fires before this menu is hidden
2002          * @param {Roo.menu.Menu} this
2003          */
2004         beforehide : true,
2005         /**
2006          * @event show
2007          * Fires after this menu is displayed
2008          * @param {Roo.menu.Menu} this
2009          */
2010         show : true,
2011         /**
2012          * @event hide
2013          * Fires after this menu is hidden
2014          * @param {Roo.menu.Menu} this
2015          */
2016         hide : true,
2017         /**
2018          * @event click
2019          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2020          * @param {Roo.menu.Menu} this
2021          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2022          * @param {Roo.EventObject} e
2023          */
2024         click : true,
2025         /**
2026          * @event mouseover
2027          * Fires when the mouse is hovering over this menu
2028          * @param {Roo.menu.Menu} this
2029          * @param {Roo.EventObject} e
2030          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2031          */
2032         mouseover : true,
2033         /**
2034          * @event mouseout
2035          * Fires when the mouse exits this menu
2036          * @param {Roo.menu.Menu} this
2037          * @param {Roo.EventObject} e
2038          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2039          */
2040         mouseout : true,
2041         /**
2042          * @event itemclick
2043          * Fires when a menu item contained in this menu is clicked
2044          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2045          * @param {Roo.EventObject} e
2046          */
2047         itemclick: true
2048     });
2049     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2050 };
2051
2052 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
2053     
2054    /// html : false,
2055     //align : '',
2056     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
2057     type: false,
2058     /**
2059      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2060      */
2061     registerMenu : true,
2062     
2063     menuItems :false, // stores the menu items..
2064     
2065     hidden:true,
2066         
2067     parentMenu : false,
2068     
2069     stopEvent : true,
2070     
2071     isLink : false,
2072     
2073     getChildContainer : function() {
2074         return this.el;  
2075     },
2076     
2077     getAutoCreate : function(){
2078          
2079         //if (['right'].indexOf(this.align)!==-1) {
2080         //    cfg.cn[1].cls += ' pull-right'
2081         //}
2082         
2083         
2084         var cfg = {
2085             tag : 'ul',
2086             cls : 'dropdown-menu' ,
2087             style : 'z-index:1000'
2088             
2089         };
2090         
2091         if (this.type === 'submenu') {
2092             cfg.cls = 'submenu active';
2093         }
2094         if (this.type === 'treeview') {
2095             cfg.cls = 'treeview-menu';
2096         }
2097         
2098         return cfg;
2099     },
2100     initEvents : function() {
2101         
2102        // Roo.log("ADD event");
2103        // Roo.log(this.triggerEl.dom);
2104         
2105         this.triggerEl.on('click', this.onTriggerClick, this);
2106         
2107         this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2108         
2109         this.triggerEl.addClass('dropdown-toggle');
2110         
2111         if (Roo.isTouch) {
2112             this.el.on('touchstart'  , this.onTouch, this);
2113         }
2114         this.el.on('click' , this.onClick, this);
2115
2116         this.el.on("mouseover", this.onMouseOver, this);
2117         this.el.on("mouseout", this.onMouseOut, this);
2118         
2119     },
2120     
2121     findTargetItem : function(e)
2122     {
2123         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
2124         if(!t){
2125             return false;
2126         }
2127         //Roo.log(t);         Roo.log(t.id);
2128         if(t && t.id){
2129             //Roo.log(this.menuitems);
2130             return this.menuitems.get(t.id);
2131             
2132             //return this.items.get(t.menuItemId);
2133         }
2134         
2135         return false;
2136     },
2137     
2138     onTouch : function(e) 
2139     {
2140         Roo.log("menu.onTouch");
2141         //e.stopEvent(); this make the user popdown broken
2142         this.onClick(e);
2143     },
2144     
2145     onClick : function(e)
2146     {
2147         Roo.log("menu.onClick");
2148         
2149         var t = this.findTargetItem(e);
2150         if(!t || t.isContainer){
2151             return;
2152         }
2153         Roo.log(e);
2154         /*
2155         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
2156             if(t == this.activeItem && t.shouldDeactivate(e)){
2157                 this.activeItem.deactivate();
2158                 delete this.activeItem;
2159                 return;
2160             }
2161             if(t.canActivate){
2162                 this.setActiveItem(t, true);
2163             }
2164             return;
2165             
2166             
2167         }
2168         */
2169        
2170         Roo.log('pass click event');
2171         
2172         t.onClick(e);
2173         
2174         this.fireEvent("click", this, t, e);
2175         
2176         var _this = this;
2177         
2178         if(!t.href.length || t.href == '#'){
2179             (function() { _this.hide(); }).defer(100);
2180         }
2181         
2182     },
2183     
2184     onMouseOver : function(e){
2185         var t  = this.findTargetItem(e);
2186         //Roo.log(t);
2187         //if(t){
2188         //    if(t.canActivate && !t.disabled){
2189         //        this.setActiveItem(t, true);
2190         //    }
2191         //}
2192         
2193         this.fireEvent("mouseover", this, e, t);
2194     },
2195     isVisible : function(){
2196         return !this.hidden;
2197     },
2198      onMouseOut : function(e){
2199         var t  = this.findTargetItem(e);
2200         
2201         //if(t ){
2202         //    if(t == this.activeItem && t.shouldDeactivate(e)){
2203         //        this.activeItem.deactivate();
2204         //        delete this.activeItem;
2205         //    }
2206         //}
2207         this.fireEvent("mouseout", this, e, t);
2208     },
2209     
2210     
2211     /**
2212      * Displays this menu relative to another element
2213      * @param {String/HTMLElement/Roo.Element} element The element to align to
2214      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2215      * the element (defaults to this.defaultAlign)
2216      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2217      */
2218     show : function(el, pos, parentMenu){
2219         this.parentMenu = parentMenu;
2220         if(!this.el){
2221             this.render();
2222         }
2223         this.fireEvent("beforeshow", this);
2224         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2225     },
2226      /**
2227      * Displays this menu at a specific xy position
2228      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2229      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2230      */
2231     showAt : function(xy, parentMenu, /* private: */_e){
2232         this.parentMenu = parentMenu;
2233         if(!this.el){
2234             this.render();
2235         }
2236         if(_e !== false){
2237             this.fireEvent("beforeshow", this);
2238             //xy = this.el.adjustForConstraints(xy);
2239         }
2240         
2241         //this.el.show();
2242         this.hideMenuItems();
2243         this.hidden = false;
2244         this.triggerEl.addClass('open');
2245         
2246         if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2247             xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2248         }
2249         
2250         if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2251             this.el.setXY(xy);
2252         }
2253         
2254         this.focus();
2255         this.fireEvent("show", this);
2256     },
2257     
2258     focus : function(){
2259         return;
2260         if(!this.hidden){
2261             this.doFocus.defer(50, this);
2262         }
2263     },
2264
2265     doFocus : function(){
2266         if(!this.hidden){
2267             this.focusEl.focus();
2268         }
2269     },
2270
2271     /**
2272      * Hides this menu and optionally all parent menus
2273      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2274      */
2275     hide : function(deep)
2276     {
2277         
2278         this.hideMenuItems();
2279         if(this.el && this.isVisible()){
2280             this.fireEvent("beforehide", this);
2281             if(this.activeItem){
2282                 this.activeItem.deactivate();
2283                 this.activeItem = null;
2284             }
2285             this.triggerEl.removeClass('open');;
2286             this.hidden = true;
2287             this.fireEvent("hide", this);
2288         }
2289         if(deep === true && this.parentMenu){
2290             this.parentMenu.hide(true);
2291         }
2292     },
2293     
2294     onTriggerClick : function(e)
2295     {
2296         Roo.log('trigger click');
2297         
2298         var target = e.getTarget();
2299         
2300         Roo.log(target.nodeName.toLowerCase());
2301         
2302         if(target.nodeName.toLowerCase() === 'i'){
2303             e.preventDefault();
2304         }
2305         
2306     },
2307     
2308     onTriggerPress  : function(e)
2309     {
2310         Roo.log('trigger press');
2311         //Roo.log(e.getTarget());
2312        // Roo.log(this.triggerEl.dom);
2313        
2314         // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2315         var pel = Roo.get(e.getTarget());
2316         if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2317             Roo.log('is treeview or dropdown?');
2318             return;
2319         }
2320         
2321         if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2322             return;
2323         }
2324         
2325         if (this.isVisible()) {
2326             Roo.log('hide');
2327             this.hide();
2328         } else {
2329             Roo.log('show');
2330             this.show(this.triggerEl, false, false);
2331         }
2332         
2333         if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2334             e.stopEvent();
2335         }
2336         
2337     },
2338        
2339     
2340     hideMenuItems : function()
2341     {
2342         Roo.log("hide Menu Items");
2343         if (!this.el) { 
2344             return;
2345         }
2346         //$(backdrop).remove()
2347         this.el.select('.open',true).each(function(aa) {
2348             
2349             aa.removeClass('open');
2350           //var parent = getParent($(this))
2351           //var relatedTarget = { relatedTarget: this }
2352           
2353            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2354           //if (e.isDefaultPrevented()) return
2355            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2356         });
2357     },
2358     addxtypeChild : function (tree, cntr) {
2359         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2360           
2361         this.menuitems.add(comp);
2362         return comp;
2363
2364     },
2365     getEl : function()
2366     {
2367         Roo.log(this.el);
2368         return this.el;
2369     },
2370     
2371     clear : function()
2372     {
2373         this.getEl().dom.innerHTML = '';
2374         this.menuitems.clear();
2375     }
2376 });
2377
2378  
2379  /*
2380  * - LGPL
2381  *
2382  * menu item
2383  * 
2384  */
2385
2386
2387 /**
2388  * @class Roo.bootstrap.MenuItem
2389  * @extends Roo.bootstrap.Component
2390  * Bootstrap MenuItem class
2391  * @cfg {String} html the menu label
2392  * @cfg {String} href the link
2393  * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2394  * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2395  * @cfg {Boolean} active  used on sidebars to highlight active itesm
2396  * @cfg {String} fa favicon to show on left of menu item.
2397  * @cfg {Roo.bootsrap.Menu} menu the child menu.
2398  * 
2399  * 
2400  * @constructor
2401  * Create a new MenuItem
2402  * @param {Object} config The config object
2403  */
2404
2405
2406 Roo.bootstrap.MenuItem = function(config){
2407     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2408     this.addEvents({
2409         // raw events
2410         /**
2411          * @event click
2412          * The raw click event for the entire grid.
2413          * @param {Roo.bootstrap.MenuItem} this
2414          * @param {Roo.EventObject} e
2415          */
2416         "click" : true
2417     });
2418 };
2419
2420 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
2421     
2422     href : false,
2423     html : false,
2424     preventDefault: false,
2425     isContainer : false,
2426     active : false,
2427     fa: false,
2428     
2429     getAutoCreate : function(){
2430         
2431         if(this.isContainer){
2432             return {
2433                 tag: 'li',
2434                 cls: 'dropdown-menu-item'
2435             };
2436         }
2437         var ctag = {
2438             tag: 'span',
2439             html: 'Link'
2440         };
2441         
2442         var anc = {
2443             tag : 'a',
2444             href : '#',
2445             cn : [  ]
2446         };
2447         
2448         if (this.fa !== false) {
2449             anc.cn.push({
2450                 tag : 'i',
2451                 cls : 'fa fa-' + this.fa
2452             });
2453         }
2454         
2455         anc.cn.push(ctag);
2456         
2457         
2458         var cfg= {
2459             tag: 'li',
2460             cls: 'dropdown-menu-item',
2461             cn: [ anc ]
2462         };
2463         if (this.parent().type == 'treeview') {
2464             cfg.cls = 'treeview-menu';
2465         }
2466         if (this.active) {
2467             cfg.cls += ' active';
2468         }
2469         
2470         
2471         
2472         anc.href = this.href || cfg.cn[0].href ;
2473         ctag.html = this.html || cfg.cn[0].html ;
2474         return cfg;
2475     },
2476     
2477     initEvents: function()
2478     {
2479         if (this.parent().type == 'treeview') {
2480             this.el.select('a').on('click', this.onClick, this);
2481         }
2482         
2483         if (this.menu) {
2484             this.menu.parentType = this.xtype;
2485             this.menu.triggerEl = this.el;
2486             this.menu = this.addxtype(Roo.apply({}, this.menu));
2487         }
2488         
2489     },
2490     onClick : function(e)
2491     {
2492         Roo.log('item on click ');
2493         
2494         if(this.preventDefault){
2495             e.preventDefault();
2496         }
2497         //this.parent().hideMenuItems();
2498         
2499         this.fireEvent('click', this, e);
2500     },
2501     getEl : function()
2502     {
2503         return this.el;
2504     } 
2505 });
2506
2507  
2508
2509  /*
2510  * - LGPL
2511  *
2512  * menu separator
2513  * 
2514  */
2515
2516
2517 /**
2518  * @class Roo.bootstrap.MenuSeparator
2519  * @extends Roo.bootstrap.Component
2520  * Bootstrap MenuSeparator class
2521  * 
2522  * @constructor
2523  * Create a new MenuItem
2524  * @param {Object} config The config object
2525  */
2526
2527
2528 Roo.bootstrap.MenuSeparator = function(config){
2529     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2530 };
2531
2532 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2533     
2534     getAutoCreate : function(){
2535         var cfg = {
2536             cls: 'divider',
2537             tag : 'li'
2538         };
2539         
2540         return cfg;
2541     }
2542    
2543 });
2544
2545  
2546
2547  
2548 /*
2549 * Licence: LGPL
2550 */
2551
2552 /**
2553  * @class Roo.bootstrap.Modal
2554  * @extends Roo.bootstrap.Component
2555  * Bootstrap Modal class
2556  * @cfg {String} title Title of dialog
2557  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2558  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn
2559  * @cfg {Boolean} specificTitle default false
2560  * @cfg {Array} buttons Array of buttons or standard button set..
2561  * @cfg {String} buttonPosition (left|right|center) default right
2562  * @cfg {Boolean} animate default true
2563  * @cfg {Boolean} allow_close default true
2564  * @cfg {Boolean} fitwindow default false
2565  * @cfg {String} size (sm|lg) default empty
2566  *
2567  *
2568  * @constructor
2569  * Create a new Modal Dialog
2570  * @param {Object} config The config object
2571  */
2572
2573 Roo.bootstrap.Modal = function(config){
2574     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2575     this.addEvents({
2576         // raw events
2577         /**
2578          * @event btnclick
2579          * The raw btnclick event for the button
2580          * @param {Roo.EventObject} e
2581          */
2582         "btnclick" : true,
2583         /**
2584          * @event resize
2585          * Fire when dialog resize
2586          * @param {Roo.bootstrap.Modal} this
2587          * @param {Roo.EventObject} e
2588          */
2589         "resize" : true
2590     });
2591     this.buttons = this.buttons || [];
2592
2593     if (this.tmpl) {
2594         this.tmpl = Roo.factory(this.tmpl);
2595     }
2596
2597 };
2598
2599 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2600
2601     title : 'test dialog',
2602
2603     buttons : false,
2604
2605     // set on load...
2606
2607     html: false,
2608
2609     tmp: false,
2610
2611     specificTitle: false,
2612
2613     buttonPosition: 'right',
2614
2615     allow_close : true,
2616
2617     animate : true,
2618
2619     fitwindow: false,
2620
2621
2622      // private
2623     dialogEl: false,
2624     bodyEl:  false,
2625     footerEl:  false,
2626     titleEl:  false,
2627     closeEl:  false,
2628
2629     size: '',
2630
2631
2632     onRender : function(ct, position)
2633     {
2634         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2635
2636         if(!this.el){
2637             var cfg = Roo.apply({},  this.getAutoCreate());
2638             cfg.id = Roo.id();
2639             //if(!cfg.name){
2640             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2641             //}
2642             //if (!cfg.name.length) {
2643             //    delete cfg.name;
2644            // }
2645             if (this.cls) {
2646                 cfg.cls += ' ' + this.cls;
2647             }
2648             if (this.style) {
2649                 cfg.style = this.style;
2650             }
2651             this.el = Roo.get(document.body).createChild(cfg, position);
2652         }
2653         //var type = this.el.dom.type;
2654
2655
2656         if(this.tabIndex !== undefined){
2657             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2658         }
2659
2660         this.dialogEl = this.el.select('.modal-dialog',true).first();
2661         this.bodyEl = this.el.select('.modal-body',true).first();
2662         this.closeEl = this.el.select('.modal-header .close', true).first();
2663         this.headerEl = this.el.select('.modal-header',true).first();
2664         this.titleEl = this.el.select('.modal-title',true).first();
2665         this.footerEl = this.el.select('.modal-footer',true).first();
2666
2667         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2668         this.maskEl.enableDisplayMode("block");
2669         this.maskEl.hide();
2670         //this.el.addClass("x-dlg-modal");
2671
2672         if (this.buttons.length) {
2673             Roo.each(this.buttons, function(bb) {
2674                 var b = Roo.apply({}, bb);
2675                 b.xns = b.xns || Roo.bootstrap;
2676                 b.xtype = b.xtype || 'Button';
2677                 if (typeof(b.listeners) == 'undefined') {
2678                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2679                 }
2680
2681                 var btn = Roo.factory(b);
2682
2683                 btn.render(this.el.select('.modal-footer div').first());
2684
2685             },this);
2686         }
2687         // render the children.
2688         var nitems = [];
2689
2690         if(typeof(this.items) != 'undefined'){
2691             var items = this.items;
2692             delete this.items;
2693
2694             for(var i =0;i < items.length;i++) {
2695                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2696             }
2697         }
2698
2699         this.items = nitems;
2700
2701         // where are these used - they used to be body/close/footer
2702
2703
2704         this.initEvents();
2705         //this.el.addClass([this.fieldClass, this.cls]);
2706
2707     },
2708
2709     getAutoCreate : function(){
2710
2711
2712         var bdy = {
2713                 cls : 'modal-body',
2714                 html : this.html || ''
2715         };
2716
2717         var title = {
2718             tag: 'h4',
2719             cls : 'modal-title',
2720             html : this.title
2721         };
2722
2723         if(this.specificTitle){
2724             title = this.title;
2725
2726         };
2727
2728         var header = [];
2729         if (this.allow_close) {
2730             header.push({
2731                 tag: 'button',
2732                 cls : 'close',
2733                 html : '&times'
2734             });
2735         }
2736
2737         header.push(title);
2738
2739         var size = '';
2740
2741         if(this.size.length){
2742             size = 'modal-' + this.size;
2743         }
2744
2745         var modal = {
2746             cls: "modal",
2747             style : 'display: none',
2748             cn : [
2749                 {
2750                     cls: "modal-dialog " + size,
2751                     cn : [
2752                         {
2753                             cls : "modal-content",
2754                             cn : [
2755                                 {
2756                                     cls : 'modal-header',
2757                                     cn : header
2758                                 },
2759                                 bdy,
2760                                 {
2761                                     cls : 'modal-footer',
2762                                     cn : [
2763                                         {
2764                                             tag: 'div',
2765                                             cls: 'btn-' + this.buttonPosition
2766                                         }
2767                                     ]
2768
2769                                 }
2770
2771
2772                             ]
2773
2774                         }
2775                     ]
2776
2777                 }
2778             ]
2779         };
2780
2781         if(this.animate){
2782             modal.cls += ' fade';
2783         }
2784
2785         return modal;
2786
2787     },
2788     getChildContainer : function() {
2789
2790          return this.bodyEl;
2791
2792     },
2793     getButtonContainer : function() {
2794          return this.el.select('.modal-footer div',true).first();
2795
2796     },
2797     initEvents : function()
2798     {
2799         if (this.allow_close) {
2800             this.closeEl.on('click', this.hide, this);
2801         }
2802         Roo.EventManager.onWindowResize(this.resize, this, true);
2803
2804
2805     },
2806
2807     resize : function()
2808     {
2809         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),  Roo.lib.Dom.getViewHeight(true));
2810         if (this.fitwindow) {
2811             var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2812             var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2813             this.setSize(w,h);
2814         }
2815     },
2816
2817     setSize : function(w,h)
2818     {
2819         if (!w && !h) {
2820             return;
2821         }
2822         this.resizeTo(w,h);
2823     },
2824
2825     show : function() {
2826
2827         if (!this.rendered) {
2828             this.render();
2829         }
2830
2831         this.el.setStyle('display', 'block');
2832
2833         if(this.animate){  // element has 'fade'  - so stuff happens after .3s ?- not sure why the delay?
2834             var _this = this;
2835             (function(){
2836                 this.el.addClass('in');
2837             }).defer(50, this);
2838         }else{
2839             this.el.addClass('in');
2840
2841         }
2842
2843         // not sure how we can show data in here..
2844         //if (this.tmpl) {
2845         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2846         //}
2847
2848         Roo.get(document.body).addClass("x-body-masked");
2849         
2850         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),   Roo.lib.Dom.getViewHeight(true));
2851         this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2852         this.maskEl.show();
2853         
2854         this.resize();
2855         
2856         this.fireEvent('show', this);
2857
2858         // set zindex here - otherwise it appears to be ignored...
2859         this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2860
2861         (function () {
2862             this.items.forEach( function(e) {
2863                 e.layout ? e.layout() : false;
2864
2865             });
2866         }).defer(100,this);
2867
2868     },
2869     hide : function()
2870     {
2871         if(this.fireEvent("beforehide", this) !== false){
2872             this.maskEl.hide();
2873             Roo.get(document.body).removeClass("x-body-masked");
2874             this.el.removeClass('in');
2875             this.el.select('.modal-dialog', true).first().setStyle('transform','');
2876
2877             if(this.animate){ // why
2878                 var _this = this;
2879                 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2880             }else{
2881                 this.el.setStyle('display', 'none');
2882             }
2883             this.fireEvent('hide', this);
2884         }
2885     },
2886
2887     addButton : function(str, cb)
2888     {
2889
2890
2891         var b = Roo.apply({}, { html : str } );
2892         b.xns = b.xns || Roo.bootstrap;
2893         b.xtype = b.xtype || 'Button';
2894         if (typeof(b.listeners) == 'undefined') {
2895             b.listeners = { click : cb.createDelegate(this)  };
2896         }
2897
2898         var btn = Roo.factory(b);
2899
2900         btn.render(this.el.select('.modal-footer div').first());
2901
2902         return btn;
2903
2904     },
2905
2906     setDefaultButton : function(btn)
2907     {
2908         //this.el.select('.modal-footer').()
2909     },
2910     diff : false,
2911
2912     resizeTo: function(w,h)
2913     {
2914         // skip.. ?? why??
2915
2916         this.dialogEl.setWidth(w);
2917         if (this.diff === false) {
2918             this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2919         }
2920
2921         this.bodyEl.setHeight(h-this.diff);
2922
2923         this.fireEvent('resize', this);
2924
2925     },
2926     setContentSize  : function(w, h)
2927     {
2928
2929     },
2930     onButtonClick: function(btn,e)
2931     {
2932         //Roo.log([a,b,c]);
2933         this.fireEvent('btnclick', btn.name, e);
2934     },
2935      /**
2936      * Set the title of the Dialog
2937      * @param {String} str new Title
2938      */
2939     setTitle: function(str) {
2940         this.titleEl.dom.innerHTML = str;
2941     },
2942     /**
2943      * Set the body of the Dialog
2944      * @param {String} str new Title
2945      */
2946     setBody: function(str) {
2947         this.bodyEl.dom.innerHTML = str;
2948     },
2949     /**
2950      * Set the body of the Dialog using the template
2951      * @param {Obj} data - apply this data to the template and replace the body contents.
2952      */
2953     applyBody: function(obj)
2954     {
2955         if (!this.tmpl) {
2956             Roo.log("Error - using apply Body without a template");
2957             //code
2958         }
2959         this.tmpl.overwrite(this.bodyEl, obj);
2960     }
2961
2962 });
2963
2964
2965 Roo.apply(Roo.bootstrap.Modal,  {
2966     /**
2967          * Button config that displays a single OK button
2968          * @type Object
2969          */
2970         OK :  [{
2971             name : 'ok',
2972             weight : 'primary',
2973             html : 'OK'
2974         }],
2975         /**
2976          * Button config that displays Yes and No buttons
2977          * @type Object
2978          */
2979         YESNO : [
2980             {
2981                 name  : 'no',
2982                 html : 'No'
2983             },
2984             {
2985                 name  :'yes',
2986                 weight : 'primary',
2987                 html : 'Yes'
2988             }
2989         ],
2990
2991         /**
2992          * Button config that displays OK and Cancel buttons
2993          * @type Object
2994          */
2995         OKCANCEL : [
2996             {
2997                name : 'cancel',
2998                 html : 'Cancel'
2999             },
3000             {
3001                 name : 'ok',
3002                 weight : 'primary',
3003                 html : 'OK'
3004             }
3005         ],
3006         /**
3007          * Button config that displays Yes, No and Cancel buttons
3008          * @type Object
3009          */
3010         YESNOCANCEL : [
3011             {
3012                 name : 'yes',
3013                 weight : 'primary',
3014                 html : 'Yes'
3015             },
3016             {
3017                 name : 'no',
3018                 html : 'No'
3019             },
3020             {
3021                 name : 'cancel',
3022                 html : 'Cancel'
3023             }
3024         ],
3025         
3026         zIndex : 10001
3027 });
3028 /*
3029  * - LGPL
3030  *
3031  * messagebox - can be used as a replace
3032  * 
3033  */
3034 /**
3035  * @class Roo.MessageBox
3036  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
3037  * Example usage:
3038  *<pre><code>
3039 // Basic alert:
3040 Roo.Msg.alert('Status', 'Changes saved successfully.');
3041
3042 // Prompt for user data:
3043 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3044     if (btn == 'ok'){
3045         // process text value...
3046     }
3047 });
3048
3049 // Show a dialog using config options:
3050 Roo.Msg.show({
3051    title:'Save Changes?',
3052    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3053    buttons: Roo.Msg.YESNOCANCEL,
3054    fn: processResult,
3055    animEl: 'elId'
3056 });
3057 </code></pre>
3058  * @singleton
3059  */
3060 Roo.bootstrap.MessageBox = function(){
3061     var dlg, opt, mask, waitTimer;
3062     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3063     var buttons, activeTextEl, bwidth;
3064
3065     
3066     // private
3067     var handleButton = function(button){
3068         dlg.hide();
3069         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3070     };
3071
3072     // private
3073     var handleHide = function(){
3074         if(opt && opt.cls){
3075             dlg.el.removeClass(opt.cls);
3076         }
3077         //if(waitTimer){
3078         //    Roo.TaskMgr.stop(waitTimer);
3079         //    waitTimer = null;
3080         //}
3081     };
3082
3083     // private
3084     var updateButtons = function(b){
3085         var width = 0;
3086         if(!b){
3087             buttons["ok"].hide();
3088             buttons["cancel"].hide();
3089             buttons["yes"].hide();
3090             buttons["no"].hide();
3091             //dlg.footer.dom.style.display = 'none';
3092             return width;
3093         }
3094         dlg.footerEl.dom.style.display = '';
3095         for(var k in buttons){
3096             if(typeof buttons[k] != "function"){
3097                 if(b[k]){
3098                     buttons[k].show();
3099                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3100                     width += buttons[k].el.getWidth()+15;
3101                 }else{
3102                     buttons[k].hide();
3103                 }
3104             }
3105         }
3106         return width;
3107     };
3108
3109     // private
3110     var handleEsc = function(d, k, e){
3111         if(opt && opt.closable !== false){
3112             dlg.hide();
3113         }
3114         if(e){
3115             e.stopEvent();
3116         }
3117     };
3118
3119     return {
3120         /**
3121          * Returns a reference to the underlying {@link Roo.BasicDialog} element
3122          * @return {Roo.BasicDialog} The BasicDialog element
3123          */
3124         getDialog : function(){
3125            if(!dlg){
3126                 dlg = new Roo.bootstrap.Modal( {
3127                     //draggable: true,
3128                     //resizable:false,
3129                     //constraintoviewport:false,
3130                     //fixedcenter:true,
3131                     //collapsible : false,
3132                     //shim:true,
3133                     //modal: true,
3134                 //    width: 'auto',
3135                   //  height:100,
3136                     //buttonAlign:"center",
3137                     closeClick : function(){
3138                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3139                             handleButton("no");
3140                         }else{
3141                             handleButton("cancel");
3142                         }
3143                     }
3144                 });
3145                 dlg.render();
3146                 dlg.on("hide", handleHide);
3147                 mask = dlg.mask;
3148                 //dlg.addKeyListener(27, handleEsc);
3149                 buttons = {};
3150                 this.buttons = buttons;
3151                 var bt = this.buttonText;
3152                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3153                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3154                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3155                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3156                 //Roo.log(buttons);
3157                 bodyEl = dlg.bodyEl.createChild({
3158
3159                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3160                         '<textarea class="roo-mb-textarea"></textarea>' +
3161                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
3162                 });
3163                 msgEl = bodyEl.dom.firstChild;
3164                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3165                 textboxEl.enableDisplayMode();
3166                 textboxEl.addKeyListener([10,13], function(){
3167                     if(dlg.isVisible() && opt && opt.buttons){
3168                         if(opt.buttons.ok){
3169                             handleButton("ok");
3170                         }else if(opt.buttons.yes){
3171                             handleButton("yes");
3172                         }
3173                     }
3174                 });
3175                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3176                 textareaEl.enableDisplayMode();
3177                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3178                 progressEl.enableDisplayMode();
3179                 
3180                 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3181                 var pf = progressEl.dom.firstChild;
3182                 if (pf) {
3183                     pp = Roo.get(pf.firstChild);
3184                     pp.setHeight(pf.offsetHeight);
3185                 }
3186                 
3187             }
3188             return dlg;
3189         },
3190
3191         /**
3192          * Updates the message box body text
3193          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3194          * the XHTML-compliant non-breaking space character '&amp;#160;')
3195          * @return {Roo.MessageBox} This message box
3196          */
3197         updateText : function(text)
3198         {
3199             if(!dlg.isVisible() && !opt.width){
3200                 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3201                 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3202             }
3203             msgEl.innerHTML = text || '&#160;';
3204       
3205             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3206             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3207             var w = Math.max(
3208                     Math.min(opt.width || cw , this.maxWidth), 
3209                     Math.max(opt.minWidth || this.minWidth, bwidth)
3210             );
3211             if(opt.prompt){
3212                 activeTextEl.setWidth(w);
3213             }
3214             if(dlg.isVisible()){
3215                 dlg.fixedcenter = false;
3216             }
3217             // to big, make it scroll. = But as usual stupid IE does not support
3218             // !important..
3219             
3220             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3221                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3222                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3223             } else {
3224                 bodyEl.dom.style.height = '';
3225                 bodyEl.dom.style.overflowY = '';
3226             }
3227             if (cw > w) {
3228                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3229             } else {
3230                 bodyEl.dom.style.overflowX = '';
3231             }
3232             
3233             dlg.setContentSize(w, bodyEl.getHeight());
3234             if(dlg.isVisible()){
3235                 dlg.fixedcenter = true;
3236             }
3237             return this;
3238         },
3239
3240         /**
3241          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
3242          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3243          * @param {Number} value Any number between 0 and 1 (e.g., .5)
3244          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3245          * @return {Roo.MessageBox} This message box
3246          */
3247         updateProgress : function(value, text){
3248             if(text){
3249                 this.updateText(text);
3250             }
3251             
3252             if (pp) { // weird bug on my firefox - for some reason this is not defined
3253                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3254                 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3255             }
3256             return this;
3257         },        
3258
3259         /**
3260          * Returns true if the message box is currently displayed
3261          * @return {Boolean} True if the message box is visible, else false
3262          */
3263         isVisible : function(){
3264             return dlg && dlg.isVisible();  
3265         },
3266
3267         /**
3268          * Hides the message box if it is displayed
3269          */
3270         hide : function(){
3271             if(this.isVisible()){
3272                 dlg.hide();
3273             }  
3274         },
3275
3276         /**
3277          * Displays a new message box, or reinitializes an existing message box, based on the config options
3278          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3279          * The following config object properties are supported:
3280          * <pre>
3281 Property    Type             Description
3282 ----------  ---------------  ------------------------------------------------------------------------------------
3283 animEl            String/Element   An id or Element from which the message box should animate as it opens and
3284                                    closes (defaults to undefined)
3285 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3286                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
3287 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
3288                                    progress and wait dialogs will ignore this property and always hide the
3289                                    close button as they can only be closed programmatically.
3290 cls               String           A custom CSS class to apply to the message box element
3291 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
3292                                    displayed (defaults to 75)
3293 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
3294                                    function will be btn (the name of the button that was clicked, if applicable,
3295                                    e.g. "ok"), and text (the value of the active text field, if applicable).
3296                                    Progress and wait dialogs will ignore this option since they do not respond to
3297                                    user actions and can only be closed programmatically, so any required function
3298                                    should be called by the same code after it closes the dialog.
3299 icon              String           A CSS class that provides a background image to be used as an icon for
3300                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3301 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
3302 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
3303 modal             Boolean          False to allow user interaction with the page while the message box is
3304                                    displayed (defaults to true)
3305 msg               String           A string that will replace the existing message box body text (defaults
3306                                    to the XHTML-compliant non-breaking space character '&#160;')
3307 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
3308 progress          Boolean          True to display a progress bar (defaults to false)
3309 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
3310 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
3311 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
3312 title             String           The title text
3313 value             String           The string value to set into the active textbox element if displayed
3314 wait              Boolean          True to display a progress bar (defaults to false)
3315 width             Number           The width of the dialog in pixels
3316 </pre>
3317          *
3318          * Example usage:
3319          * <pre><code>
3320 Roo.Msg.show({
3321    title: 'Address',
3322    msg: 'Please enter your address:',
3323    width: 300,
3324    buttons: Roo.MessageBox.OKCANCEL,
3325    multiline: true,
3326    fn: saveAddress,
3327    animEl: 'addAddressBtn'
3328 });
3329 </code></pre>
3330          * @param {Object} config Configuration options
3331          * @return {Roo.MessageBox} This message box
3332          */
3333         show : function(options)
3334         {
3335             
3336             // this causes nightmares if you show one dialog after another
3337             // especially on callbacks..
3338              
3339             if(this.isVisible()){
3340                 
3341                 this.hide();
3342                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3343                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
3344                 Roo.log("New Dialog Message:" +  options.msg )
3345                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3346                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3347                 
3348             }
3349             var d = this.getDialog();
3350             opt = options;
3351             d.setTitle(opt.title || "&#160;");
3352             d.closeEl.setDisplayed(opt.closable !== false);
3353             activeTextEl = textboxEl;
3354             opt.prompt = opt.prompt || (opt.multiline ? true : false);
3355             if(opt.prompt){
3356                 if(opt.multiline){
3357                     textboxEl.hide();
3358                     textareaEl.show();
3359                     textareaEl.setHeight(typeof opt.multiline == "number" ?
3360                         opt.multiline : this.defaultTextHeight);
3361                     activeTextEl = textareaEl;
3362                 }else{
3363                     textboxEl.show();
3364                     textareaEl.hide();
3365                 }
3366             }else{
3367                 textboxEl.hide();
3368                 textareaEl.hide();
3369             }
3370             progressEl.setDisplayed(opt.progress === true);
3371             this.updateProgress(0);
3372             activeTextEl.dom.value = opt.value || "";
3373             if(opt.prompt){
3374                 dlg.setDefaultButton(activeTextEl);
3375             }else{
3376                 var bs = opt.buttons;
3377                 var db = null;
3378                 if(bs && bs.ok){
3379                     db = buttons["ok"];
3380                 }else if(bs && bs.yes){
3381                     db = buttons["yes"];
3382                 }
3383                 dlg.setDefaultButton(db);
3384             }
3385             bwidth = updateButtons(opt.buttons);
3386             this.updateText(opt.msg);
3387             if(opt.cls){
3388                 d.el.addClass(opt.cls);
3389             }
3390             d.proxyDrag = opt.proxyDrag === true;
3391             d.modal = opt.modal !== false;
3392             d.mask = opt.modal !== false ? mask : false;
3393             if(!d.isVisible()){
3394                 // force it to the end of the z-index stack so it gets a cursor in FF
3395                 document.body.appendChild(dlg.el.dom);
3396                 d.animateTarget = null;
3397                 d.show(options.animEl);
3398             }
3399             return this;
3400         },
3401
3402         /**
3403          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
3404          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3405          * and closing the message box when the process is complete.
3406          * @param {String} title The title bar text
3407          * @param {String} msg The message box body text
3408          * @return {Roo.MessageBox} This message box
3409          */
3410         progress : function(title, msg){
3411             this.show({
3412                 title : title,
3413                 msg : msg,
3414                 buttons: false,
3415                 progress:true,
3416                 closable:false,
3417                 minWidth: this.minProgressWidth,
3418                 modal : true
3419             });
3420             return this;
3421         },
3422
3423         /**
3424          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3425          * If a callback function is passed it will be called after the user clicks the button, and the
3426          * id of the button that was clicked will be passed as the only parameter to the callback
3427          * (could also be the top-right close button).
3428          * @param {String} title The title bar text
3429          * @param {String} msg The message box body text
3430          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3431          * @param {Object} scope (optional) The scope of the callback function
3432          * @return {Roo.MessageBox} This message box
3433          */
3434         alert : function(title, msg, fn, scope)
3435         {
3436             this.show({
3437                 title : title,
3438                 msg : msg,
3439                 buttons: this.OK,
3440                 fn: fn,
3441                 closable : false,
3442                 scope : scope,
3443                 modal : true
3444             });
3445             return this;
3446         },
3447
3448         /**
3449          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
3450          * interaction while waiting for a long-running process to complete that does not have defined intervals.
3451          * You are responsible for closing the message box when the process is complete.
3452          * @param {String} msg The message box body text
3453          * @param {String} title (optional) The title bar text
3454          * @return {Roo.MessageBox} This message box
3455          */
3456         wait : function(msg, title){
3457             this.show({
3458                 title : title,
3459                 msg : msg,
3460                 buttons: false,
3461                 closable:false,
3462                 progress:true,
3463                 modal:true,
3464                 width:300,
3465                 wait:true
3466             });
3467             waitTimer = Roo.TaskMgr.start({
3468                 run: function(i){
3469                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3470                 },
3471                 interval: 1000
3472             });
3473             return this;
3474         },
3475
3476         /**
3477          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3478          * If a callback function is passed it will be called after the user clicks either button, and the id of the
3479          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3480          * @param {String} title The title bar text
3481          * @param {String} msg The message box body text
3482          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3483          * @param {Object} scope (optional) The scope of the callback function
3484          * @return {Roo.MessageBox} This message box
3485          */
3486         confirm : function(title, msg, fn, scope){
3487             this.show({
3488                 title : title,
3489                 msg : msg,
3490                 buttons: this.YESNO,
3491                 fn: fn,
3492                 scope : scope,
3493                 modal : true
3494             });
3495             return this;
3496         },
3497
3498         /**
3499          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3500          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
3501          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3502          * (could also be the top-right close button) and the text that was entered will be passed as the two
3503          * parameters to the callback.
3504          * @param {String} title The title bar text
3505          * @param {String} msg The message box body text
3506          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3507          * @param {Object} scope (optional) The scope of the callback function
3508          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3509          * property, or the height in pixels to create the textbox (defaults to false / single-line)
3510          * @return {Roo.MessageBox} This message box
3511          */
3512         prompt : function(title, msg, fn, scope, multiline){
3513             this.show({
3514                 title : title,
3515                 msg : msg,
3516                 buttons: this.OKCANCEL,
3517                 fn: fn,
3518                 minWidth:250,
3519                 scope : scope,
3520                 prompt:true,
3521                 multiline: multiline,
3522                 modal : true
3523             });
3524             return this;
3525         },
3526
3527         /**
3528          * Button config that displays a single OK button
3529          * @type Object
3530          */
3531         OK : {ok:true},
3532         /**
3533          * Button config that displays Yes and No buttons
3534          * @type Object
3535          */
3536         YESNO : {yes:true, no:true},
3537         /**
3538          * Button config that displays OK and Cancel buttons
3539          * @type Object
3540          */
3541         OKCANCEL : {ok:true, cancel:true},
3542         /**
3543          * Button config that displays Yes, No and Cancel buttons
3544          * @type Object
3545          */
3546         YESNOCANCEL : {yes:true, no:true, cancel:true},
3547
3548         /**
3549          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3550          * @type Number
3551          */
3552         defaultTextHeight : 75,
3553         /**
3554          * The maximum width in pixels of the message box (defaults to 600)
3555          * @type Number
3556          */
3557         maxWidth : 600,
3558         /**
3559          * The minimum width in pixels of the message box (defaults to 100)
3560          * @type Number
3561          */
3562         minWidth : 100,
3563         /**
3564          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
3565          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3566          * @type Number
3567          */
3568         minProgressWidth : 250,
3569         /**
3570          * An object containing the default button text strings that can be overriden for localized language support.
3571          * Supported properties are: ok, cancel, yes and no.
3572          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3573          * @type Object
3574          */
3575         buttonText : {
3576             ok : "OK",
3577             cancel : "Cancel",
3578             yes : "Yes",
3579             no : "No"
3580         }
3581     };
3582 }();
3583
3584 /**
3585  * Shorthand for {@link Roo.MessageBox}
3586  */
3587 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3588 Roo.Msg = Roo.Msg || Roo.MessageBox;
3589 /*
3590  * - LGPL
3591  *
3592  * navbar
3593  * 
3594  */
3595
3596 /**
3597  * @class Roo.bootstrap.Navbar
3598  * @extends Roo.bootstrap.Component
3599  * Bootstrap Navbar class
3600
3601  * @constructor
3602  * Create a new Navbar
3603  * @param {Object} config The config object
3604  */
3605
3606
3607 Roo.bootstrap.Navbar = function(config){
3608     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3609     this.addEvents({
3610         // raw events
3611         /**
3612          * @event beforetoggle
3613          * Fire before toggle the menu
3614          * @param {Roo.EventObject} e
3615          */
3616         "beforetoggle" : true
3617     });
3618 };
3619
3620 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3621     
3622     
3623    
3624     // private
3625     navItems : false,
3626     loadMask : false,
3627     
3628     
3629     getAutoCreate : function(){
3630         
3631         
3632         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3633         
3634     },
3635     
3636     initEvents :function ()
3637     {
3638         //Roo.log(this.el.select('.navbar-toggle',true));
3639         this.el.select('.navbar-toggle',true).on('click', function() {
3640             if(this.fireEvent('beforetoggle', this) !== false){
3641                this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3642             }
3643             
3644         }, this);
3645         
3646         var mark = {
3647             tag: "div",
3648             cls:"x-dlg-mask"
3649         };
3650         
3651         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3652         
3653         var size = this.el.getSize();
3654         this.maskEl.setSize(size.width, size.height);
3655         this.maskEl.enableDisplayMode("block");
3656         this.maskEl.hide();
3657         
3658         if(this.loadMask){
3659             this.maskEl.show();
3660         }
3661     },
3662     
3663     
3664     getChildContainer : function()
3665     {
3666         if (this.el.select('.collapse').getCount()) {
3667             return this.el.select('.collapse',true).first();
3668         }
3669         
3670         return this.el;
3671     },
3672     
3673     mask : function()
3674     {
3675         this.maskEl.show();
3676     },
3677     
3678     unmask : function()
3679     {
3680         this.maskEl.hide();
3681     } 
3682     
3683     
3684     
3685     
3686 });
3687
3688
3689
3690  
3691
3692  /*
3693  * - LGPL
3694  *
3695  * navbar
3696  * 
3697  */
3698
3699 /**
3700  * @class Roo.bootstrap.NavSimplebar
3701  * @extends Roo.bootstrap.Navbar
3702  * Bootstrap Sidebar class
3703  *
3704  * @cfg {Boolean} inverse is inverted color
3705  * 
3706  * @cfg {String} type (nav | pills | tabs)
3707  * @cfg {Boolean} arrangement stacked | justified
3708  * @cfg {String} align (left | right) alignment
3709  * 
3710  * @cfg {Boolean} main (true|false) main nav bar? default false
3711  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3712  * 
3713  * @cfg {String} tag (header|footer|nav|div) default is nav 
3714
3715  * 
3716  * 
3717  * 
3718  * @constructor
3719  * Create a new Sidebar
3720  * @param {Object} config The config object
3721  */
3722
3723
3724 Roo.bootstrap.NavSimplebar = function(config){
3725     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3726 };
3727
3728 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3729     
3730     inverse: false,
3731     
3732     type: false,
3733     arrangement: '',
3734     align : false,
3735     
3736     
3737     
3738     main : false,
3739     
3740     
3741     tag : false,
3742     
3743     
3744     getAutoCreate : function(){
3745         
3746         
3747         var cfg = {
3748             tag : this.tag || 'div',
3749             cls : 'navbar'
3750         };
3751           
3752         
3753         cfg.cn = [
3754             {
3755                 cls: 'nav',
3756                 tag : 'ul'
3757             }
3758         ];
3759         
3760          
3761         this.type = this.type || 'nav';
3762         if (['tabs','pills'].indexOf(this.type)!==-1) {
3763             cfg.cn[0].cls += ' nav-' + this.type
3764         
3765         
3766         } else {
3767             if (this.type!=='nav') {
3768                 Roo.log('nav type must be nav/tabs/pills')
3769             }
3770             cfg.cn[0].cls += ' navbar-nav'
3771         }
3772         
3773         
3774         
3775         
3776         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3777             cfg.cn[0].cls += ' nav-' + this.arrangement;
3778         }
3779         
3780         
3781         if (this.align === 'right') {
3782             cfg.cn[0].cls += ' navbar-right';
3783         }
3784         
3785         if (this.inverse) {
3786             cfg.cls += ' navbar-inverse';
3787             
3788         }
3789         
3790         
3791         return cfg;
3792     
3793         
3794     }
3795     
3796     
3797     
3798 });
3799
3800
3801
3802  
3803
3804  
3805        /*
3806  * - LGPL
3807  *
3808  * navbar
3809  * 
3810  */
3811
3812 /**
3813  * @class Roo.bootstrap.NavHeaderbar
3814  * @extends Roo.bootstrap.NavSimplebar
3815  * Bootstrap Sidebar class
3816  *
3817  * @cfg {String} brand what is brand
3818  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3819  * @cfg {String} brand_href href of the brand
3820  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3821  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3822  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3823  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3824  * 
3825  * @constructor
3826  * Create a new Sidebar
3827  * @param {Object} config The config object
3828  */
3829
3830
3831 Roo.bootstrap.NavHeaderbar = function(config){
3832     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3833       
3834 };
3835
3836 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3837     
3838     position: '',
3839     brand: '',
3840     brand_href: false,
3841     srButton : true,
3842     autohide : false,
3843     desktopCenter : false,
3844    
3845     
3846     getAutoCreate : function(){
3847         
3848         var   cfg = {
3849             tag: this.nav || 'nav',
3850             cls: 'navbar',
3851             role: 'navigation',
3852             cn: []
3853         };
3854         
3855         var cn = cfg.cn;
3856         if (this.desktopCenter) {
3857             cn.push({cls : 'container', cn : []});
3858             cn = cn[0].cn;
3859         }
3860         
3861         if(this.srButton){
3862             cn.push({
3863                 tag: 'div',
3864                 cls: 'navbar-header',
3865                 cn: [
3866                     {
3867                         tag: 'button',
3868                         type: 'button',
3869                         cls: 'navbar-toggle',
3870                         'data-toggle': 'collapse',
3871                         cn: [
3872                             {
3873                                 tag: 'span',
3874                                 cls: 'sr-only',
3875                                 html: 'Toggle navigation'
3876                             },
3877                             {
3878                                 tag: 'span',
3879                                 cls: 'icon-bar'
3880                             },
3881                             {
3882                                 tag: 'span',
3883                                 cls: 'icon-bar'
3884                             },
3885                             {
3886                                 tag: 'span',
3887                                 cls: 'icon-bar'
3888                             }
3889                         ]
3890                     }
3891                 ]
3892             });
3893         }
3894         
3895         cn.push({
3896             tag: 'div',
3897             cls: 'collapse navbar-collapse',
3898             cn : []
3899         });
3900         
3901         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3902         
3903         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3904             cfg.cls += ' navbar-' + this.position;
3905             
3906             // tag can override this..
3907             
3908             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3909         }
3910         
3911         if (this.brand !== '') {
3912             cn[0].cn.push({
3913                 tag: 'a',
3914                 href: this.brand_href ? this.brand_href : '#',
3915                 cls: 'navbar-brand',
3916                 cn: [
3917                 this.brand
3918                 ]
3919             });
3920         }
3921         
3922         if(this.main){
3923             cfg.cls += ' main-nav';
3924         }
3925         
3926         
3927         return cfg;
3928
3929         
3930     },
3931     getHeaderChildContainer : function()
3932     {
3933         if (this.srButton && this.el.select('.navbar-header').getCount()) {
3934             return this.el.select('.navbar-header',true).first();
3935         }
3936         
3937         return this.getChildContainer();
3938     },
3939     
3940     
3941     initEvents : function()
3942     {
3943         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3944         
3945         if (this.autohide) {
3946             
3947             var prevScroll = 0;
3948             var ft = this.el;
3949             
3950             Roo.get(document).on('scroll',function(e) {
3951                 var ns = Roo.get(document).getScroll().top;
3952                 var os = prevScroll;
3953                 prevScroll = ns;
3954                 
3955                 if(ns > os){
3956                     ft.removeClass('slideDown');
3957                     ft.addClass('slideUp');
3958                     return;
3959                 }
3960                 ft.removeClass('slideUp');
3961                 ft.addClass('slideDown');
3962                  
3963               
3964           },this);
3965         }
3966     }    
3967     
3968 });
3969
3970
3971
3972  
3973
3974  /*
3975  * - LGPL
3976  *
3977  * navbar
3978  * 
3979  */
3980
3981 /**
3982  * @class Roo.bootstrap.NavSidebar
3983  * @extends Roo.bootstrap.Navbar
3984  * Bootstrap Sidebar class
3985  * 
3986  * @constructor
3987  * Create a new Sidebar
3988  * @param {Object} config The config object
3989  */
3990
3991
3992 Roo.bootstrap.NavSidebar = function(config){
3993     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3994 };
3995
3996 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
3997     
3998     sidebar : true, // used by Navbar Item and NavbarGroup at present...
3999     
4000     getAutoCreate : function(){
4001         
4002         
4003         return  {
4004             tag: 'div',
4005             cls: 'sidebar sidebar-nav'
4006         };
4007     
4008         
4009     }
4010     
4011     
4012     
4013 });
4014
4015
4016
4017  
4018
4019  /*
4020  * - LGPL
4021  *
4022  * nav group
4023  * 
4024  */
4025
4026 /**
4027  * @class Roo.bootstrap.NavGroup
4028  * @extends Roo.bootstrap.Component
4029  * Bootstrap NavGroup class
4030  * @cfg {String} align (left|right)
4031  * @cfg {Boolean} inverse
4032  * @cfg {String} type (nav|pills|tab) default nav
4033  * @cfg {String} navId - reference Id for navbar.
4034
4035  * 
4036  * @constructor
4037  * Create a new nav group
4038  * @param {Object} config The config object
4039  */
4040
4041 Roo.bootstrap.NavGroup = function(config){
4042     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4043     this.navItems = [];
4044    
4045     Roo.bootstrap.NavGroup.register(this);
4046      this.addEvents({
4047         /**
4048              * @event changed
4049              * Fires when the active item changes
4050              * @param {Roo.bootstrap.NavGroup} this
4051              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4052              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
4053          */
4054         'changed': true
4055      });
4056     
4057 };
4058
4059 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
4060     
4061     align: '',
4062     inverse: false,
4063     form: false,
4064     type: 'nav',
4065     navId : '',
4066     // private
4067     
4068     navItems : false, 
4069     
4070     getAutoCreate : function()
4071     {
4072         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4073         
4074         cfg = {
4075             tag : 'ul',
4076             cls: 'nav' 
4077         };
4078         
4079         if (['tabs','pills'].indexOf(this.type)!==-1) {
4080             cfg.cls += ' nav-' + this.type
4081         } else {
4082             if (this.type!=='nav') {
4083                 Roo.log('nav type must be nav/tabs/pills')
4084             }
4085             cfg.cls += ' navbar-nav'
4086         }
4087         
4088         if (this.parent() && this.parent().sidebar) {
4089             cfg = {
4090                 tag: 'ul',
4091                 cls: 'dashboard-menu sidebar-menu'
4092             };
4093             
4094             return cfg;
4095         }
4096         
4097         if (this.form === true) {
4098             cfg = {
4099                 tag: 'form',
4100                 cls: 'navbar-form'
4101             };
4102             
4103             if (this.align === 'right') {
4104                 cfg.cls += ' navbar-right';
4105             } else {
4106                 cfg.cls += ' navbar-left';
4107             }
4108         }
4109         
4110         if (this.align === 'right') {
4111             cfg.cls += ' navbar-right';
4112         }
4113         
4114         if (this.inverse) {
4115             cfg.cls += ' navbar-inverse';
4116             
4117         }
4118         
4119         
4120         return cfg;
4121     },
4122     /**
4123     * sets the active Navigation item
4124     * @param {Roo.bootstrap.NavItem} the new current navitem
4125     */
4126     setActiveItem : function(item)
4127     {
4128         var prev = false;
4129         Roo.each(this.navItems, function(v){
4130             if (v == item) {
4131                 return ;
4132             }
4133             if (v.isActive()) {
4134                 v.setActive(false, true);
4135                 prev = v;
4136                 
4137             }
4138             
4139         });
4140
4141         item.setActive(true, true);
4142         this.fireEvent('changed', this, item, prev);
4143         
4144         
4145     },
4146     /**
4147     * gets the active Navigation item
4148     * @return {Roo.bootstrap.NavItem} the current navitem
4149     */
4150     getActive : function()
4151     {
4152         
4153         var prev = false;
4154         Roo.each(this.navItems, function(v){
4155             
4156             if (v.isActive()) {
4157                 prev = v;
4158                 
4159             }
4160             
4161         });
4162         return prev;
4163     },
4164     
4165     indexOfNav : function()
4166     {
4167         
4168         var prev = false;
4169         Roo.each(this.navItems, function(v,i){
4170             
4171             if (v.isActive()) {
4172                 prev = i;
4173                 
4174             }
4175             
4176         });
4177         return prev;
4178     },
4179     /**
4180     * adds a Navigation item
4181     * @param {Roo.bootstrap.NavItem} the navitem to add
4182     */
4183     addItem : function(cfg)
4184     {
4185         var cn = new Roo.bootstrap.NavItem(cfg);
4186         this.register(cn);
4187         cn.parentId = this.id;
4188         cn.onRender(this.el, null);
4189         return cn;
4190     },
4191     /**
4192     * register a Navigation item
4193     * @param {Roo.bootstrap.NavItem} the navitem to add
4194     */
4195     register : function(item)
4196     {
4197         this.navItems.push( item);
4198         item.navId = this.navId;
4199     
4200     },
4201     
4202     /**
4203     * clear all the Navigation item
4204     */
4205    
4206     clearAll : function()
4207     {
4208         this.navItems = [];
4209         this.el.dom.innerHTML = '';
4210     },
4211     
4212     getNavItem: function(tabId)
4213     {
4214         var ret = false;
4215         Roo.each(this.navItems, function(e) {
4216             if (e.tabId == tabId) {
4217                ret =  e;
4218                return false;
4219             }
4220             return true;
4221             
4222         });
4223         return ret;
4224     },
4225     
4226     setActiveNext : function()
4227     {
4228         var i = this.indexOfNav(this.getActive());
4229         if (i > this.navItems.length) {
4230             return;
4231         }
4232         this.setActiveItem(this.navItems[i+1]);
4233     },
4234     setActivePrev : function()
4235     {
4236         var i = this.indexOfNav(this.getActive());
4237         if (i  < 1) {
4238             return;
4239         }
4240         this.setActiveItem(this.navItems[i-1]);
4241     },
4242     clearWasActive : function(except) {
4243         Roo.each(this.navItems, function(e) {
4244             if (e.tabId != except.tabId && e.was_active) {
4245                e.was_active = false;
4246                return false;
4247             }
4248             return true;
4249             
4250         });
4251     },
4252     getWasActive : function ()
4253     {
4254         var r = false;
4255         Roo.each(this.navItems, function(e) {
4256             if (e.was_active) {
4257                r = e;
4258                return false;
4259             }
4260             return true;
4261             
4262         });
4263         return r;
4264     }
4265     
4266     
4267 });
4268
4269  
4270 Roo.apply(Roo.bootstrap.NavGroup, {
4271     
4272     groups: {},
4273      /**
4274     * register a Navigation Group
4275     * @param {Roo.bootstrap.NavGroup} the navgroup to add
4276     */
4277     register : function(navgrp)
4278     {
4279         this.groups[navgrp.navId] = navgrp;
4280         
4281     },
4282     /**
4283     * fetch a Navigation Group based on the navigation ID
4284     * @param {string} the navgroup to add
4285     * @returns {Roo.bootstrap.NavGroup} the navgroup 
4286     */
4287     get: function(navId) {
4288         if (typeof(this.groups[navId]) == 'undefined') {
4289             return false;
4290             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4291         }
4292         return this.groups[navId] ;
4293     }
4294     
4295     
4296     
4297 });
4298
4299  /*
4300  * - LGPL
4301  *
4302  * row
4303  * 
4304  */
4305
4306 /**
4307  * @class Roo.bootstrap.NavItem
4308  * @extends Roo.bootstrap.Component
4309  * Bootstrap Navbar.NavItem class
4310  * @cfg {String} href  link to
4311  * @cfg {String} html content of button
4312  * @cfg {String} badge text inside badge
4313  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4314  * @cfg {String} glyphicon name of glyphicon
4315  * @cfg {String} icon name of font awesome icon
4316  * @cfg {Boolean} active Is item active
4317  * @cfg {Boolean} disabled Is item disabled
4318  
4319  * @cfg {Boolean} preventDefault (true | false) default false
4320  * @cfg {String} tabId the tab that this item activates.
4321  * @cfg {String} tagtype (a|span) render as a href or span?
4322  * @cfg {Boolean} animateRef (true|false) link to element default false  
4323   
4324  * @constructor
4325  * Create a new Navbar Item
4326  * @param {Object} config The config object
4327  */
4328 Roo.bootstrap.NavItem = function(config){
4329     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4330     this.addEvents({
4331         // raw events
4332         /**
4333          * @event click
4334          * The raw click event for the entire grid.
4335          * @param {Roo.EventObject} e
4336          */
4337         "click" : true,
4338          /**
4339             * @event changed
4340             * Fires when the active item active state changes
4341             * @param {Roo.bootstrap.NavItem} this
4342             * @param {boolean} state the new state
4343              
4344          */
4345         'changed': true,
4346         /**
4347             * @event scrollto
4348             * Fires when scroll to element
4349             * @param {Roo.bootstrap.NavItem} this
4350             * @param {Object} options
4351             * @param {Roo.EventObject} e
4352              
4353          */
4354         'scrollto': true
4355     });
4356    
4357 };
4358
4359 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
4360     
4361     href: false,
4362     html: '',
4363     badge: '',
4364     icon: false,
4365     glyphicon: false,
4366     active: false,
4367     preventDefault : false,
4368     tabId : false,
4369     tagtype : 'a',
4370     disabled : false,
4371     animateRef : false,
4372     was_active : false,
4373     
4374     getAutoCreate : function(){
4375          
4376         var cfg = {
4377             tag: 'li',
4378             cls: 'nav-item'
4379             
4380         };
4381         
4382         if (this.active) {
4383             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4384         }
4385         if (this.disabled) {
4386             cfg.cls += ' disabled';
4387         }
4388         
4389         if (this.href || this.html || this.glyphicon || this.icon) {
4390             cfg.cn = [
4391                 {
4392                     tag: this.tagtype,
4393                     href : this.href || "#",
4394                     html: this.html || ''
4395                 }
4396             ];
4397             
4398             if (this.icon) {
4399                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4400             }
4401
4402             if(this.glyphicon) {
4403                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
4404             }
4405             
4406             if (this.menu) {
4407                 
4408                 cfg.cn[0].html += " <span class='caret'></span>";
4409              
4410             }
4411             
4412             if (this.badge !== '') {
4413                  
4414                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4415             }
4416         }
4417         
4418         
4419         
4420         return cfg;
4421     },
4422     initEvents: function() 
4423     {
4424         if (typeof (this.menu) != 'undefined') {
4425             this.menu.parentType = this.xtype;
4426             this.menu.triggerEl = this.el;
4427             this.menu = this.addxtype(Roo.apply({}, this.menu));
4428         }
4429         
4430         this.el.select('a',true).on('click', this.onClick, this);
4431         
4432         if(this.tagtype == 'span'){
4433             this.el.select('span',true).on('click', this.onClick, this);
4434         }
4435        
4436         // at this point parent should be available..
4437         this.parent().register(this);
4438     },
4439     
4440     onClick : function(e)
4441     {
4442         if (e.getTarget('.dropdown-menu-item')) {
4443             // did you click on a menu itemm.... - then don't trigger onclick..
4444             return;
4445         }
4446         
4447         if(
4448                 this.preventDefault || 
4449                 this.href == '#' 
4450         ){
4451             Roo.log("NavItem - prevent Default?");
4452             e.preventDefault();
4453         }
4454         
4455         if (this.disabled) {
4456             return;
4457         }
4458         
4459         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4460         if (tg && tg.transition) {
4461             Roo.log("waiting for the transitionend");
4462             return;
4463         }
4464         
4465         
4466         
4467         //Roo.log("fire event clicked");
4468         if(this.fireEvent('click', this, e) === false){
4469             return;
4470         };
4471         
4472         if(this.tagtype == 'span'){
4473             return;
4474         }
4475         
4476         //Roo.log(this.href);
4477         var ael = this.el.select('a',true).first();
4478         //Roo.log(ael);
4479         
4480         if(ael && this.animateRef && this.href.indexOf('#') > -1){
4481             //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4482             if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4483                 return; // ignore... - it's a 'hash' to another page.
4484             }
4485             Roo.log("NavItem - prevent Default?");
4486             e.preventDefault();
4487             this.scrollToElement(e);
4488         }
4489         
4490         
4491         var p =  this.parent();
4492    
4493         if (['tabs','pills'].indexOf(p.type)!==-1) {
4494             if (typeof(p.setActiveItem) !== 'undefined') {
4495                 p.setActiveItem(this);
4496             }
4497         }
4498         
4499         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4500         if (p.parentType == 'NavHeaderbar' && !this.menu) {
4501             // remove the collapsed menu expand...
4502             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
4503         }
4504     },
4505     
4506     isActive: function () {
4507         return this.active
4508     },
4509     setActive : function(state, fire, is_was_active)
4510     {
4511         if (this.active && !state && this.navId) {
4512             this.was_active = true;
4513             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4514             if (nv) {
4515                 nv.clearWasActive(this);
4516             }
4517             
4518         }
4519         this.active = state;
4520         
4521         if (!state ) {
4522             this.el.removeClass('active');
4523         } else if (!this.el.hasClass('active')) {
4524             this.el.addClass('active');
4525         }
4526         if (fire) {
4527             this.fireEvent('changed', this, state);
4528         }
4529         
4530         // show a panel if it's registered and related..
4531         
4532         if (!this.navId || !this.tabId || !state || is_was_active) {
4533             return;
4534         }
4535         
4536         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4537         if (!tg) {
4538             return;
4539         }
4540         var pan = tg.getPanelByName(this.tabId);
4541         if (!pan) {
4542             return;
4543         }
4544         // if we can not flip to new panel - go back to old nav highlight..
4545         if (false == tg.showPanel(pan)) {
4546             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4547             if (nv) {
4548                 var onav = nv.getWasActive();
4549                 if (onav) {
4550                     onav.setActive(true, false, true);
4551                 }
4552             }
4553             
4554         }
4555         
4556         
4557         
4558     },
4559      // this should not be here...
4560     setDisabled : function(state)
4561     {
4562         this.disabled = state;
4563         if (!state ) {
4564             this.el.removeClass('disabled');
4565         } else if (!this.el.hasClass('disabled')) {
4566             this.el.addClass('disabled');
4567         }
4568         
4569     },
4570     
4571     /**
4572      * Fetch the element to display the tooltip on.
4573      * @return {Roo.Element} defaults to this.el
4574      */
4575     tooltipEl : function()
4576     {
4577         return this.el.select('' + this.tagtype + '', true).first();
4578     },
4579     
4580     scrollToElement : function(e)
4581     {
4582         var c = document.body;
4583         
4584         /*
4585          * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4586          */
4587         if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4588             c = document.documentElement;
4589         }
4590         
4591         var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4592         
4593         if(!target){
4594             return;
4595         }
4596
4597         var o = target.calcOffsetsTo(c);
4598         
4599         var options = {
4600             target : target,
4601             value : o[1]
4602         };
4603         
4604         this.fireEvent('scrollto', this, options, e);
4605         
4606         Roo.get(c).scrollTo('top', options.value, true);
4607         
4608         return;
4609     }
4610 });
4611  
4612
4613  /*
4614  * - LGPL
4615  *
4616  * sidebar item
4617  *
4618  *  li
4619  *    <span> icon </span>
4620  *    <span> text </span>
4621  *    <span>badge </span>
4622  */
4623
4624 /**
4625  * @class Roo.bootstrap.NavSidebarItem
4626  * @extends Roo.bootstrap.NavItem
4627  * Bootstrap Navbar.NavSidebarItem class
4628  * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4629  * {Boolean} open is the menu open
4630  * {Boolean} buttonView use button as the tigger el rather that a (default false)
4631  * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4632  * {String} buttonSize (sm|md|lg)the extra classes for the button
4633  * {Boolean} showArrow show arrow next to the text (default true)
4634  * @constructor
4635  * Create a new Navbar Button
4636  * @param {Object} config The config object
4637  */
4638 Roo.bootstrap.NavSidebarItem = function(config){
4639     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4640     this.addEvents({
4641         // raw events
4642         /**
4643          * @event click
4644          * The raw click event for the entire grid.
4645          * @param {Roo.EventObject} e
4646          */
4647         "click" : true,
4648          /**
4649             * @event changed
4650             * Fires when the active item active state changes
4651             * @param {Roo.bootstrap.NavSidebarItem} this
4652             * @param {boolean} state the new state
4653              
4654          */
4655         'changed': true
4656     });
4657    
4658 };
4659
4660 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4661     
4662     badgeWeight : 'default',
4663     
4664     open: false,
4665     
4666     buttonView : false,
4667     
4668     buttonWeight : 'default',
4669     
4670     buttonSize : 'md',
4671     
4672     showArrow : true,
4673     
4674     getAutoCreate : function(){
4675         
4676         
4677         var a = {
4678                 tag: 'a',
4679                 href : this.href || '#',
4680                 cls: '',
4681                 html : '',
4682                 cn : []
4683         };
4684         
4685         if(this.buttonView){
4686             a = {
4687                 tag: 'button',
4688                 href : this.href || '#',
4689                 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4690                 html : this.html,
4691                 cn : []
4692             };
4693         }
4694         
4695         var cfg = {
4696             tag: 'li',
4697             cls: '',
4698             cn: [ a ]
4699         };
4700         
4701         if (this.active) {
4702             cfg.cls += ' active';
4703         }
4704         
4705         if (this.disabled) {
4706             cfg.cls += ' disabled';
4707         }
4708         if (this.open) {
4709             cfg.cls += ' open x-open';
4710         }
4711         // left icon..
4712         if (this.glyphicon || this.icon) {
4713             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4714             a.cn.push({ tag : 'i', cls : c }) ;
4715         }
4716         
4717         if(!this.buttonView){
4718             var span = {
4719                 tag: 'span',
4720                 html : this.html || ''
4721             };
4722
4723             a.cn.push(span);
4724             
4725         }
4726         
4727         if (this.badge !== '') {
4728             a.cn.push({ tag: 'span',  cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge }); 
4729         }
4730         
4731         if (this.menu) {
4732             
4733             if(this.showArrow){
4734                 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4735             }
4736             
4737             a.cls += ' dropdown-toggle treeview' ;
4738         }
4739         
4740         return cfg;
4741     },
4742     
4743     initEvents : function()
4744     { 
4745         if (typeof (this.menu) != 'undefined') {
4746             this.menu.parentType = this.xtype;
4747             this.menu.triggerEl = this.el;
4748             this.menu = this.addxtype(Roo.apply({}, this.menu));
4749         }
4750         
4751         this.el.on('click', this.onClick, this);
4752         
4753         if(this.badge !== ''){
4754             this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4755         }
4756         
4757     },
4758     
4759     onClick : function(e)
4760     {
4761         if(this.disabled){
4762             e.preventDefault();
4763             return;
4764         }
4765         
4766         if(this.preventDefault){
4767             e.preventDefault();
4768         }
4769         
4770         this.fireEvent('click', this);
4771     },
4772     
4773     disable : function()
4774     {
4775         this.setDisabled(true);
4776     },
4777     
4778     enable : function()
4779     {
4780         this.setDisabled(false);
4781     },
4782     
4783     setDisabled : function(state)
4784     {
4785         if(this.disabled == state){
4786             return;
4787         }
4788         
4789         this.disabled = state;
4790         
4791         if (state) {
4792             this.el.addClass('disabled');
4793             return;
4794         }
4795         
4796         this.el.removeClass('disabled');
4797         
4798         return;
4799     },
4800     
4801     setActive : function(state)
4802     {
4803         if(this.active == state){
4804             return;
4805         }
4806         
4807         this.active = state;
4808         
4809         if (state) {
4810             this.el.addClass('active');
4811             return;
4812         }
4813         
4814         this.el.removeClass('active');
4815         
4816         return;
4817     },
4818     
4819     isActive: function () 
4820     {
4821         return this.active;
4822     },
4823     
4824     setBadge : function(str)
4825     {
4826         if(!this.badgeEl){
4827             return;
4828         }
4829         
4830         this.badgeEl.dom.innerHTML = str;
4831     }
4832     
4833    
4834      
4835  
4836 });
4837  
4838
4839  /*
4840  * - LGPL
4841  *
4842  * row
4843  * 
4844  */
4845
4846 /**
4847  * @class Roo.bootstrap.Row
4848  * @extends Roo.bootstrap.Component
4849  * Bootstrap Row class (contains columns...)
4850  * 
4851  * @constructor
4852  * Create a new Row
4853  * @param {Object} config The config object
4854  */
4855
4856 Roo.bootstrap.Row = function(config){
4857     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4858 };
4859
4860 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4861     
4862     getAutoCreate : function(){
4863        return {
4864             cls: 'row clearfix'
4865        };
4866     }
4867     
4868     
4869 });
4870
4871  
4872
4873  /*
4874  * - LGPL
4875  *
4876  * element
4877  * 
4878  */
4879
4880 /**
4881  * @class Roo.bootstrap.Element
4882  * @extends Roo.bootstrap.Component
4883  * Bootstrap Element class
4884  * @cfg {String} html contents of the element
4885  * @cfg {String} tag tag of the element
4886  * @cfg {String} cls class of the element
4887  * @cfg {Boolean} preventDefault (true|false) default false
4888  * @cfg {Boolean} clickable (true|false) default false
4889  * 
4890  * @constructor
4891  * Create a new Element
4892  * @param {Object} config The config object
4893  */
4894
4895 Roo.bootstrap.Element = function(config){
4896     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4897     
4898     this.addEvents({
4899         // raw events
4900         /**
4901          * @event click
4902          * When a element is chick
4903          * @param {Roo.bootstrap.Element} this
4904          * @param {Roo.EventObject} e
4905          */
4906         "click" : true
4907     });
4908 };
4909
4910 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4911     
4912     tag: 'div',
4913     cls: '',
4914     html: '',
4915     preventDefault: false, 
4916     clickable: false,
4917     
4918     getAutoCreate : function(){
4919         
4920         var cfg = {
4921             tag: this.tag,
4922             cls: this.cls,
4923             html: this.html
4924         };
4925         
4926         return cfg;
4927     },
4928     
4929     initEvents: function() 
4930     {
4931         Roo.bootstrap.Element.superclass.initEvents.call(this);
4932         
4933         if(this.clickable){
4934             this.el.on('click', this.onClick, this);
4935         }
4936         
4937     },
4938     
4939     onClick : function(e)
4940     {
4941         if(this.preventDefault){
4942             e.preventDefault();
4943         }
4944         
4945         this.fireEvent('click', this, e);
4946     },
4947     
4948     getValue : function()
4949     {
4950         return this.el.dom.innerHTML;
4951     },
4952     
4953     setValue : function(value)
4954     {
4955         this.el.dom.innerHTML = value;
4956     }
4957    
4958 });
4959
4960  
4961
4962  /*
4963  * - LGPL
4964  *
4965  * pagination
4966  * 
4967  */
4968
4969 /**
4970  * @class Roo.bootstrap.Pagination
4971  * @extends Roo.bootstrap.Component
4972  * Bootstrap Pagination class
4973  * @cfg {String} size xs | sm | md | lg
4974  * @cfg {Boolean} inverse false | true
4975  * 
4976  * @constructor
4977  * Create a new Pagination
4978  * @param {Object} config The config object
4979  */
4980
4981 Roo.bootstrap.Pagination = function(config){
4982     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4983 };
4984
4985 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
4986     
4987     cls: false,
4988     size: false,
4989     inverse: false,
4990     
4991     getAutoCreate : function(){
4992         var cfg = {
4993             tag: 'ul',
4994                 cls: 'pagination'
4995         };
4996         if (this.inverse) {
4997             cfg.cls += ' inverse';
4998         }
4999         if (this.html) {
5000             cfg.html=this.html;
5001         }
5002         if (this.cls) {
5003             cfg.cls += " " + this.cls;
5004         }
5005         return cfg;
5006     }
5007    
5008 });
5009
5010  
5011
5012  /*
5013  * - LGPL
5014  *
5015  * Pagination item
5016  * 
5017  */
5018
5019
5020 /**
5021  * @class Roo.bootstrap.PaginationItem
5022  * @extends Roo.bootstrap.Component
5023  * Bootstrap PaginationItem class
5024  * @cfg {String} html text
5025  * @cfg {String} href the link
5026  * @cfg {Boolean} preventDefault (true | false) default true
5027  * @cfg {Boolean} active (true | false) default false
5028  * @cfg {Boolean} disabled default false
5029  * 
5030  * 
5031  * @constructor
5032  * Create a new PaginationItem
5033  * @param {Object} config The config object
5034  */
5035
5036
5037 Roo.bootstrap.PaginationItem = function(config){
5038     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5039     this.addEvents({
5040         // raw events
5041         /**
5042          * @event click
5043          * The raw click event for the entire grid.
5044          * @param {Roo.EventObject} e
5045          */
5046         "click" : true
5047     });
5048 };
5049
5050 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
5051     
5052     href : false,
5053     html : false,
5054     preventDefault: true,
5055     active : false,
5056     cls : false,
5057     disabled: false,
5058     
5059     getAutoCreate : function(){
5060         var cfg= {
5061             tag: 'li',
5062             cn: [
5063                 {
5064                     tag : 'a',
5065                     href : this.href ? this.href : '#',
5066                     html : this.html ? this.html : ''
5067                 }
5068             ]
5069         };
5070         
5071         if(this.cls){
5072             cfg.cls = this.cls;
5073         }
5074         
5075         if(this.disabled){
5076             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5077         }
5078         
5079         if(this.active){
5080             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5081         }
5082         
5083         return cfg;
5084     },
5085     
5086     initEvents: function() {
5087         
5088         this.el.on('click', this.onClick, this);
5089         
5090     },
5091     onClick : function(e)
5092     {
5093         Roo.log('PaginationItem on click ');
5094         if(this.preventDefault){
5095             e.preventDefault();
5096         }
5097         
5098         if(this.disabled){
5099             return;
5100         }
5101         
5102         this.fireEvent('click', this, e);
5103     }
5104    
5105 });
5106
5107  
5108
5109  /*
5110  * - LGPL
5111  *
5112  * slider
5113  * 
5114  */
5115
5116
5117 /**
5118  * @class Roo.bootstrap.Slider
5119  * @extends Roo.bootstrap.Component
5120  * Bootstrap Slider class
5121  *    
5122  * @constructor
5123  * Create a new Slider
5124  * @param {Object} config The config object
5125  */
5126
5127 Roo.bootstrap.Slider = function(config){
5128     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5129 };
5130
5131 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
5132     
5133     getAutoCreate : function(){
5134         
5135         var cfg = {
5136             tag: 'div',
5137             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5138             cn: [
5139                 {
5140                     tag: 'a',
5141                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
5142                 }
5143             ]
5144         };
5145         
5146         return cfg;
5147     }
5148    
5149 });
5150
5151  /*
5152  * Based on:
5153  * Ext JS Library 1.1.1
5154  * Copyright(c) 2006-2007, Ext JS, LLC.
5155  *
5156  * Originally Released Under LGPL - original licence link has changed is not relivant.
5157  *
5158  * Fork - LGPL
5159  * <script type="text/javascript">
5160  */
5161  
5162
5163 /**
5164  * @class Roo.grid.ColumnModel
5165  * @extends Roo.util.Observable
5166  * This is the default implementation of a ColumnModel used by the Grid. It defines
5167  * the columns in the grid.
5168  * <br>Usage:<br>
5169  <pre><code>
5170  var colModel = new Roo.grid.ColumnModel([
5171         {header: "Ticker", width: 60, sortable: true, locked: true},
5172         {header: "Company Name", width: 150, sortable: true},
5173         {header: "Market Cap.", width: 100, sortable: true},
5174         {header: "$ Sales", width: 100, sortable: true, renderer: money},
5175         {header: "Employees", width: 100, sortable: true, resizable: false}
5176  ]);
5177  </code></pre>
5178  * <p>
5179  
5180  * The config options listed for this class are options which may appear in each
5181  * individual column definition.
5182  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5183  * @constructor
5184  * @param {Object} config An Array of column config objects. See this class's
5185  * config objects for details.
5186 */
5187 Roo.grid.ColumnModel = function(config){
5188         /**
5189      * The config passed into the constructor
5190      */
5191     this.config = config;
5192     this.lookup = {};
5193
5194     // if no id, create one
5195     // if the column does not have a dataIndex mapping,
5196     // map it to the order it is in the config
5197     for(var i = 0, len = config.length; i < len; i++){
5198         var c = config[i];
5199         if(typeof c.dataIndex == "undefined"){
5200             c.dataIndex = i;
5201         }
5202         if(typeof c.renderer == "string"){
5203             c.renderer = Roo.util.Format[c.renderer];
5204         }
5205         if(typeof c.id == "undefined"){
5206             c.id = Roo.id();
5207         }
5208         if(c.editor && c.editor.xtype){
5209             c.editor  = Roo.factory(c.editor, Roo.grid);
5210         }
5211         if(c.editor && c.editor.isFormField){
5212             c.editor = new Roo.grid.GridEditor(c.editor);
5213         }
5214         this.lookup[c.id] = c;
5215     }
5216
5217     /**
5218      * The width of columns which have no width specified (defaults to 100)
5219      * @type Number
5220      */
5221     this.defaultWidth = 100;
5222
5223     /**
5224      * Default sortable of columns which have no sortable specified (defaults to false)
5225      * @type Boolean
5226      */
5227     this.defaultSortable = false;
5228
5229     this.addEvents({
5230         /**
5231              * @event widthchange
5232              * Fires when the width of a column changes.
5233              * @param {ColumnModel} this
5234              * @param {Number} columnIndex The column index
5235              * @param {Number} newWidth The new width
5236              */
5237             "widthchange": true,
5238         /**
5239              * @event headerchange
5240              * Fires when the text of a header changes.
5241              * @param {ColumnModel} this
5242              * @param {Number} columnIndex The column index
5243              * @param {Number} newText The new header text
5244              */
5245             "headerchange": true,
5246         /**
5247              * @event hiddenchange
5248              * Fires when a column is hidden or "unhidden".
5249              * @param {ColumnModel} this
5250              * @param {Number} columnIndex The column index
5251              * @param {Boolean} hidden true if hidden, false otherwise
5252              */
5253             "hiddenchange": true,
5254             /**
5255          * @event columnmoved
5256          * Fires when a column is moved.
5257          * @param {ColumnModel} this
5258          * @param {Number} oldIndex
5259          * @param {Number} newIndex
5260          */
5261         "columnmoved" : true,
5262         /**
5263          * @event columlockchange
5264          * Fires when a column's locked state is changed
5265          * @param {ColumnModel} this
5266          * @param {Number} colIndex
5267          * @param {Boolean} locked true if locked
5268          */
5269         "columnlockchange" : true
5270     });
5271     Roo.grid.ColumnModel.superclass.constructor.call(this);
5272 };
5273 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5274     /**
5275      * @cfg {String} header The header text to display in the Grid view.
5276      */
5277     /**
5278      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5279      * {@link Roo.data.Record} definition from which to draw the column's value. If not
5280      * specified, the column's index is used as an index into the Record's data Array.
5281      */
5282     /**
5283      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5284      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5285      */
5286     /**
5287      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5288      * Defaults to the value of the {@link #defaultSortable} property.
5289      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5290      */
5291     /**
5292      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
5293      */
5294     /**
5295      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
5296      */
5297     /**
5298      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5299      */
5300     /**
5301      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5302      */
5303     /**
5304      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5305      * given the cell's data value. See {@link #setRenderer}. If not specified, the
5306      * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5307      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5308      */
5309        /**
5310      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
5311      */
5312     /**
5313      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
5314      */
5315     /**
5316      * @cfg {String} cursor (Optional)
5317      */
5318     /**
5319      * @cfg {String} tooltip (Optional)
5320      */
5321     /**
5322      * @cfg {Number} xs (Optional)
5323      */
5324     /**
5325      * @cfg {Number} sm (Optional)
5326      */
5327     /**
5328      * @cfg {Number} md (Optional)
5329      */
5330     /**
5331      * @cfg {Number} lg (Optional)
5332      */
5333     /**
5334      * Returns the id of the column at the specified index.
5335      * @param {Number} index The column index
5336      * @return {String} the id
5337      */
5338     getColumnId : function(index){
5339         return this.config[index].id;
5340     },
5341
5342     /**
5343      * Returns the column for a specified id.
5344      * @param {String} id The column id
5345      * @return {Object} the column
5346      */
5347     getColumnById : function(id){
5348         return this.lookup[id];
5349     },
5350
5351     
5352     /**
5353      * Returns the column for a specified dataIndex.
5354      * @param {String} dataIndex The column dataIndex
5355      * @return {Object|Boolean} the column or false if not found
5356      */
5357     getColumnByDataIndex: function(dataIndex){
5358         var index = this.findColumnIndex(dataIndex);
5359         return index > -1 ? this.config[index] : false;
5360     },
5361     
5362     /**
5363      * Returns the index for a specified column id.
5364      * @param {String} id The column id
5365      * @return {Number} the index, or -1 if not found
5366      */
5367     getIndexById : function(id){
5368         for(var i = 0, len = this.config.length; i < len; i++){
5369             if(this.config[i].id == id){
5370                 return i;
5371             }
5372         }
5373         return -1;
5374     },
5375     
5376     /**
5377      * Returns the index for a specified column dataIndex.
5378      * @param {String} dataIndex The column dataIndex
5379      * @return {Number} the index, or -1 if not found
5380      */
5381     
5382     findColumnIndex : function(dataIndex){
5383         for(var i = 0, len = this.config.length; i < len; i++){
5384             if(this.config[i].dataIndex == dataIndex){
5385                 return i;
5386             }
5387         }
5388         return -1;
5389     },
5390     
5391     
5392     moveColumn : function(oldIndex, newIndex){
5393         var c = this.config[oldIndex];
5394         this.config.splice(oldIndex, 1);
5395         this.config.splice(newIndex, 0, c);
5396         this.dataMap = null;
5397         this.fireEvent("columnmoved", this, oldIndex, newIndex);
5398     },
5399
5400     isLocked : function(colIndex){
5401         return this.config[colIndex].locked === true;
5402     },
5403
5404     setLocked : function(colIndex, value, suppressEvent){
5405         if(this.isLocked(colIndex) == value){
5406             return;
5407         }
5408         this.config[colIndex].locked = value;
5409         if(!suppressEvent){
5410             this.fireEvent("columnlockchange", this, colIndex, value);
5411         }
5412     },
5413
5414     getTotalLockedWidth : function(){
5415         var totalWidth = 0;
5416         for(var i = 0; i < this.config.length; i++){
5417             if(this.isLocked(i) && !this.isHidden(i)){
5418                 this.totalWidth += this.getColumnWidth(i);
5419             }
5420         }
5421         return totalWidth;
5422     },
5423
5424     getLockedCount : function(){
5425         for(var i = 0, len = this.config.length; i < len; i++){
5426             if(!this.isLocked(i)){
5427                 return i;
5428             }
5429         }
5430         
5431         return this.config.length;
5432     },
5433
5434     /**
5435      * Returns the number of columns.
5436      * @return {Number}
5437      */
5438     getColumnCount : function(visibleOnly){
5439         if(visibleOnly === true){
5440             var c = 0;
5441             for(var i = 0, len = this.config.length; i < len; i++){
5442                 if(!this.isHidden(i)){
5443                     c++;
5444                 }
5445             }
5446             return c;
5447         }
5448         return this.config.length;
5449     },
5450
5451     /**
5452      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5453      * @param {Function} fn
5454      * @param {Object} scope (optional)
5455      * @return {Array} result
5456      */
5457     getColumnsBy : function(fn, scope){
5458         var r = [];
5459         for(var i = 0, len = this.config.length; i < len; i++){
5460             var c = this.config[i];
5461             if(fn.call(scope||this, c, i) === true){
5462                 r[r.length] = c;
5463             }
5464         }
5465         return r;
5466     },
5467
5468     /**
5469      * Returns true if the specified column is sortable.
5470      * @param {Number} col The column index
5471      * @return {Boolean}
5472      */
5473     isSortable : function(col){
5474         if(typeof this.config[col].sortable == "undefined"){
5475             return this.defaultSortable;
5476         }
5477         return this.config[col].sortable;
5478     },
5479
5480     /**
5481      * Returns the rendering (formatting) function defined for the column.
5482      * @param {Number} col The column index.
5483      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5484      */
5485     getRenderer : function(col){
5486         if(!this.config[col].renderer){
5487             return Roo.grid.ColumnModel.defaultRenderer;
5488         }
5489         return this.config[col].renderer;
5490     },
5491
5492     /**
5493      * Sets the rendering (formatting) function for a column.
5494      * @param {Number} col The column index
5495      * @param {Function} fn The function to use to process the cell's raw data
5496      * to return HTML markup for the grid view. The render function is called with
5497      * the following parameters:<ul>
5498      * <li>Data value.</li>
5499      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5500      * <li>css A CSS style string to apply to the table cell.</li>
5501      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5502      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5503      * <li>Row index</li>
5504      * <li>Column index</li>
5505      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5506      */
5507     setRenderer : function(col, fn){
5508         this.config[col].renderer = fn;
5509     },
5510
5511     /**
5512      * Returns the width for the specified column.
5513      * @param {Number} col The column index
5514      * @return {Number}
5515      */
5516     getColumnWidth : function(col){
5517         return this.config[col].width * 1 || this.defaultWidth;
5518     },
5519
5520     /**
5521      * Sets the width for a column.
5522      * @param {Number} col The column index
5523      * @param {Number} width The new width
5524      */
5525     setColumnWidth : function(col, width, suppressEvent){
5526         this.config[col].width = width;
5527         this.totalWidth = null;
5528         if(!suppressEvent){
5529              this.fireEvent("widthchange", this, col, width);
5530         }
5531     },
5532
5533     /**
5534      * Returns the total width of all columns.
5535      * @param {Boolean} includeHidden True to include hidden column widths
5536      * @return {Number}
5537      */
5538     getTotalWidth : function(includeHidden){
5539         if(!this.totalWidth){
5540             this.totalWidth = 0;
5541             for(var i = 0, len = this.config.length; i < len; i++){
5542                 if(includeHidden || !this.isHidden(i)){
5543                     this.totalWidth += this.getColumnWidth(i);
5544                 }
5545             }
5546         }
5547         return this.totalWidth;
5548     },
5549
5550     /**
5551      * Returns the header for the specified column.
5552      * @param {Number} col The column index
5553      * @return {String}
5554      */
5555     getColumnHeader : function(col){
5556         return this.config[col].header;
5557     },
5558
5559     /**
5560      * Sets the header for a column.
5561      * @param {Number} col The column index
5562      * @param {String} header The new header
5563      */
5564     setColumnHeader : function(col, header){
5565         this.config[col].header = header;
5566         this.fireEvent("headerchange", this, col, header);
5567     },
5568
5569     /**
5570      * Returns the tooltip for the specified column.
5571      * @param {Number} col The column index
5572      * @return {String}
5573      */
5574     getColumnTooltip : function(col){
5575             return this.config[col].tooltip;
5576     },
5577     /**
5578      * Sets the tooltip for a column.
5579      * @param {Number} col The column index
5580      * @param {String} tooltip The new tooltip
5581      */
5582     setColumnTooltip : function(col, tooltip){
5583             this.config[col].tooltip = tooltip;
5584     },
5585
5586     /**
5587      * Returns the dataIndex for the specified column.
5588      * @param {Number} col The column index
5589      * @return {Number}
5590      */
5591     getDataIndex : function(col){
5592         return this.config[col].dataIndex;
5593     },
5594
5595     /**
5596      * Sets the dataIndex for a column.
5597      * @param {Number} col The column index
5598      * @param {Number} dataIndex The new dataIndex
5599      */
5600     setDataIndex : function(col, dataIndex){
5601         this.config[col].dataIndex = dataIndex;
5602     },
5603
5604     
5605     
5606     /**
5607      * Returns true if the cell is editable.
5608      * @param {Number} colIndex The column index
5609      * @param {Number} rowIndex The row index - this is nto actually used..?
5610      * @return {Boolean}
5611      */
5612     isCellEditable : function(colIndex, rowIndex){
5613         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5614     },
5615
5616     /**
5617      * Returns the editor defined for the cell/column.
5618      * return false or null to disable editing.
5619      * @param {Number} colIndex The column index
5620      * @param {Number} rowIndex The row index
5621      * @return {Object}
5622      */
5623     getCellEditor : function(colIndex, rowIndex){
5624         return this.config[colIndex].editor;
5625     },
5626
5627     /**
5628      * Sets if a column is editable.
5629      * @param {Number} col The column index
5630      * @param {Boolean} editable True if the column is editable
5631      */
5632     setEditable : function(col, editable){
5633         this.config[col].editable = editable;
5634     },
5635
5636
5637     /**
5638      * Returns true if the column is hidden.
5639      * @param {Number} colIndex The column index
5640      * @return {Boolean}
5641      */
5642     isHidden : function(colIndex){
5643         return this.config[colIndex].hidden;
5644     },
5645
5646
5647     /**
5648      * Returns true if the column width cannot be changed
5649      */
5650     isFixed : function(colIndex){
5651         return this.config[colIndex].fixed;
5652     },
5653
5654     /**
5655      * Returns true if the column can be resized
5656      * @return {Boolean}
5657      */
5658     isResizable : function(colIndex){
5659         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5660     },
5661     /**
5662      * Sets if a column is hidden.
5663      * @param {Number} colIndex The column index
5664      * @param {Boolean} hidden True if the column is hidden
5665      */
5666     setHidden : function(colIndex, hidden){
5667         this.config[colIndex].hidden = hidden;
5668         this.totalWidth = null;
5669         this.fireEvent("hiddenchange", this, colIndex, hidden);
5670     },
5671
5672     /**
5673      * Sets the editor for a column.
5674      * @param {Number} col The column index
5675      * @param {Object} editor The editor object
5676      */
5677     setEditor : function(col, editor){
5678         this.config[col].editor = editor;
5679     }
5680 });
5681
5682 Roo.grid.ColumnModel.defaultRenderer = function(value)
5683 {
5684     if(typeof value == "object") {
5685         return value;
5686     }
5687         if(typeof value == "string" && value.length < 1){
5688             return "&#160;";
5689         }
5690     
5691         return String.format("{0}", value);
5692 };
5693
5694 // Alias for backwards compatibility
5695 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5696 /*
5697  * Based on:
5698  * Ext JS Library 1.1.1
5699  * Copyright(c) 2006-2007, Ext JS, LLC.
5700  *
5701  * Originally Released Under LGPL - original licence link has changed is not relivant.
5702  *
5703  * Fork - LGPL
5704  * <script type="text/javascript">
5705  */
5706  
5707 /**
5708  * @class Roo.LoadMask
5709  * A simple utility class for generically masking elements while loading data.  If the element being masked has
5710  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5711  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
5712  * element's UpdateManager load indicator and will be destroyed after the initial load.
5713  * @constructor
5714  * Create a new LoadMask
5715  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5716  * @param {Object} config The config object
5717  */
5718 Roo.LoadMask = function(el, config){
5719     this.el = Roo.get(el);
5720     Roo.apply(this, config);
5721     if(this.store){
5722         this.store.on('beforeload', this.onBeforeLoad, this);
5723         this.store.on('load', this.onLoad, this);
5724         this.store.on('loadexception', this.onLoadException, this);
5725         this.removeMask = false;
5726     }else{
5727         var um = this.el.getUpdateManager();
5728         um.showLoadIndicator = false; // disable the default indicator
5729         um.on('beforeupdate', this.onBeforeLoad, this);
5730         um.on('update', this.onLoad, this);
5731         um.on('failure', this.onLoad, this);
5732         this.removeMask = true;
5733     }
5734 };
5735
5736 Roo.LoadMask.prototype = {
5737     /**
5738      * @cfg {Boolean} removeMask
5739      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5740      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
5741      */
5742     /**
5743      * @cfg {String} msg
5744      * The text to display in a centered loading message box (defaults to 'Loading...')
5745      */
5746     msg : 'Loading...',
5747     /**
5748      * @cfg {String} msgCls
5749      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5750      */
5751     msgCls : 'x-mask-loading',
5752
5753     /**
5754      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5755      * @type Boolean
5756      */
5757     disabled: false,
5758
5759     /**
5760      * Disables the mask to prevent it from being displayed
5761      */
5762     disable : function(){
5763        this.disabled = true;
5764     },
5765
5766     /**
5767      * Enables the mask so that it can be displayed
5768      */
5769     enable : function(){
5770         this.disabled = false;
5771     },
5772     
5773     onLoadException : function()
5774     {
5775         Roo.log(arguments);
5776         
5777         if (typeof(arguments[3]) != 'undefined') {
5778             Roo.MessageBox.alert("Error loading",arguments[3]);
5779         } 
5780         /*
5781         try {
5782             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5783                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5784             }   
5785         } catch(e) {
5786             
5787         }
5788         */
5789     
5790         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5791     },
5792     // private
5793     onLoad : function()
5794     {
5795         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5796     },
5797
5798     // private
5799     onBeforeLoad : function(){
5800         if(!this.disabled){
5801             (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5802         }
5803     },
5804
5805     // private
5806     destroy : function(){
5807         if(this.store){
5808             this.store.un('beforeload', this.onBeforeLoad, this);
5809             this.store.un('load', this.onLoad, this);
5810             this.store.un('loadexception', this.onLoadException, this);
5811         }else{
5812             var um = this.el.getUpdateManager();
5813             um.un('beforeupdate', this.onBeforeLoad, this);
5814             um.un('update', this.onLoad, this);
5815             um.un('failure', this.onLoad, this);
5816         }
5817     }
5818 };/*
5819  * - LGPL
5820  *
5821  * table
5822  * 
5823  */
5824
5825 /**
5826  * @class Roo.bootstrap.Table
5827  * @extends Roo.bootstrap.Component
5828  * Bootstrap Table class
5829  * @cfg {String} cls table class
5830  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5831  * @cfg {String} bgcolor Specifies the background color for a table
5832  * @cfg {Number} border Specifies whether the table cells should have borders or not
5833  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5834  * @cfg {Number} cellspacing Specifies the space between cells
5835  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5836  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5837  * @cfg {String} sortable Specifies that the table should be sortable
5838  * @cfg {String} summary Specifies a summary of the content of a table
5839  * @cfg {Number} width Specifies the width of a table
5840  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5841  * 
5842  * @cfg {boolean} striped Should the rows be alternative striped
5843  * @cfg {boolean} bordered Add borders to the table
5844  * @cfg {boolean} hover Add hover highlighting
5845  * @cfg {boolean} condensed Format condensed
5846  * @cfg {boolean} responsive Format condensed
5847  * @cfg {Boolean} loadMask (true|false) default false
5848  * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5849  * @cfg {Boolean} headerShow (true|false) generate thead, default true
5850  * @cfg {Boolean} rowSelection (true|false) default false
5851  * @cfg {Boolean} cellSelection (true|false) default false
5852  * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5853  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5854  * @cfg {Boolean} lazyLoad  auto load data while scrolling to the end (default false)
5855  
5856  * 
5857  * @constructor
5858  * Create a new Table
5859  * @param {Object} config The config object
5860  */
5861
5862 Roo.bootstrap.Table = function(config){
5863     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5864     
5865   
5866     
5867     // BC...
5868     this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5869     this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5870     this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5871     this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5872     
5873     this.sm = this.sm || {xtype: 'RowSelectionModel'};
5874     if (this.sm) {
5875         this.sm.grid = this;
5876         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5877         this.sm = this.selModel;
5878         this.sm.xmodule = this.xmodule || false;
5879     }
5880     
5881     if (this.cm && typeof(this.cm.config) == 'undefined') {
5882         this.colModel = new Roo.grid.ColumnModel(this.cm);
5883         this.cm = this.colModel;
5884         this.cm.xmodule = this.xmodule || false;
5885     }
5886     if (this.store) {
5887         this.store= Roo.factory(this.store, Roo.data);
5888         this.ds = this.store;
5889         this.ds.xmodule = this.xmodule || false;
5890          
5891     }
5892     if (this.footer && this.store) {
5893         this.footer.dataSource = this.ds;
5894         this.footer = Roo.factory(this.footer);
5895     }
5896     
5897     /** @private */
5898     this.addEvents({
5899         /**
5900          * @event cellclick
5901          * Fires when a cell is clicked
5902          * @param {Roo.bootstrap.Table} this
5903          * @param {Roo.Element} el
5904          * @param {Number} rowIndex
5905          * @param {Number} columnIndex
5906          * @param {Roo.EventObject} e
5907          */
5908         "cellclick" : true,
5909         /**
5910          * @event celldblclick
5911          * Fires when a cell is double clicked
5912          * @param {Roo.bootstrap.Table} this
5913          * @param {Roo.Element} el
5914          * @param {Number} rowIndex
5915          * @param {Number} columnIndex
5916          * @param {Roo.EventObject} e
5917          */
5918         "celldblclick" : true,
5919         /**
5920          * @event rowclick
5921          * Fires when a row is clicked
5922          * @param {Roo.bootstrap.Table} this
5923          * @param {Roo.Element} el
5924          * @param {Number} rowIndex
5925          * @param {Roo.EventObject} e
5926          */
5927         "rowclick" : true,
5928         /**
5929          * @event rowdblclick
5930          * Fires when a row is double clicked
5931          * @param {Roo.bootstrap.Table} this
5932          * @param {Roo.Element} el
5933          * @param {Number} rowIndex
5934          * @param {Roo.EventObject} e
5935          */
5936         "rowdblclick" : true,
5937         /**
5938          * @event mouseover
5939          * Fires when a mouseover occur
5940          * @param {Roo.bootstrap.Table} this
5941          * @param {Roo.Element} el
5942          * @param {Number} rowIndex
5943          * @param {Number} columnIndex
5944          * @param {Roo.EventObject} e
5945          */
5946         "mouseover" : true,
5947         /**
5948          * @event mouseout
5949          * Fires when a mouseout occur
5950          * @param {Roo.bootstrap.Table} this
5951          * @param {Roo.Element} el
5952          * @param {Number} rowIndex
5953          * @param {Number} columnIndex
5954          * @param {Roo.EventObject} e
5955          */
5956         "mouseout" : true,
5957         /**
5958          * @event rowclass
5959          * Fires when a row is rendered, so you can change add a style to it.
5960          * @param {Roo.bootstrap.Table} this
5961          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5962          */
5963         'rowclass' : true,
5964           /**
5965          * @event rowsrendered
5966          * Fires when all the  rows have been rendered
5967          * @param {Roo.bootstrap.Table} this
5968          */
5969         'rowsrendered' : true,
5970         /**
5971          * @event contextmenu
5972          * The raw contextmenu event for the entire grid.
5973          * @param {Roo.EventObject} e
5974          */
5975         "contextmenu" : true,
5976         /**
5977          * @event rowcontextmenu
5978          * Fires when a row is right clicked
5979          * @param {Roo.bootstrap.Table} this
5980          * @param {Number} rowIndex
5981          * @param {Roo.EventObject} e
5982          */
5983         "rowcontextmenu" : true,
5984         /**
5985          * @event cellcontextmenu
5986          * Fires when a cell is right clicked
5987          * @param {Roo.bootstrap.Table} this
5988          * @param {Number} rowIndex
5989          * @param {Number} cellIndex
5990          * @param {Roo.EventObject} e
5991          */
5992          "cellcontextmenu" : true,
5993          /**
5994          * @event headercontextmenu
5995          * Fires when a header is right clicked
5996          * @param {Roo.bootstrap.Table} this
5997          * @param {Number} columnIndex
5998          * @param {Roo.EventObject} e
5999          */
6000         "headercontextmenu" : true
6001     });
6002 };
6003
6004 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
6005     
6006     cls: false,
6007     align: false,
6008     bgcolor: false,
6009     border: false,
6010     cellpadding: false,
6011     cellspacing: false,
6012     frame: false,
6013     rules: false,
6014     sortable: false,
6015     summary: false,
6016     width: false,
6017     striped : false,
6018     scrollBody : false,
6019     bordered: false,
6020     hover:  false,
6021     condensed : false,
6022     responsive : false,
6023     sm : false,
6024     cm : false,
6025     store : false,
6026     loadMask : false,
6027     footerShow : true,
6028     headerShow : true,
6029   
6030     rowSelection : false,
6031     cellSelection : false,
6032     layout : false,
6033     
6034     // Roo.Element - the tbody
6035     mainBody: false,
6036     // Roo.Element - thead element
6037     mainHead: false,
6038     
6039     container: false, // used by gridpanel...
6040     
6041     lazyLoad : false,
6042     
6043     getAutoCreate : function()
6044     {
6045         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6046         
6047         cfg = {
6048             tag: 'table',
6049             cls : 'table',
6050             cn : []
6051         };
6052         if (this.scrollBody) {
6053             cfg.cls += ' table-body-fixed';
6054         }    
6055         if (this.striped) {
6056             cfg.cls += ' table-striped';
6057         }
6058         
6059         if (this.hover) {
6060             cfg.cls += ' table-hover';
6061         }
6062         if (this.bordered) {
6063             cfg.cls += ' table-bordered';
6064         }
6065         if (this.condensed) {
6066             cfg.cls += ' table-condensed';
6067         }
6068         if (this.responsive) {
6069             cfg.cls += ' table-responsive';
6070         }
6071         
6072         if (this.cls) {
6073             cfg.cls+=  ' ' +this.cls;
6074         }
6075         
6076         // this lot should be simplifed...
6077         
6078         if (this.align) {
6079             cfg.align=this.align;
6080         }
6081         if (this.bgcolor) {
6082             cfg.bgcolor=this.bgcolor;
6083         }
6084         if (this.border) {
6085             cfg.border=this.border;
6086         }
6087         if (this.cellpadding) {
6088             cfg.cellpadding=this.cellpadding;
6089         }
6090         if (this.cellspacing) {
6091             cfg.cellspacing=this.cellspacing;
6092         }
6093         if (this.frame) {
6094             cfg.frame=this.frame;
6095         }
6096         if (this.rules) {
6097             cfg.rules=this.rules;
6098         }
6099         if (this.sortable) {
6100             cfg.sortable=this.sortable;
6101         }
6102         if (this.summary) {
6103             cfg.summary=this.summary;
6104         }
6105         if (this.width) {
6106             cfg.width=this.width;
6107         }
6108         if (this.layout) {
6109             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6110         }
6111         
6112         if(this.store || this.cm){
6113             if(this.headerShow){
6114                 cfg.cn.push(this.renderHeader());
6115             }
6116             
6117             cfg.cn.push(this.renderBody());
6118             
6119             if(this.footerShow){
6120                 cfg.cn.push(this.renderFooter());
6121             }
6122             // where does this come from?
6123             //cfg.cls+=  ' TableGrid';
6124         }
6125         
6126         return { cn : [ cfg ] };
6127     },
6128     
6129     initEvents : function()
6130     {   
6131         if(!this.store || !this.cm){
6132             return;
6133         }
6134         if (this.selModel) {
6135             this.selModel.initEvents();
6136         }
6137         
6138         
6139         //Roo.log('initEvents with ds!!!!');
6140         
6141         this.mainBody = this.el.select('tbody', true).first();
6142         this.mainHead = this.el.select('thead', true).first();
6143         
6144         
6145         
6146         
6147         var _this = this;
6148         
6149         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6150             e.on('click', _this.sort, _this);
6151         });
6152         
6153         this.mainBody.on("click", this.onClick, this);
6154         this.mainBody.on("dblclick", this.onDblClick, this);
6155         
6156         // why is this done????? = it breaks dialogs??
6157         //this.parent().el.setStyle('position', 'relative');
6158         
6159         
6160         if (this.footer) {
6161             this.footer.parentId = this.id;
6162             this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6163             
6164             if(this.lazyLoad){
6165                 this.el.select('tfoot tr td').first().addClass('hide');
6166             }
6167         } 
6168         
6169         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6170         
6171         this.store.on('load', this.onLoad, this);
6172         this.store.on('beforeload', this.onBeforeLoad, this);
6173         this.store.on('update', this.onUpdate, this);
6174         this.store.on('add', this.onAdd, this);
6175         this.store.on("clear", this.clear, this);
6176         
6177         this.el.on("contextmenu", this.onContextMenu, this);
6178         
6179         this.mainBody.on('scroll', this.onBodyScroll, this);
6180         
6181         this.cm.on("headerchange", this.onHeaderChange, this);
6182         
6183     },
6184     
6185     onContextMenu : function(e, t)
6186     {
6187         this.processEvent("contextmenu", e);
6188     },
6189     
6190     processEvent : function(name, e)
6191     {
6192         if (name != 'touchstart' ) {
6193             this.fireEvent(name, e);    
6194         }
6195         
6196         var t = e.getTarget();
6197         
6198         var cell = Roo.get(t);
6199         
6200         if(!cell){
6201             return;
6202         }
6203         
6204         if(cell.findParent('tfoot', false, true)){
6205             return;
6206         }
6207         
6208         if(cell.findParent('thead', false, true)){
6209             
6210             if(e.getTarget().nodeName.toLowerCase() != 'th'){
6211                 cell = Roo.get(t).findParent('th', false, true);
6212                 if (!cell) {
6213                     Roo.log("failed to find th in thead?");
6214                     Roo.log(e.getTarget());
6215                     return;
6216                 }
6217             }
6218             
6219             var cellIndex = cell.dom.cellIndex;
6220             
6221             var ename = name == 'touchstart' ? 'click' : name;
6222             this.fireEvent("header" + ename, this, cellIndex, e);
6223             
6224             return;
6225         }
6226         
6227         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6228             cell = Roo.get(t).findParent('td', false, true);
6229             if (!cell) {
6230                 Roo.log("failed to find th in tbody?");
6231                 Roo.log(e.getTarget());
6232                 return;
6233             }
6234         }
6235         
6236         var row = cell.findParent('tr', false, true);
6237         var cellIndex = cell.dom.cellIndex;
6238         var rowIndex = row.dom.rowIndex - 1;
6239         
6240         if(row !== false){
6241             
6242             this.fireEvent("row" + name, this, rowIndex, e);
6243             
6244             if(cell !== false){
6245             
6246                 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6247             }
6248         }
6249         
6250     },
6251     
6252     onMouseover : function(e, el)
6253     {
6254         var cell = Roo.get(el);
6255         
6256         if(!cell){
6257             return;
6258         }
6259         
6260         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6261             cell = cell.findParent('td', false, true);
6262         }
6263         
6264         var row = cell.findParent('tr', false, true);
6265         var cellIndex = cell.dom.cellIndex;
6266         var rowIndex = row.dom.rowIndex - 1; // start from 0
6267         
6268         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6269         
6270     },
6271     
6272     onMouseout : function(e, el)
6273     {
6274         var cell = Roo.get(el);
6275         
6276         if(!cell){
6277             return;
6278         }
6279         
6280         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6281             cell = cell.findParent('td', false, true);
6282         }
6283         
6284         var row = cell.findParent('tr', false, true);
6285         var cellIndex = cell.dom.cellIndex;
6286         var rowIndex = row.dom.rowIndex - 1; // start from 0
6287         
6288         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6289         
6290     },
6291     
6292     onClick : function(e, el)
6293     {
6294         var cell = Roo.get(el);
6295         
6296         if(!cell || (!this.cellSelection && !this.rowSelection)){
6297             return;
6298         }
6299         
6300         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6301             cell = cell.findParent('td', false, true);
6302         }
6303         
6304         if(!cell || typeof(cell) == 'undefined'){
6305             return;
6306         }
6307         
6308         var row = cell.findParent('tr', false, true);
6309         
6310         if(!row || typeof(row) == 'undefined'){
6311             return;
6312         }
6313         
6314         var cellIndex = cell.dom.cellIndex;
6315         var rowIndex = this.getRowIndex(row);
6316         
6317         // why??? - should these not be based on SelectionModel?
6318         if(this.cellSelection){
6319             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6320         }
6321         
6322         if(this.rowSelection){
6323             this.fireEvent('rowclick', this, row, rowIndex, e);
6324         }
6325         
6326         
6327     },
6328         
6329     onDblClick : function(e,el)
6330     {
6331         var cell = Roo.get(el);
6332         
6333         if(!cell || (!this.cellSelection && !this.rowSelection)){
6334             return;
6335         }
6336         
6337         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6338             cell = cell.findParent('td', false, true);
6339         }
6340         
6341         if(!cell || typeof(cell) == 'undefined'){
6342             return;
6343         }
6344         
6345         var row = cell.findParent('tr', false, true);
6346         
6347         if(!row || typeof(row) == 'undefined'){
6348             return;
6349         }
6350         
6351         var cellIndex = cell.dom.cellIndex;
6352         var rowIndex = this.getRowIndex(row);
6353         
6354         if(this.cellSelection){
6355             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6356         }
6357         
6358         if(this.rowSelection){
6359             this.fireEvent('rowdblclick', this, row, rowIndex, e);
6360         }
6361     },
6362     
6363     sort : function(e,el)
6364     {
6365         var col = Roo.get(el);
6366         
6367         if(!col.hasClass('sortable')){
6368             return;
6369         }
6370         
6371         var sort = col.attr('sort');
6372         var dir = 'ASC';
6373         
6374         if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6375             dir = 'DESC';
6376         }
6377         
6378         this.store.sortInfo = {field : sort, direction : dir};
6379         
6380         if (this.footer) {
6381             Roo.log("calling footer first");
6382             this.footer.onClick('first');
6383         } else {
6384         
6385             this.store.load({ params : { start : 0 } });
6386         }
6387     },
6388     
6389     renderHeader : function()
6390     {
6391         var header = {
6392             tag: 'thead',
6393             cn : []
6394         };
6395         
6396         var cm = this.cm;
6397         this.totalWidth = 0;
6398         
6399         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6400             
6401             var config = cm.config[i];
6402             
6403             var c = {
6404                 tag: 'th',
6405                 style : '',
6406                 html: cm.getColumnHeader(i)
6407             };
6408             
6409             var hh = '';
6410             
6411             if(typeof(config.sortable) != 'undefined' && config.sortable){
6412                 c.cls = 'sortable';
6413                 c.html = '<i class="glyphicon"></i>' + c.html;
6414             }
6415             
6416             if(typeof(config.lgHeader) != 'undefined'){
6417                 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6418             }
6419             
6420             if(typeof(config.mdHeader) != 'undefined'){
6421                 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6422             }
6423             
6424             if(typeof(config.smHeader) != 'undefined'){
6425                 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6426             }
6427             
6428             if(typeof(config.xsHeader) != 'undefined'){
6429                 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6430             }
6431             
6432             if(hh.length){
6433                 c.html = hh;
6434             }
6435             
6436             if(typeof(config.tooltip) != 'undefined'){
6437                 c.tooltip = config.tooltip;
6438             }
6439             
6440             if(typeof(config.colspan) != 'undefined'){
6441                 c.colspan = config.colspan;
6442             }
6443             
6444             if(typeof(config.hidden) != 'undefined' && config.hidden){
6445                 c.style += ' display:none;';
6446             }
6447             
6448             if(typeof(config.dataIndex) != 'undefined'){
6449                 c.sort = config.dataIndex;
6450             }
6451             
6452            
6453             
6454             if(typeof(config.align) != 'undefined' && config.align.length){
6455                 c.style += ' text-align:' + config.align + ';';
6456             }
6457             
6458             if(typeof(config.width) != 'undefined'){
6459                 c.style += ' width:' + config.width + 'px;';
6460                 this.totalWidth += config.width;
6461             } else {
6462                 this.totalWidth += 100; // assume minimum of 100 per column?
6463             }
6464             
6465             if(typeof(config.cls) != 'undefined'){
6466                 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6467             }
6468             
6469             ['xs','sm','md','lg'].map(function(size){
6470                 
6471                 if(typeof(config[size]) == 'undefined'){
6472                     return;
6473                 }
6474                 
6475                 if (!config[size]) { // 0 = hidden
6476                     c.cls += ' hidden-' + size;
6477                     return;
6478                 }
6479                 
6480                 c.cls += ' col-' + size + '-' + config[size];
6481
6482             });
6483             
6484             header.cn.push(c)
6485         }
6486         
6487         return header;
6488     },
6489     
6490     renderBody : function()
6491     {
6492         var body = {
6493             tag: 'tbody',
6494             cn : [
6495                 {
6496                     tag: 'tr',
6497                     cn : [
6498                         {
6499                             tag : 'td',
6500                             colspan :  this.cm.getColumnCount()
6501                         }
6502                     ]
6503                 }
6504             ]
6505         };
6506         
6507         return body;
6508     },
6509     
6510     renderFooter : function()
6511     {
6512         var footer = {
6513             tag: 'tfoot',
6514             cn : [
6515                 {
6516                     tag: 'tr',
6517                     cn : [
6518                         {
6519                             tag : 'td',
6520                             colspan :  this.cm.getColumnCount()
6521                         }
6522                     ]
6523                 }
6524             ]
6525         };
6526         
6527         return footer;
6528     },
6529     
6530     
6531     
6532     onLoad : function()
6533     {
6534 //        Roo.log('ds onload');
6535         this.clear();
6536         
6537         var _this = this;
6538         var cm = this.cm;
6539         var ds = this.store;
6540         
6541         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6542             e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6543             if (_this.store.sortInfo) {
6544                     
6545                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6546                     e.select('i', true).addClass(['glyphicon-arrow-up']);
6547                 }
6548                 
6549                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6550                     e.select('i', true).addClass(['glyphicon-arrow-down']);
6551                 }
6552             }
6553         });
6554         
6555         var tbody =  this.mainBody;
6556               
6557         if(ds.getCount() > 0){
6558             ds.data.each(function(d,rowIndex){
6559                 var row =  this.renderRow(cm, ds, rowIndex);
6560                 
6561                 tbody.createChild(row);
6562                 
6563                 var _this = this;
6564                 
6565                 if(row.cellObjects.length){
6566                     Roo.each(row.cellObjects, function(r){
6567                         _this.renderCellObject(r);
6568                     })
6569                 }
6570                 
6571             }, this);
6572         }
6573         
6574         Roo.each(this.el.select('tbody td', true).elements, function(e){
6575             e.on('mouseover', _this.onMouseover, _this);
6576         });
6577         
6578         Roo.each(this.el.select('tbody td', true).elements, function(e){
6579             e.on('mouseout', _this.onMouseout, _this);
6580         });
6581         this.fireEvent('rowsrendered', this);
6582         //if(this.loadMask){
6583         //    this.maskEl.hide();
6584         //}
6585         
6586         this.autoSize();
6587     },
6588     
6589     
6590     onUpdate : function(ds,record)
6591     {
6592         this.refreshRow(record);
6593         this.autoSize();
6594     },
6595     
6596     onRemove : function(ds, record, index, isUpdate){
6597         if(isUpdate !== true){
6598             this.fireEvent("beforerowremoved", this, index, record);
6599         }
6600         var bt = this.mainBody.dom;
6601         
6602         var rows = this.el.select('tbody > tr', true).elements;
6603         
6604         if(typeof(rows[index]) != 'undefined'){
6605             bt.removeChild(rows[index].dom);
6606         }
6607         
6608 //        if(bt.rows[index]){
6609 //            bt.removeChild(bt.rows[index]);
6610 //        }
6611         
6612         if(isUpdate !== true){
6613             //this.stripeRows(index);
6614             //this.syncRowHeights(index, index);
6615             //this.layout();
6616             this.fireEvent("rowremoved", this, index, record);
6617         }
6618     },
6619     
6620     onAdd : function(ds, records, rowIndex)
6621     {
6622         //Roo.log('on Add called');
6623         // - note this does not handle multiple adding very well..
6624         var bt = this.mainBody.dom;
6625         for (var i =0 ; i < records.length;i++) {
6626             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6627             //Roo.log(records[i]);
6628             //Roo.log(this.store.getAt(rowIndex+i));
6629             this.insertRow(this.store, rowIndex + i, false);
6630             return;
6631         }
6632         
6633     },
6634     
6635     
6636     refreshRow : function(record){
6637         var ds = this.store, index;
6638         if(typeof record == 'number'){
6639             index = record;
6640             record = ds.getAt(index);
6641         }else{
6642             index = ds.indexOf(record);
6643         }
6644         this.insertRow(ds, index, true);
6645         this.autoSize();
6646         this.onRemove(ds, record, index+1, true);
6647         this.autoSize();
6648         //this.syncRowHeights(index, index);
6649         //this.layout();
6650         this.fireEvent("rowupdated", this, index, record);
6651     },
6652     
6653     insertRow : function(dm, rowIndex, isUpdate){
6654         
6655         if(!isUpdate){
6656             this.fireEvent("beforerowsinserted", this, rowIndex);
6657         }
6658             //var s = this.getScrollState();
6659         var row = this.renderRow(this.cm, this.store, rowIndex);
6660         // insert before rowIndex..
6661         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6662         
6663         var _this = this;
6664                 
6665         if(row.cellObjects.length){
6666             Roo.each(row.cellObjects, function(r){
6667                 _this.renderCellObject(r);
6668             })
6669         }
6670             
6671         if(!isUpdate){
6672             this.fireEvent("rowsinserted", this, rowIndex);
6673             //this.syncRowHeights(firstRow, lastRow);
6674             //this.stripeRows(firstRow);
6675             //this.layout();
6676         }
6677         
6678     },
6679     
6680     
6681     getRowDom : function(rowIndex)
6682     {
6683         var rows = this.el.select('tbody > tr', true).elements;
6684         
6685         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6686         
6687     },
6688     // returns the object tree for a tr..
6689   
6690     
6691     renderRow : function(cm, ds, rowIndex) 
6692     {
6693         
6694         var d = ds.getAt(rowIndex);
6695         
6696         var row = {
6697             tag : 'tr',
6698             cn : []
6699         };
6700             
6701         var cellObjects = [];
6702         
6703         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6704             var config = cm.config[i];
6705             
6706             var renderer = cm.getRenderer(i);
6707             var value = '';
6708             var id = false;
6709             
6710             if(typeof(renderer) !== 'undefined'){
6711                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6712             }
6713             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6714             // and are rendered into the cells after the row is rendered - using the id for the element.
6715             
6716             if(typeof(value) === 'object'){
6717                 id = Roo.id();
6718                 cellObjects.push({
6719                     container : id,
6720                     cfg : value 
6721                 })
6722             }
6723             
6724             var rowcfg = {
6725                 record: d,
6726                 rowIndex : rowIndex,
6727                 colIndex : i,
6728                 rowClass : ''
6729             };
6730
6731             this.fireEvent('rowclass', this, rowcfg);
6732             
6733             var td = {
6734                 tag: 'td',
6735                 cls : rowcfg.rowClass,
6736                 style: '',
6737                 html: (typeof(value) === 'object') ? '' : value
6738             };
6739             
6740             if (id) {
6741                 td.id = id;
6742             }
6743             
6744             if(typeof(config.colspan) != 'undefined'){
6745                 td.colspan = config.colspan;
6746             }
6747             
6748             if(typeof(config.hidden) != 'undefined' && config.hidden){
6749                 td.style += ' display:none;';
6750             }
6751             
6752             if(typeof(config.align) != 'undefined' && config.align.length){
6753                 td.style += ' text-align:' + config.align + ';';
6754             }
6755             
6756             if(typeof(config.width) != 'undefined'){
6757                 td.style += ' width:' +  config.width + 'px;';
6758             }
6759             
6760             if(typeof(config.cursor) != 'undefined'){
6761                 td.style += ' cursor:' +  config.cursor + ';';
6762             }
6763             
6764             if(typeof(config.cls) != 'undefined'){
6765                 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6766             }
6767             
6768             ['xs','sm','md','lg'].map(function(size){
6769                 
6770                 if(typeof(config[size]) == 'undefined'){
6771                     return;
6772                 }
6773                 
6774                 if (!config[size]) { // 0 = hidden
6775                     td.cls += ' hidden-' + size;
6776                     return;
6777                 }
6778                 
6779                 td.cls += ' col-' + size + '-' + config[size];
6780
6781             });
6782              
6783             row.cn.push(td);
6784            
6785         }
6786         
6787         row.cellObjects = cellObjects;
6788         
6789         return row;
6790           
6791     },
6792     
6793     
6794     
6795     onBeforeLoad : function()
6796     {
6797         //Roo.log('ds onBeforeLoad');
6798         
6799         //this.clear();
6800         
6801         //if(this.loadMask){
6802         //    this.maskEl.show();
6803         //}
6804     },
6805      /**
6806      * Remove all rows
6807      */
6808     clear : function()
6809     {
6810         this.el.select('tbody', true).first().dom.innerHTML = '';
6811     },
6812     /**
6813      * Show or hide a row.
6814      * @param {Number} rowIndex to show or hide
6815      * @param {Boolean} state hide
6816      */
6817     setRowVisibility : function(rowIndex, state)
6818     {
6819         var bt = this.mainBody.dom;
6820         
6821         var rows = this.el.select('tbody > tr', true).elements;
6822         
6823         if(typeof(rows[rowIndex]) == 'undefined'){
6824             return;
6825         }
6826         rows[rowIndex].dom.style.display = state ? '' : 'none';
6827     },
6828     
6829     
6830     getSelectionModel : function(){
6831         if(!this.selModel){
6832             this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6833         }
6834         return this.selModel;
6835     },
6836     /*
6837      * Render the Roo.bootstrap object from renderder
6838      */
6839     renderCellObject : function(r)
6840     {
6841         var _this = this;
6842         
6843         r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6844         
6845         var t = r.cfg.render(r.container);
6846         
6847         if(r.cfg.cn){
6848             Roo.each(r.cfg.cn, function(c){
6849                 var child = {
6850                     container: t.getChildContainer(),
6851                     cfg: c
6852                 };
6853                 _this.renderCellObject(child);
6854             })
6855         }
6856     },
6857     
6858     getRowIndex : function(row)
6859     {
6860         var rowIndex = -1;
6861         
6862         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6863             if(el != row){
6864                 return;
6865             }
6866             
6867             rowIndex = index;
6868         });
6869         
6870         return rowIndex;
6871     },
6872      /**
6873      * Returns the grid's underlying element = used by panel.Grid
6874      * @return {Element} The element
6875      */
6876     getGridEl : function(){
6877         return this.el;
6878     },
6879      /**
6880      * Forces a resize - used by panel.Grid
6881      * @return {Element} The element
6882      */
6883     autoSize : function()
6884     {
6885         //var ctr = Roo.get(this.container.dom.parentElement);
6886         var ctr = Roo.get(this.el.dom);
6887         
6888         var thd = this.getGridEl().select('thead',true).first();
6889         var tbd = this.getGridEl().select('tbody', true).first();
6890         var tfd = this.getGridEl().select('tfoot', true).first();
6891         
6892         var cw = ctr.getWidth();
6893         
6894         if (tbd) {
6895             
6896             tbd.setSize(ctr.getWidth(),
6897                         ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6898             );
6899             var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6900             cw -= barsize;
6901         }
6902         cw = Math.max(cw, this.totalWidth);
6903         this.getGridEl().select('tr',true).setWidth(cw);
6904         // resize 'expandable coloumn?
6905         
6906         return; // we doe not have a view in this design..
6907         
6908     },
6909     onBodyScroll: function()
6910     {
6911         //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6912         if(this.mainHead){
6913             this.mainHead.setStyle({
6914                 'position' : 'relative',
6915                 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6916             });
6917         }
6918         
6919         if(this.lazyLoad){
6920             
6921             var scrollHeight = this.mainBody.dom.scrollHeight;
6922             
6923             var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6924             
6925             var height = this.mainBody.getHeight();
6926             
6927             if(scrollHeight - height == scrollTop) {
6928                 
6929                 var total = this.ds.getTotalCount();
6930                 
6931                 if(this.footer.cursor + this.footer.pageSize < total){
6932                     
6933                     this.footer.ds.load({
6934                         params : {
6935                             start : this.footer.cursor + this.footer.pageSize,
6936                             limit : this.footer.pageSize
6937                         },
6938                         add : true
6939                     });
6940                 }
6941             }
6942             
6943         }
6944     },
6945     
6946     onHeaderChange : function()
6947     {
6948         
6949         var header = this.renderHeader();
6950         var table = this.el.select('table', true).first();
6951         
6952         this.mainHead.remove();
6953         this.mainHead = table.createChild(header, this.mainBody, false);
6954     }
6955     
6956 });
6957
6958  
6959
6960  /*
6961  * - LGPL
6962  *
6963  * table cell
6964  * 
6965  */
6966
6967 /**
6968  * @class Roo.bootstrap.TableCell
6969  * @extends Roo.bootstrap.Component
6970  * Bootstrap TableCell class
6971  * @cfg {String} html cell contain text
6972  * @cfg {String} cls cell class
6973  * @cfg {String} tag cell tag (td|th) default td
6974  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6975  * @cfg {String} align Aligns the content in a cell
6976  * @cfg {String} axis Categorizes cells
6977  * @cfg {String} bgcolor Specifies the background color of a cell
6978  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6979  * @cfg {Number} colspan Specifies the number of columns a cell should span
6980  * @cfg {String} headers Specifies one or more header cells a cell is related to
6981  * @cfg {Number} height Sets the height of a cell
6982  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6983  * @cfg {Number} rowspan Sets the number of rows a cell should span
6984  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6985  * @cfg {String} valign Vertical aligns the content in a cell
6986  * @cfg {Number} width Specifies the width of a cell
6987  * 
6988  * @constructor
6989  * Create a new TableCell
6990  * @param {Object} config The config object
6991  */
6992
6993 Roo.bootstrap.TableCell = function(config){
6994     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6995 };
6996
6997 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
6998     
6999     html: false,
7000     cls: false,
7001     tag: false,
7002     abbr: false,
7003     align: false,
7004     axis: false,
7005     bgcolor: false,
7006     charoff: false,
7007     colspan: false,
7008     headers: false,
7009     height: false,
7010     nowrap: false,
7011     rowspan: false,
7012     scope: false,
7013     valign: false,
7014     width: false,
7015     
7016     
7017     getAutoCreate : function(){
7018         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7019         
7020         cfg = {
7021             tag: 'td'
7022         };
7023         
7024         if(this.tag){
7025             cfg.tag = this.tag;
7026         }
7027         
7028         if (this.html) {
7029             cfg.html=this.html
7030         }
7031         if (this.cls) {
7032             cfg.cls=this.cls
7033         }
7034         if (this.abbr) {
7035             cfg.abbr=this.abbr
7036         }
7037         if (this.align) {
7038             cfg.align=this.align
7039         }
7040         if (this.axis) {
7041             cfg.axis=this.axis
7042         }
7043         if (this.bgcolor) {
7044             cfg.bgcolor=this.bgcolor
7045         }
7046         if (this.charoff) {
7047             cfg.charoff=this.charoff
7048         }
7049         if (this.colspan) {
7050             cfg.colspan=this.colspan
7051         }
7052         if (this.headers) {
7053             cfg.headers=this.headers
7054         }
7055         if (this.height) {
7056             cfg.height=this.height
7057         }
7058         if (this.nowrap) {
7059             cfg.nowrap=this.nowrap
7060         }
7061         if (this.rowspan) {
7062             cfg.rowspan=this.rowspan
7063         }
7064         if (this.scope) {
7065             cfg.scope=this.scope
7066         }
7067         if (this.valign) {
7068             cfg.valign=this.valign
7069         }
7070         if (this.width) {
7071             cfg.width=this.width
7072         }
7073         
7074         
7075         return cfg;
7076     }
7077    
7078 });
7079
7080  
7081
7082  /*
7083  * - LGPL
7084  *
7085  * table row
7086  * 
7087  */
7088
7089 /**
7090  * @class Roo.bootstrap.TableRow
7091  * @extends Roo.bootstrap.Component
7092  * Bootstrap TableRow class
7093  * @cfg {String} cls row class
7094  * @cfg {String} align Aligns the content in a table row
7095  * @cfg {String} bgcolor Specifies a background color for a table row
7096  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7097  * @cfg {String} valign Vertical aligns the content in a table row
7098  * 
7099  * @constructor
7100  * Create a new TableRow
7101  * @param {Object} config The config object
7102  */
7103
7104 Roo.bootstrap.TableRow = function(config){
7105     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7106 };
7107
7108 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
7109     
7110     cls: false,
7111     align: false,
7112     bgcolor: false,
7113     charoff: false,
7114     valign: false,
7115     
7116     getAutoCreate : function(){
7117         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7118         
7119         cfg = {
7120             tag: 'tr'
7121         };
7122             
7123         if(this.cls){
7124             cfg.cls = this.cls;
7125         }
7126         if(this.align){
7127             cfg.align = this.align;
7128         }
7129         if(this.bgcolor){
7130             cfg.bgcolor = this.bgcolor;
7131         }
7132         if(this.charoff){
7133             cfg.charoff = this.charoff;
7134         }
7135         if(this.valign){
7136             cfg.valign = this.valign;
7137         }
7138         
7139         return cfg;
7140     }
7141    
7142 });
7143
7144  
7145
7146  /*
7147  * - LGPL
7148  *
7149  * table body
7150  * 
7151  */
7152
7153 /**
7154  * @class Roo.bootstrap.TableBody
7155  * @extends Roo.bootstrap.Component
7156  * Bootstrap TableBody class
7157  * @cfg {String} cls element class
7158  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7159  * @cfg {String} align Aligns the content inside the element
7160  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7161  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7162  * 
7163  * @constructor
7164  * Create a new TableBody
7165  * @param {Object} config The config object
7166  */
7167
7168 Roo.bootstrap.TableBody = function(config){
7169     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7170 };
7171
7172 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
7173     
7174     cls: false,
7175     tag: false,
7176     align: false,
7177     charoff: false,
7178     valign: false,
7179     
7180     getAutoCreate : function(){
7181         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7182         
7183         cfg = {
7184             tag: 'tbody'
7185         };
7186             
7187         if (this.cls) {
7188             cfg.cls=this.cls
7189         }
7190         if(this.tag){
7191             cfg.tag = this.tag;
7192         }
7193         
7194         if(this.align){
7195             cfg.align = this.align;
7196         }
7197         if(this.charoff){
7198             cfg.charoff = this.charoff;
7199         }
7200         if(this.valign){
7201             cfg.valign = this.valign;
7202         }
7203         
7204         return cfg;
7205     }
7206     
7207     
7208 //    initEvents : function()
7209 //    {
7210 //        
7211 //        if(!this.store){
7212 //            return;
7213 //        }
7214 //        
7215 //        this.store = Roo.factory(this.store, Roo.data);
7216 //        this.store.on('load', this.onLoad, this);
7217 //        
7218 //        this.store.load();
7219 //        
7220 //    },
7221 //    
7222 //    onLoad: function () 
7223 //    {   
7224 //        this.fireEvent('load', this);
7225 //    }
7226 //    
7227 //   
7228 });
7229
7230  
7231
7232  /*
7233  * Based on:
7234  * Ext JS Library 1.1.1
7235  * Copyright(c) 2006-2007, Ext JS, LLC.
7236  *
7237  * Originally Released Under LGPL - original licence link has changed is not relivant.
7238  *
7239  * Fork - LGPL
7240  * <script type="text/javascript">
7241  */
7242
7243 // as we use this in bootstrap.
7244 Roo.namespace('Roo.form');
7245  /**
7246  * @class Roo.form.Action
7247  * Internal Class used to handle form actions
7248  * @constructor
7249  * @param {Roo.form.BasicForm} el The form element or its id
7250  * @param {Object} config Configuration options
7251  */
7252
7253  
7254  
7255 // define the action interface
7256 Roo.form.Action = function(form, options){
7257     this.form = form;
7258     this.options = options || {};
7259 };
7260 /**
7261  * Client Validation Failed
7262  * @const 
7263  */
7264 Roo.form.Action.CLIENT_INVALID = 'client';
7265 /**
7266  * Server Validation Failed
7267  * @const 
7268  */
7269 Roo.form.Action.SERVER_INVALID = 'server';
7270  /**
7271  * Connect to Server Failed
7272  * @const 
7273  */
7274 Roo.form.Action.CONNECT_FAILURE = 'connect';
7275 /**
7276  * Reading Data from Server Failed
7277  * @const 
7278  */
7279 Roo.form.Action.LOAD_FAILURE = 'load';
7280
7281 Roo.form.Action.prototype = {
7282     type : 'default',
7283     failureType : undefined,
7284     response : undefined,
7285     result : undefined,
7286
7287     // interface method
7288     run : function(options){
7289
7290     },
7291
7292     // interface method
7293     success : function(response){
7294
7295     },
7296
7297     // interface method
7298     handleResponse : function(response){
7299
7300     },
7301
7302     // default connection failure
7303     failure : function(response){
7304         
7305         this.response = response;
7306         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7307         this.form.afterAction(this, false);
7308     },
7309
7310     processResponse : function(response){
7311         this.response = response;
7312         if(!response.responseText){
7313             return true;
7314         }
7315         this.result = this.handleResponse(response);
7316         return this.result;
7317     },
7318
7319     // utility functions used internally
7320     getUrl : function(appendParams){
7321         var url = this.options.url || this.form.url || this.form.el.dom.action;
7322         if(appendParams){
7323             var p = this.getParams();
7324             if(p){
7325                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7326             }
7327         }
7328         return url;
7329     },
7330
7331     getMethod : function(){
7332         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7333     },
7334
7335     getParams : function(){
7336         var bp = this.form.baseParams;
7337         var p = this.options.params;
7338         if(p){
7339             if(typeof p == "object"){
7340                 p = Roo.urlEncode(Roo.applyIf(p, bp));
7341             }else if(typeof p == 'string' && bp){
7342                 p += '&' + Roo.urlEncode(bp);
7343             }
7344         }else if(bp){
7345             p = Roo.urlEncode(bp);
7346         }
7347         return p;
7348     },
7349
7350     createCallback : function(){
7351         return {
7352             success: this.success,
7353             failure: this.failure,
7354             scope: this,
7355             timeout: (this.form.timeout*1000),
7356             upload: this.form.fileUpload ? this.success : undefined
7357         };
7358     }
7359 };
7360
7361 Roo.form.Action.Submit = function(form, options){
7362     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7363 };
7364
7365 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7366     type : 'submit',
7367
7368     haveProgress : false,
7369     uploadComplete : false,
7370     
7371     // uploadProgress indicator.
7372     uploadProgress : function()
7373     {
7374         if (!this.form.progressUrl) {
7375             return;
7376         }
7377         
7378         if (!this.haveProgress) {
7379             Roo.MessageBox.progress("Uploading", "Uploading");
7380         }
7381         if (this.uploadComplete) {
7382            Roo.MessageBox.hide();
7383            return;
7384         }
7385         
7386         this.haveProgress = true;
7387    
7388         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7389         
7390         var c = new Roo.data.Connection();
7391         c.request({
7392             url : this.form.progressUrl,
7393             params: {
7394                 id : uid
7395             },
7396             method: 'GET',
7397             success : function(req){
7398                //console.log(data);
7399                 var rdata = false;
7400                 var edata;
7401                 try  {
7402                    rdata = Roo.decode(req.responseText)
7403                 } catch (e) {
7404                     Roo.log("Invalid data from server..");
7405                     Roo.log(edata);
7406                     return;
7407                 }
7408                 if (!rdata || !rdata.success) {
7409                     Roo.log(rdata);
7410                     Roo.MessageBox.alert(Roo.encode(rdata));
7411                     return;
7412                 }
7413                 var data = rdata.data;
7414                 
7415                 if (this.uploadComplete) {
7416                    Roo.MessageBox.hide();
7417                    return;
7418                 }
7419                    
7420                 if (data){
7421                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7422                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7423                     );
7424                 }
7425                 this.uploadProgress.defer(2000,this);
7426             },
7427        
7428             failure: function(data) {
7429                 Roo.log('progress url failed ');
7430                 Roo.log(data);
7431             },
7432             scope : this
7433         });
7434            
7435     },
7436     
7437     
7438     run : function()
7439     {
7440         // run get Values on the form, so it syncs any secondary forms.
7441         this.form.getValues();
7442         
7443         var o = this.options;
7444         var method = this.getMethod();
7445         var isPost = method == 'POST';
7446         if(o.clientValidation === false || this.form.isValid()){
7447             
7448             if (this.form.progressUrl) {
7449                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7450                     (new Date() * 1) + '' + Math.random());
7451                     
7452             } 
7453             
7454             
7455             Roo.Ajax.request(Roo.apply(this.createCallback(), {
7456                 form:this.form.el.dom,
7457                 url:this.getUrl(!isPost),
7458                 method: method,
7459                 params:isPost ? this.getParams() : null,
7460                 isUpload: this.form.fileUpload
7461             }));
7462             
7463             this.uploadProgress();
7464
7465         }else if (o.clientValidation !== false){ // client validation failed
7466             this.failureType = Roo.form.Action.CLIENT_INVALID;
7467             this.form.afterAction(this, false);
7468         }
7469     },
7470
7471     success : function(response)
7472     {
7473         this.uploadComplete= true;
7474         if (this.haveProgress) {
7475             Roo.MessageBox.hide();
7476         }
7477         
7478         
7479         var result = this.processResponse(response);
7480         if(result === true || result.success){
7481             this.form.afterAction(this, true);
7482             return;
7483         }
7484         if(result.errors){
7485             this.form.markInvalid(result.errors);
7486             this.failureType = Roo.form.Action.SERVER_INVALID;
7487         }
7488         this.form.afterAction(this, false);
7489     },
7490     failure : function(response)
7491     {
7492         this.uploadComplete= true;
7493         if (this.haveProgress) {
7494             Roo.MessageBox.hide();
7495         }
7496         
7497         this.response = response;
7498         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7499         this.form.afterAction(this, false);
7500     },
7501     
7502     handleResponse : function(response){
7503         if(this.form.errorReader){
7504             var rs = this.form.errorReader.read(response);
7505             var errors = [];
7506             if(rs.records){
7507                 for(var i = 0, len = rs.records.length; i < len; i++) {
7508                     var r = rs.records[i];
7509                     errors[i] = r.data;
7510                 }
7511             }
7512             if(errors.length < 1){
7513                 errors = null;
7514             }
7515             return {
7516                 success : rs.success,
7517                 errors : errors
7518             };
7519         }
7520         var ret = false;
7521         try {
7522             ret = Roo.decode(response.responseText);
7523         } catch (e) {
7524             ret = {
7525                 success: false,
7526                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7527                 errors : []
7528             };
7529         }
7530         return ret;
7531         
7532     }
7533 });
7534
7535
7536 Roo.form.Action.Load = function(form, options){
7537     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7538     this.reader = this.form.reader;
7539 };
7540
7541 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7542     type : 'load',
7543
7544     run : function(){
7545         
7546         Roo.Ajax.request(Roo.apply(
7547                 this.createCallback(), {
7548                     method:this.getMethod(),
7549                     url:this.getUrl(false),
7550                     params:this.getParams()
7551         }));
7552     },
7553
7554     success : function(response){
7555         
7556         var result = this.processResponse(response);
7557         if(result === true || !result.success || !result.data){
7558             this.failureType = Roo.form.Action.LOAD_FAILURE;
7559             this.form.afterAction(this, false);
7560             return;
7561         }
7562         this.form.clearInvalid();
7563         this.form.setValues(result.data);
7564         this.form.afterAction(this, true);
7565     },
7566
7567     handleResponse : function(response){
7568         if(this.form.reader){
7569             var rs = this.form.reader.read(response);
7570             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7571             return {
7572                 success : rs.success,
7573                 data : data
7574             };
7575         }
7576         return Roo.decode(response.responseText);
7577     }
7578 });
7579
7580 Roo.form.Action.ACTION_TYPES = {
7581     'load' : Roo.form.Action.Load,
7582     'submit' : Roo.form.Action.Submit
7583 };/*
7584  * - LGPL
7585  *
7586  * form
7587  *
7588  */
7589
7590 /**
7591  * @class Roo.bootstrap.Form
7592  * @extends Roo.bootstrap.Component
7593  * Bootstrap Form class
7594  * @cfg {String} method  GET | POST (default POST)
7595  * @cfg {String} labelAlign top | left (default top)
7596  * @cfg {String} align left  | right - for navbars
7597  * @cfg {Boolean} loadMask load mask when submit (default true)
7598
7599  *
7600  * @constructor
7601  * Create a new Form
7602  * @param {Object} config The config object
7603  */
7604
7605
7606 Roo.bootstrap.Form = function(config){
7607     
7608     Roo.bootstrap.Form.superclass.constructor.call(this, config);
7609     
7610     Roo.bootstrap.Form.popover.apply();
7611     
7612     this.addEvents({
7613         /**
7614          * @event clientvalidation
7615          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7616          * @param {Form} this
7617          * @param {Boolean} valid true if the form has passed client-side validation
7618          */
7619         clientvalidation: true,
7620         /**
7621          * @event beforeaction
7622          * Fires before any action is performed. Return false to cancel the action.
7623          * @param {Form} this
7624          * @param {Action} action The action to be performed
7625          */
7626         beforeaction: true,
7627         /**
7628          * @event actionfailed
7629          * Fires when an action fails.
7630          * @param {Form} this
7631          * @param {Action} action The action that failed
7632          */
7633         actionfailed : true,
7634         /**
7635          * @event actioncomplete
7636          * Fires when an action is completed.
7637          * @param {Form} this
7638          * @param {Action} action The action that completed
7639          */
7640         actioncomplete : true
7641     });
7642 };
7643
7644 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
7645
7646      /**
7647      * @cfg {String} method
7648      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7649      */
7650     method : 'POST',
7651     /**
7652      * @cfg {String} url
7653      * The URL to use for form actions if one isn't supplied in the action options.
7654      */
7655     /**
7656      * @cfg {Boolean} fileUpload
7657      * Set to true if this form is a file upload.
7658      */
7659
7660     /**
7661      * @cfg {Object} baseParams
7662      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7663      */
7664
7665     /**
7666      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7667      */
7668     timeout: 30,
7669     /**
7670      * @cfg {Sting} align (left|right) for navbar forms
7671      */
7672     align : 'left',
7673
7674     // private
7675     activeAction : null,
7676
7677     /**
7678      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7679      * element by passing it or its id or mask the form itself by passing in true.
7680      * @type Mixed
7681      */
7682     waitMsgTarget : false,
7683
7684     loadMask : true,
7685     
7686     /**
7687      * @cfg {Boolean} errorMask (true|false) default false
7688      */
7689     errorMask : false,
7690     
7691     /**
7692      * @cfg {Number} maskOffset Default 100
7693      */
7694     maskOffset : 100,
7695     
7696     /**
7697      * @cfg {Boolean} maskBody
7698      */
7699     maskBody : false,
7700
7701     getAutoCreate : function(){
7702
7703         var cfg = {
7704             tag: 'form',
7705             method : this.method || 'POST',
7706             id : this.id || Roo.id(),
7707             cls : ''
7708         };
7709         if (this.parent().xtype.match(/^Nav/)) {
7710             cfg.cls = 'navbar-form navbar-' + this.align;
7711
7712         }
7713
7714         if (this.labelAlign == 'left' ) {
7715             cfg.cls += ' form-horizontal';
7716         }
7717
7718
7719         return cfg;
7720     },
7721     initEvents : function()
7722     {
7723         this.el.on('submit', this.onSubmit, this);
7724         // this was added as random key presses on the form where triggering form submit.
7725         this.el.on('keypress', function(e) {
7726             if (e.getCharCode() != 13) {
7727                 return true;
7728             }
7729             // we might need to allow it for textareas.. and some other items.
7730             // check e.getTarget().
7731
7732             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7733                 return true;
7734             }
7735
7736             Roo.log("keypress blocked");
7737
7738             e.preventDefault();
7739             return false;
7740         });
7741         
7742     },
7743     // private
7744     onSubmit : function(e){
7745         e.stopEvent();
7746     },
7747
7748      /**
7749      * Returns true if client-side validation on the form is successful.
7750      * @return Boolean
7751      */
7752     isValid : function(){
7753         var items = this.getItems();
7754         var valid = true;
7755         var target = false;
7756         
7757         items.each(function(f){
7758             if(f.validate()){
7759                 return;
7760             }
7761             valid = false;
7762
7763             if(!target && f.el.isVisible(true)){
7764                 target = f;
7765             }
7766            
7767         });
7768         
7769         if(this.errorMask && !valid){
7770             Roo.bootstrap.Form.popover.mask(this, target);
7771         }
7772         
7773         return valid;
7774     },
7775     
7776     /**
7777      * Returns true if any fields in this form have changed since their original load.
7778      * @return Boolean
7779      */
7780     isDirty : function(){
7781         var dirty = false;
7782         var items = this.getItems();
7783         items.each(function(f){
7784            if(f.isDirty()){
7785                dirty = true;
7786                return false;
7787            }
7788            return true;
7789         });
7790         return dirty;
7791     },
7792      /**
7793      * Performs a predefined action (submit or load) or custom actions you define on this form.
7794      * @param {String} actionName The name of the action type
7795      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
7796      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7797      * accept other config options):
7798      * <pre>
7799 Property          Type             Description
7800 ----------------  ---------------  ----------------------------------------------------------------------------------
7801 url               String           The url for the action (defaults to the form's url)
7802 method            String           The form method to use (defaults to the form's method, or POST if not defined)
7803 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
7804 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
7805                                    validate the form on the client (defaults to false)
7806      * </pre>
7807      * @return {BasicForm} this
7808      */
7809     doAction : function(action, options){
7810         if(typeof action == 'string'){
7811             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7812         }
7813         if(this.fireEvent('beforeaction', this, action) !== false){
7814             this.beforeAction(action);
7815             action.run.defer(100, action);
7816         }
7817         return this;
7818     },
7819
7820     // private
7821     beforeAction : function(action){
7822         var o = action.options;
7823         
7824         if(this.loadMask){
7825             
7826             if(this.maskBody){
7827                 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7828             } else {
7829                 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7830             }
7831         }
7832         // not really supported yet.. ??
7833
7834         //if(this.waitMsgTarget === true){
7835         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7836         //}else if(this.waitMsgTarget){
7837         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7838         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7839         //}else {
7840         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7841        // }
7842
7843     },
7844
7845     // private
7846     afterAction : function(action, success){
7847         this.activeAction = null;
7848         var o = action.options;
7849
7850         if(this.loadMask){
7851             
7852             if(this.maskBody){
7853                 Roo.get(document.body).unmask();
7854             } else {
7855                 this.el.unmask();
7856             }
7857         }
7858         
7859         //if(this.waitMsgTarget === true){
7860 //            this.el.unmask();
7861         //}else if(this.waitMsgTarget){
7862         //    this.waitMsgTarget.unmask();
7863         //}else{
7864         //    Roo.MessageBox.updateProgress(1);
7865         //    Roo.MessageBox.hide();
7866        // }
7867         //
7868         if(success){
7869             if(o.reset){
7870                 this.reset();
7871             }
7872             Roo.callback(o.success, o.scope, [this, action]);
7873             this.fireEvent('actioncomplete', this, action);
7874
7875         }else{
7876
7877             // failure condition..
7878             // we have a scenario where updates need confirming.
7879             // eg. if a locking scenario exists..
7880             // we look for { errors : { needs_confirm : true }} in the response.
7881             if (
7882                 (typeof(action.result) != 'undefined')  &&
7883                 (typeof(action.result.errors) != 'undefined')  &&
7884                 (typeof(action.result.errors.needs_confirm) != 'undefined')
7885            ){
7886                 var _t = this;
7887                 Roo.log("not supported yet");
7888                  /*
7889
7890                 Roo.MessageBox.confirm(
7891                     "Change requires confirmation",
7892                     action.result.errorMsg,
7893                     function(r) {
7894                         if (r != 'yes') {
7895                             return;
7896                         }
7897                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
7898                     }
7899
7900                 );
7901                 */
7902
7903
7904                 return;
7905             }
7906
7907             Roo.callback(o.failure, o.scope, [this, action]);
7908             // show an error message if no failed handler is set..
7909             if (!this.hasListener('actionfailed')) {
7910                 Roo.log("need to add dialog support");
7911                 /*
7912                 Roo.MessageBox.alert("Error",
7913                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7914                         action.result.errorMsg :
7915                         "Saving Failed, please check your entries or try again"
7916                 );
7917                 */
7918             }
7919
7920             this.fireEvent('actionfailed', this, action);
7921         }
7922
7923     },
7924     /**
7925      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7926      * @param {String} id The value to search for
7927      * @return Field
7928      */
7929     findField : function(id){
7930         var items = this.getItems();
7931         var field = items.get(id);
7932         if(!field){
7933              items.each(function(f){
7934                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7935                     field = f;
7936                     return false;
7937                 }
7938                 return true;
7939             });
7940         }
7941         return field || null;
7942     },
7943      /**
7944      * Mark fields in this form invalid in bulk.
7945      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7946      * @return {BasicForm} this
7947      */
7948     markInvalid : function(errors){
7949         if(errors instanceof Array){
7950             for(var i = 0, len = errors.length; i < len; i++){
7951                 var fieldError = errors[i];
7952                 var f = this.findField(fieldError.id);
7953                 if(f){
7954                     f.markInvalid(fieldError.msg);
7955                 }
7956             }
7957         }else{
7958             var field, id;
7959             for(id in errors){
7960                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7961                     field.markInvalid(errors[id]);
7962                 }
7963             }
7964         }
7965         //Roo.each(this.childForms || [], function (f) {
7966         //    f.markInvalid(errors);
7967         //});
7968
7969         return this;
7970     },
7971
7972     /**
7973      * Set values for fields in this form in bulk.
7974      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7975      * @return {BasicForm} this
7976      */
7977     setValues : function(values){
7978         if(values instanceof Array){ // array of objects
7979             for(var i = 0, len = values.length; i < len; i++){
7980                 var v = values[i];
7981                 var f = this.findField(v.id);
7982                 if(f){
7983                     f.setValue(v.value);
7984                     if(this.trackResetOnLoad){
7985                         f.originalValue = f.getValue();
7986                     }
7987                 }
7988             }
7989         }else{ // object hash
7990             var field, id;
7991             for(id in values){
7992                 if(typeof values[id] != 'function' && (field = this.findField(id))){
7993
7994                     if (field.setFromData &&
7995                         field.valueField &&
7996                         field.displayField &&
7997                         // combos' with local stores can
7998                         // be queried via setValue()
7999                         // to set their value..
8000                         (field.store && !field.store.isLocal)
8001                         ) {
8002                         // it's a combo
8003                         var sd = { };
8004                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8005                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8006                         field.setFromData(sd);
8007
8008                     } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8009                         
8010                         field.setFromData(values);
8011                         
8012                     } else {
8013                         field.setValue(values[id]);
8014                     }
8015
8016
8017                     if(this.trackResetOnLoad){
8018                         field.originalValue = field.getValue();
8019                     }
8020                 }
8021             }
8022         }
8023
8024         //Roo.each(this.childForms || [], function (f) {
8025         //    f.setValues(values);
8026         //});
8027
8028         return this;
8029     },
8030
8031     /**
8032      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8033      * they are returned as an array.
8034      * @param {Boolean} asString
8035      * @return {Object}
8036      */
8037     getValues : function(asString){
8038         //if (this.childForms) {
8039             // copy values from the child forms
8040         //    Roo.each(this.childForms, function (f) {
8041         //        this.setValues(f.getValues());
8042         //    }, this);
8043         //}
8044
8045
8046
8047         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8048         if(asString === true){
8049             return fs;
8050         }
8051         return Roo.urlDecode(fs);
8052     },
8053
8054     /**
8055      * Returns the fields in this form as an object with key/value pairs.
8056      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8057      * @return {Object}
8058      */
8059     getFieldValues : function(with_hidden)
8060     {
8061         var items = this.getItems();
8062         var ret = {};
8063         items.each(function(f){
8064             
8065             if (!f.getName()) {
8066                 return;
8067             }
8068             
8069             var v = f.getValue();
8070             
8071             if (f.inputType =='radio') {
8072                 if (typeof(ret[f.getName()]) == 'undefined') {
8073                     ret[f.getName()] = ''; // empty..
8074                 }
8075
8076                 if (!f.el.dom.checked) {
8077                     return;
8078
8079                 }
8080                 v = f.el.dom.value;
8081
8082             }
8083             
8084             if(f.xtype == 'MoneyField'){
8085                 ret[f.currencyName] = f.getCurrency();
8086             }
8087
8088             // not sure if this supported any more..
8089             if ((typeof(v) == 'object') && f.getRawValue) {
8090                 v = f.getRawValue() ; // dates..
8091             }
8092             // combo boxes where name != hiddenName...
8093             if (f.name !== false && f.name != '' && f.name != f.getName()) {
8094                 ret[f.name] = f.getRawValue();
8095             }
8096             ret[f.getName()] = v;
8097         });
8098
8099         return ret;
8100     },
8101
8102     /**
8103      * Clears all invalid messages in this form.
8104      * @return {BasicForm} this
8105      */
8106     clearInvalid : function(){
8107         var items = this.getItems();
8108
8109         items.each(function(f){
8110            f.clearInvalid();
8111         });
8112
8113         return this;
8114     },
8115
8116     /**
8117      * Resets this form.
8118      * @return {BasicForm} this
8119      */
8120     reset : function(){
8121         var items = this.getItems();
8122         items.each(function(f){
8123             f.reset();
8124         });
8125
8126         Roo.each(this.childForms || [], function (f) {
8127             f.reset();
8128         });
8129
8130
8131         return this;
8132     },
8133     
8134     getItems : function()
8135     {
8136         var r=new Roo.util.MixedCollection(false, function(o){
8137             return o.id || (o.id = Roo.id());
8138         });
8139         var iter = function(el) {
8140             if (el.inputEl) {
8141                 r.add(el);
8142             }
8143             if (!el.items) {
8144                 return;
8145             }
8146             Roo.each(el.items,function(e) {
8147                 iter(e);
8148             });
8149         };
8150
8151         iter(this);
8152         return r;
8153     },
8154     
8155     hideFields : function(items)
8156     {
8157         Roo.each(items, function(i){
8158             
8159             var f = this.findField(i);
8160             
8161             if(!f){
8162                 return;
8163             }
8164             
8165             if(f.xtype == 'DateField'){
8166                 f.setVisible(false);
8167                 return;
8168             }
8169             
8170             f.hide();
8171             
8172         }, this);
8173     },
8174     
8175     showFields : function(items)
8176     {
8177         Roo.each(items, function(i){
8178             
8179             var f = this.findField(i);
8180             
8181             if(!f){
8182                 return;
8183             }
8184             
8185             if(f.xtype == 'DateField'){
8186                 f.setVisible(true);
8187                 return;
8188             }
8189             
8190             f.show();
8191             
8192         }, this);
8193     }
8194
8195 });
8196
8197 Roo.apply(Roo.bootstrap.Form, {
8198     
8199     popover : {
8200         
8201         padding : 5,
8202         
8203         isApplied : false,
8204         
8205         isMasked : false,
8206         
8207         form : false,
8208         
8209         target : false,
8210         
8211         toolTip : false,
8212         
8213         intervalID : false,
8214         
8215         maskEl : false,
8216         
8217         apply : function()
8218         {
8219             if(this.isApplied){
8220                 return;
8221             }
8222             
8223             this.maskEl = {
8224                 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8225                 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8226                 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8227                 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8228             };
8229             
8230             this.maskEl.top.enableDisplayMode("block");
8231             this.maskEl.left.enableDisplayMode("block");
8232             this.maskEl.bottom.enableDisplayMode("block");
8233             this.maskEl.right.enableDisplayMode("block");
8234             
8235             this.toolTip = new Roo.bootstrap.Tooltip({
8236                 cls : 'roo-form-error-popover',
8237                 alignment : {
8238                     'left' : ['r-l', [-2,0], 'right'],
8239                     'right' : ['l-r', [2,0], 'left'],
8240                     'bottom' : ['tl-bl', [0,2], 'top'],
8241                     'top' : [ 'bl-tl', [0,-2], 'bottom']
8242                 }
8243             });
8244             
8245             this.toolTip.render(Roo.get(document.body));
8246
8247             this.toolTip.el.enableDisplayMode("block");
8248             
8249             Roo.get(document.body).on('click', function(){
8250                 this.unmask();
8251             }, this);
8252             
8253             Roo.get(document.body).on('touchstart', function(){
8254                 this.unmask();
8255             }, this);
8256             
8257             this.isApplied = true
8258         },
8259         
8260         mask : function(form, target)
8261         {
8262             this.form = form;
8263             
8264             this.target = target;
8265             
8266             if(!this.form.errorMask || !target.el){
8267                 return;
8268             }
8269             
8270             var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8271             
8272             Roo.log(scrollable);
8273             
8274             var ot = this.target.el.calcOffsetsTo(scrollable);
8275             
8276             var scrollTo = ot[1] - this.form.maskOffset;
8277             
8278             scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8279             
8280             scrollable.scrollTo('top', scrollTo);
8281             
8282             var box = this.target.el.getBox();
8283             Roo.log(box);
8284             var zIndex = Roo.bootstrap.Modal.zIndex++;
8285
8286             
8287             this.maskEl.top.setStyle('position', 'absolute');
8288             this.maskEl.top.setStyle('z-index', zIndex);
8289             this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8290             this.maskEl.top.setLeft(0);
8291             this.maskEl.top.setTop(0);
8292             this.maskEl.top.show();
8293             
8294             this.maskEl.left.setStyle('position', 'absolute');
8295             this.maskEl.left.setStyle('z-index', zIndex);
8296             this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8297             this.maskEl.left.setLeft(0);
8298             this.maskEl.left.setTop(box.y - this.padding);
8299             this.maskEl.left.show();
8300
8301             this.maskEl.bottom.setStyle('position', 'absolute');
8302             this.maskEl.bottom.setStyle('z-index', zIndex);
8303             this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8304             this.maskEl.bottom.setLeft(0);
8305             this.maskEl.bottom.setTop(box.bottom + this.padding);
8306             this.maskEl.bottom.show();
8307
8308             this.maskEl.right.setStyle('position', 'absolute');
8309             this.maskEl.right.setStyle('z-index', zIndex);
8310             this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8311             this.maskEl.right.setLeft(box.right + this.padding);
8312             this.maskEl.right.setTop(box.y - this.padding);
8313             this.maskEl.right.show();
8314
8315             this.toolTip.bindEl = this.target.el;
8316
8317             this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8318
8319             var tip = this.target.blankText;
8320
8321             if(this.target.getValue() !== '' ) {
8322                 
8323                 if (this.target.invalidText.length) {
8324                     tip = this.target.invalidText;
8325                 } else if (this.target.regexText.length){
8326                     tip = this.target.regexText;
8327                 }
8328             }
8329
8330             this.toolTip.show(tip);
8331
8332             this.intervalID = window.setInterval(function() {
8333                 Roo.bootstrap.Form.popover.unmask();
8334             }, 10000);
8335
8336             window.onwheel = function(){ return false;};
8337             
8338             (function(){ this.isMasked = true; }).defer(500, this);
8339             
8340         },
8341         
8342         unmask : function()
8343         {
8344             if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8345                 return;
8346             }
8347             
8348             this.maskEl.top.setStyle('position', 'absolute');
8349             this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8350             this.maskEl.top.hide();
8351
8352             this.maskEl.left.setStyle('position', 'absolute');
8353             this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8354             this.maskEl.left.hide();
8355
8356             this.maskEl.bottom.setStyle('position', 'absolute');
8357             this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8358             this.maskEl.bottom.hide();
8359
8360             this.maskEl.right.setStyle('position', 'absolute');
8361             this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8362             this.maskEl.right.hide();
8363             
8364             this.toolTip.hide();
8365             
8366             this.toolTip.el.hide();
8367             
8368             window.onwheel = function(){ return true;};
8369             
8370             if(this.intervalID){
8371                 window.clearInterval(this.intervalID);
8372                 this.intervalID = false;
8373             }
8374             
8375             this.isMasked = false;
8376             
8377         }
8378         
8379     }
8380     
8381 });
8382
8383 /*
8384  * Based on:
8385  * Ext JS Library 1.1.1
8386  * Copyright(c) 2006-2007, Ext JS, LLC.
8387  *
8388  * Originally Released Under LGPL - original licence link has changed is not relivant.
8389  *
8390  * Fork - LGPL
8391  * <script type="text/javascript">
8392  */
8393 /**
8394  * @class Roo.form.VTypes
8395  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8396  * @singleton
8397  */
8398 Roo.form.VTypes = function(){
8399     // closure these in so they are only created once.
8400     var alpha = /^[a-zA-Z_]+$/;
8401     var alphanum = /^[a-zA-Z0-9_]+$/;
8402     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8403     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8404
8405     // All these messages and functions are configurable
8406     return {
8407         /**
8408          * The function used to validate email addresses
8409          * @param {String} value The email address
8410          */
8411         'email' : function(v){
8412             return email.test(v);
8413         },
8414         /**
8415          * The error text to display when the email validation function returns false
8416          * @type String
8417          */
8418         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8419         /**
8420          * The keystroke filter mask to be applied on email input
8421          * @type RegExp
8422          */
8423         'emailMask' : /[a-z0-9_\.\-@]/i,
8424
8425         /**
8426          * The function used to validate URLs
8427          * @param {String} value The URL
8428          */
8429         'url' : function(v){
8430             return url.test(v);
8431         },
8432         /**
8433          * The error text to display when the url validation function returns false
8434          * @type String
8435          */
8436         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8437         
8438         /**
8439          * The function used to validate alpha values
8440          * @param {String} value The value
8441          */
8442         'alpha' : function(v){
8443             return alpha.test(v);
8444         },
8445         /**
8446          * The error text to display when the alpha validation function returns false
8447          * @type String
8448          */
8449         'alphaText' : 'This field should only contain letters and _',
8450         /**
8451          * The keystroke filter mask to be applied on alpha input
8452          * @type RegExp
8453          */
8454         'alphaMask' : /[a-z_]/i,
8455
8456         /**
8457          * The function used to validate alphanumeric values
8458          * @param {String} value The value
8459          */
8460         'alphanum' : function(v){
8461             return alphanum.test(v);
8462         },
8463         /**
8464          * The error text to display when the alphanumeric validation function returns false
8465          * @type String
8466          */
8467         'alphanumText' : 'This field should only contain letters, numbers and _',
8468         /**
8469          * The keystroke filter mask to be applied on alphanumeric input
8470          * @type RegExp
8471          */
8472         'alphanumMask' : /[a-z0-9_]/i
8473     };
8474 }();/*
8475  * - LGPL
8476  *
8477  * Input
8478  * 
8479  */
8480
8481 /**
8482  * @class Roo.bootstrap.Input
8483  * @extends Roo.bootstrap.Component
8484  * Bootstrap Input class
8485  * @cfg {Boolean} disabled is it disabled
8486  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8487  * @cfg {String} name name of the input
8488  * @cfg {string} fieldLabel - the label associated
8489  * @cfg {string} placeholder - placeholder to put in text.
8490  * @cfg {string}  before - input group add on before
8491  * @cfg {string} after - input group add on after
8492  * @cfg {string} size - (lg|sm) or leave empty..
8493  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8494  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8495  * @cfg {Number} md colspan out of 12 for computer-sized screens
8496  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8497  * @cfg {string} value default value of the input
8498  * @cfg {Number} labelWidth set the width of label 
8499  * @cfg {Number} labellg set the width of label (1-12)
8500  * @cfg {Number} labelmd set the width of label (1-12)
8501  * @cfg {Number} labelsm set the width of label (1-12)
8502  * @cfg {Number} labelxs set the width of label (1-12)
8503  * @cfg {String} labelAlign (top|left)
8504  * @cfg {Boolean} readOnly Specifies that the field should be read-only
8505  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8506  * @cfg {String} indicatorpos (left|right) default left
8507
8508  * @cfg {String} align (left|center|right) Default left
8509  * @cfg {Boolean} forceFeedback (true|false) Default false
8510  * 
8511  * 
8512  * 
8513  * 
8514  * @constructor
8515  * Create a new Input
8516  * @param {Object} config The config object
8517  */
8518
8519 Roo.bootstrap.Input = function(config){
8520     
8521     Roo.bootstrap.Input.superclass.constructor.call(this, config);
8522     
8523     this.addEvents({
8524         /**
8525          * @event focus
8526          * Fires when this field receives input focus.
8527          * @param {Roo.form.Field} this
8528          */
8529         focus : true,
8530         /**
8531          * @event blur
8532          * Fires when this field loses input focus.
8533          * @param {Roo.form.Field} this
8534          */
8535         blur : true,
8536         /**
8537          * @event specialkey
8538          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
8539          * {@link Roo.EventObject#getKey} to determine which key was pressed.
8540          * @param {Roo.form.Field} this
8541          * @param {Roo.EventObject} e The event object
8542          */
8543         specialkey : true,
8544         /**
8545          * @event change
8546          * Fires just before the field blurs if the field value has changed.
8547          * @param {Roo.form.Field} this
8548          * @param {Mixed} newValue The new value
8549          * @param {Mixed} oldValue The original value
8550          */
8551         change : true,
8552         /**
8553          * @event invalid
8554          * Fires after the field has been marked as invalid.
8555          * @param {Roo.form.Field} this
8556          * @param {String} msg The validation message
8557          */
8558         invalid : true,
8559         /**
8560          * @event valid
8561          * Fires after the field has been validated with no errors.
8562          * @param {Roo.form.Field} this
8563          */
8564         valid : true,
8565          /**
8566          * @event keyup
8567          * Fires after the key up
8568          * @param {Roo.form.Field} this
8569          * @param {Roo.EventObject}  e The event Object
8570          */
8571         keyup : true
8572     });
8573 };
8574
8575 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
8576      /**
8577      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8578       automatic validation (defaults to "keyup").
8579      */
8580     validationEvent : "keyup",
8581      /**
8582      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8583      */
8584     validateOnBlur : true,
8585     /**
8586      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8587      */
8588     validationDelay : 250,
8589      /**
8590      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8591      */
8592     focusClass : "x-form-focus",  // not needed???
8593     
8594        
8595     /**
8596      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8597      */
8598     invalidClass : "has-warning",
8599     
8600     /**
8601      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8602      */
8603     validClass : "has-success",
8604     
8605     /**
8606      * @cfg {Boolean} hasFeedback (true|false) default true
8607      */
8608     hasFeedback : true,
8609     
8610     /**
8611      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8612      */
8613     invalidFeedbackClass : "glyphicon-warning-sign",
8614     
8615     /**
8616      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8617      */
8618     validFeedbackClass : "glyphicon-ok",
8619     
8620     /**
8621      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8622      */
8623     selectOnFocus : false,
8624     
8625      /**
8626      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8627      */
8628     maskRe : null,
8629        /**
8630      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8631      */
8632     vtype : null,
8633     
8634       /**
8635      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8636      */
8637     disableKeyFilter : false,
8638     
8639        /**
8640      * @cfg {Boolean} disabled True to disable the field (defaults to false).
8641      */
8642     disabled : false,
8643      /**
8644      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8645      */
8646     allowBlank : true,
8647     /**
8648      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8649      */
8650     blankText : "Please complete this mandatory field",
8651     
8652      /**
8653      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8654      */
8655     minLength : 0,
8656     /**
8657      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8658      */
8659     maxLength : Number.MAX_VALUE,
8660     /**
8661      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8662      */
8663     minLengthText : "The minimum length for this field is {0}",
8664     /**
8665      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8666      */
8667     maxLengthText : "The maximum length for this field is {0}",
8668   
8669     
8670     /**
8671      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8672      * If available, this function will be called only after the basic validators all return true, and will be passed the
8673      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8674      */
8675     validator : null,
8676     /**
8677      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8678      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8679      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
8680      */
8681     regex : null,
8682     /**
8683      * @cfg {String} regexText -- Depricated - use Invalid Text
8684      */
8685     regexText : "",
8686     
8687     /**
8688      * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8689      */
8690     invalidText : "",
8691     
8692     
8693     
8694     autocomplete: false,
8695     
8696     
8697     fieldLabel : '',
8698     inputType : 'text',
8699     
8700     name : false,
8701     placeholder: false,
8702     before : false,
8703     after : false,
8704     size : false,
8705     hasFocus : false,
8706     preventMark: false,
8707     isFormField : true,
8708     value : '',
8709     labelWidth : 2,
8710     labelAlign : false,
8711     readOnly : false,
8712     align : false,
8713     formatedValue : false,
8714     forceFeedback : false,
8715     
8716     indicatorpos : 'left',
8717     
8718     labellg : 0,
8719     labelmd : 0,
8720     labelsm : 0,
8721     labelxs : 0,
8722     
8723     parentLabelAlign : function()
8724     {
8725         var parent = this;
8726         while (parent.parent()) {
8727             parent = parent.parent();
8728             if (typeof(parent.labelAlign) !='undefined') {
8729                 return parent.labelAlign;
8730             }
8731         }
8732         return 'left';
8733         
8734     },
8735     
8736     getAutoCreate : function()
8737     {
8738         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8739         
8740         var id = Roo.id();
8741         
8742         var cfg = {};
8743         
8744         if(this.inputType != 'hidden'){
8745             cfg.cls = 'form-group' //input-group
8746         }
8747         
8748         var input =  {
8749             tag: 'input',
8750             id : id,
8751             type : this.inputType,
8752             value : this.value,
8753             cls : 'form-control',
8754             placeholder : this.placeholder || '',
8755             autocomplete : this.autocomplete || 'new-password'
8756         };
8757         
8758         if(this.align){
8759             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8760         }
8761         
8762         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8763             input.maxLength = this.maxLength;
8764         }
8765         
8766         if (this.disabled) {
8767             input.disabled=true;
8768         }
8769         
8770         if (this.readOnly) {
8771             input.readonly=true;
8772         }
8773         
8774         if (this.name) {
8775             input.name = this.name;
8776         }
8777         
8778         if (this.size) {
8779             input.cls += ' input-' + this.size;
8780         }
8781         
8782         var settings=this;
8783         ['xs','sm','md','lg'].map(function(size){
8784             if (settings[size]) {
8785                 cfg.cls += ' col-' + size + '-' + settings[size];
8786             }
8787         });
8788         
8789         var inputblock = input;
8790         
8791         var feedback = {
8792             tag: 'span',
8793             cls: 'glyphicon form-control-feedback'
8794         };
8795             
8796         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8797             
8798             inputblock = {
8799                 cls : 'has-feedback',
8800                 cn :  [
8801                     input,
8802                     feedback
8803                 ] 
8804             };  
8805         }
8806         
8807         if (this.before || this.after) {
8808             
8809             inputblock = {
8810                 cls : 'input-group',
8811                 cn :  [] 
8812             };
8813             
8814             if (this.before && typeof(this.before) == 'string') {
8815                 
8816                 inputblock.cn.push({
8817                     tag :'span',
8818                     cls : 'roo-input-before input-group-addon',
8819                     html : this.before
8820                 });
8821             }
8822             if (this.before && typeof(this.before) == 'object') {
8823                 this.before = Roo.factory(this.before);
8824                 
8825                 inputblock.cn.push({
8826                     tag :'span',
8827                     cls : 'roo-input-before input-group-' +
8828                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8829                 });
8830             }
8831             
8832             inputblock.cn.push(input);
8833             
8834             if (this.after && typeof(this.after) == 'string') {
8835                 inputblock.cn.push({
8836                     tag :'span',
8837                     cls : 'roo-input-after input-group-addon',
8838                     html : this.after
8839                 });
8840             }
8841             if (this.after && typeof(this.after) == 'object') {
8842                 this.after = Roo.factory(this.after);
8843                 
8844                 inputblock.cn.push({
8845                     tag :'span',
8846                     cls : 'roo-input-after input-group-' +
8847                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8848                 });
8849             }
8850             
8851             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8852                 inputblock.cls += ' has-feedback';
8853                 inputblock.cn.push(feedback);
8854             }
8855         };
8856         
8857         if (align ==='left' && this.fieldLabel.length) {
8858             
8859             cfg.cls += ' roo-form-group-label-left';
8860             
8861             cfg.cn = [
8862                 {
8863                     tag : 'i',
8864                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8865                     tooltip : 'This field is required'
8866                 },
8867                 {
8868                     tag: 'label',
8869                     'for' :  id,
8870                     cls : 'control-label',
8871                     html : this.fieldLabel
8872
8873                 },
8874                 {
8875                     cls : "", 
8876                     cn: [
8877                         inputblock
8878                     ]
8879                 }
8880             ];
8881             
8882             var labelCfg = cfg.cn[1];
8883             var contentCfg = cfg.cn[2];
8884             
8885             if(this.indicatorpos == 'right'){
8886                 cfg.cn = [
8887                     {
8888                         tag: 'label',
8889                         'for' :  id,
8890                         cls : 'control-label',
8891                         cn : [
8892                             {
8893                                 tag : 'span',
8894                                 html : this.fieldLabel
8895                             },
8896                             {
8897                                 tag : 'i',
8898                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8899                                 tooltip : 'This field is required'
8900                             }
8901                         ]
8902                     },
8903                     {
8904                         cls : "",
8905                         cn: [
8906                             inputblock
8907                         ]
8908                     }
8909
8910                 ];
8911                 
8912                 labelCfg = cfg.cn[0];
8913                 contentCfg = cfg.cn[1];
8914             
8915             }
8916             
8917             if(this.labelWidth > 12){
8918                 labelCfg.style = "width: " + this.labelWidth + 'px';
8919             }
8920             
8921             if(this.labelWidth < 13 && this.labelmd == 0){
8922                 this.labelmd = this.labelWidth;
8923             }
8924             
8925             if(this.labellg > 0){
8926                 labelCfg.cls += ' col-lg-' + this.labellg;
8927                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8928             }
8929             
8930             if(this.labelmd > 0){
8931                 labelCfg.cls += ' col-md-' + this.labelmd;
8932                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8933             }
8934             
8935             if(this.labelsm > 0){
8936                 labelCfg.cls += ' col-sm-' + this.labelsm;
8937                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8938             }
8939             
8940             if(this.labelxs > 0){
8941                 labelCfg.cls += ' col-xs-' + this.labelxs;
8942                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8943             }
8944             
8945             
8946         } else if ( this.fieldLabel.length) {
8947                 
8948             cfg.cn = [
8949                 {
8950                     tag : 'i',
8951                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8952                     tooltip : 'This field is required'
8953                 },
8954                 {
8955                     tag: 'label',
8956                    //cls : 'input-group-addon',
8957                     html : this.fieldLabel
8958
8959                 },
8960
8961                inputblock
8962
8963            ];
8964            
8965            if(this.indicatorpos == 'right'){
8966                 
8967                 cfg.cn = [
8968                     {
8969                         tag: 'label',
8970                        //cls : 'input-group-addon',
8971                         html : this.fieldLabel
8972
8973                     },
8974                     {
8975                         tag : 'i',
8976                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8977                         tooltip : 'This field is required'
8978                     },
8979
8980                    inputblock
8981
8982                ];
8983
8984             }
8985
8986         } else {
8987             
8988             cfg.cn = [
8989
8990                     inputblock
8991
8992             ];
8993                 
8994                 
8995         };
8996         
8997         if (this.parentType === 'Navbar' &&  this.parent().bar) {
8998            cfg.cls += ' navbar-form';
8999         }
9000         
9001         if (this.parentType === 'NavGroup') {
9002            cfg.cls += ' navbar-form';
9003            cfg.tag = 'li';
9004         }
9005         
9006         return cfg;
9007         
9008     },
9009     /**
9010      * return the real input element.
9011      */
9012     inputEl: function ()
9013     {
9014         return this.el.select('input.form-control',true).first();
9015     },
9016     
9017     tooltipEl : function()
9018     {
9019         return this.inputEl();
9020     },
9021     
9022     indicatorEl : function()
9023     {
9024         var indicator = this.el.select('i.roo-required-indicator',true).first();
9025         
9026         if(!indicator){
9027             return false;
9028         }
9029         
9030         return indicator;
9031         
9032     },
9033     
9034     setDisabled : function(v)
9035     {
9036         var i  = this.inputEl().dom;
9037         if (!v) {
9038             i.removeAttribute('disabled');
9039             return;
9040             
9041         }
9042         i.setAttribute('disabled','true');
9043     },
9044     initEvents : function()
9045     {
9046           
9047         this.inputEl().on("keydown" , this.fireKey,  this);
9048         this.inputEl().on("focus", this.onFocus,  this);
9049         this.inputEl().on("blur", this.onBlur,  this);
9050         
9051         this.inputEl().relayEvent('keyup', this);
9052         
9053         this.indicator = this.indicatorEl();
9054         
9055         if(this.indicator){
9056             this.indicator.addClass('invisible');
9057             
9058         }
9059  
9060         // reference to original value for reset
9061         this.originalValue = this.getValue();
9062         //Roo.form.TextField.superclass.initEvents.call(this);
9063         if(this.validationEvent == 'keyup'){
9064             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9065             this.inputEl().on('keyup', this.filterValidation, this);
9066         }
9067         else if(this.validationEvent !== false){
9068             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9069         }
9070         
9071         if(this.selectOnFocus){
9072             this.on("focus", this.preFocus, this);
9073             
9074         }
9075         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9076             this.inputEl().on("keypress", this.filterKeys, this);
9077         } else {
9078             this.inputEl().relayEvent('keypress', this);
9079         }
9080        /* if(this.grow){
9081             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
9082             this.el.on("click", this.autoSize,  this);
9083         }
9084         */
9085         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9086             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9087         }
9088         
9089         if (typeof(this.before) == 'object') {
9090             this.before.render(this.el.select('.roo-input-before',true).first());
9091         }
9092         if (typeof(this.after) == 'object') {
9093             this.after.render(this.el.select('.roo-input-after',true).first());
9094         }
9095         
9096         
9097     },
9098     filterValidation : function(e){
9099         if(!e.isNavKeyPress()){
9100             this.validationTask.delay(this.validationDelay);
9101         }
9102     },
9103      /**
9104      * Validates the field value
9105      * @return {Boolean} True if the value is valid, else false
9106      */
9107     validate : function(){
9108         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9109         if(this.disabled || this.validateValue(this.getRawValue())){
9110             this.markValid();
9111             return true;
9112         }
9113         
9114         this.markInvalid();
9115         return false;
9116     },
9117     
9118     
9119     /**
9120      * Validates a value according to the field's validation rules and marks the field as invalid
9121      * if the validation fails
9122      * @param {Mixed} value The value to validate
9123      * @return {Boolean} True if the value is valid, else false
9124      */
9125     validateValue : function(value)
9126     {
9127         if(this.getEl().hasClass('hidden')){
9128             return true;
9129         }
9130         
9131         if(value.length < 1)  { // if it's blank
9132             if(this.allowBlank){
9133                 return true;
9134             }
9135             return false;
9136         }
9137         
9138         if(value.length < this.minLength){
9139             return false;
9140         }
9141         if(value.length > this.maxLength){
9142             return false;
9143         }
9144         if(this.vtype){
9145             var vt = Roo.form.VTypes;
9146             if(!vt[this.vtype](value, this)){
9147                 return false;
9148             }
9149         }
9150         if(typeof this.validator == "function"){
9151             var msg = this.validator(value);
9152             if(msg !== true){
9153                 return false;
9154             }
9155             if (typeof(msg) == 'string') {
9156                 this.invalidText = msg;
9157             }
9158         }
9159         
9160         if(this.regex && !this.regex.test(value)){
9161             return false;
9162         }
9163         
9164         return true;
9165     },
9166     
9167      // private
9168     fireKey : function(e){
9169         //Roo.log('field ' + e.getKey());
9170         if(e.isNavKeyPress()){
9171             this.fireEvent("specialkey", this, e);
9172         }
9173     },
9174     focus : function (selectText){
9175         if(this.rendered){
9176             this.inputEl().focus();
9177             if(selectText === true){
9178                 this.inputEl().dom.select();
9179             }
9180         }
9181         return this;
9182     } ,
9183     
9184     onFocus : function(){
9185         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9186            // this.el.addClass(this.focusClass);
9187         }
9188         if(!this.hasFocus){
9189             this.hasFocus = true;
9190             this.startValue = this.getValue();
9191             this.fireEvent("focus", this);
9192         }
9193     },
9194     
9195     beforeBlur : Roo.emptyFn,
9196
9197     
9198     // private
9199     onBlur : function(){
9200         this.beforeBlur();
9201         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9202             //this.el.removeClass(this.focusClass);
9203         }
9204         this.hasFocus = false;
9205         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9206             this.validate();
9207         }
9208         var v = this.getValue();
9209         if(String(v) !== String(this.startValue)){
9210             this.fireEvent('change', this, v, this.startValue);
9211         }
9212         this.fireEvent("blur", this);
9213     },
9214     
9215     /**
9216      * Resets the current field value to the originally loaded value and clears any validation messages
9217      */
9218     reset : function(){
9219         this.setValue(this.originalValue);
9220         this.validate();
9221     },
9222      /**
9223      * Returns the name of the field
9224      * @return {Mixed} name The name field
9225      */
9226     getName: function(){
9227         return this.name;
9228     },
9229      /**
9230      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
9231      * @return {Mixed} value The field value
9232      */
9233     getValue : function(){
9234         
9235         var v = this.inputEl().getValue();
9236         
9237         return v;
9238     },
9239     /**
9240      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
9241      * @return {Mixed} value The field value
9242      */
9243     getRawValue : function(){
9244         var v = this.inputEl().getValue();
9245         
9246         return v;
9247     },
9248     
9249     /**
9250      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
9251      * @param {Mixed} value The value to set
9252      */
9253     setRawValue : function(v){
9254         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9255     },
9256     
9257     selectText : function(start, end){
9258         var v = this.getRawValue();
9259         if(v.length > 0){
9260             start = start === undefined ? 0 : start;
9261             end = end === undefined ? v.length : end;
9262             var d = this.inputEl().dom;
9263             if(d.setSelectionRange){
9264                 d.setSelectionRange(start, end);
9265             }else if(d.createTextRange){
9266                 var range = d.createTextRange();
9267                 range.moveStart("character", start);
9268                 range.moveEnd("character", v.length-end);
9269                 range.select();
9270             }
9271         }
9272     },
9273     
9274     /**
9275      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
9276      * @param {Mixed} value The value to set
9277      */
9278     setValue : function(v){
9279         this.value = v;
9280         if(this.rendered){
9281             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9282             this.validate();
9283         }
9284     },
9285     
9286     /*
9287     processValue : function(value){
9288         if(this.stripCharsRe){
9289             var newValue = value.replace(this.stripCharsRe, '');
9290             if(newValue !== value){
9291                 this.setRawValue(newValue);
9292                 return newValue;
9293             }
9294         }
9295         return value;
9296     },
9297   */
9298     preFocus : function(){
9299         
9300         if(this.selectOnFocus){
9301             this.inputEl().dom.select();
9302         }
9303     },
9304     filterKeys : function(e){
9305         var k = e.getKey();
9306         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9307             return;
9308         }
9309         var c = e.getCharCode(), cc = String.fromCharCode(c);
9310         if(Roo.isIE && (e.isSpecialKey() || !cc)){
9311             return;
9312         }
9313         if(!this.maskRe.test(cc)){
9314             e.stopEvent();
9315         }
9316     },
9317      /**
9318      * Clear any invalid styles/messages for this field
9319      */
9320     clearInvalid : function(){
9321         
9322         if(!this.el || this.preventMark){ // not rendered
9323             return;
9324         }
9325         
9326      
9327         this.el.removeClass(this.invalidClass);
9328         
9329         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9330             
9331             var feedback = this.el.select('.form-control-feedback', true).first();
9332             
9333             if(feedback){
9334                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9335             }
9336             
9337         }
9338         
9339         this.fireEvent('valid', this);
9340     },
9341     
9342      /**
9343      * Mark this field as valid
9344      */
9345     markValid : function()
9346     {
9347         if(!this.el  || this.preventMark){ // not rendered...
9348             return;
9349         }
9350         
9351         this.el.removeClass([this.invalidClass, this.validClass]);
9352         
9353         var feedback = this.el.select('.form-control-feedback', true).first();
9354             
9355         if(feedback){
9356             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9357         }
9358         
9359         if(this.indicator){
9360             this.indicator.removeClass('visible');
9361             this.indicator.addClass('invisible');
9362         }
9363         
9364         if(this.disabled){
9365             return;
9366         }
9367         
9368         if(this.allowBlank && !this.getRawValue().length){
9369             return;
9370         }
9371         
9372         this.el.addClass(this.validClass);
9373         
9374         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9375             
9376             var feedback = this.el.select('.form-control-feedback', true).first();
9377             
9378             if(feedback){
9379                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9380                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9381             }
9382             
9383         }
9384         
9385         this.fireEvent('valid', this);
9386     },
9387     
9388      /**
9389      * Mark this field as invalid
9390      * @param {String} msg The validation message
9391      */
9392     markInvalid : function(msg)
9393     {
9394         if(!this.el  || this.preventMark){ // not rendered
9395             return;
9396         }
9397         
9398         this.el.removeClass([this.invalidClass, this.validClass]);
9399         
9400         var feedback = this.el.select('.form-control-feedback', true).first();
9401             
9402         if(feedback){
9403             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9404         }
9405
9406         if(this.disabled){
9407             return;
9408         }
9409         
9410         if(this.allowBlank && !this.getRawValue().length){
9411             return;
9412         }
9413         
9414         if(this.indicator){
9415             this.indicator.removeClass('invisible');
9416             this.indicator.addClass('visible');
9417         }
9418         
9419         this.el.addClass(this.invalidClass);
9420         
9421         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9422             
9423             var feedback = this.el.select('.form-control-feedback', true).first();
9424             
9425             if(feedback){
9426                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9427                 
9428                 if(this.getValue().length || this.forceFeedback){
9429                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9430                 }
9431                 
9432             }
9433             
9434         }
9435         
9436         this.fireEvent('invalid', this, msg);
9437     },
9438     // private
9439     SafariOnKeyDown : function(event)
9440     {
9441         // this is a workaround for a password hang bug on chrome/ webkit.
9442         if (this.inputEl().dom.type != 'password') {
9443             return;
9444         }
9445         
9446         var isSelectAll = false;
9447         
9448         if(this.inputEl().dom.selectionEnd > 0){
9449             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9450         }
9451         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9452             event.preventDefault();
9453             this.setValue('');
9454             return;
9455         }
9456         
9457         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9458             
9459             event.preventDefault();
9460             // this is very hacky as keydown always get's upper case.
9461             //
9462             var cc = String.fromCharCode(event.getCharCode());
9463             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
9464             
9465         }
9466     },
9467     adjustWidth : function(tag, w){
9468         tag = tag.toLowerCase();
9469         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9470             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9471                 if(tag == 'input'){
9472                     return w + 2;
9473                 }
9474                 if(tag == 'textarea'){
9475                     return w-2;
9476                 }
9477             }else if(Roo.isOpera){
9478                 if(tag == 'input'){
9479                     return w + 2;
9480                 }
9481                 if(tag == 'textarea'){
9482                     return w-2;
9483                 }
9484             }
9485         }
9486         return w;
9487     },
9488     
9489     setFieldLabel : function(v)
9490     {
9491         if(!this.rendered){
9492             return;
9493         }
9494         
9495         if(this.indicator){
9496             var ar = this.el.select('label > span',true);
9497             
9498             if (ar.elements.length) {
9499                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9500                 this.fieldLabel = v;
9501                 return;
9502             }
9503             
9504             var br = this.el.select('label',true);
9505             
9506             if(br.elements.length) {
9507                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9508                 this.fieldLabel = v;
9509                 return;
9510             }
9511             
9512             Roo.log('Cannot Found any of label > span || label in input');
9513             return;
9514         }
9515         
9516         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9517         this.fieldLabel = v;
9518         
9519         
9520     }
9521 });
9522
9523  
9524 /*
9525  * - LGPL
9526  *
9527  * Input
9528  * 
9529  */
9530
9531 /**
9532  * @class Roo.bootstrap.TextArea
9533  * @extends Roo.bootstrap.Input
9534  * Bootstrap TextArea class
9535  * @cfg {Number} cols Specifies the visible width of a text area
9536  * @cfg {Number} rows Specifies the visible number of lines in a text area
9537  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9538  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9539  * @cfg {string} html text
9540  * 
9541  * @constructor
9542  * Create a new TextArea
9543  * @param {Object} config The config object
9544  */
9545
9546 Roo.bootstrap.TextArea = function(config){
9547     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9548    
9549 };
9550
9551 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
9552      
9553     cols : false,
9554     rows : 5,
9555     readOnly : false,
9556     warp : 'soft',
9557     resize : false,
9558     value: false,
9559     html: false,
9560     
9561     getAutoCreate : function(){
9562         
9563         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9564         
9565         var id = Roo.id();
9566         
9567         var cfg = {};
9568         
9569         if(this.inputType != 'hidden'){
9570             cfg.cls = 'form-group' //input-group
9571         }
9572         
9573         var input =  {
9574             tag: 'textarea',
9575             id : id,
9576             warp : this.warp,
9577             rows : this.rows,
9578             value : this.value || '',
9579             html: this.html || '',
9580             cls : 'form-control',
9581             placeholder : this.placeholder || '' 
9582             
9583         };
9584         
9585         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9586             input.maxLength = this.maxLength;
9587         }
9588         
9589         if(this.resize){
9590             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9591         }
9592         
9593         if(this.cols){
9594             input.cols = this.cols;
9595         }
9596         
9597         if (this.readOnly) {
9598             input.readonly = true;
9599         }
9600         
9601         if (this.name) {
9602             input.name = this.name;
9603         }
9604         
9605         if (this.size) {
9606             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9607         }
9608         
9609         var settings=this;
9610         ['xs','sm','md','lg'].map(function(size){
9611             if (settings[size]) {
9612                 cfg.cls += ' col-' + size + '-' + settings[size];
9613             }
9614         });
9615         
9616         var inputblock = input;
9617         
9618         if(this.hasFeedback && !this.allowBlank){
9619             
9620             var feedback = {
9621                 tag: 'span',
9622                 cls: 'glyphicon form-control-feedback'
9623             };
9624
9625             inputblock = {
9626                 cls : 'has-feedback',
9627                 cn :  [
9628                     input,
9629                     feedback
9630                 ] 
9631             };  
9632         }
9633         
9634         
9635         if (this.before || this.after) {
9636             
9637             inputblock = {
9638                 cls : 'input-group',
9639                 cn :  [] 
9640             };
9641             if (this.before) {
9642                 inputblock.cn.push({
9643                     tag :'span',
9644                     cls : 'input-group-addon',
9645                     html : this.before
9646                 });
9647             }
9648             
9649             inputblock.cn.push(input);
9650             
9651             if(this.hasFeedback && !this.allowBlank){
9652                 inputblock.cls += ' has-feedback';
9653                 inputblock.cn.push(feedback);
9654             }
9655             
9656             if (this.after) {
9657                 inputblock.cn.push({
9658                     tag :'span',
9659                     cls : 'input-group-addon',
9660                     html : this.after
9661                 });
9662             }
9663             
9664         }
9665         
9666         if (align ==='left' && this.fieldLabel.length) {
9667             cfg.cn = [
9668                 {
9669                     tag: 'label',
9670                     'for' :  id,
9671                     cls : 'control-label',
9672                     html : this.fieldLabel
9673                 },
9674                 {
9675                     cls : "",
9676                     cn: [
9677                         inputblock
9678                     ]
9679                 }
9680
9681             ];
9682             
9683             if(this.labelWidth > 12){
9684                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9685             }
9686
9687             if(this.labelWidth < 13 && this.labelmd == 0){
9688                 this.labelmd = this.labelWidth;
9689             }
9690
9691             if(this.labellg > 0){
9692                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9693                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9694             }
9695
9696             if(this.labelmd > 0){
9697                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9698                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9699             }
9700
9701             if(this.labelsm > 0){
9702                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9703                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9704             }
9705
9706             if(this.labelxs > 0){
9707                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9708                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9709             }
9710             
9711         } else if ( this.fieldLabel.length) {
9712             cfg.cn = [
9713
9714                {
9715                    tag: 'label',
9716                    //cls : 'input-group-addon',
9717                    html : this.fieldLabel
9718
9719                },
9720
9721                inputblock
9722
9723            ];
9724
9725         } else {
9726
9727             cfg.cn = [
9728
9729                 inputblock
9730
9731             ];
9732                 
9733         }
9734         
9735         if (this.disabled) {
9736             input.disabled=true;
9737         }
9738         
9739         return cfg;
9740         
9741     },
9742     /**
9743      * return the real textarea element.
9744      */
9745     inputEl: function ()
9746     {
9747         return this.el.select('textarea.form-control',true).first();
9748     },
9749     
9750     /**
9751      * Clear any invalid styles/messages for this field
9752      */
9753     clearInvalid : function()
9754     {
9755         
9756         if(!this.el || this.preventMark){ // not rendered
9757             return;
9758         }
9759         
9760         var label = this.el.select('label', true).first();
9761         var icon = this.el.select('i.fa-star', true).first();
9762         
9763         if(label && icon){
9764             icon.remove();
9765         }
9766         
9767         this.el.removeClass(this.invalidClass);
9768         
9769         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9770             
9771             var feedback = this.el.select('.form-control-feedback', true).first();
9772             
9773             if(feedback){
9774                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9775             }
9776             
9777         }
9778         
9779         this.fireEvent('valid', this);
9780     },
9781     
9782      /**
9783      * Mark this field as valid
9784      */
9785     markValid : function()
9786     {
9787         if(!this.el  || this.preventMark){ // not rendered
9788             return;
9789         }
9790         
9791         this.el.removeClass([this.invalidClass, this.validClass]);
9792         
9793         var feedback = this.el.select('.form-control-feedback', true).first();
9794             
9795         if(feedback){
9796             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9797         }
9798
9799         if(this.disabled || this.allowBlank){
9800             return;
9801         }
9802         
9803         var label = this.el.select('label', true).first();
9804         var icon = this.el.select('i.fa-star', true).first();
9805         
9806         if(label && icon){
9807             icon.remove();
9808         }
9809         
9810         this.el.addClass(this.validClass);
9811         
9812         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9813             
9814             var feedback = this.el.select('.form-control-feedback', true).first();
9815             
9816             if(feedback){
9817                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9818                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9819             }
9820             
9821         }
9822         
9823         this.fireEvent('valid', this);
9824     },
9825     
9826      /**
9827      * Mark this field as invalid
9828      * @param {String} msg The validation message
9829      */
9830     markInvalid : function(msg)
9831     {
9832         if(!this.el  || this.preventMark){ // not rendered
9833             return;
9834         }
9835         
9836         this.el.removeClass([this.invalidClass, this.validClass]);
9837         
9838         var feedback = this.el.select('.form-control-feedback', true).first();
9839             
9840         if(feedback){
9841             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9842         }
9843
9844         if(this.disabled || this.allowBlank){
9845             return;
9846         }
9847         
9848         var label = this.el.select('label', true).first();
9849         var icon = this.el.select('i.fa-star', true).first();
9850         
9851         if(!this.getValue().length && label && !icon){
9852             this.el.createChild({
9853                 tag : 'i',
9854                 cls : 'text-danger fa fa-lg fa-star',
9855                 tooltip : 'This field is required',
9856                 style : 'margin-right:5px;'
9857             }, label, true);
9858         }
9859
9860         this.el.addClass(this.invalidClass);
9861         
9862         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9863             
9864             var feedback = this.el.select('.form-control-feedback', true).first();
9865             
9866             if(feedback){
9867                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9868                 
9869                 if(this.getValue().length || this.forceFeedback){
9870                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9871                 }
9872                 
9873             }
9874             
9875         }
9876         
9877         this.fireEvent('invalid', this, msg);
9878     }
9879 });
9880
9881  
9882 /*
9883  * - LGPL
9884  *
9885  * trigger field - base class for combo..
9886  * 
9887  */
9888  
9889 /**
9890  * @class Roo.bootstrap.TriggerField
9891  * @extends Roo.bootstrap.Input
9892  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9893  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9894  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9895  * for which you can provide a custom implementation.  For example:
9896  * <pre><code>
9897 var trigger = new Roo.bootstrap.TriggerField();
9898 trigger.onTriggerClick = myTriggerFn;
9899 trigger.applyTo('my-field');
9900 </code></pre>
9901  *
9902  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9903  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9904  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
9905  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9906  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9907
9908  * @constructor
9909  * Create a new TriggerField.
9910  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9911  * to the base TextField)
9912  */
9913 Roo.bootstrap.TriggerField = function(config){
9914     this.mimicing = false;
9915     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9916 };
9917
9918 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
9919     /**
9920      * @cfg {String} triggerClass A CSS class to apply to the trigger
9921      */
9922      /**
9923      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9924      */
9925     hideTrigger:false,
9926
9927     /**
9928      * @cfg {Boolean} removable (true|false) special filter default false
9929      */
9930     removable : false,
9931     
9932     /** @cfg {Boolean} grow @hide */
9933     /** @cfg {Number} growMin @hide */
9934     /** @cfg {Number} growMax @hide */
9935
9936     /**
9937      * @hide 
9938      * @method
9939      */
9940     autoSize: Roo.emptyFn,
9941     // private
9942     monitorTab : true,
9943     // private
9944     deferHeight : true,
9945
9946     
9947     actionMode : 'wrap',
9948     
9949     caret : false,
9950     
9951     
9952     getAutoCreate : function(){
9953        
9954         var align = this.labelAlign || this.parentLabelAlign();
9955         
9956         var id = Roo.id();
9957         
9958         var cfg = {
9959             cls: 'form-group' //input-group
9960         };
9961         
9962         
9963         var input =  {
9964             tag: 'input',
9965             id : id,
9966             type : this.inputType,
9967             cls : 'form-control',
9968             autocomplete: 'new-password',
9969             placeholder : this.placeholder || '' 
9970             
9971         };
9972         if (this.name) {
9973             input.name = this.name;
9974         }
9975         if (this.size) {
9976             input.cls += ' input-' + this.size;
9977         }
9978         
9979         if (this.disabled) {
9980             input.disabled=true;
9981         }
9982         
9983         var inputblock = input;
9984         
9985         if(this.hasFeedback && !this.allowBlank){
9986             
9987             var feedback = {
9988                 tag: 'span',
9989                 cls: 'glyphicon form-control-feedback'
9990             };
9991             
9992             if(this.removable && !this.editable && !this.tickable){
9993                 inputblock = {
9994                     cls : 'has-feedback',
9995                     cn :  [
9996                         inputblock,
9997                         {
9998                             tag: 'button',
9999                             html : 'x',
10000                             cls : 'roo-combo-removable-btn close'
10001                         },
10002                         feedback
10003                     ] 
10004                 };
10005             } else {
10006                 inputblock = {
10007                     cls : 'has-feedback',
10008                     cn :  [
10009                         inputblock,
10010                         feedback
10011                     ] 
10012                 };
10013             }
10014
10015         } else {
10016             if(this.removable && !this.editable && !this.tickable){
10017                 inputblock = {
10018                     cls : 'roo-removable',
10019                     cn :  [
10020                         inputblock,
10021                         {
10022                             tag: 'button',
10023                             html : 'x',
10024                             cls : 'roo-combo-removable-btn close'
10025                         }
10026                     ] 
10027                 };
10028             }
10029         }
10030         
10031         if (this.before || this.after) {
10032             
10033             inputblock = {
10034                 cls : 'input-group',
10035                 cn :  [] 
10036             };
10037             if (this.before) {
10038                 inputblock.cn.push({
10039                     tag :'span',
10040                     cls : 'input-group-addon',
10041                     html : this.before
10042                 });
10043             }
10044             
10045             inputblock.cn.push(input);
10046             
10047             if(this.hasFeedback && !this.allowBlank){
10048                 inputblock.cls += ' has-feedback';
10049                 inputblock.cn.push(feedback);
10050             }
10051             
10052             if (this.after) {
10053                 inputblock.cn.push({
10054                     tag :'span',
10055                     cls : 'input-group-addon',
10056                     html : this.after
10057                 });
10058             }
10059             
10060         };
10061         
10062         var box = {
10063             tag: 'div',
10064             cn: [
10065                 {
10066                     tag: 'input',
10067                     type : 'hidden',
10068                     cls: 'form-hidden-field'
10069                 },
10070                 inputblock
10071             ]
10072             
10073         };
10074         
10075         if(this.multiple){
10076             box = {
10077                 tag: 'div',
10078                 cn: [
10079                     {
10080                         tag: 'input',
10081                         type : 'hidden',
10082                         cls: 'form-hidden-field'
10083                     },
10084                     {
10085                         tag: 'ul',
10086                         cls: 'roo-select2-choices',
10087                         cn:[
10088                             {
10089                                 tag: 'li',
10090                                 cls: 'roo-select2-search-field',
10091                                 cn: [
10092
10093                                     inputblock
10094                                 ]
10095                             }
10096                         ]
10097                     }
10098                 ]
10099             }
10100         };
10101         
10102         var combobox = {
10103             cls: 'roo-select2-container input-group',
10104             cn: [
10105                 box
10106 //                {
10107 //                    tag: 'ul',
10108 //                    cls: 'typeahead typeahead-long dropdown-menu',
10109 //                    style: 'display:none'
10110 //                }
10111             ]
10112         };
10113         
10114         if(!this.multiple && this.showToggleBtn){
10115             
10116             var caret = {
10117                         tag: 'span',
10118                         cls: 'caret'
10119              };
10120             if (this.caret != false) {
10121                 caret = {
10122                      tag: 'i',
10123                      cls: 'fa fa-' + this.caret
10124                 };
10125                 
10126             }
10127             
10128             combobox.cn.push({
10129                 tag :'span',
10130                 cls : 'input-group-addon btn dropdown-toggle',
10131                 cn : [
10132                     caret,
10133                     {
10134                         tag: 'span',
10135                         cls: 'combobox-clear',
10136                         cn  : [
10137                             {
10138                                 tag : 'i',
10139                                 cls: 'icon-remove'
10140                             }
10141                         ]
10142                     }
10143                 ]
10144
10145             })
10146         }
10147         
10148         if(this.multiple){
10149             combobox.cls += ' roo-select2-container-multi';
10150         }
10151         
10152         if (align ==='left' && this.fieldLabel.length) {
10153             
10154             cfg.cls += ' roo-form-group-label-left';
10155
10156             cfg.cn = [
10157                 {
10158                     tag : 'i',
10159                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10160                     tooltip : 'This field is required'
10161                 },
10162                 {
10163                     tag: 'label',
10164                     'for' :  id,
10165                     cls : 'control-label',
10166                     html : this.fieldLabel
10167
10168                 },
10169                 {
10170                     cls : "", 
10171                     cn: [
10172                         combobox
10173                     ]
10174                 }
10175
10176             ];
10177             
10178             var labelCfg = cfg.cn[1];
10179             var contentCfg = cfg.cn[2];
10180             
10181             if(this.indicatorpos == 'right'){
10182                 cfg.cn = [
10183                     {
10184                         tag: 'label',
10185                         'for' :  id,
10186                         cls : 'control-label',
10187                         cn : [
10188                             {
10189                                 tag : 'span',
10190                                 html : this.fieldLabel
10191                             },
10192                             {
10193                                 tag : 'i',
10194                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10195                                 tooltip : 'This field is required'
10196                             }
10197                         ]
10198                     },
10199                     {
10200                         cls : "", 
10201                         cn: [
10202                             combobox
10203                         ]
10204                     }
10205
10206                 ];
10207                 
10208                 labelCfg = cfg.cn[0];
10209                 contentCfg = cfg.cn[1];
10210             }
10211             
10212             if(this.labelWidth > 12){
10213                 labelCfg.style = "width: " + this.labelWidth + 'px';
10214             }
10215             
10216             if(this.labelWidth < 13 && this.labelmd == 0){
10217                 this.labelmd = this.labelWidth;
10218             }
10219             
10220             if(this.labellg > 0){
10221                 labelCfg.cls += ' col-lg-' + this.labellg;
10222                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10223             }
10224             
10225             if(this.labelmd > 0){
10226                 labelCfg.cls += ' col-md-' + this.labelmd;
10227                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10228             }
10229             
10230             if(this.labelsm > 0){
10231                 labelCfg.cls += ' col-sm-' + this.labelsm;
10232                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10233             }
10234             
10235             if(this.labelxs > 0){
10236                 labelCfg.cls += ' col-xs-' + this.labelxs;
10237                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10238             }
10239             
10240         } else if ( this.fieldLabel.length) {
10241 //                Roo.log(" label");
10242             cfg.cn = [
10243                 {
10244                    tag : 'i',
10245                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10246                    tooltip : 'This field is required'
10247                },
10248                {
10249                    tag: 'label',
10250                    //cls : 'input-group-addon',
10251                    html : this.fieldLabel
10252
10253                },
10254
10255                combobox
10256
10257             ];
10258             
10259             if(this.indicatorpos == 'right'){
10260                 
10261                 cfg.cn = [
10262                     {
10263                        tag: 'label',
10264                        cn : [
10265                            {
10266                                tag : 'span',
10267                                html : this.fieldLabel
10268                            },
10269                            {
10270                               tag : 'i',
10271                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10272                               tooltip : 'This field is required'
10273                            }
10274                        ]
10275
10276                     },
10277                     combobox
10278
10279                 ];
10280
10281             }
10282
10283         } else {
10284             
10285 //                Roo.log(" no label && no align");
10286                 cfg = combobox
10287                      
10288                 
10289         }
10290         
10291         var settings=this;
10292         ['xs','sm','md','lg'].map(function(size){
10293             if (settings[size]) {
10294                 cfg.cls += ' col-' + size + '-' + settings[size];
10295             }
10296         });
10297         
10298         return cfg;
10299         
10300     },
10301     
10302     
10303     
10304     // private
10305     onResize : function(w, h){
10306 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10307 //        if(typeof w == 'number'){
10308 //            var x = w - this.trigger.getWidth();
10309 //            this.inputEl().setWidth(this.adjustWidth('input', x));
10310 //            this.trigger.setStyle('left', x+'px');
10311 //        }
10312     },
10313
10314     // private
10315     adjustSize : Roo.BoxComponent.prototype.adjustSize,
10316
10317     // private
10318     getResizeEl : function(){
10319         return this.inputEl();
10320     },
10321
10322     // private
10323     getPositionEl : function(){
10324         return this.inputEl();
10325     },
10326
10327     // private
10328     alignErrorIcon : function(){
10329         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10330     },
10331
10332     // private
10333     initEvents : function(){
10334         
10335         this.createList();
10336         
10337         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10338         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10339         if(!this.multiple && this.showToggleBtn){
10340             this.trigger = this.el.select('span.dropdown-toggle',true).first();
10341             if(this.hideTrigger){
10342                 this.trigger.setDisplayed(false);
10343             }
10344             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10345         }
10346         
10347         if(this.multiple){
10348             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10349         }
10350         
10351         if(this.removable && !this.editable && !this.tickable){
10352             var close = this.closeTriggerEl();
10353             
10354             if(close){
10355                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10356                 close.on('click', this.removeBtnClick, this, close);
10357             }
10358         }
10359         
10360         //this.trigger.addClassOnOver('x-form-trigger-over');
10361         //this.trigger.addClassOnClick('x-form-trigger-click');
10362         
10363         //if(!this.width){
10364         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10365         //}
10366     },
10367     
10368     closeTriggerEl : function()
10369     {
10370         var close = this.el.select('.roo-combo-removable-btn', true).first();
10371         return close ? close : false;
10372     },
10373     
10374     removeBtnClick : function(e, h, el)
10375     {
10376         e.preventDefault();
10377         
10378         if(this.fireEvent("remove", this) !== false){
10379             this.reset();
10380             this.fireEvent("afterremove", this)
10381         }
10382     },
10383     
10384     createList : function()
10385     {
10386         this.list = Roo.get(document.body).createChild({
10387             tag: 'ul',
10388             cls: 'typeahead typeahead-long dropdown-menu',
10389             style: 'display:none'
10390         });
10391         
10392         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10393         
10394     },
10395
10396     // private
10397     initTrigger : function(){
10398        
10399     },
10400
10401     // private
10402     onDestroy : function(){
10403         if(this.trigger){
10404             this.trigger.removeAllListeners();
10405           //  this.trigger.remove();
10406         }
10407         //if(this.wrap){
10408         //    this.wrap.remove();
10409         //}
10410         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10411     },
10412
10413     // private
10414     onFocus : function(){
10415         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10416         /*
10417         if(!this.mimicing){
10418             this.wrap.addClass('x-trigger-wrap-focus');
10419             this.mimicing = true;
10420             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10421             if(this.monitorTab){
10422                 this.el.on("keydown", this.checkTab, this);
10423             }
10424         }
10425         */
10426     },
10427
10428     // private
10429     checkTab : function(e){
10430         if(e.getKey() == e.TAB){
10431             this.triggerBlur();
10432         }
10433     },
10434
10435     // private
10436     onBlur : function(){
10437         // do nothing
10438     },
10439
10440     // private
10441     mimicBlur : function(e, t){
10442         /*
10443         if(!this.wrap.contains(t) && this.validateBlur()){
10444             this.triggerBlur();
10445         }
10446         */
10447     },
10448
10449     // private
10450     triggerBlur : function(){
10451         this.mimicing = false;
10452         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10453         if(this.monitorTab){
10454             this.el.un("keydown", this.checkTab, this);
10455         }
10456         //this.wrap.removeClass('x-trigger-wrap-focus');
10457         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10458     },
10459
10460     // private
10461     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10462     validateBlur : function(e, t){
10463         return true;
10464     },
10465
10466     // private
10467     onDisable : function(){
10468         this.inputEl().dom.disabled = true;
10469         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10470         //if(this.wrap){
10471         //    this.wrap.addClass('x-item-disabled');
10472         //}
10473     },
10474
10475     // private
10476     onEnable : function(){
10477         this.inputEl().dom.disabled = false;
10478         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10479         //if(this.wrap){
10480         //    this.el.removeClass('x-item-disabled');
10481         //}
10482     },
10483
10484     // private
10485     onShow : function(){
10486         var ae = this.getActionEl();
10487         
10488         if(ae){
10489             ae.dom.style.display = '';
10490             ae.dom.style.visibility = 'visible';
10491         }
10492     },
10493
10494     // private
10495     
10496     onHide : function(){
10497         var ae = this.getActionEl();
10498         ae.dom.style.display = 'none';
10499     },
10500
10501     /**
10502      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
10503      * by an implementing function.
10504      * @method
10505      * @param {EventObject} e
10506      */
10507     onTriggerClick : Roo.emptyFn
10508 });
10509  /*
10510  * Based on:
10511  * Ext JS Library 1.1.1
10512  * Copyright(c) 2006-2007, Ext JS, LLC.
10513  *
10514  * Originally Released Under LGPL - original licence link has changed is not relivant.
10515  *
10516  * Fork - LGPL
10517  * <script type="text/javascript">
10518  */
10519
10520
10521 /**
10522  * @class Roo.data.SortTypes
10523  * @singleton
10524  * Defines the default sorting (casting?) comparison functions used when sorting data.
10525  */
10526 Roo.data.SortTypes = {
10527     /**
10528      * Default sort that does nothing
10529      * @param {Mixed} s The value being converted
10530      * @return {Mixed} The comparison value
10531      */
10532     none : function(s){
10533         return s;
10534     },
10535     
10536     /**
10537      * The regular expression used to strip tags
10538      * @type {RegExp}
10539      * @property
10540      */
10541     stripTagsRE : /<\/?[^>]+>/gi,
10542     
10543     /**
10544      * Strips all HTML tags to sort on text only
10545      * @param {Mixed} s The value being converted
10546      * @return {String} The comparison value
10547      */
10548     asText : function(s){
10549         return String(s).replace(this.stripTagsRE, "");
10550     },
10551     
10552     /**
10553      * Strips all HTML tags to sort on text only - Case insensitive
10554      * @param {Mixed} s The value being converted
10555      * @return {String} The comparison value
10556      */
10557     asUCText : function(s){
10558         return String(s).toUpperCase().replace(this.stripTagsRE, "");
10559     },
10560     
10561     /**
10562      * Case insensitive string
10563      * @param {Mixed} s The value being converted
10564      * @return {String} The comparison value
10565      */
10566     asUCString : function(s) {
10567         return String(s).toUpperCase();
10568     },
10569     
10570     /**
10571      * Date sorting
10572      * @param {Mixed} s The value being converted
10573      * @return {Number} The comparison value
10574      */
10575     asDate : function(s) {
10576         if(!s){
10577             return 0;
10578         }
10579         if(s instanceof Date){
10580             return s.getTime();
10581         }
10582         return Date.parse(String(s));
10583     },
10584     
10585     /**
10586      * Float sorting
10587      * @param {Mixed} s The value being converted
10588      * @return {Float} The comparison value
10589      */
10590     asFloat : function(s) {
10591         var val = parseFloat(String(s).replace(/,/g, ""));
10592         if(isNaN(val)) {
10593             val = 0;
10594         }
10595         return val;
10596     },
10597     
10598     /**
10599      * Integer sorting
10600      * @param {Mixed} s The value being converted
10601      * @return {Number} The comparison value
10602      */
10603     asInt : function(s) {
10604         var val = parseInt(String(s).replace(/,/g, ""));
10605         if(isNaN(val)) {
10606             val = 0;
10607         }
10608         return val;
10609     }
10610 };/*
10611  * Based on:
10612  * Ext JS Library 1.1.1
10613  * Copyright(c) 2006-2007, Ext JS, LLC.
10614  *
10615  * Originally Released Under LGPL - original licence link has changed is not relivant.
10616  *
10617  * Fork - LGPL
10618  * <script type="text/javascript">
10619  */
10620
10621 /**
10622 * @class Roo.data.Record
10623  * Instances of this class encapsulate both record <em>definition</em> information, and record
10624  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10625  * to access Records cached in an {@link Roo.data.Store} object.<br>
10626  * <p>
10627  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10628  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10629  * objects.<br>
10630  * <p>
10631  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10632  * @constructor
10633  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10634  * {@link #create}. The parameters are the same.
10635  * @param {Array} data An associative Array of data values keyed by the field name.
10636  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10637  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10638  * not specified an integer id is generated.
10639  */
10640 Roo.data.Record = function(data, id){
10641     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10642     this.data = data;
10643 };
10644
10645 /**
10646  * Generate a constructor for a specific record layout.
10647  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10648  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10649  * Each field definition object may contain the following properties: <ul>
10650  * <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,
10651  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10652  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10653  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10654  * is being used, then this is a string containing the javascript expression to reference the data relative to 
10655  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10656  * to the data item relative to the record element. If the mapping expression is the same as the field name,
10657  * this may be omitted.</p></li>
10658  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10659  * <ul><li>auto (Default, implies no conversion)</li>
10660  * <li>string</li>
10661  * <li>int</li>
10662  * <li>float</li>
10663  * <li>boolean</li>
10664  * <li>date</li></ul></p></li>
10665  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10666  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10667  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10668  * by the Reader into an object that will be stored in the Record. It is passed the
10669  * following parameters:<ul>
10670  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10671  * </ul></p></li>
10672  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10673  * </ul>
10674  * <br>usage:<br><pre><code>
10675 var TopicRecord = Roo.data.Record.create(
10676     {name: 'title', mapping: 'topic_title'},
10677     {name: 'author', mapping: 'username'},
10678     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10679     {name: 'lastPost', mapping: 'post_time', type: 'date'},
10680     {name: 'lastPoster', mapping: 'user2'},
10681     {name: 'excerpt', mapping: 'post_text'}
10682 );
10683
10684 var myNewRecord = new TopicRecord({
10685     title: 'Do my job please',
10686     author: 'noobie',
10687     totalPosts: 1,
10688     lastPost: new Date(),
10689     lastPoster: 'Animal',
10690     excerpt: 'No way dude!'
10691 });
10692 myStore.add(myNewRecord);
10693 </code></pre>
10694  * @method create
10695  * @static
10696  */
10697 Roo.data.Record.create = function(o){
10698     var f = function(){
10699         f.superclass.constructor.apply(this, arguments);
10700     };
10701     Roo.extend(f, Roo.data.Record);
10702     var p = f.prototype;
10703     p.fields = new Roo.util.MixedCollection(false, function(field){
10704         return field.name;
10705     });
10706     for(var i = 0, len = o.length; i < len; i++){
10707         p.fields.add(new Roo.data.Field(o[i]));
10708     }
10709     f.getField = function(name){
10710         return p.fields.get(name);  
10711     };
10712     return f;
10713 };
10714
10715 Roo.data.Record.AUTO_ID = 1000;
10716 Roo.data.Record.EDIT = 'edit';
10717 Roo.data.Record.REJECT = 'reject';
10718 Roo.data.Record.COMMIT = 'commit';
10719
10720 Roo.data.Record.prototype = {
10721     /**
10722      * Readonly flag - true if this record has been modified.
10723      * @type Boolean
10724      */
10725     dirty : false,
10726     editing : false,
10727     error: null,
10728     modified: null,
10729
10730     // private
10731     join : function(store){
10732         this.store = store;
10733     },
10734
10735     /**
10736      * Set the named field to the specified value.
10737      * @param {String} name The name of the field to set.
10738      * @param {Object} value The value to set the field to.
10739      */
10740     set : function(name, value){
10741         if(this.data[name] == value){
10742             return;
10743         }
10744         this.dirty = true;
10745         if(!this.modified){
10746             this.modified = {};
10747         }
10748         if(typeof this.modified[name] == 'undefined'){
10749             this.modified[name] = this.data[name];
10750         }
10751         this.data[name] = value;
10752         if(!this.editing && this.store){
10753             this.store.afterEdit(this);
10754         }       
10755     },
10756
10757     /**
10758      * Get the value of the named field.
10759      * @param {String} name The name of the field to get the value of.
10760      * @return {Object} The value of the field.
10761      */
10762     get : function(name){
10763         return this.data[name]; 
10764     },
10765
10766     // private
10767     beginEdit : function(){
10768         this.editing = true;
10769         this.modified = {}; 
10770     },
10771
10772     // private
10773     cancelEdit : function(){
10774         this.editing = false;
10775         delete this.modified;
10776     },
10777
10778     // private
10779     endEdit : function(){
10780         this.editing = false;
10781         if(this.dirty && this.store){
10782             this.store.afterEdit(this);
10783         }
10784     },
10785
10786     /**
10787      * Usually called by the {@link Roo.data.Store} which owns the Record.
10788      * Rejects all changes made to the Record since either creation, or the last commit operation.
10789      * Modified fields are reverted to their original values.
10790      * <p>
10791      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10792      * of reject operations.
10793      */
10794     reject : function(){
10795         var m = this.modified;
10796         for(var n in m){
10797             if(typeof m[n] != "function"){
10798                 this.data[n] = m[n];
10799             }
10800         }
10801         this.dirty = false;
10802         delete this.modified;
10803         this.editing = false;
10804         if(this.store){
10805             this.store.afterReject(this);
10806         }
10807     },
10808
10809     /**
10810      * Usually called by the {@link Roo.data.Store} which owns the Record.
10811      * Commits all changes made to the Record since either creation, or the last commit operation.
10812      * <p>
10813      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10814      * of commit operations.
10815      */
10816     commit : function(){
10817         this.dirty = false;
10818         delete this.modified;
10819         this.editing = false;
10820         if(this.store){
10821             this.store.afterCommit(this);
10822         }
10823     },
10824
10825     // private
10826     hasError : function(){
10827         return this.error != null;
10828     },
10829
10830     // private
10831     clearError : function(){
10832         this.error = null;
10833     },
10834
10835     /**
10836      * Creates a copy of this record.
10837      * @param {String} id (optional) A new record id if you don't want to use this record's id
10838      * @return {Record}
10839      */
10840     copy : function(newId) {
10841         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10842     }
10843 };/*
10844  * Based on:
10845  * Ext JS Library 1.1.1
10846  * Copyright(c) 2006-2007, Ext JS, LLC.
10847  *
10848  * Originally Released Under LGPL - original licence link has changed is not relivant.
10849  *
10850  * Fork - LGPL
10851  * <script type="text/javascript">
10852  */
10853
10854
10855
10856 /**
10857  * @class Roo.data.Store
10858  * @extends Roo.util.Observable
10859  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10860  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10861  * <p>
10862  * 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
10863  * has no knowledge of the format of the data returned by the Proxy.<br>
10864  * <p>
10865  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10866  * instances from the data object. These records are cached and made available through accessor functions.
10867  * @constructor
10868  * Creates a new Store.
10869  * @param {Object} config A config object containing the objects needed for the Store to access data,
10870  * and read the data into Records.
10871  */
10872 Roo.data.Store = function(config){
10873     this.data = new Roo.util.MixedCollection(false);
10874     this.data.getKey = function(o){
10875         return o.id;
10876     };
10877     this.baseParams = {};
10878     // private
10879     this.paramNames = {
10880         "start" : "start",
10881         "limit" : "limit",
10882         "sort" : "sort",
10883         "dir" : "dir",
10884         "multisort" : "_multisort"
10885     };
10886
10887     if(config && config.data){
10888         this.inlineData = config.data;
10889         delete config.data;
10890     }
10891
10892     Roo.apply(this, config);
10893     
10894     if(this.reader){ // reader passed
10895         this.reader = Roo.factory(this.reader, Roo.data);
10896         this.reader.xmodule = this.xmodule || false;
10897         if(!this.recordType){
10898             this.recordType = this.reader.recordType;
10899         }
10900         if(this.reader.onMetaChange){
10901             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10902         }
10903     }
10904
10905     if(this.recordType){
10906         this.fields = this.recordType.prototype.fields;
10907     }
10908     this.modified = [];
10909
10910     this.addEvents({
10911         /**
10912          * @event datachanged
10913          * Fires when the data cache has changed, and a widget which is using this Store
10914          * as a Record cache should refresh its view.
10915          * @param {Store} this
10916          */
10917         datachanged : true,
10918         /**
10919          * @event metachange
10920          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10921          * @param {Store} this
10922          * @param {Object} meta The JSON metadata
10923          */
10924         metachange : true,
10925         /**
10926          * @event add
10927          * Fires when Records have been added to the Store
10928          * @param {Store} this
10929          * @param {Roo.data.Record[]} records The array of Records added
10930          * @param {Number} index The index at which the record(s) were added
10931          */
10932         add : true,
10933         /**
10934          * @event remove
10935          * Fires when a Record has been removed from the Store
10936          * @param {Store} this
10937          * @param {Roo.data.Record} record The Record that was removed
10938          * @param {Number} index The index at which the record was removed
10939          */
10940         remove : true,
10941         /**
10942          * @event update
10943          * Fires when a Record has been updated
10944          * @param {Store} this
10945          * @param {Roo.data.Record} record The Record that was updated
10946          * @param {String} operation The update operation being performed.  Value may be one of:
10947          * <pre><code>
10948  Roo.data.Record.EDIT
10949  Roo.data.Record.REJECT
10950  Roo.data.Record.COMMIT
10951          * </code></pre>
10952          */
10953         update : true,
10954         /**
10955          * @event clear
10956          * Fires when the data cache has been cleared.
10957          * @param {Store} this
10958          */
10959         clear : true,
10960         /**
10961          * @event beforeload
10962          * Fires before a request is made for a new data object.  If the beforeload handler returns false
10963          * the load action will be canceled.
10964          * @param {Store} this
10965          * @param {Object} options The loading options that were specified (see {@link #load} for details)
10966          */
10967         beforeload : true,
10968         /**
10969          * @event beforeloadadd
10970          * Fires after a new set of Records has been loaded.
10971          * @param {Store} this
10972          * @param {Roo.data.Record[]} records The Records that were loaded
10973          * @param {Object} options The loading options that were specified (see {@link #load} for details)
10974          */
10975         beforeloadadd : true,
10976         /**
10977          * @event load
10978          * Fires after a new set of Records has been loaded, before they are added to the store.
10979          * @param {Store} this
10980          * @param {Roo.data.Record[]} records The Records that were loaded
10981          * @param {Object} options The loading options that were specified (see {@link #load} for details)
10982          * @params {Object} return from reader
10983          */
10984         load : true,
10985         /**
10986          * @event loadexception
10987          * Fires if an exception occurs in the Proxy during loading.
10988          * Called with the signature of the Proxy's "loadexception" event.
10989          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10990          * 
10991          * @param {Proxy} 
10992          * @param {Object} return from JsonData.reader() - success, totalRecords, records
10993          * @param {Object} load options 
10994          * @param {Object} jsonData from your request (normally this contains the Exception)
10995          */
10996         loadexception : true
10997     });
10998     
10999     if(this.proxy){
11000         this.proxy = Roo.factory(this.proxy, Roo.data);
11001         this.proxy.xmodule = this.xmodule || false;
11002         this.relayEvents(this.proxy,  ["loadexception"]);
11003     }
11004     this.sortToggle = {};
11005     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11006
11007     Roo.data.Store.superclass.constructor.call(this);
11008
11009     if(this.inlineData){
11010         this.loadData(this.inlineData);
11011         delete this.inlineData;
11012     }
11013 };
11014
11015 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11016      /**
11017     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
11018     * without a remote query - used by combo/forms at present.
11019     */
11020     
11021     /**
11022     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11023     */
11024     /**
11025     * @cfg {Array} data Inline data to be loaded when the store is initialized.
11026     */
11027     /**
11028     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11029     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11030     */
11031     /**
11032     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11033     * on any HTTP request
11034     */
11035     /**
11036     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11037     */
11038     /**
11039     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11040     */
11041     multiSort: false,
11042     /**
11043     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11044     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11045     */
11046     remoteSort : false,
11047
11048     /**
11049     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11050      * loaded or when a record is removed. (defaults to false).
11051     */
11052     pruneModifiedRecords : false,
11053
11054     // private
11055     lastOptions : null,
11056
11057     /**
11058      * Add Records to the Store and fires the add event.
11059      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11060      */
11061     add : function(records){
11062         records = [].concat(records);
11063         for(var i = 0, len = records.length; i < len; i++){
11064             records[i].join(this);
11065         }
11066         var index = this.data.length;
11067         this.data.addAll(records);
11068         this.fireEvent("add", this, records, index);
11069     },
11070
11071     /**
11072      * Remove a Record from the Store and fires the remove event.
11073      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11074      */
11075     remove : function(record){
11076         var index = this.data.indexOf(record);
11077         this.data.removeAt(index);
11078         if(this.pruneModifiedRecords){
11079             this.modified.remove(record);
11080         }
11081         this.fireEvent("remove", this, record, index);
11082     },
11083
11084     /**
11085      * Remove all Records from the Store and fires the clear event.
11086      */
11087     removeAll : function(){
11088         this.data.clear();
11089         if(this.pruneModifiedRecords){
11090             this.modified = [];
11091         }
11092         this.fireEvent("clear", this);
11093     },
11094
11095     /**
11096      * Inserts Records to the Store at the given index and fires the add event.
11097      * @param {Number} index The start index at which to insert the passed Records.
11098      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11099      */
11100     insert : function(index, records){
11101         records = [].concat(records);
11102         for(var i = 0, len = records.length; i < len; i++){
11103             this.data.insert(index, records[i]);
11104             records[i].join(this);
11105         }
11106         this.fireEvent("add", this, records, index);
11107     },
11108
11109     /**
11110      * Get the index within the cache of the passed Record.
11111      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11112      * @return {Number} The index of the passed Record. Returns -1 if not found.
11113      */
11114     indexOf : function(record){
11115         return this.data.indexOf(record);
11116     },
11117
11118     /**
11119      * Get the index within the cache of the Record with the passed id.
11120      * @param {String} id The id of the Record to find.
11121      * @return {Number} The index of the Record. Returns -1 if not found.
11122      */
11123     indexOfId : function(id){
11124         return this.data.indexOfKey(id);
11125     },
11126
11127     /**
11128      * Get the Record with the specified id.
11129      * @param {String} id The id of the Record to find.
11130      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11131      */
11132     getById : function(id){
11133         return this.data.key(id);
11134     },
11135
11136     /**
11137      * Get the Record at the specified index.
11138      * @param {Number} index The index of the Record to find.
11139      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11140      */
11141     getAt : function(index){
11142         return this.data.itemAt(index);
11143     },
11144
11145     /**
11146      * Returns a range of Records between specified indices.
11147      * @param {Number} startIndex (optional) The starting index (defaults to 0)
11148      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11149      * @return {Roo.data.Record[]} An array of Records
11150      */
11151     getRange : function(start, end){
11152         return this.data.getRange(start, end);
11153     },
11154
11155     // private
11156     storeOptions : function(o){
11157         o = Roo.apply({}, o);
11158         delete o.callback;
11159         delete o.scope;
11160         this.lastOptions = o;
11161     },
11162
11163     /**
11164      * Loads the Record cache from the configured Proxy using the configured Reader.
11165      * <p>
11166      * If using remote paging, then the first load call must specify the <em>start</em>
11167      * and <em>limit</em> properties in the options.params property to establish the initial
11168      * position within the dataset, and the number of Records to cache on each read from the Proxy.
11169      * <p>
11170      * <strong>It is important to note that for remote data sources, loading is asynchronous,
11171      * and this call will return before the new data has been loaded. Perform any post-processing
11172      * in a callback function, or in a "load" event handler.</strong>
11173      * <p>
11174      * @param {Object} options An object containing properties which control loading options:<ul>
11175      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11176      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11177      * passed the following arguments:<ul>
11178      * <li>r : Roo.data.Record[]</li>
11179      * <li>options: Options object from the load call</li>
11180      * <li>success: Boolean success indicator</li></ul></li>
11181      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11182      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11183      * </ul>
11184      */
11185     load : function(options){
11186         options = options || {};
11187         if(this.fireEvent("beforeload", this, options) !== false){
11188             this.storeOptions(options);
11189             var p = Roo.apply(options.params || {}, this.baseParams);
11190             // if meta was not loaded from remote source.. try requesting it.
11191             if (!this.reader.metaFromRemote) {
11192                 p._requestMeta = 1;
11193             }
11194             if(this.sortInfo && this.remoteSort){
11195                 var pn = this.paramNames;
11196                 p[pn["sort"]] = this.sortInfo.field;
11197                 p[pn["dir"]] = this.sortInfo.direction;
11198             }
11199             if (this.multiSort) {
11200                 var pn = this.paramNames;
11201                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11202             }
11203             
11204             this.proxy.load(p, this.reader, this.loadRecords, this, options);
11205         }
11206     },
11207
11208     /**
11209      * Reloads the Record cache from the configured Proxy using the configured Reader and
11210      * the options from the last load operation performed.
11211      * @param {Object} options (optional) An object containing properties which may override the options
11212      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11213      * the most recently used options are reused).
11214      */
11215     reload : function(options){
11216         this.load(Roo.applyIf(options||{}, this.lastOptions));
11217     },
11218
11219     // private
11220     // Called as a callback by the Reader during a load operation.
11221     loadRecords : function(o, options, success){
11222         if(!o || success === false){
11223             if(success !== false){
11224                 this.fireEvent("load", this, [], options, o);
11225             }
11226             if(options.callback){
11227                 options.callback.call(options.scope || this, [], options, false);
11228             }
11229             return;
11230         }
11231         // if data returned failure - throw an exception.
11232         if (o.success === false) {
11233             // show a message if no listener is registered.
11234             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11235                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11236             }
11237             // loadmask wil be hooked into this..
11238             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11239             return;
11240         }
11241         var r = o.records, t = o.totalRecords || r.length;
11242         
11243         this.fireEvent("beforeloadadd", this, r, options, o);
11244         
11245         if(!options || options.add !== true){
11246             if(this.pruneModifiedRecords){
11247                 this.modified = [];
11248             }
11249             for(var i = 0, len = r.length; i < len; i++){
11250                 r[i].join(this);
11251             }
11252             if(this.snapshot){
11253                 this.data = this.snapshot;
11254                 delete this.snapshot;
11255             }
11256             this.data.clear();
11257             this.data.addAll(r);
11258             this.totalLength = t;
11259             this.applySort();
11260             this.fireEvent("datachanged", this);
11261         }else{
11262             this.totalLength = Math.max(t, this.data.length+r.length);
11263             this.add(r);
11264         }
11265         
11266         if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11267                 
11268             var e = new Roo.data.Record({});
11269
11270             e.set(this.parent.displayField, this.parent.emptyTitle);
11271             e.set(this.parent.valueField, '');
11272
11273             this.insert(0, e);
11274         }
11275             
11276         this.fireEvent("load", this, r, options, o);
11277         if(options.callback){
11278             options.callback.call(options.scope || this, r, options, true);
11279         }
11280     },
11281
11282
11283     /**
11284      * Loads data from a passed data block. A Reader which understands the format of the data
11285      * must have been configured in the constructor.
11286      * @param {Object} data The data block from which to read the Records.  The format of the data expected
11287      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11288      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11289      */
11290     loadData : function(o, append){
11291         var r = this.reader.readRecords(o);
11292         this.loadRecords(r, {add: append}, true);
11293     },
11294
11295     /**
11296      * Gets the number of cached records.
11297      * <p>
11298      * <em>If using paging, this may not be the total size of the dataset. If the data object
11299      * used by the Reader contains the dataset size, then the getTotalCount() function returns
11300      * the data set size</em>
11301      */
11302     getCount : function(){
11303         return this.data.length || 0;
11304     },
11305
11306     /**
11307      * Gets the total number of records in the dataset as returned by the server.
11308      * <p>
11309      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11310      * the dataset size</em>
11311      */
11312     getTotalCount : function(){
11313         return this.totalLength || 0;
11314     },
11315
11316     /**
11317      * Returns the sort state of the Store as an object with two properties:
11318      * <pre><code>
11319  field {String} The name of the field by which the Records are sorted
11320  direction {String} The sort order, "ASC" or "DESC"
11321      * </code></pre>
11322      */
11323     getSortState : function(){
11324         return this.sortInfo;
11325     },
11326
11327     // private
11328     applySort : function(){
11329         if(this.sortInfo && !this.remoteSort){
11330             var s = this.sortInfo, f = s.field;
11331             var st = this.fields.get(f).sortType;
11332             var fn = function(r1, r2){
11333                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11334                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11335             };
11336             this.data.sort(s.direction, fn);
11337             if(this.snapshot && this.snapshot != this.data){
11338                 this.snapshot.sort(s.direction, fn);
11339             }
11340         }
11341     },
11342
11343     /**
11344      * Sets the default sort column and order to be used by the next load operation.
11345      * @param {String} fieldName The name of the field to sort by.
11346      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11347      */
11348     setDefaultSort : function(field, dir){
11349         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11350     },
11351
11352     /**
11353      * Sort the Records.
11354      * If remote sorting is used, the sort is performed on the server, and the cache is
11355      * reloaded. If local sorting is used, the cache is sorted internally.
11356      * @param {String} fieldName The name of the field to sort by.
11357      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11358      */
11359     sort : function(fieldName, dir){
11360         var f = this.fields.get(fieldName);
11361         if(!dir){
11362             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11363             
11364             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11365                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11366             }else{
11367                 dir = f.sortDir;
11368             }
11369         }
11370         this.sortToggle[f.name] = dir;
11371         this.sortInfo = {field: f.name, direction: dir};
11372         if(!this.remoteSort){
11373             this.applySort();
11374             this.fireEvent("datachanged", this);
11375         }else{
11376             this.load(this.lastOptions);
11377         }
11378     },
11379
11380     /**
11381      * Calls the specified function for each of the Records in the cache.
11382      * @param {Function} fn The function to call. The Record is passed as the first parameter.
11383      * Returning <em>false</em> aborts and exits the iteration.
11384      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11385      */
11386     each : function(fn, scope){
11387         this.data.each(fn, scope);
11388     },
11389
11390     /**
11391      * Gets all records modified since the last commit.  Modified records are persisted across load operations
11392      * (e.g., during paging).
11393      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11394      */
11395     getModifiedRecords : function(){
11396         return this.modified;
11397     },
11398
11399     // private
11400     createFilterFn : function(property, value, anyMatch){
11401         if(!value.exec){ // not a regex
11402             value = String(value);
11403             if(value.length == 0){
11404                 return false;
11405             }
11406             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11407         }
11408         return function(r){
11409             return value.test(r.data[property]);
11410         };
11411     },
11412
11413     /**
11414      * Sums the value of <i>property</i> for each record between start and end and returns the result.
11415      * @param {String} property A field on your records
11416      * @param {Number} start The record index to start at (defaults to 0)
11417      * @param {Number} end The last record index to include (defaults to length - 1)
11418      * @return {Number} The sum
11419      */
11420     sum : function(property, start, end){
11421         var rs = this.data.items, v = 0;
11422         start = start || 0;
11423         end = (end || end === 0) ? end : rs.length-1;
11424
11425         for(var i = start; i <= end; i++){
11426             v += (rs[i].data[property] || 0);
11427         }
11428         return v;
11429     },
11430
11431     /**
11432      * Filter the records by a specified property.
11433      * @param {String} field A field on your records
11434      * @param {String/RegExp} value Either a string that the field
11435      * should start with or a RegExp to test against the field
11436      * @param {Boolean} anyMatch True to match any part not just the beginning
11437      */
11438     filter : function(property, value, anyMatch){
11439         var fn = this.createFilterFn(property, value, anyMatch);
11440         return fn ? this.filterBy(fn) : this.clearFilter();
11441     },
11442
11443     /**
11444      * Filter by a function. The specified function will be called with each
11445      * record in this data source. If the function returns true the record is included,
11446      * otherwise it is filtered.
11447      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11448      * @param {Object} scope (optional) The scope of the function (defaults to this)
11449      */
11450     filterBy : function(fn, scope){
11451         this.snapshot = this.snapshot || this.data;
11452         this.data = this.queryBy(fn, scope||this);
11453         this.fireEvent("datachanged", this);
11454     },
11455
11456     /**
11457      * Query the records by a specified property.
11458      * @param {String} field A field on your records
11459      * @param {String/RegExp} value Either a string that the field
11460      * should start with or a RegExp to test against the field
11461      * @param {Boolean} anyMatch True to match any part not just the beginning
11462      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11463      */
11464     query : function(property, value, anyMatch){
11465         var fn = this.createFilterFn(property, value, anyMatch);
11466         return fn ? this.queryBy(fn) : this.data.clone();
11467     },
11468
11469     /**
11470      * Query by a function. The specified function will be called with each
11471      * record in this data source. If the function returns true the record is included
11472      * in the results.
11473      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11474      * @param {Object} scope (optional) The scope of the function (defaults to this)
11475       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11476      **/
11477     queryBy : function(fn, scope){
11478         var data = this.snapshot || this.data;
11479         return data.filterBy(fn, scope||this);
11480     },
11481
11482     /**
11483      * Collects unique values for a particular dataIndex from this store.
11484      * @param {String} dataIndex The property to collect
11485      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11486      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11487      * @return {Array} An array of the unique values
11488      **/
11489     collect : function(dataIndex, allowNull, bypassFilter){
11490         var d = (bypassFilter === true && this.snapshot) ?
11491                 this.snapshot.items : this.data.items;
11492         var v, sv, r = [], l = {};
11493         for(var i = 0, len = d.length; i < len; i++){
11494             v = d[i].data[dataIndex];
11495             sv = String(v);
11496             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11497                 l[sv] = true;
11498                 r[r.length] = v;
11499             }
11500         }
11501         return r;
11502     },
11503
11504     /**
11505      * Revert to a view of the Record cache with no filtering applied.
11506      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11507      */
11508     clearFilter : function(suppressEvent){
11509         if(this.snapshot && this.snapshot != this.data){
11510             this.data = this.snapshot;
11511             delete this.snapshot;
11512             if(suppressEvent !== true){
11513                 this.fireEvent("datachanged", this);
11514             }
11515         }
11516     },
11517
11518     // private
11519     afterEdit : function(record){
11520         if(this.modified.indexOf(record) == -1){
11521             this.modified.push(record);
11522         }
11523         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11524     },
11525     
11526     // private
11527     afterReject : function(record){
11528         this.modified.remove(record);
11529         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11530     },
11531
11532     // private
11533     afterCommit : function(record){
11534         this.modified.remove(record);
11535         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11536     },
11537
11538     /**
11539      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11540      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11541      */
11542     commitChanges : function(){
11543         var m = this.modified.slice(0);
11544         this.modified = [];
11545         for(var i = 0, len = m.length; i < len; i++){
11546             m[i].commit();
11547         }
11548     },
11549
11550     /**
11551      * Cancel outstanding changes on all changed records.
11552      */
11553     rejectChanges : function(){
11554         var m = this.modified.slice(0);
11555         this.modified = [];
11556         for(var i = 0, len = m.length; i < len; i++){
11557             m[i].reject();
11558         }
11559     },
11560
11561     onMetaChange : function(meta, rtype, o){
11562         this.recordType = rtype;
11563         this.fields = rtype.prototype.fields;
11564         delete this.snapshot;
11565         this.sortInfo = meta.sortInfo || this.sortInfo;
11566         this.modified = [];
11567         this.fireEvent('metachange', this, this.reader.meta);
11568     },
11569     
11570     moveIndex : function(data, type)
11571     {
11572         var index = this.indexOf(data);
11573         
11574         var newIndex = index + type;
11575         
11576         this.remove(data);
11577         
11578         this.insert(newIndex, data);
11579         
11580     }
11581 });/*
11582  * Based on:
11583  * Ext JS Library 1.1.1
11584  * Copyright(c) 2006-2007, Ext JS, LLC.
11585  *
11586  * Originally Released Under LGPL - original licence link has changed is not relivant.
11587  *
11588  * Fork - LGPL
11589  * <script type="text/javascript">
11590  */
11591
11592 /**
11593  * @class Roo.data.SimpleStore
11594  * @extends Roo.data.Store
11595  * Small helper class to make creating Stores from Array data easier.
11596  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11597  * @cfg {Array} fields An array of field definition objects, or field name strings.
11598  * @cfg {Array} data The multi-dimensional array of data
11599  * @constructor
11600  * @param {Object} config
11601  */
11602 Roo.data.SimpleStore = function(config){
11603     Roo.data.SimpleStore.superclass.constructor.call(this, {
11604         isLocal : true,
11605         reader: new Roo.data.ArrayReader({
11606                 id: config.id
11607             },
11608             Roo.data.Record.create(config.fields)
11609         ),
11610         proxy : new Roo.data.MemoryProxy(config.data)
11611     });
11612     this.load();
11613 };
11614 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11615  * Based on:
11616  * Ext JS Library 1.1.1
11617  * Copyright(c) 2006-2007, Ext JS, LLC.
11618  *
11619  * Originally Released Under LGPL - original licence link has changed is not relivant.
11620  *
11621  * Fork - LGPL
11622  * <script type="text/javascript">
11623  */
11624
11625 /**
11626 /**
11627  * @extends Roo.data.Store
11628  * @class Roo.data.JsonStore
11629  * Small helper class to make creating Stores for JSON data easier. <br/>
11630 <pre><code>
11631 var store = new Roo.data.JsonStore({
11632     url: 'get-images.php',
11633     root: 'images',
11634     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11635 });
11636 </code></pre>
11637  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11638  * JsonReader and HttpProxy (unless inline data is provided).</b>
11639  * @cfg {Array} fields An array of field definition objects, or field name strings.
11640  * @constructor
11641  * @param {Object} config
11642  */
11643 Roo.data.JsonStore = function(c){
11644     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11645         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11646         reader: new Roo.data.JsonReader(c, c.fields)
11647     }));
11648 };
11649 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11650  * Based on:
11651  * Ext JS Library 1.1.1
11652  * Copyright(c) 2006-2007, Ext JS, LLC.
11653  *
11654  * Originally Released Under LGPL - original licence link has changed is not relivant.
11655  *
11656  * Fork - LGPL
11657  * <script type="text/javascript">
11658  */
11659
11660  
11661 Roo.data.Field = function(config){
11662     if(typeof config == "string"){
11663         config = {name: config};
11664     }
11665     Roo.apply(this, config);
11666     
11667     if(!this.type){
11668         this.type = "auto";
11669     }
11670     
11671     var st = Roo.data.SortTypes;
11672     // named sortTypes are supported, here we look them up
11673     if(typeof this.sortType == "string"){
11674         this.sortType = st[this.sortType];
11675     }
11676     
11677     // set default sortType for strings and dates
11678     if(!this.sortType){
11679         switch(this.type){
11680             case "string":
11681                 this.sortType = st.asUCString;
11682                 break;
11683             case "date":
11684                 this.sortType = st.asDate;
11685                 break;
11686             default:
11687                 this.sortType = st.none;
11688         }
11689     }
11690
11691     // define once
11692     var stripRe = /[\$,%]/g;
11693
11694     // prebuilt conversion function for this field, instead of
11695     // switching every time we're reading a value
11696     if(!this.convert){
11697         var cv, dateFormat = this.dateFormat;
11698         switch(this.type){
11699             case "":
11700             case "auto":
11701             case undefined:
11702                 cv = function(v){ return v; };
11703                 break;
11704             case "string":
11705                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11706                 break;
11707             case "int":
11708                 cv = function(v){
11709                     return v !== undefined && v !== null && v !== '' ?
11710                            parseInt(String(v).replace(stripRe, ""), 10) : '';
11711                     };
11712                 break;
11713             case "float":
11714                 cv = function(v){
11715                     return v !== undefined && v !== null && v !== '' ?
11716                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
11717                     };
11718                 break;
11719             case "bool":
11720             case "boolean":
11721                 cv = function(v){ return v === true || v === "true" || v == 1; };
11722                 break;
11723             case "date":
11724                 cv = function(v){
11725                     if(!v){
11726                         return '';
11727                     }
11728                     if(v instanceof Date){
11729                         return v;
11730                     }
11731                     if(dateFormat){
11732                         if(dateFormat == "timestamp"){
11733                             return new Date(v*1000);
11734                         }
11735                         return Date.parseDate(v, dateFormat);
11736                     }
11737                     var parsed = Date.parse(v);
11738                     return parsed ? new Date(parsed) : null;
11739                 };
11740              break;
11741             
11742         }
11743         this.convert = cv;
11744     }
11745 };
11746
11747 Roo.data.Field.prototype = {
11748     dateFormat: null,
11749     defaultValue: "",
11750     mapping: null,
11751     sortType : null,
11752     sortDir : "ASC"
11753 };/*
11754  * Based on:
11755  * Ext JS Library 1.1.1
11756  * Copyright(c) 2006-2007, Ext JS, LLC.
11757  *
11758  * Originally Released Under LGPL - original licence link has changed is not relivant.
11759  *
11760  * Fork - LGPL
11761  * <script type="text/javascript">
11762  */
11763  
11764 // Base class for reading structured data from a data source.  This class is intended to be
11765 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11766
11767 /**
11768  * @class Roo.data.DataReader
11769  * Base class for reading structured data from a data source.  This class is intended to be
11770  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11771  */
11772
11773 Roo.data.DataReader = function(meta, recordType){
11774     
11775     this.meta = meta;
11776     
11777     this.recordType = recordType instanceof Array ? 
11778         Roo.data.Record.create(recordType) : recordType;
11779 };
11780
11781 Roo.data.DataReader.prototype = {
11782      /**
11783      * Create an empty record
11784      * @param {Object} data (optional) - overlay some values
11785      * @return {Roo.data.Record} record created.
11786      */
11787     newRow :  function(d) {
11788         var da =  {};
11789         this.recordType.prototype.fields.each(function(c) {
11790             switch( c.type) {
11791                 case 'int' : da[c.name] = 0; break;
11792                 case 'date' : da[c.name] = new Date(); break;
11793                 case 'float' : da[c.name] = 0.0; break;
11794                 case 'boolean' : da[c.name] = false; break;
11795                 default : da[c.name] = ""; break;
11796             }
11797             
11798         });
11799         return new this.recordType(Roo.apply(da, d));
11800     }
11801     
11802 };/*
11803  * Based on:
11804  * Ext JS Library 1.1.1
11805  * Copyright(c) 2006-2007, Ext JS, LLC.
11806  *
11807  * Originally Released Under LGPL - original licence link has changed is not relivant.
11808  *
11809  * Fork - LGPL
11810  * <script type="text/javascript">
11811  */
11812
11813 /**
11814  * @class Roo.data.DataProxy
11815  * @extends Roo.data.Observable
11816  * This class is an abstract base class for implementations which provide retrieval of
11817  * unformatted data objects.<br>
11818  * <p>
11819  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11820  * (of the appropriate type which knows how to parse the data object) to provide a block of
11821  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11822  * <p>
11823  * Custom implementations must implement the load method as described in
11824  * {@link Roo.data.HttpProxy#load}.
11825  */
11826 Roo.data.DataProxy = function(){
11827     this.addEvents({
11828         /**
11829          * @event beforeload
11830          * Fires before a network request is made to retrieve a data object.
11831          * @param {Object} This DataProxy object.
11832          * @param {Object} params The params parameter to the load function.
11833          */
11834         beforeload : true,
11835         /**
11836          * @event load
11837          * Fires before the load method's callback is called.
11838          * @param {Object} This DataProxy object.
11839          * @param {Object} o The data object.
11840          * @param {Object} arg The callback argument object passed to the load function.
11841          */
11842         load : true,
11843         /**
11844          * @event loadexception
11845          * Fires if an Exception occurs during data retrieval.
11846          * @param {Object} This DataProxy object.
11847          * @param {Object} o The data object.
11848          * @param {Object} arg The callback argument object passed to the load function.
11849          * @param {Object} e The Exception.
11850          */
11851         loadexception : true
11852     });
11853     Roo.data.DataProxy.superclass.constructor.call(this);
11854 };
11855
11856 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11857
11858     /**
11859      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11860      */
11861 /*
11862  * Based on:
11863  * Ext JS Library 1.1.1
11864  * Copyright(c) 2006-2007, Ext JS, LLC.
11865  *
11866  * Originally Released Under LGPL - original licence link has changed is not relivant.
11867  *
11868  * Fork - LGPL
11869  * <script type="text/javascript">
11870  */
11871 /**
11872  * @class Roo.data.MemoryProxy
11873  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11874  * to the Reader when its load method is called.
11875  * @constructor
11876  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11877  */
11878 Roo.data.MemoryProxy = function(data){
11879     if (data.data) {
11880         data = data.data;
11881     }
11882     Roo.data.MemoryProxy.superclass.constructor.call(this);
11883     this.data = data;
11884 };
11885
11886 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11887     
11888     /**
11889      * Load data from the requested source (in this case an in-memory
11890      * data object passed to the constructor), read the data object into
11891      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11892      * process that block using the passed callback.
11893      * @param {Object} params This parameter is not used by the MemoryProxy class.
11894      * @param {Roo.data.DataReader} reader The Reader object which converts the data
11895      * object into a block of Roo.data.Records.
11896      * @param {Function} callback The function into which to pass the block of Roo.data.records.
11897      * The function must be passed <ul>
11898      * <li>The Record block object</li>
11899      * <li>The "arg" argument from the load function</li>
11900      * <li>A boolean success indicator</li>
11901      * </ul>
11902      * @param {Object} scope The scope in which to call the callback
11903      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11904      */
11905     load : function(params, reader, callback, scope, arg){
11906         params = params || {};
11907         var result;
11908         try {
11909             result = reader.readRecords(this.data);
11910         }catch(e){
11911             this.fireEvent("loadexception", this, arg, null, e);
11912             callback.call(scope, null, arg, false);
11913             return;
11914         }
11915         callback.call(scope, result, arg, true);
11916     },
11917     
11918     // private
11919     update : function(params, records){
11920         
11921     }
11922 });/*
11923  * Based on:
11924  * Ext JS Library 1.1.1
11925  * Copyright(c) 2006-2007, Ext JS, LLC.
11926  *
11927  * Originally Released Under LGPL - original licence link has changed is not relivant.
11928  *
11929  * Fork - LGPL
11930  * <script type="text/javascript">
11931  */
11932 /**
11933  * @class Roo.data.HttpProxy
11934  * @extends Roo.data.DataProxy
11935  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11936  * configured to reference a certain URL.<br><br>
11937  * <p>
11938  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11939  * from which the running page was served.<br><br>
11940  * <p>
11941  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11942  * <p>
11943  * Be aware that to enable the browser to parse an XML document, the server must set
11944  * the Content-Type header in the HTTP response to "text/xml".
11945  * @constructor
11946  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11947  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
11948  * will be used to make the request.
11949  */
11950 Roo.data.HttpProxy = function(conn){
11951     Roo.data.HttpProxy.superclass.constructor.call(this);
11952     // is conn a conn config or a real conn?
11953     this.conn = conn;
11954     this.useAjax = !conn || !conn.events;
11955   
11956 };
11957
11958 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11959     // thse are take from connection...
11960     
11961     /**
11962      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11963      */
11964     /**
11965      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11966      * extra parameters to each request made by this object. (defaults to undefined)
11967      */
11968     /**
11969      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11970      *  to each request made by this object. (defaults to undefined)
11971      */
11972     /**
11973      * @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)
11974      */
11975     /**
11976      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11977      */
11978      /**
11979      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11980      * @type Boolean
11981      */
11982   
11983
11984     /**
11985      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11986      * @type Boolean
11987      */
11988     /**
11989      * Return the {@link Roo.data.Connection} object being used by this Proxy.
11990      * @return {Connection} The Connection object. This object may be used to subscribe to events on
11991      * a finer-grained basis than the DataProxy events.
11992      */
11993     getConnection : function(){
11994         return this.useAjax ? Roo.Ajax : this.conn;
11995     },
11996
11997     /**
11998      * Load data from the configured {@link Roo.data.Connection}, read the data object into
11999      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12000      * process that block using the passed callback.
12001      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12002      * for the request to the remote server.
12003      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12004      * object into a block of Roo.data.Records.
12005      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12006      * The function must be passed <ul>
12007      * <li>The Record block object</li>
12008      * <li>The "arg" argument from the load function</li>
12009      * <li>A boolean success indicator</li>
12010      * </ul>
12011      * @param {Object} scope The scope in which to call the callback
12012      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12013      */
12014     load : function(params, reader, callback, scope, arg){
12015         if(this.fireEvent("beforeload", this, params) !== false){
12016             var  o = {
12017                 params : params || {},
12018                 request: {
12019                     callback : callback,
12020                     scope : scope,
12021                     arg : arg
12022                 },
12023                 reader: reader,
12024                 callback : this.loadResponse,
12025                 scope: this
12026             };
12027             if(this.useAjax){
12028                 Roo.applyIf(o, this.conn);
12029                 if(this.activeRequest){
12030                     Roo.Ajax.abort(this.activeRequest);
12031                 }
12032                 this.activeRequest = Roo.Ajax.request(o);
12033             }else{
12034                 this.conn.request(o);
12035             }
12036         }else{
12037             callback.call(scope||this, null, arg, false);
12038         }
12039     },
12040
12041     // private
12042     loadResponse : function(o, success, response){
12043         delete this.activeRequest;
12044         if(!success){
12045             this.fireEvent("loadexception", this, o, response);
12046             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12047             return;
12048         }
12049         var result;
12050         try {
12051             result = o.reader.read(response);
12052         }catch(e){
12053             this.fireEvent("loadexception", this, o, response, e);
12054             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12055             return;
12056         }
12057         
12058         this.fireEvent("load", this, o, o.request.arg);
12059         o.request.callback.call(o.request.scope, result, o.request.arg, true);
12060     },
12061
12062     // private
12063     update : function(dataSet){
12064
12065     },
12066
12067     // private
12068     updateResponse : function(dataSet){
12069
12070     }
12071 });/*
12072  * Based on:
12073  * Ext JS Library 1.1.1
12074  * Copyright(c) 2006-2007, Ext JS, LLC.
12075  *
12076  * Originally Released Under LGPL - original licence link has changed is not relivant.
12077  *
12078  * Fork - LGPL
12079  * <script type="text/javascript">
12080  */
12081
12082 /**
12083  * @class Roo.data.ScriptTagProxy
12084  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12085  * other than the originating domain of the running page.<br><br>
12086  * <p>
12087  * <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
12088  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12089  * <p>
12090  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12091  * source code that is used as the source inside a &lt;script> tag.<br><br>
12092  * <p>
12093  * In order for the browser to process the returned data, the server must wrap the data object
12094  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12095  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12096  * depending on whether the callback name was passed:
12097  * <p>
12098  * <pre><code>
12099 boolean scriptTag = false;
12100 String cb = request.getParameter("callback");
12101 if (cb != null) {
12102     scriptTag = true;
12103     response.setContentType("text/javascript");
12104 } else {
12105     response.setContentType("application/x-json");
12106 }
12107 Writer out = response.getWriter();
12108 if (scriptTag) {
12109     out.write(cb + "(");
12110 }
12111 out.print(dataBlock.toJsonString());
12112 if (scriptTag) {
12113     out.write(");");
12114 }
12115 </pre></code>
12116  *
12117  * @constructor
12118  * @param {Object} config A configuration object.
12119  */
12120 Roo.data.ScriptTagProxy = function(config){
12121     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12122     Roo.apply(this, config);
12123     this.head = document.getElementsByTagName("head")[0];
12124 };
12125
12126 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12127
12128 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12129     /**
12130      * @cfg {String} url The URL from which to request the data object.
12131      */
12132     /**
12133      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12134      */
12135     timeout : 30000,
12136     /**
12137      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12138      * the server the name of the callback function set up by the load call to process the returned data object.
12139      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12140      * javascript output which calls this named function passing the data object as its only parameter.
12141      */
12142     callbackParam : "callback",
12143     /**
12144      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12145      * name to the request.
12146      */
12147     nocache : true,
12148
12149     /**
12150      * Load data from the configured URL, read the data object into
12151      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12152      * process that block using the passed callback.
12153      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12154      * for the request to the remote server.
12155      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12156      * object into a block of Roo.data.Records.
12157      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12158      * The function must be passed <ul>
12159      * <li>The Record block object</li>
12160      * <li>The "arg" argument from the load function</li>
12161      * <li>A boolean success indicator</li>
12162      * </ul>
12163      * @param {Object} scope The scope in which to call the callback
12164      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12165      */
12166     load : function(params, reader, callback, scope, arg){
12167         if(this.fireEvent("beforeload", this, params) !== false){
12168
12169             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12170
12171             var url = this.url;
12172             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12173             if(this.nocache){
12174                 url += "&_dc=" + (new Date().getTime());
12175             }
12176             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12177             var trans = {
12178                 id : transId,
12179                 cb : "stcCallback"+transId,
12180                 scriptId : "stcScript"+transId,
12181                 params : params,
12182                 arg : arg,
12183                 url : url,
12184                 callback : callback,
12185                 scope : scope,
12186                 reader : reader
12187             };
12188             var conn = this;
12189
12190             window[trans.cb] = function(o){
12191                 conn.handleResponse(o, trans);
12192             };
12193
12194             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12195
12196             if(this.autoAbort !== false){
12197                 this.abort();
12198             }
12199
12200             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12201
12202             var script = document.createElement("script");
12203             script.setAttribute("src", url);
12204             script.setAttribute("type", "text/javascript");
12205             script.setAttribute("id", trans.scriptId);
12206             this.head.appendChild(script);
12207
12208             this.trans = trans;
12209         }else{
12210             callback.call(scope||this, null, arg, false);
12211         }
12212     },
12213
12214     // private
12215     isLoading : function(){
12216         return this.trans ? true : false;
12217     },
12218
12219     /**
12220      * Abort the current server request.
12221      */
12222     abort : function(){
12223         if(this.isLoading()){
12224             this.destroyTrans(this.trans);
12225         }
12226     },
12227
12228     // private
12229     destroyTrans : function(trans, isLoaded){
12230         this.head.removeChild(document.getElementById(trans.scriptId));
12231         clearTimeout(trans.timeoutId);
12232         if(isLoaded){
12233             window[trans.cb] = undefined;
12234             try{
12235                 delete window[trans.cb];
12236             }catch(e){}
12237         }else{
12238             // if hasn't been loaded, wait for load to remove it to prevent script error
12239             window[trans.cb] = function(){
12240                 window[trans.cb] = undefined;
12241                 try{
12242                     delete window[trans.cb];
12243                 }catch(e){}
12244             };
12245         }
12246     },
12247
12248     // private
12249     handleResponse : function(o, trans){
12250         this.trans = false;
12251         this.destroyTrans(trans, true);
12252         var result;
12253         try {
12254             result = trans.reader.readRecords(o);
12255         }catch(e){
12256             this.fireEvent("loadexception", this, o, trans.arg, e);
12257             trans.callback.call(trans.scope||window, null, trans.arg, false);
12258             return;
12259         }
12260         this.fireEvent("load", this, o, trans.arg);
12261         trans.callback.call(trans.scope||window, result, trans.arg, true);
12262     },
12263
12264     // private
12265     handleFailure : function(trans){
12266         this.trans = false;
12267         this.destroyTrans(trans, false);
12268         this.fireEvent("loadexception", this, null, trans.arg);
12269         trans.callback.call(trans.scope||window, null, trans.arg, false);
12270     }
12271 });/*
12272  * Based on:
12273  * Ext JS Library 1.1.1
12274  * Copyright(c) 2006-2007, Ext JS, LLC.
12275  *
12276  * Originally Released Under LGPL - original licence link has changed is not relivant.
12277  *
12278  * Fork - LGPL
12279  * <script type="text/javascript">
12280  */
12281
12282 /**
12283  * @class Roo.data.JsonReader
12284  * @extends Roo.data.DataReader
12285  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12286  * based on mappings in a provided Roo.data.Record constructor.
12287  * 
12288  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12289  * in the reply previously. 
12290  * 
12291  * <p>
12292  * Example code:
12293  * <pre><code>
12294 var RecordDef = Roo.data.Record.create([
12295     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
12296     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
12297 ]);
12298 var myReader = new Roo.data.JsonReader({
12299     totalProperty: "results",    // The property which contains the total dataset size (optional)
12300     root: "rows",                // The property which contains an Array of row objects
12301     id: "id"                     // The property within each row object that provides an ID for the record (optional)
12302 }, RecordDef);
12303 </code></pre>
12304  * <p>
12305  * This would consume a JSON file like this:
12306  * <pre><code>
12307 { 'results': 2, 'rows': [
12308     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12309     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12310 }
12311 </code></pre>
12312  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12313  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12314  * paged from the remote server.
12315  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12316  * @cfg {String} root name of the property which contains the Array of row objects.
12317  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12318  * @cfg {Array} fields Array of field definition objects
12319  * @constructor
12320  * Create a new JsonReader
12321  * @param {Object} meta Metadata configuration options
12322  * @param {Object} recordType Either an Array of field definition objects,
12323  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12324  */
12325 Roo.data.JsonReader = function(meta, recordType){
12326     
12327     meta = meta || {};
12328     // set some defaults:
12329     Roo.applyIf(meta, {
12330         totalProperty: 'total',
12331         successProperty : 'success',
12332         root : 'data',
12333         id : 'id'
12334     });
12335     
12336     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12337 };
12338 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12339     
12340     /**
12341      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
12342      * Used by Store query builder to append _requestMeta to params.
12343      * 
12344      */
12345     metaFromRemote : false,
12346     /**
12347      * This method is only used by a DataProxy which has retrieved data from a remote server.
12348      * @param {Object} response The XHR object which contains the JSON data in its responseText.
12349      * @return {Object} data A data block which is used by an Roo.data.Store object as
12350      * a cache of Roo.data.Records.
12351      */
12352     read : function(response){
12353         var json = response.responseText;
12354        
12355         var o = /* eval:var:o */ eval("("+json+")");
12356         if(!o) {
12357             throw {message: "JsonReader.read: Json object not found"};
12358         }
12359         
12360         if(o.metaData){
12361             
12362             delete this.ef;
12363             this.metaFromRemote = true;
12364             this.meta = o.metaData;
12365             this.recordType = Roo.data.Record.create(o.metaData.fields);
12366             this.onMetaChange(this.meta, this.recordType, o);
12367         }
12368         return this.readRecords(o);
12369     },
12370
12371     // private function a store will implement
12372     onMetaChange : function(meta, recordType, o){
12373
12374     },
12375
12376     /**
12377          * @ignore
12378          */
12379     simpleAccess: function(obj, subsc) {
12380         return obj[subsc];
12381     },
12382
12383         /**
12384          * @ignore
12385          */
12386     getJsonAccessor: function(){
12387         var re = /[\[\.]/;
12388         return function(expr) {
12389             try {
12390                 return(re.test(expr))
12391                     ? new Function("obj", "return obj." + expr)
12392                     : function(obj){
12393                         return obj[expr];
12394                     };
12395             } catch(e){}
12396             return Roo.emptyFn;
12397         };
12398     }(),
12399
12400     /**
12401      * Create a data block containing Roo.data.Records from an XML document.
12402      * @param {Object} o An object which contains an Array of row objects in the property specified
12403      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12404      * which contains the total size of the dataset.
12405      * @return {Object} data A data block which is used by an Roo.data.Store object as
12406      * a cache of Roo.data.Records.
12407      */
12408     readRecords : function(o){
12409         /**
12410          * After any data loads, the raw JSON data is available for further custom processing.
12411          * @type Object
12412          */
12413         this.o = o;
12414         var s = this.meta, Record = this.recordType,
12415             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12416
12417 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
12418         if (!this.ef) {
12419             if(s.totalProperty) {
12420                     this.getTotal = this.getJsonAccessor(s.totalProperty);
12421                 }
12422                 if(s.successProperty) {
12423                     this.getSuccess = this.getJsonAccessor(s.successProperty);
12424                 }
12425                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12426                 if (s.id) {
12427                         var g = this.getJsonAccessor(s.id);
12428                         this.getId = function(rec) {
12429                                 var r = g(rec);  
12430                                 return (r === undefined || r === "") ? null : r;
12431                         };
12432                 } else {
12433                         this.getId = function(){return null;};
12434                 }
12435             this.ef = [];
12436             for(var jj = 0; jj < fl; jj++){
12437                 f = fi[jj];
12438                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12439                 this.ef[jj] = this.getJsonAccessor(map);
12440             }
12441         }
12442
12443         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12444         if(s.totalProperty){
12445             var vt = parseInt(this.getTotal(o), 10);
12446             if(!isNaN(vt)){
12447                 totalRecords = vt;
12448             }
12449         }
12450         if(s.successProperty){
12451             var vs = this.getSuccess(o);
12452             if(vs === false || vs === 'false'){
12453                 success = false;
12454             }
12455         }
12456         var records = [];
12457         for(var i = 0; i < c; i++){
12458                 var n = root[i];
12459             var values = {};
12460             var id = this.getId(n);
12461             for(var j = 0; j < fl; j++){
12462                 f = fi[j];
12463             var v = this.ef[j](n);
12464             if (!f.convert) {
12465                 Roo.log('missing convert for ' + f.name);
12466                 Roo.log(f);
12467                 continue;
12468             }
12469             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12470             }
12471             var record = new Record(values, id);
12472             record.json = n;
12473             records[i] = record;
12474         }
12475         return {
12476             raw : o,
12477             success : success,
12478             records : records,
12479             totalRecords : totalRecords
12480         };
12481     }
12482 });/*
12483  * Based on:
12484  * Ext JS Library 1.1.1
12485  * Copyright(c) 2006-2007, Ext JS, LLC.
12486  *
12487  * Originally Released Under LGPL - original licence link has changed is not relivant.
12488  *
12489  * Fork - LGPL
12490  * <script type="text/javascript">
12491  */
12492
12493 /**
12494  * @class Roo.data.ArrayReader
12495  * @extends Roo.data.DataReader
12496  * Data reader class to create an Array of Roo.data.Record objects from an Array.
12497  * Each element of that Array represents a row of data fields. The
12498  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12499  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12500  * <p>
12501  * Example code:.
12502  * <pre><code>
12503 var RecordDef = Roo.data.Record.create([
12504     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
12505     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
12506 ]);
12507 var myReader = new Roo.data.ArrayReader({
12508     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
12509 }, RecordDef);
12510 </code></pre>
12511  * <p>
12512  * This would consume an Array like this:
12513  * <pre><code>
12514 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12515   </code></pre>
12516  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12517  * @constructor
12518  * Create a new JsonReader
12519  * @param {Object} meta Metadata configuration options.
12520  * @param {Object} recordType Either an Array of field definition objects
12521  * as specified to {@link Roo.data.Record#create},
12522  * or an {@link Roo.data.Record} object
12523  * created using {@link Roo.data.Record#create}.
12524  */
12525 Roo.data.ArrayReader = function(meta, recordType){
12526     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12527 };
12528
12529 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12530     /**
12531      * Create a data block containing Roo.data.Records from an XML document.
12532      * @param {Object} o An Array of row objects which represents the dataset.
12533      * @return {Object} data A data block which is used by an Roo.data.Store object as
12534      * a cache of Roo.data.Records.
12535      */
12536     readRecords : function(o){
12537         var sid = this.meta ? this.meta.id : null;
12538         var recordType = this.recordType, fields = recordType.prototype.fields;
12539         var records = [];
12540         var root = o;
12541             for(var i = 0; i < root.length; i++){
12542                     var n = root[i];
12543                 var values = {};
12544                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12545                 for(var j = 0, jlen = fields.length; j < jlen; j++){
12546                 var f = fields.items[j];
12547                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12548                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12549                 v = f.convert(v);
12550                 values[f.name] = v;
12551             }
12552                 var record = new recordType(values, id);
12553                 record.json = n;
12554                 records[records.length] = record;
12555             }
12556             return {
12557                 records : records,
12558                 totalRecords : records.length
12559             };
12560     }
12561 });/*
12562  * - LGPL
12563  * * 
12564  */
12565
12566 /**
12567  * @class Roo.bootstrap.ComboBox
12568  * @extends Roo.bootstrap.TriggerField
12569  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12570  * @cfg {Boolean} append (true|false) default false
12571  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12572  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12573  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12574  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12575  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12576  * @cfg {Boolean} animate default true
12577  * @cfg {Boolean} emptyResultText only for touch device
12578  * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12579  * @cfg {String} emptyTitle default ''
12580  * @constructor
12581  * Create a new ComboBox.
12582  * @param {Object} config Configuration options
12583  */
12584 Roo.bootstrap.ComboBox = function(config){
12585     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12586     this.addEvents({
12587         /**
12588          * @event expand
12589          * Fires when the dropdown list is expanded
12590         * @param {Roo.bootstrap.ComboBox} combo This combo box
12591         */
12592         'expand' : true,
12593         /**
12594          * @event collapse
12595          * Fires when the dropdown list is collapsed
12596         * @param {Roo.bootstrap.ComboBox} combo This combo box
12597         */
12598         'collapse' : true,
12599         /**
12600          * @event beforeselect
12601          * Fires before a list item is selected. Return false to cancel the selection.
12602         * @param {Roo.bootstrap.ComboBox} combo This combo box
12603         * @param {Roo.data.Record} record The data record returned from the underlying store
12604         * @param {Number} index The index of the selected item in the dropdown list
12605         */
12606         'beforeselect' : true,
12607         /**
12608          * @event select
12609          * Fires when a list item is selected
12610         * @param {Roo.bootstrap.ComboBox} combo This combo box
12611         * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12612         * @param {Number} index The index of the selected item in the dropdown list
12613         */
12614         'select' : true,
12615         /**
12616          * @event beforequery
12617          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12618          * The event object passed has these properties:
12619         * @param {Roo.bootstrap.ComboBox} combo This combo box
12620         * @param {String} query The query
12621         * @param {Boolean} forceAll true to force "all" query
12622         * @param {Boolean} cancel true to cancel the query
12623         * @param {Object} e The query event object
12624         */
12625         'beforequery': true,
12626          /**
12627          * @event add
12628          * Fires when the 'add' icon is pressed (add a listener to enable add button)
12629         * @param {Roo.bootstrap.ComboBox} combo This combo box
12630         */
12631         'add' : true,
12632         /**
12633          * @event edit
12634          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12635         * @param {Roo.bootstrap.ComboBox} combo This combo box
12636         * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12637         */
12638         'edit' : true,
12639         /**
12640          * @event remove
12641          * Fires when the remove value from the combobox array
12642         * @param {Roo.bootstrap.ComboBox} combo This combo box
12643         */
12644         'remove' : true,
12645         /**
12646          * @event afterremove
12647          * Fires when the remove value from the combobox array
12648         * @param {Roo.bootstrap.ComboBox} combo This combo box
12649         */
12650         'afterremove' : true,
12651         /**
12652          * @event specialfilter
12653          * Fires when specialfilter
12654             * @param {Roo.bootstrap.ComboBox} combo This combo box
12655             */
12656         'specialfilter' : true,
12657         /**
12658          * @event tick
12659          * Fires when tick the element
12660             * @param {Roo.bootstrap.ComboBox} combo This combo box
12661             */
12662         'tick' : true,
12663         /**
12664          * @event touchviewdisplay
12665          * Fires when touch view require special display (default is using displayField)
12666             * @param {Roo.bootstrap.ComboBox} combo This combo box
12667             * @param {Object} cfg set html .
12668             */
12669         'touchviewdisplay' : true
12670         
12671     });
12672     
12673     this.item = [];
12674     this.tickItems = [];
12675     
12676     this.selectedIndex = -1;
12677     if(this.mode == 'local'){
12678         if(config.queryDelay === undefined){
12679             this.queryDelay = 10;
12680         }
12681         if(config.minChars === undefined){
12682             this.minChars = 0;
12683         }
12684     }
12685 };
12686
12687 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12688      
12689     /**
12690      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12691      * rendering into an Roo.Editor, defaults to false)
12692      */
12693     /**
12694      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12695      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12696      */
12697     /**
12698      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12699      */
12700     /**
12701      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12702      * the dropdown list (defaults to undefined, with no header element)
12703      */
12704
12705      /**
12706      * @cfg {String/Roo.Template} tpl The template to use to render the output
12707      */
12708      
12709      /**
12710      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12711      */
12712     listWidth: undefined,
12713     /**
12714      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12715      * mode = 'remote' or 'text' if mode = 'local')
12716      */
12717     displayField: undefined,
12718     
12719     /**
12720      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12721      * mode = 'remote' or 'value' if mode = 'local'). 
12722      * Note: use of a valueField requires the user make a selection
12723      * in order for a value to be mapped.
12724      */
12725     valueField: undefined,
12726     /**
12727      * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12728      */
12729     modalTitle : '',
12730     
12731     /**
12732      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12733      * field's data value (defaults to the underlying DOM element's name)
12734      */
12735     hiddenName: undefined,
12736     /**
12737      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12738      */
12739     listClass: '',
12740     /**
12741      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12742      */
12743     selectedClass: 'active',
12744     
12745     /**
12746      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12747      */
12748     shadow:'sides',
12749     /**
12750      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12751      * anchor positions (defaults to 'tl-bl')
12752      */
12753     listAlign: 'tl-bl?',
12754     /**
12755      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12756      */
12757     maxHeight: 300,
12758     /**
12759      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
12760      * query specified by the allQuery config option (defaults to 'query')
12761      */
12762     triggerAction: 'query',
12763     /**
12764      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12765      * (defaults to 4, does not apply if editable = false)
12766      */
12767     minChars : 4,
12768     /**
12769      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12770      * delay (typeAheadDelay) if it matches a known value (defaults to false)
12771      */
12772     typeAhead: false,
12773     /**
12774      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12775      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12776      */
12777     queryDelay: 500,
12778     /**
12779      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12780      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
12781      */
12782     pageSize: 0,
12783     /**
12784      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
12785      * when editable = true (defaults to false)
12786      */
12787     selectOnFocus:false,
12788     /**
12789      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12790      */
12791     queryParam: 'query',
12792     /**
12793      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
12794      * when mode = 'remote' (defaults to 'Loading...')
12795      */
12796     loadingText: 'Loading...',
12797     /**
12798      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12799      */
12800     resizable: false,
12801     /**
12802      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12803      */
12804     handleHeight : 8,
12805     /**
12806      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12807      * traditional select (defaults to true)
12808      */
12809     editable: true,
12810     /**
12811      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12812      */
12813     allQuery: '',
12814     /**
12815      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12816      */
12817     mode: 'remote',
12818     /**
12819      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12820      * listWidth has a higher value)
12821      */
12822     minListWidth : 70,
12823     /**
12824      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12825      * allow the user to set arbitrary text into the field (defaults to false)
12826      */
12827     forceSelection:false,
12828     /**
12829      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12830      * if typeAhead = true (defaults to 250)
12831      */
12832     typeAheadDelay : 250,
12833     /**
12834      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12835      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12836      */
12837     valueNotFoundText : undefined,
12838     /**
12839      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12840      */
12841     blockFocus : false,
12842     
12843     /**
12844      * @cfg {Boolean} disableClear Disable showing of clear button.
12845      */
12846     disableClear : false,
12847     /**
12848      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
12849      */
12850     alwaysQuery : false,
12851     
12852     /**
12853      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
12854      */
12855     multiple : false,
12856     
12857     /**
12858      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12859      */
12860     invalidClass : "has-warning",
12861     
12862     /**
12863      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12864      */
12865     validClass : "has-success",
12866     
12867     /**
12868      * @cfg {Boolean} specialFilter (true|false) special filter default false
12869      */
12870     specialFilter : false,
12871     
12872     /**
12873      * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12874      */
12875     mobileTouchView : true,
12876     
12877     /**
12878      * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12879      */
12880     useNativeIOS : false,
12881     
12882     ios_options : false,
12883     
12884     //private
12885     addicon : false,
12886     editicon: false,
12887     
12888     page: 0,
12889     hasQuery: false,
12890     append: false,
12891     loadNext: false,
12892     autoFocus : true,
12893     tickable : false,
12894     btnPosition : 'right',
12895     triggerList : true,
12896     showToggleBtn : true,
12897     animate : true,
12898     emptyResultText: 'Empty',
12899     triggerText : 'Select',
12900     emptyTitle : '',
12901     
12902     // element that contains real text value.. (when hidden is used..)
12903     
12904     getAutoCreate : function()
12905     {   
12906         var cfg = false;
12907         //render
12908         /*
12909          * Render classic select for iso
12910          */
12911         
12912         if(Roo.isIOS && this.useNativeIOS){
12913             cfg = this.getAutoCreateNativeIOS();
12914             return cfg;
12915         }
12916         
12917         /*
12918          * Touch Devices
12919          */
12920         
12921         if(Roo.isTouch && this.mobileTouchView){
12922             cfg = this.getAutoCreateTouchView();
12923             return cfg;;
12924         }
12925         
12926         /*
12927          *  Normal ComboBox
12928          */
12929         if(!this.tickable){
12930             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12931             return cfg;
12932         }
12933         
12934         /*
12935          *  ComboBox with tickable selections
12936          */
12937              
12938         var align = this.labelAlign || this.parentLabelAlign();
12939         
12940         cfg = {
12941             cls : 'form-group roo-combobox-tickable' //input-group
12942         };
12943         
12944         var btn_text_select = '';
12945         var btn_text_done = '';
12946         var btn_text_cancel = '';
12947         
12948         if (this.btn_text_show) {
12949             btn_text_select = 'Select';
12950             btn_text_done = 'Done';
12951             btn_text_cancel = 'Cancel'; 
12952         }
12953         
12954         var buttons = {
12955             tag : 'div',
12956             cls : 'tickable-buttons',
12957             cn : [
12958                 {
12959                     tag : 'button',
12960                     type : 'button',
12961                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12962                     //html : this.triggerText
12963                     html: btn_text_select
12964                 },
12965                 {
12966                     tag : 'button',
12967                     type : 'button',
12968                     name : 'ok',
12969                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12970                     //html : 'Done'
12971                     html: btn_text_done
12972                 },
12973                 {
12974                     tag : 'button',
12975                     type : 'button',
12976                     name : 'cancel',
12977                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12978                     //html : 'Cancel'
12979                     html: btn_text_cancel
12980                 }
12981             ]
12982         };
12983         
12984         if(this.editable){
12985             buttons.cn.unshift({
12986                 tag: 'input',
12987                 cls: 'roo-select2-search-field-input'
12988             });
12989         }
12990         
12991         var _this = this;
12992         
12993         Roo.each(buttons.cn, function(c){
12994             if (_this.size) {
12995                 c.cls += ' btn-' + _this.size;
12996             }
12997
12998             if (_this.disabled) {
12999                 c.disabled = true;
13000             }
13001         });
13002         
13003         var box = {
13004             tag: 'div',
13005             cn: [
13006                 {
13007                     tag: 'input',
13008                     type : 'hidden',
13009                     cls: 'form-hidden-field'
13010                 },
13011                 {
13012                     tag: 'ul',
13013                     cls: 'roo-select2-choices',
13014                     cn:[
13015                         {
13016                             tag: 'li',
13017                             cls: 'roo-select2-search-field',
13018                             cn: [
13019                                 buttons
13020                             ]
13021                         }
13022                     ]
13023                 }
13024             ]
13025         };
13026         
13027         var combobox = {
13028             cls: 'roo-select2-container input-group roo-select2-container-multi',
13029             cn: [
13030                 box
13031 //                {
13032 //                    tag: 'ul',
13033 //                    cls: 'typeahead typeahead-long dropdown-menu',
13034 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
13035 //                }
13036             ]
13037         };
13038         
13039         if(this.hasFeedback && !this.allowBlank){
13040             
13041             var feedback = {
13042                 tag: 'span',
13043                 cls: 'glyphicon form-control-feedback'
13044             };
13045
13046             combobox.cn.push(feedback);
13047         }
13048         
13049         
13050         if (align ==='left' && this.fieldLabel.length) {
13051             
13052             cfg.cls += ' roo-form-group-label-left';
13053             
13054             cfg.cn = [
13055                 {
13056                     tag : 'i',
13057                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13058                     tooltip : 'This field is required'
13059                 },
13060                 {
13061                     tag: 'label',
13062                     'for' :  id,
13063                     cls : 'control-label',
13064                     html : this.fieldLabel
13065
13066                 },
13067                 {
13068                     cls : "", 
13069                     cn: [
13070                         combobox
13071                     ]
13072                 }
13073
13074             ];
13075             
13076             var labelCfg = cfg.cn[1];
13077             var contentCfg = cfg.cn[2];
13078             
13079
13080             if(this.indicatorpos == 'right'){
13081                 
13082                 cfg.cn = [
13083                     {
13084                         tag: 'label',
13085                         'for' :  id,
13086                         cls : 'control-label',
13087                         cn : [
13088                             {
13089                                 tag : 'span',
13090                                 html : this.fieldLabel
13091                             },
13092                             {
13093                                 tag : 'i',
13094                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13095                                 tooltip : 'This field is required'
13096                             }
13097                         ]
13098                     },
13099                     {
13100                         cls : "",
13101                         cn: [
13102                             combobox
13103                         ]
13104                     }
13105
13106                 ];
13107                 
13108                 
13109                 
13110                 labelCfg = cfg.cn[0];
13111                 contentCfg = cfg.cn[1];
13112             
13113             }
13114             
13115             if(this.labelWidth > 12){
13116                 labelCfg.style = "width: " + this.labelWidth + 'px';
13117             }
13118             
13119             if(this.labelWidth < 13 && this.labelmd == 0){
13120                 this.labelmd = this.labelWidth;
13121             }
13122             
13123             if(this.labellg > 0){
13124                 labelCfg.cls += ' col-lg-' + this.labellg;
13125                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13126             }
13127             
13128             if(this.labelmd > 0){
13129                 labelCfg.cls += ' col-md-' + this.labelmd;
13130                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13131             }
13132             
13133             if(this.labelsm > 0){
13134                 labelCfg.cls += ' col-sm-' + this.labelsm;
13135                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13136             }
13137             
13138             if(this.labelxs > 0){
13139                 labelCfg.cls += ' col-xs-' + this.labelxs;
13140                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13141             }
13142                 
13143                 
13144         } else if ( this.fieldLabel.length) {
13145 //                Roo.log(" label");
13146                  cfg.cn = [
13147                     {
13148                         tag : 'i',
13149                         cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13150                         tooltip : 'This field is required'
13151                     },
13152                     {
13153                         tag: 'label',
13154                         //cls : 'input-group-addon',
13155                         html : this.fieldLabel
13156                     },
13157                     combobox
13158                 ];
13159                 
13160                 if(this.indicatorpos == 'right'){
13161                     cfg.cn = [
13162                         {
13163                             tag: 'label',
13164                             //cls : 'input-group-addon',
13165                             html : this.fieldLabel
13166                         },
13167                         {
13168                             tag : 'i',
13169                             cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13170                             tooltip : 'This field is required'
13171                         },
13172                         combobox
13173                     ];
13174                     
13175                 }
13176
13177         } else {
13178             
13179 //                Roo.log(" no label && no align");
13180                 cfg = combobox
13181                      
13182                 
13183         }
13184          
13185         var settings=this;
13186         ['xs','sm','md','lg'].map(function(size){
13187             if (settings[size]) {
13188                 cfg.cls += ' col-' + size + '-' + settings[size];
13189             }
13190         });
13191         
13192         return cfg;
13193         
13194     },
13195     
13196     _initEventsCalled : false,
13197     
13198     // private
13199     initEvents: function()
13200     {   
13201         if (this._initEventsCalled) { // as we call render... prevent looping...
13202             return;
13203         }
13204         this._initEventsCalled = true;
13205         
13206         if (!this.store) {
13207             throw "can not find store for combo";
13208         }
13209         
13210         this.indicator = this.indicatorEl();
13211         
13212         this.store = Roo.factory(this.store, Roo.data);
13213         this.store.parent = this;
13214         
13215         // if we are building from html. then this element is so complex, that we can not really
13216         // use the rendered HTML.
13217         // so we have to trash and replace the previous code.
13218         if (Roo.XComponent.build_from_html) {
13219             // remove this element....
13220             var e = this.el.dom, k=0;
13221             while (e ) { e = e.previousSibling;  ++k;}
13222
13223             this.el.remove();
13224             
13225             this.el=false;
13226             this.rendered = false;
13227             
13228             this.render(this.parent().getChildContainer(true), k);
13229         }
13230         
13231         if(Roo.isIOS && this.useNativeIOS){
13232             this.initIOSView();
13233             return;
13234         }
13235         
13236         /*
13237          * Touch Devices
13238          */
13239         
13240         if(Roo.isTouch && this.mobileTouchView){
13241             this.initTouchView();
13242             return;
13243         }
13244         
13245         if(this.tickable){
13246             this.initTickableEvents();
13247             return;
13248         }
13249         
13250         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13251         
13252         if(this.hiddenName){
13253             
13254             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13255             
13256             this.hiddenField.dom.value =
13257                 this.hiddenValue !== undefined ? this.hiddenValue :
13258                 this.value !== undefined ? this.value : '';
13259
13260             // prevent input submission
13261             this.el.dom.removeAttribute('name');
13262             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13263              
13264              
13265         }
13266         //if(Roo.isGecko){
13267         //    this.el.dom.setAttribute('autocomplete', 'off');
13268         //}
13269         
13270         var cls = 'x-combo-list';
13271         
13272         //this.list = new Roo.Layer({
13273         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13274         //});
13275         
13276         var _this = this;
13277         
13278         (function(){
13279             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13280             _this.list.setWidth(lw);
13281         }).defer(100);
13282         
13283         this.list.on('mouseover', this.onViewOver, this);
13284         this.list.on('mousemove', this.onViewMove, this);
13285         this.list.on('scroll', this.onViewScroll, this);
13286         
13287         /*
13288         this.list.swallowEvent('mousewheel');
13289         this.assetHeight = 0;
13290
13291         if(this.title){
13292             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13293             this.assetHeight += this.header.getHeight();
13294         }
13295
13296         this.innerList = this.list.createChild({cls:cls+'-inner'});
13297         this.innerList.on('mouseover', this.onViewOver, this);
13298         this.innerList.on('mousemove', this.onViewMove, this);
13299         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13300         
13301         if(this.allowBlank && !this.pageSize && !this.disableClear){
13302             this.footer = this.list.createChild({cls:cls+'-ft'});
13303             this.pageTb = new Roo.Toolbar(this.footer);
13304            
13305         }
13306         if(this.pageSize){
13307             this.footer = this.list.createChild({cls:cls+'-ft'});
13308             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13309                     {pageSize: this.pageSize});
13310             
13311         }
13312         
13313         if (this.pageTb && this.allowBlank && !this.disableClear) {
13314             var _this = this;
13315             this.pageTb.add(new Roo.Toolbar.Fill(), {
13316                 cls: 'x-btn-icon x-btn-clear',
13317                 text: '&#160;',
13318                 handler: function()
13319                 {
13320                     _this.collapse();
13321                     _this.clearValue();
13322                     _this.onSelect(false, -1);
13323                 }
13324             });
13325         }
13326         if (this.footer) {
13327             this.assetHeight += this.footer.getHeight();
13328         }
13329         */
13330             
13331         if(!this.tpl){
13332             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13333         }
13334
13335         this.view = new Roo.View(this.list, this.tpl, {
13336             singleSelect:true, store: this.store, selectedClass: this.selectedClass
13337         });
13338         //this.view.wrapEl.setDisplayed(false);
13339         this.view.on('click', this.onViewClick, this);
13340         
13341         
13342         this.store.on('beforeload', this.onBeforeLoad, this);
13343         this.store.on('load', this.onLoad, this);
13344         this.store.on('loadexception', this.onLoadException, this);
13345         /*
13346         if(this.resizable){
13347             this.resizer = new Roo.Resizable(this.list,  {
13348                pinned:true, handles:'se'
13349             });
13350             this.resizer.on('resize', function(r, w, h){
13351                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13352                 this.listWidth = w;
13353                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13354                 this.restrictHeight();
13355             }, this);
13356             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13357         }
13358         */
13359         if(!this.editable){
13360             this.editable = true;
13361             this.setEditable(false);
13362         }
13363         
13364         /*
13365         
13366         if (typeof(this.events.add.listeners) != 'undefined') {
13367             
13368             this.addicon = this.wrap.createChild(
13369                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
13370        
13371             this.addicon.on('click', function(e) {
13372                 this.fireEvent('add', this);
13373             }, this);
13374         }
13375         if (typeof(this.events.edit.listeners) != 'undefined') {
13376             
13377             this.editicon = this.wrap.createChild(
13378                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
13379             if (this.addicon) {
13380                 this.editicon.setStyle('margin-left', '40px');
13381             }
13382             this.editicon.on('click', function(e) {
13383                 
13384                 // we fire even  if inothing is selected..
13385                 this.fireEvent('edit', this, this.lastData );
13386                 
13387             }, this);
13388         }
13389         */
13390         
13391         this.keyNav = new Roo.KeyNav(this.inputEl(), {
13392             "up" : function(e){
13393                 this.inKeyMode = true;
13394                 this.selectPrev();
13395             },
13396
13397             "down" : function(e){
13398                 if(!this.isExpanded()){
13399                     this.onTriggerClick();
13400                 }else{
13401                     this.inKeyMode = true;
13402                     this.selectNext();
13403                 }
13404             },
13405
13406             "enter" : function(e){
13407 //                this.onViewClick();
13408                 //return true;
13409                 this.collapse();
13410                 
13411                 if(this.fireEvent("specialkey", this, e)){
13412                     this.onViewClick(false);
13413                 }
13414                 
13415                 return true;
13416             },
13417
13418             "esc" : function(e){
13419                 this.collapse();
13420             },
13421
13422             "tab" : function(e){
13423                 this.collapse();
13424                 
13425                 if(this.fireEvent("specialkey", this, e)){
13426                     this.onViewClick(false);
13427                 }
13428                 
13429                 return true;
13430             },
13431
13432             scope : this,
13433
13434             doRelay : function(foo, bar, hname){
13435                 if(hname == 'down' || this.scope.isExpanded()){
13436                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13437                 }
13438                 return true;
13439             },
13440
13441             forceKeyDown: true
13442         });
13443         
13444         
13445         this.queryDelay = Math.max(this.queryDelay || 10,
13446                 this.mode == 'local' ? 10 : 250);
13447         
13448         
13449         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13450         
13451         if(this.typeAhead){
13452             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13453         }
13454         if(this.editable !== false){
13455             this.inputEl().on("keyup", this.onKeyUp, this);
13456         }
13457         if(this.forceSelection){
13458             this.inputEl().on('blur', this.doForce, this);
13459         }
13460         
13461         if(this.multiple){
13462             this.choices = this.el.select('ul.roo-select2-choices', true).first();
13463             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13464         }
13465     },
13466     
13467     initTickableEvents: function()
13468     {   
13469         this.createList();
13470         
13471         if(this.hiddenName){
13472             
13473             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13474             
13475             this.hiddenField.dom.value =
13476                 this.hiddenValue !== undefined ? this.hiddenValue :
13477                 this.value !== undefined ? this.value : '';
13478
13479             // prevent input submission
13480             this.el.dom.removeAttribute('name');
13481             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13482              
13483              
13484         }
13485         
13486 //        this.list = this.el.select('ul.dropdown-menu',true).first();
13487         
13488         this.choices = this.el.select('ul.roo-select2-choices', true).first();
13489         this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13490         if(this.triggerList){
13491             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13492         }
13493          
13494         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13495         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13496         
13497         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13498         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13499         
13500         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13501         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13502         
13503         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13504         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13505         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13506         
13507         this.okBtn.hide();
13508         this.cancelBtn.hide();
13509         
13510         var _this = this;
13511         
13512         (function(){
13513             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13514             _this.list.setWidth(lw);
13515         }).defer(100);
13516         
13517         this.list.on('mouseover', this.onViewOver, this);
13518         this.list.on('mousemove', this.onViewMove, this);
13519         
13520         this.list.on('scroll', this.onViewScroll, this);
13521         
13522         if(!this.tpl){
13523             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>';
13524         }
13525
13526         this.view = new Roo.View(this.list, this.tpl, {
13527             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13528         });
13529         
13530         //this.view.wrapEl.setDisplayed(false);
13531         this.view.on('click', this.onViewClick, this);
13532         
13533         
13534         
13535         this.store.on('beforeload', this.onBeforeLoad, this);
13536         this.store.on('load', this.onLoad, this);
13537         this.store.on('loadexception', this.onLoadException, this);
13538         
13539         if(this.editable){
13540             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13541                 "up" : function(e){
13542                     this.inKeyMode = true;
13543                     this.selectPrev();
13544                 },
13545
13546                 "down" : function(e){
13547                     this.inKeyMode = true;
13548                     this.selectNext();
13549                 },
13550
13551                 "enter" : function(e){
13552                     if(this.fireEvent("specialkey", this, e)){
13553                         this.onViewClick(false);
13554                     }
13555                     
13556                     return true;
13557                 },
13558
13559                 "esc" : function(e){
13560                     this.onTickableFooterButtonClick(e, false, false);
13561                 },
13562
13563                 "tab" : function(e){
13564                     this.fireEvent("specialkey", this, e);
13565                     
13566                     this.onTickableFooterButtonClick(e, false, false);
13567                     
13568                     return true;
13569                 },
13570
13571                 scope : this,
13572
13573                 doRelay : function(e, fn, key){
13574                     if(this.scope.isExpanded()){
13575                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13576                     }
13577                     return true;
13578                 },
13579
13580                 forceKeyDown: true
13581             });
13582         }
13583         
13584         this.queryDelay = Math.max(this.queryDelay || 10,
13585                 this.mode == 'local' ? 10 : 250);
13586         
13587         
13588         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13589         
13590         if(this.typeAhead){
13591             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13592         }
13593         
13594         if(this.editable !== false){
13595             this.tickableInputEl().on("keyup", this.onKeyUp, this);
13596         }
13597         
13598         this.indicator = this.indicatorEl();
13599         
13600         if(this.indicator){
13601             this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13602             this.indicator.hide();
13603         }
13604         
13605     },
13606
13607     onDestroy : function(){
13608         if(this.view){
13609             this.view.setStore(null);
13610             this.view.el.removeAllListeners();
13611             this.view.el.remove();
13612             this.view.purgeListeners();
13613         }
13614         if(this.list){
13615             this.list.dom.innerHTML  = '';
13616         }
13617         
13618         if(this.store){
13619             this.store.un('beforeload', this.onBeforeLoad, this);
13620             this.store.un('load', this.onLoad, this);
13621             this.store.un('loadexception', this.onLoadException, this);
13622         }
13623         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13624     },
13625
13626     // private
13627     fireKey : function(e){
13628         if(e.isNavKeyPress() && !this.list.isVisible()){
13629             this.fireEvent("specialkey", this, e);
13630         }
13631     },
13632
13633     // private
13634     onResize: function(w, h){
13635 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13636 //        
13637 //        if(typeof w != 'number'){
13638 //            // we do not handle it!?!?
13639 //            return;
13640 //        }
13641 //        var tw = this.trigger.getWidth();
13642 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
13643 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
13644 //        var x = w - tw;
13645 //        this.inputEl().setWidth( this.adjustWidth('input', x));
13646 //            
13647 //        //this.trigger.setStyle('left', x+'px');
13648 //        
13649 //        if(this.list && this.listWidth === undefined){
13650 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13651 //            this.list.setWidth(lw);
13652 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13653 //        }
13654         
13655     
13656         
13657     },
13658
13659     /**
13660      * Allow or prevent the user from directly editing the field text.  If false is passed,
13661      * the user will only be able to select from the items defined in the dropdown list.  This method
13662      * is the runtime equivalent of setting the 'editable' config option at config time.
13663      * @param {Boolean} value True to allow the user to directly edit the field text
13664      */
13665     setEditable : function(value){
13666         if(value == this.editable){
13667             return;
13668         }
13669         this.editable = value;
13670         if(!value){
13671             this.inputEl().dom.setAttribute('readOnly', true);
13672             this.inputEl().on('mousedown', this.onTriggerClick,  this);
13673             this.inputEl().addClass('x-combo-noedit');
13674         }else{
13675             this.inputEl().dom.setAttribute('readOnly', false);
13676             this.inputEl().un('mousedown', this.onTriggerClick,  this);
13677             this.inputEl().removeClass('x-combo-noedit');
13678         }
13679     },
13680
13681     // private
13682     
13683     onBeforeLoad : function(combo,opts){
13684         if(!this.hasFocus){
13685             return;
13686         }
13687          if (!opts.add) {
13688             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13689          }
13690         this.restrictHeight();
13691         this.selectedIndex = -1;
13692     },
13693
13694     // private
13695     onLoad : function(){
13696         
13697         this.hasQuery = false;
13698         
13699         if(!this.hasFocus){
13700             return;
13701         }
13702         
13703         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13704             this.loading.hide();
13705         }
13706         
13707         if(this.store.getCount() > 0){
13708             
13709             this.expand();
13710             this.restrictHeight();
13711             if(this.lastQuery == this.allQuery){
13712                 if(this.editable && !this.tickable){
13713                     this.inputEl().dom.select();
13714                 }
13715                 
13716                 if(
13717                     !this.selectByValue(this.value, true) &&
13718                     this.autoFocus && 
13719                     (
13720                         !this.store.lastOptions ||
13721                         typeof(this.store.lastOptions.add) == 'undefined' || 
13722                         this.store.lastOptions.add != true
13723                     )
13724                 ){
13725                     this.select(0, true);
13726                 }
13727             }else{
13728                 if(this.autoFocus){
13729                     this.selectNext();
13730                 }
13731                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13732                     this.taTask.delay(this.typeAheadDelay);
13733                 }
13734             }
13735         }else{
13736             this.onEmptyResults();
13737         }
13738         
13739         //this.el.focus();
13740     },
13741     // private
13742     onLoadException : function()
13743     {
13744         this.hasQuery = false;
13745         
13746         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13747             this.loading.hide();
13748         }
13749         
13750         if(this.tickable && this.editable){
13751             return;
13752         }
13753         
13754         this.collapse();
13755         // only causes errors at present
13756         //Roo.log(this.store.reader.jsonData);
13757         //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13758             // fixme
13759             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13760         //}
13761         
13762         
13763     },
13764     // private
13765     onTypeAhead : function(){
13766         if(this.store.getCount() > 0){
13767             var r = this.store.getAt(0);
13768             var newValue = r.data[this.displayField];
13769             var len = newValue.length;
13770             var selStart = this.getRawValue().length;
13771             
13772             if(selStart != len){
13773                 this.setRawValue(newValue);
13774                 this.selectText(selStart, newValue.length);
13775             }
13776         }
13777     },
13778
13779     // private
13780     onSelect : function(record, index){
13781         
13782         if(this.fireEvent('beforeselect', this, record, index) !== false){
13783         
13784             this.setFromData(index > -1 ? record.data : false);
13785             
13786             this.collapse();
13787             this.fireEvent('select', this, record, index);
13788         }
13789     },
13790
13791     /**
13792      * Returns the currently selected field value or empty string if no value is set.
13793      * @return {String} value The selected value
13794      */
13795     getValue : function()
13796     {
13797         if(Roo.isIOS && this.useNativeIOS){
13798             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13799         }
13800         
13801         if(this.multiple){
13802             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13803         }
13804         
13805         if(this.valueField){
13806             return typeof this.value != 'undefined' ? this.value : '';
13807         }else{
13808             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13809         }
13810     },
13811     
13812     getRawValue : function()
13813     {
13814         if(Roo.isIOS && this.useNativeIOS){
13815             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13816         }
13817         
13818         var v = this.inputEl().getValue();
13819         
13820         return v;
13821     },
13822
13823     /**
13824      * Clears any text/value currently set in the field
13825      */
13826     clearValue : function(){
13827         
13828         if(this.hiddenField){
13829             this.hiddenField.dom.value = '';
13830         }
13831         this.value = '';
13832         this.setRawValue('');
13833         this.lastSelectionText = '';
13834         this.lastData = false;
13835         
13836         var close = this.closeTriggerEl();
13837         
13838         if(close){
13839             close.hide();
13840         }
13841         
13842         this.validate();
13843         
13844     },
13845
13846     /**
13847      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
13848      * will be displayed in the field.  If the value does not match the data value of an existing item,
13849      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13850      * Otherwise the field will be blank (although the value will still be set).
13851      * @param {String} value The value to match
13852      */
13853     setValue : function(v)
13854     {
13855         if(Roo.isIOS && this.useNativeIOS){
13856             this.setIOSValue(v);
13857             return;
13858         }
13859         
13860         if(this.multiple){
13861             this.syncValue();
13862             return;
13863         }
13864         
13865         var text = v;
13866         if(this.valueField){
13867             var r = this.findRecord(this.valueField, v);
13868             if(r){
13869                 text = r.data[this.displayField];
13870             }else if(this.valueNotFoundText !== undefined){
13871                 text = this.valueNotFoundText;
13872             }
13873         }
13874         this.lastSelectionText = text;
13875         if(this.hiddenField){
13876             this.hiddenField.dom.value = v;
13877         }
13878         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13879         this.value = v;
13880         
13881         var close = this.closeTriggerEl();
13882         
13883         if(close){
13884             (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13885         }
13886         
13887         this.validate();
13888     },
13889     /**
13890      * @property {Object} the last set data for the element
13891      */
13892     
13893     lastData : false,
13894     /**
13895      * Sets the value of the field based on a object which is related to the record format for the store.
13896      * @param {Object} value the value to set as. or false on reset?
13897      */
13898     setFromData : function(o){
13899         
13900         if(this.multiple){
13901             this.addItem(o);
13902             return;
13903         }
13904             
13905         var dv = ''; // display value
13906         var vv = ''; // value value..
13907         this.lastData = o;
13908         if (this.displayField) {
13909             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13910         } else {
13911             // this is an error condition!!!
13912             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
13913         }
13914         
13915         if(this.valueField){
13916             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13917         }
13918         
13919         var close = this.closeTriggerEl();
13920         
13921         if(close){
13922             if(dv.length || vv * 1 > 0){
13923                 close.show() ;
13924                 this.blockFocus=true;
13925             } else {
13926                 close.hide();
13927             }             
13928         }
13929         
13930         if(this.hiddenField){
13931             this.hiddenField.dom.value = vv;
13932             
13933             this.lastSelectionText = dv;
13934             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13935             this.value = vv;
13936             return;
13937         }
13938         // no hidden field.. - we store the value in 'value', but still display
13939         // display field!!!!
13940         this.lastSelectionText = dv;
13941         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13942         this.value = vv;
13943         
13944         
13945         
13946     },
13947     // private
13948     reset : function(){
13949         // overridden so that last data is reset..
13950         
13951         if(this.multiple){
13952             this.clearItem();
13953             return;
13954         }
13955         
13956         this.setValue(this.originalValue);
13957         //this.clearInvalid();
13958         this.lastData = false;
13959         if (this.view) {
13960             this.view.clearSelections();
13961         }
13962         
13963         this.validate();
13964     },
13965     // private
13966     findRecord : function(prop, value){
13967         var record;
13968         if(this.store.getCount() > 0){
13969             this.store.each(function(r){
13970                 if(r.data[prop] == value){
13971                     record = r;
13972                     return false;
13973                 }
13974                 return true;
13975             });
13976         }
13977         return record;
13978     },
13979     
13980     getName: function()
13981     {
13982         // returns hidden if it's set..
13983         if (!this.rendered) {return ''};
13984         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
13985         
13986     },
13987     // private
13988     onViewMove : function(e, t){
13989         this.inKeyMode = false;
13990     },
13991
13992     // private
13993     onViewOver : function(e, t){
13994         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13995             return;
13996         }
13997         var item = this.view.findItemFromChild(t);
13998         
13999         if(item){
14000             var index = this.view.indexOf(item);
14001             this.select(index, false);
14002         }
14003     },
14004
14005     // private
14006     onViewClick : function(view, doFocus, el, e)
14007     {
14008         var index = this.view.getSelectedIndexes()[0];
14009         
14010         var r = this.store.getAt(index);
14011         
14012         if(this.tickable){
14013             
14014             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14015                 return;
14016             }
14017             
14018             var rm = false;
14019             var _this = this;
14020             
14021             Roo.each(this.tickItems, function(v,k){
14022                 
14023                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14024                     Roo.log(v);
14025                     _this.tickItems.splice(k, 1);
14026                     
14027                     if(typeof(e) == 'undefined' && view == false){
14028                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14029                     }
14030                     
14031                     rm = true;
14032                     return;
14033                 }
14034             });
14035             
14036             if(rm){
14037                 return;
14038             }
14039             
14040             if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14041                 this.tickItems.push(r.data);
14042             }
14043             
14044             if(typeof(e) == 'undefined' && view == false){
14045                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14046             }
14047                     
14048             return;
14049         }
14050         
14051         if(r){
14052             this.onSelect(r, index);
14053         }
14054         if(doFocus !== false && !this.blockFocus){
14055             this.inputEl().focus();
14056         }
14057     },
14058
14059     // private
14060     restrictHeight : function(){
14061         //this.innerList.dom.style.height = '';
14062         //var inner = this.innerList.dom;
14063         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14064         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14065         //this.list.beginUpdate();
14066         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14067         this.list.alignTo(this.inputEl(), this.listAlign);
14068         this.list.alignTo(this.inputEl(), this.listAlign);
14069         //this.list.endUpdate();
14070     },
14071
14072     // private
14073     onEmptyResults : function(){
14074         
14075         if(this.tickable && this.editable){
14076             this.hasFocus = false;
14077             this.restrictHeight();
14078             return;
14079         }
14080         
14081         this.collapse();
14082     },
14083
14084     /**
14085      * Returns true if the dropdown list is expanded, else false.
14086      */
14087     isExpanded : function(){
14088         return this.list.isVisible();
14089     },
14090
14091     /**
14092      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14093      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14094      * @param {String} value The data value of the item to select
14095      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14096      * selected item if it is not currently in view (defaults to true)
14097      * @return {Boolean} True if the value matched an item in the list, else false
14098      */
14099     selectByValue : function(v, scrollIntoView){
14100         if(v !== undefined && v !== null){
14101             var r = this.findRecord(this.valueField || this.displayField, v);
14102             if(r){
14103                 this.select(this.store.indexOf(r), scrollIntoView);
14104                 return true;
14105             }
14106         }
14107         return false;
14108     },
14109
14110     /**
14111      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14112      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14113      * @param {Number} index The zero-based index of the list item to select
14114      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14115      * selected item if it is not currently in view (defaults to true)
14116      */
14117     select : function(index, scrollIntoView){
14118         this.selectedIndex = index;
14119         this.view.select(index);
14120         if(scrollIntoView !== false){
14121             var el = this.view.getNode(index);
14122             /*
14123              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14124              */
14125             if(el){
14126                 this.list.scrollChildIntoView(el, false);
14127             }
14128         }
14129     },
14130
14131     // private
14132     selectNext : function(){
14133         var ct = this.store.getCount();
14134         if(ct > 0){
14135             if(this.selectedIndex == -1){
14136                 this.select(0);
14137             }else if(this.selectedIndex < ct-1){
14138                 this.select(this.selectedIndex+1);
14139             }
14140         }
14141     },
14142
14143     // private
14144     selectPrev : function(){
14145         var ct = this.store.getCount();
14146         if(ct > 0){
14147             if(this.selectedIndex == -1){
14148                 this.select(0);
14149             }else if(this.selectedIndex != 0){
14150                 this.select(this.selectedIndex-1);
14151             }
14152         }
14153     },
14154
14155     // private
14156     onKeyUp : function(e){
14157         if(this.editable !== false && !e.isSpecialKey()){
14158             this.lastKey = e.getKey();
14159             this.dqTask.delay(this.queryDelay);
14160         }
14161     },
14162
14163     // private
14164     validateBlur : function(){
14165         return !this.list || !this.list.isVisible();   
14166     },
14167
14168     // private
14169     initQuery : function(){
14170         
14171         var v = this.getRawValue();
14172         
14173         if(this.tickable && this.editable){
14174             v = this.tickableInputEl().getValue();
14175         }
14176         
14177         this.doQuery(v);
14178     },
14179
14180     // private
14181     doForce : function(){
14182         if(this.inputEl().dom.value.length > 0){
14183             this.inputEl().dom.value =
14184                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14185              
14186         }
14187     },
14188
14189     /**
14190      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
14191      * query allowing the query action to be canceled if needed.
14192      * @param {String} query The SQL query to execute
14193      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14194      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
14195      * saved in the current store (defaults to false)
14196      */
14197     doQuery : function(q, forceAll){
14198         
14199         if(q === undefined || q === null){
14200             q = '';
14201         }
14202         var qe = {
14203             query: q,
14204             forceAll: forceAll,
14205             combo: this,
14206             cancel:false
14207         };
14208         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14209             return false;
14210         }
14211         q = qe.query;
14212         
14213         forceAll = qe.forceAll;
14214         if(forceAll === true || (q.length >= this.minChars)){
14215             
14216             this.hasQuery = true;
14217             
14218             if(this.lastQuery != q || this.alwaysQuery){
14219                 this.lastQuery = q;
14220                 if(this.mode == 'local'){
14221                     this.selectedIndex = -1;
14222                     if(forceAll){
14223                         this.store.clearFilter();
14224                     }else{
14225                         
14226                         if(this.specialFilter){
14227                             this.fireEvent('specialfilter', this);
14228                             this.onLoad();
14229                             return;
14230                         }
14231                         
14232                         this.store.filter(this.displayField, q);
14233                     }
14234                     
14235                     this.store.fireEvent("datachanged", this.store);
14236                     
14237                     this.onLoad();
14238                     
14239                     
14240                 }else{
14241                     
14242                     this.store.baseParams[this.queryParam] = q;
14243                     
14244                     var options = {params : this.getParams(q)};
14245                     
14246                     if(this.loadNext){
14247                         options.add = true;
14248                         options.params.start = this.page * this.pageSize;
14249                     }
14250                     
14251                     this.store.load(options);
14252                     
14253                     /*
14254                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
14255                      *  we should expand the list on onLoad
14256                      *  so command out it
14257                      */
14258 //                    this.expand();
14259                 }
14260             }else{
14261                 this.selectedIndex = -1;
14262                 this.onLoad();   
14263             }
14264         }
14265         
14266         this.loadNext = false;
14267     },
14268     
14269     // private
14270     getParams : function(q){
14271         var p = {};
14272         //p[this.queryParam] = q;
14273         
14274         if(this.pageSize){
14275             p.start = 0;
14276             p.limit = this.pageSize;
14277         }
14278         return p;
14279     },
14280
14281     /**
14282      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14283      */
14284     collapse : function(){
14285         if(!this.isExpanded()){
14286             return;
14287         }
14288         
14289         this.list.hide();
14290         
14291         this.hasFocus = false;
14292         
14293         if(this.tickable){
14294             this.okBtn.hide();
14295             this.cancelBtn.hide();
14296             this.trigger.show();
14297             
14298             if(this.editable){
14299                 this.tickableInputEl().dom.value = '';
14300                 this.tickableInputEl().blur();
14301             }
14302             
14303         }
14304         
14305         Roo.get(document).un('mousedown', this.collapseIf, this);
14306         Roo.get(document).un('mousewheel', this.collapseIf, this);
14307         if (!this.editable) {
14308             Roo.get(document).un('keydown', this.listKeyPress, this);
14309         }
14310         this.fireEvent('collapse', this);
14311         
14312         this.validate();
14313     },
14314
14315     // private
14316     collapseIf : function(e){
14317         var in_combo  = e.within(this.el);
14318         var in_list =  e.within(this.list);
14319         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14320         
14321         if (in_combo || in_list || is_list) {
14322             //e.stopPropagation();
14323             return;
14324         }
14325         
14326         if(this.tickable){
14327             this.onTickableFooterButtonClick(e, false, false);
14328         }
14329
14330         this.collapse();
14331         
14332     },
14333
14334     /**
14335      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14336      */
14337     expand : function(){
14338        
14339         if(this.isExpanded() || !this.hasFocus){
14340             return;
14341         }
14342         
14343         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14344         this.list.setWidth(lw);
14345         
14346         Roo.log('expand');
14347         
14348         this.list.show();
14349         
14350         this.restrictHeight();
14351         
14352         if(this.tickable){
14353             
14354             this.tickItems = Roo.apply([], this.item);
14355             
14356             this.okBtn.show();
14357             this.cancelBtn.show();
14358             this.trigger.hide();
14359             
14360             if(this.editable){
14361                 this.tickableInputEl().focus();
14362             }
14363             
14364         }
14365         
14366         Roo.get(document).on('mousedown', this.collapseIf, this);
14367         Roo.get(document).on('mousewheel', this.collapseIf, this);
14368         if (!this.editable) {
14369             Roo.get(document).on('keydown', this.listKeyPress, this);
14370         }
14371         
14372         this.fireEvent('expand', this);
14373     },
14374
14375     // private
14376     // Implements the default empty TriggerField.onTriggerClick function
14377     onTriggerClick : function(e)
14378     {
14379         Roo.log('trigger click');
14380         
14381         if(this.disabled || !this.triggerList){
14382             return;
14383         }
14384         
14385         this.page = 0;
14386         this.loadNext = false;
14387         
14388         if(this.isExpanded()){
14389             this.collapse();
14390             if (!this.blockFocus) {
14391                 this.inputEl().focus();
14392             }
14393             
14394         }else {
14395             this.hasFocus = true;
14396             if(this.triggerAction == 'all') {
14397                 this.doQuery(this.allQuery, true);
14398             } else {
14399                 this.doQuery(this.getRawValue());
14400             }
14401             if (!this.blockFocus) {
14402                 this.inputEl().focus();
14403             }
14404         }
14405     },
14406     
14407     onTickableTriggerClick : function(e)
14408     {
14409         if(this.disabled){
14410             return;
14411         }
14412         
14413         this.page = 0;
14414         this.loadNext = false;
14415         this.hasFocus = true;
14416         
14417         if(this.triggerAction == 'all') {
14418             this.doQuery(this.allQuery, true);
14419         } else {
14420             this.doQuery(this.getRawValue());
14421         }
14422     },
14423     
14424     onSearchFieldClick : function(e)
14425     {
14426         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14427             this.onTickableFooterButtonClick(e, false, false);
14428             return;
14429         }
14430         
14431         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14432             return;
14433         }
14434         
14435         this.page = 0;
14436         this.loadNext = false;
14437         this.hasFocus = true;
14438         
14439         if(this.triggerAction == 'all') {
14440             this.doQuery(this.allQuery, true);
14441         } else {
14442             this.doQuery(this.getRawValue());
14443         }
14444     },
14445     
14446     listKeyPress : function(e)
14447     {
14448         //Roo.log('listkeypress');
14449         // scroll to first matching element based on key pres..
14450         if (e.isSpecialKey()) {
14451             return false;
14452         }
14453         var k = String.fromCharCode(e.getKey()).toUpperCase();
14454         //Roo.log(k);
14455         var match  = false;
14456         var csel = this.view.getSelectedNodes();
14457         var cselitem = false;
14458         if (csel.length) {
14459             var ix = this.view.indexOf(csel[0]);
14460             cselitem  = this.store.getAt(ix);
14461             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14462                 cselitem = false;
14463             }
14464             
14465         }
14466         
14467         this.store.each(function(v) { 
14468             if (cselitem) {
14469                 // start at existing selection.
14470                 if (cselitem.id == v.id) {
14471                     cselitem = false;
14472                 }
14473                 return true;
14474             }
14475                 
14476             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14477                 match = this.store.indexOf(v);
14478                 return false;
14479             }
14480             return true;
14481         }, this);
14482         
14483         if (match === false) {
14484             return true; // no more action?
14485         }
14486         // scroll to?
14487         this.view.select(match);
14488         var sn = Roo.get(this.view.getSelectedNodes()[0]);
14489         sn.scrollIntoView(sn.dom.parentNode, false);
14490     },
14491     
14492     onViewScroll : function(e, t){
14493         
14494         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){
14495             return;
14496         }
14497         
14498         this.hasQuery = true;
14499         
14500         this.loading = this.list.select('.loading', true).first();
14501         
14502         if(this.loading === null){
14503             this.list.createChild({
14504                 tag: 'div',
14505                 cls: 'loading roo-select2-more-results roo-select2-active',
14506                 html: 'Loading more results...'
14507             });
14508             
14509             this.loading = this.list.select('.loading', true).first();
14510             
14511             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14512             
14513             this.loading.hide();
14514         }
14515         
14516         this.loading.show();
14517         
14518         var _combo = this;
14519         
14520         this.page++;
14521         this.loadNext = true;
14522         
14523         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14524         
14525         return;
14526     },
14527     
14528     addItem : function(o)
14529     {   
14530         var dv = ''; // display value
14531         
14532         if (this.displayField) {
14533             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14534         } else {
14535             // this is an error condition!!!
14536             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14537         }
14538         
14539         if(!dv.length){
14540             return;
14541         }
14542         
14543         var choice = this.choices.createChild({
14544             tag: 'li',
14545             cls: 'roo-select2-search-choice',
14546             cn: [
14547                 {
14548                     tag: 'div',
14549                     html: dv
14550                 },
14551                 {
14552                     tag: 'a',
14553                     href: '#',
14554                     cls: 'roo-select2-search-choice-close fa fa-times',
14555                     tabindex: '-1'
14556                 }
14557             ]
14558             
14559         }, this.searchField);
14560         
14561         var close = choice.select('a.roo-select2-search-choice-close', true).first();
14562         
14563         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14564         
14565         this.item.push(o);
14566         
14567         this.lastData = o;
14568         
14569         this.syncValue();
14570         
14571         this.inputEl().dom.value = '';
14572         
14573         this.validate();
14574     },
14575     
14576     onRemoveItem : function(e, _self, o)
14577     {
14578         e.preventDefault();
14579         
14580         this.lastItem = Roo.apply([], this.item);
14581         
14582         var index = this.item.indexOf(o.data) * 1;
14583         
14584         if( index < 0){
14585             Roo.log('not this item?!');
14586             return;
14587         }
14588         
14589         this.item.splice(index, 1);
14590         o.item.remove();
14591         
14592         this.syncValue();
14593         
14594         this.fireEvent('remove', this, e);
14595         
14596         this.validate();
14597         
14598     },
14599     
14600     syncValue : function()
14601     {
14602         if(!this.item.length){
14603             this.clearValue();
14604             return;
14605         }
14606             
14607         var value = [];
14608         var _this = this;
14609         Roo.each(this.item, function(i){
14610             if(_this.valueField){
14611                 value.push(i[_this.valueField]);
14612                 return;
14613             }
14614
14615             value.push(i);
14616         });
14617
14618         this.value = value.join(',');
14619
14620         if(this.hiddenField){
14621             this.hiddenField.dom.value = this.value;
14622         }
14623         
14624         this.store.fireEvent("datachanged", this.store);
14625         
14626         this.validate();
14627     },
14628     
14629     clearItem : function()
14630     {
14631         if(!this.multiple){
14632             return;
14633         }
14634         
14635         this.item = [];
14636         
14637         Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14638            c.remove();
14639         });
14640         
14641         this.syncValue();
14642         
14643         this.validate();
14644         
14645         if(this.tickable && !Roo.isTouch){
14646             this.view.refresh();
14647         }
14648     },
14649     
14650     inputEl: function ()
14651     {
14652         if(Roo.isIOS && this.useNativeIOS){
14653             return this.el.select('select.roo-ios-select', true).first();
14654         }
14655         
14656         if(Roo.isTouch && this.mobileTouchView){
14657             return this.el.select('input.form-control',true).first();
14658         }
14659         
14660         if(this.tickable){
14661             return this.searchField;
14662         }
14663         
14664         return this.el.select('input.form-control',true).first();
14665     },
14666     
14667     onTickableFooterButtonClick : function(e, btn, el)
14668     {
14669         e.preventDefault();
14670         
14671         this.lastItem = Roo.apply([], this.item);
14672         
14673         if(btn && btn.name == 'cancel'){
14674             this.tickItems = Roo.apply([], this.item);
14675             this.collapse();
14676             return;
14677         }
14678         
14679         this.clearItem();
14680         
14681         var _this = this;
14682         
14683         Roo.each(this.tickItems, function(o){
14684             _this.addItem(o);
14685         });
14686         
14687         this.collapse();
14688         
14689     },
14690     
14691     validate : function()
14692     {
14693         if(this.getEl().hasClass('hidden')){
14694             return true;
14695         }
14696         
14697         var v = this.getRawValue();
14698         
14699         if(this.multiple){
14700             v = this.getValue();
14701         }
14702         
14703         if(this.disabled || this.allowBlank || v.length){
14704             this.markValid();
14705             return true;
14706         }
14707         
14708         this.markInvalid();
14709         return false;
14710     },
14711     
14712     tickableInputEl : function()
14713     {
14714         if(!this.tickable || !this.editable){
14715             return this.inputEl();
14716         }
14717         
14718         return this.inputEl().select('.roo-select2-search-field-input', true).first();
14719     },
14720     
14721     
14722     getAutoCreateTouchView : function()
14723     {
14724         var id = Roo.id();
14725         
14726         var cfg = {
14727             cls: 'form-group' //input-group
14728         };
14729         
14730         var input =  {
14731             tag: 'input',
14732             id : id,
14733             type : this.inputType,
14734             cls : 'form-control x-combo-noedit',
14735             autocomplete: 'new-password',
14736             placeholder : this.placeholder || '',
14737             readonly : true
14738         };
14739         
14740         if (this.name) {
14741             input.name = this.name;
14742         }
14743         
14744         if (this.size) {
14745             input.cls += ' input-' + this.size;
14746         }
14747         
14748         if (this.disabled) {
14749             input.disabled = true;
14750         }
14751         
14752         var inputblock = {
14753             cls : '',
14754             cn : [
14755                 input
14756             ]
14757         };
14758         
14759         if(this.before){
14760             inputblock.cls += ' input-group';
14761             
14762             inputblock.cn.unshift({
14763                 tag :'span',
14764                 cls : 'input-group-addon',
14765                 html : this.before
14766             });
14767         }
14768         
14769         if(this.removable && !this.multiple){
14770             inputblock.cls += ' roo-removable';
14771             
14772             inputblock.cn.push({
14773                 tag: 'button',
14774                 html : 'x',
14775                 cls : 'roo-combo-removable-btn close'
14776             });
14777         }
14778
14779         if(this.hasFeedback && !this.allowBlank){
14780             
14781             inputblock.cls += ' has-feedback';
14782             
14783             inputblock.cn.push({
14784                 tag: 'span',
14785                 cls: 'glyphicon form-control-feedback'
14786             });
14787             
14788         }
14789         
14790         if (this.after) {
14791             
14792             inputblock.cls += (this.before) ? '' : ' input-group';
14793             
14794             inputblock.cn.push({
14795                 tag :'span',
14796                 cls : 'input-group-addon',
14797                 html : this.after
14798             });
14799         }
14800
14801         var box = {
14802             tag: 'div',
14803             cn: [
14804                 {
14805                     tag: 'input',
14806                     type : 'hidden',
14807                     cls: 'form-hidden-field'
14808                 },
14809                 inputblock
14810             ]
14811             
14812         };
14813         
14814         if(this.multiple){
14815             box = {
14816                 tag: 'div',
14817                 cn: [
14818                     {
14819                         tag: 'input',
14820                         type : 'hidden',
14821                         cls: 'form-hidden-field'
14822                     },
14823                     {
14824                         tag: 'ul',
14825                         cls: 'roo-select2-choices',
14826                         cn:[
14827                             {
14828                                 tag: 'li',
14829                                 cls: 'roo-select2-search-field',
14830                                 cn: [
14831
14832                                     inputblock
14833                                 ]
14834                             }
14835                         ]
14836                     }
14837                 ]
14838             }
14839         };
14840         
14841         var combobox = {
14842             cls: 'roo-select2-container input-group roo-touchview-combobox ',
14843             cn: [
14844                 box
14845             ]
14846         };
14847         
14848         if(!this.multiple && this.showToggleBtn){
14849             
14850             var caret = {
14851                         tag: 'span',
14852                         cls: 'caret'
14853             };
14854             
14855             if (this.caret != false) {
14856                 caret = {
14857                      tag: 'i',
14858                      cls: 'fa fa-' + this.caret
14859                 };
14860                 
14861             }
14862             
14863             combobox.cn.push({
14864                 tag :'span',
14865                 cls : 'input-group-addon btn dropdown-toggle',
14866                 cn : [
14867                     caret,
14868                     {
14869                         tag: 'span',
14870                         cls: 'combobox-clear',
14871                         cn  : [
14872                             {
14873                                 tag : 'i',
14874                                 cls: 'icon-remove'
14875                             }
14876                         ]
14877                     }
14878                 ]
14879
14880             })
14881         }
14882         
14883         if(this.multiple){
14884             combobox.cls += ' roo-select2-container-multi';
14885         }
14886         
14887         var align = this.labelAlign || this.parentLabelAlign();
14888         
14889         if (align ==='left' && this.fieldLabel.length) {
14890
14891             cfg.cn = [
14892                 {
14893                    tag : 'i',
14894                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14895                    tooltip : 'This field is required'
14896                 },
14897                 {
14898                     tag: 'label',
14899                     cls : 'control-label',
14900                     html : this.fieldLabel
14901
14902                 },
14903                 {
14904                     cls : '', 
14905                     cn: [
14906                         combobox
14907                     ]
14908                 }
14909             ];
14910             
14911             var labelCfg = cfg.cn[1];
14912             var contentCfg = cfg.cn[2];
14913             
14914
14915             if(this.indicatorpos == 'right'){
14916                 cfg.cn = [
14917                     {
14918                         tag: 'label',
14919                         'for' :  id,
14920                         cls : 'control-label',
14921                         cn : [
14922                             {
14923                                 tag : 'span',
14924                                 html : this.fieldLabel
14925                             },
14926                             {
14927                                 tag : 'i',
14928                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14929                                 tooltip : 'This field is required'
14930                             }
14931                         ]
14932                     },
14933                     {
14934                         cls : "",
14935                         cn: [
14936                             combobox
14937                         ]
14938                     }
14939
14940                 ];
14941                 
14942                 labelCfg = cfg.cn[0];
14943                 contentCfg = cfg.cn[1];
14944             }
14945             
14946            
14947             
14948             if(this.labelWidth > 12){
14949                 labelCfg.style = "width: " + this.labelWidth + 'px';
14950             }
14951             
14952             if(this.labelWidth < 13 && this.labelmd == 0){
14953                 this.labelmd = this.labelWidth;
14954             }
14955             
14956             if(this.labellg > 0){
14957                 labelCfg.cls += ' col-lg-' + this.labellg;
14958                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14959             }
14960             
14961             if(this.labelmd > 0){
14962                 labelCfg.cls += ' col-md-' + this.labelmd;
14963                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14964             }
14965             
14966             if(this.labelsm > 0){
14967                 labelCfg.cls += ' col-sm-' + this.labelsm;
14968                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14969             }
14970             
14971             if(this.labelxs > 0){
14972                 labelCfg.cls += ' col-xs-' + this.labelxs;
14973                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14974             }
14975                 
14976                 
14977         } else if ( this.fieldLabel.length) {
14978             cfg.cn = [
14979                 {
14980                    tag : 'i',
14981                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14982                    tooltip : 'This field is required'
14983                 },
14984                 {
14985                     tag: 'label',
14986                     cls : 'control-label',
14987                     html : this.fieldLabel
14988
14989                 },
14990                 {
14991                     cls : '', 
14992                     cn: [
14993                         combobox
14994                     ]
14995                 }
14996             ];
14997             
14998             if(this.indicatorpos == 'right'){
14999                 cfg.cn = [
15000                     {
15001                         tag: 'label',
15002                         cls : 'control-label',
15003                         html : this.fieldLabel,
15004                         cn : [
15005                             {
15006                                tag : 'i',
15007                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15008                                tooltip : 'This field is required'
15009                             }
15010                         ]
15011                     },
15012                     {
15013                         cls : '', 
15014                         cn: [
15015                             combobox
15016                         ]
15017                     }
15018                 ];
15019             }
15020         } else {
15021             cfg.cn = combobox;    
15022         }
15023         
15024         
15025         var settings = this;
15026         
15027         ['xs','sm','md','lg'].map(function(size){
15028             if (settings[size]) {
15029                 cfg.cls += ' col-' + size + '-' + settings[size];
15030             }
15031         });
15032         
15033         return cfg;
15034     },
15035     
15036     initTouchView : function()
15037     {
15038         this.renderTouchView();
15039         
15040         this.touchViewEl.on('scroll', function(){
15041             this.el.dom.scrollTop = 0;
15042         }, this);
15043         
15044         this.originalValue = this.getValue();
15045         
15046         this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15047         
15048         this.inputEl().on("click", this.showTouchView, this);
15049         if (this.triggerEl) {
15050             this.triggerEl.on("click", this.showTouchView, this);
15051         }
15052         
15053         
15054         this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15055         this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15056         
15057         this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15058         
15059         this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15060         this.store.on('load', this.onTouchViewLoad, this);
15061         this.store.on('loadexception', this.onTouchViewLoadException, this);
15062         
15063         if(this.hiddenName){
15064             
15065             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15066             
15067             this.hiddenField.dom.value =
15068                 this.hiddenValue !== undefined ? this.hiddenValue :
15069                 this.value !== undefined ? this.value : '';
15070         
15071             this.el.dom.removeAttribute('name');
15072             this.hiddenField.dom.setAttribute('name', this.hiddenName);
15073         }
15074         
15075         if(this.multiple){
15076             this.choices = this.el.select('ul.roo-select2-choices', true).first();
15077             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15078         }
15079         
15080         if(this.removable && !this.multiple){
15081             var close = this.closeTriggerEl();
15082             if(close){
15083                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15084                 close.on('click', this.removeBtnClick, this, close);
15085             }
15086         }
15087         /*
15088          * fix the bug in Safari iOS8
15089          */
15090         this.inputEl().on("focus", function(e){
15091             document.activeElement.blur();
15092         }, this);
15093         
15094         return;
15095         
15096         
15097     },
15098     
15099     renderTouchView : function()
15100     {
15101         this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15102         this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15103         
15104         this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15105         this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15106         
15107         this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15108         this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15109         this.touchViewBodyEl.setStyle('overflow', 'auto');
15110         
15111         this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15112         this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15113         
15114         this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15115         this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15116         
15117     },
15118     
15119     showTouchView : function()
15120     {
15121         if(this.disabled){
15122             return;
15123         }
15124         
15125         this.touchViewHeaderEl.hide();
15126
15127         if(this.modalTitle.length){
15128             this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15129             this.touchViewHeaderEl.show();
15130         }
15131
15132         this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15133         this.touchViewEl.show();
15134
15135         this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15136         
15137         //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15138         //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15139
15140         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15141
15142         if(this.modalTitle.length){
15143             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15144         }
15145         
15146         this.touchViewBodyEl.setHeight(bodyHeight);
15147
15148         if(this.animate){
15149             var _this = this;
15150             (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15151         }else{
15152             this.touchViewEl.addClass('in');
15153         }
15154
15155         this.doTouchViewQuery();
15156         
15157     },
15158     
15159     hideTouchView : function()
15160     {
15161         this.touchViewEl.removeClass('in');
15162
15163         if(this.animate){
15164             var _this = this;
15165             (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15166         }else{
15167             this.touchViewEl.setStyle('display', 'none');
15168         }
15169         
15170     },
15171     
15172     setTouchViewValue : function()
15173     {
15174         if(this.multiple){
15175             this.clearItem();
15176         
15177             var _this = this;
15178
15179             Roo.each(this.tickItems, function(o){
15180                 this.addItem(o);
15181             }, this);
15182         }
15183         
15184         this.hideTouchView();
15185     },
15186     
15187     doTouchViewQuery : function()
15188     {
15189         var qe = {
15190             query: '',
15191             forceAll: true,
15192             combo: this,
15193             cancel:false
15194         };
15195         
15196         if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15197             return false;
15198         }
15199         
15200         if(!this.alwaysQuery || this.mode == 'local'){
15201             this.onTouchViewLoad();
15202             return;
15203         }
15204         
15205         this.store.load();
15206     },
15207     
15208     onTouchViewBeforeLoad : function(combo,opts)
15209     {
15210         return;
15211     },
15212
15213     // private
15214     onTouchViewLoad : function()
15215     {
15216         if(this.store.getCount() < 1){
15217             this.onTouchViewEmptyResults();
15218             return;
15219         }
15220         
15221         this.clearTouchView();
15222         
15223         var rawValue = this.getRawValue();
15224         
15225         var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15226         
15227         this.tickItems = [];
15228         
15229         this.store.data.each(function(d, rowIndex){
15230             var row = this.touchViewListGroup.createChild(template);
15231             
15232             if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15233                 row.addClass(d.data.cls);
15234             }
15235             
15236             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15237                 var cfg = {
15238                     data : d.data,
15239                     html : d.data[this.displayField]
15240                 };
15241                 
15242                 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15243                     row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15244                 }
15245             }
15246             row.removeClass('selected');
15247             if(!this.multiple && this.valueField &&
15248                     typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15249             {
15250                 // radio buttons..
15251                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15252                 row.addClass('selected');
15253             }
15254             
15255             if(this.multiple && this.valueField &&
15256                     typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15257             {
15258                 
15259                 // checkboxes...
15260                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15261                 this.tickItems.push(d.data);
15262             }
15263             
15264             row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15265             
15266         }, this);
15267         
15268         var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15269         
15270         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15271
15272         if(this.modalTitle.length){
15273             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15274         }
15275
15276         var listHeight = this.touchViewListGroup.getHeight();
15277         
15278         var _this = this;
15279         
15280         if(firstChecked && listHeight > bodyHeight){
15281             (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15282         }
15283         
15284     },
15285     
15286     onTouchViewLoadException : function()
15287     {
15288         this.hideTouchView();
15289     },
15290     
15291     onTouchViewEmptyResults : function()
15292     {
15293         this.clearTouchView();
15294         
15295         this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15296         
15297         this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15298         
15299     },
15300     
15301     clearTouchView : function()
15302     {
15303         this.touchViewListGroup.dom.innerHTML = '';
15304     },
15305     
15306     onTouchViewClick : function(e, el, o)
15307     {
15308         e.preventDefault();
15309         
15310         var row = o.row;
15311         var rowIndex = o.rowIndex;
15312         
15313         var r = this.store.getAt(rowIndex);
15314         
15315         if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15316             
15317             if(!this.multiple){
15318                 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15319                     c.dom.removeAttribute('checked');
15320                 }, this);
15321
15322                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15323
15324                 this.setFromData(r.data);
15325
15326                 var close = this.closeTriggerEl();
15327
15328                 if(close){
15329                     close.show();
15330                 }
15331
15332                 this.hideTouchView();
15333
15334                 this.fireEvent('select', this, r, rowIndex);
15335
15336                 return;
15337             }
15338
15339             if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15340                 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15341                 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15342                 return;
15343             }
15344
15345             row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15346             this.addItem(r.data);
15347             this.tickItems.push(r.data);
15348         }
15349     },
15350     
15351     getAutoCreateNativeIOS : function()
15352     {
15353         var cfg = {
15354             cls: 'form-group' //input-group,
15355         };
15356         
15357         var combobox =  {
15358             tag: 'select',
15359             cls : 'roo-ios-select'
15360         };
15361         
15362         if (this.name) {
15363             combobox.name = this.name;
15364         }
15365         
15366         if (this.disabled) {
15367             combobox.disabled = true;
15368         }
15369         
15370         var settings = this;
15371         
15372         ['xs','sm','md','lg'].map(function(size){
15373             if (settings[size]) {
15374                 cfg.cls += ' col-' + size + '-' + settings[size];
15375             }
15376         });
15377         
15378         cfg.cn = combobox;
15379         
15380         return cfg;
15381         
15382     },
15383     
15384     initIOSView : function()
15385     {
15386         this.store.on('load', this.onIOSViewLoad, this);
15387         
15388         return;
15389     },
15390     
15391     onIOSViewLoad : function()
15392     {
15393         if(this.store.getCount() < 1){
15394             return;
15395         }
15396         
15397         this.clearIOSView();
15398         
15399         if(this.allowBlank) {
15400             
15401             var default_text = '-- SELECT --';
15402             
15403             if(this.placeholder.length){
15404                 default_text = this.placeholder;
15405             }
15406             
15407             if(this.emptyTitle.length){
15408                 default_text += ' - ' + this.emptyTitle + ' -';
15409             }
15410             
15411             var opt = this.inputEl().createChild({
15412                 tag: 'option',
15413                 value : 0,
15414                 html : default_text
15415             });
15416             
15417             var o = {};
15418             o[this.valueField] = 0;
15419             o[this.displayField] = default_text;
15420             
15421             this.ios_options.push({
15422                 data : o,
15423                 el : opt
15424             });
15425             
15426         }
15427         
15428         this.store.data.each(function(d, rowIndex){
15429             
15430             var html = '';
15431             
15432             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15433                 html = d.data[this.displayField];
15434             }
15435             
15436             var value = '';
15437             
15438             if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15439                 value = d.data[this.valueField];
15440             }
15441             
15442             var option = {
15443                 tag: 'option',
15444                 value : value,
15445                 html : html
15446             };
15447             
15448             if(this.value == d.data[this.valueField]){
15449                 option['selected'] = true;
15450             }
15451             
15452             var opt = this.inputEl().createChild(option);
15453             
15454             this.ios_options.push({
15455                 data : d.data,
15456                 el : opt
15457             });
15458             
15459         }, this);
15460         
15461         this.inputEl().on('change', function(){
15462            this.fireEvent('select', this);
15463         }, this);
15464         
15465     },
15466     
15467     clearIOSView: function()
15468     {
15469         this.inputEl().dom.innerHTML = '';
15470         
15471         this.ios_options = [];
15472     },
15473     
15474     setIOSValue: function(v)
15475     {
15476         this.value = v;
15477         
15478         if(!this.ios_options){
15479             return;
15480         }
15481         
15482         Roo.each(this.ios_options, function(opts){
15483            
15484            opts.el.dom.removeAttribute('selected');
15485            
15486            if(opts.data[this.valueField] != v){
15487                return;
15488            }
15489            
15490            opts.el.dom.setAttribute('selected', true);
15491            
15492         }, this);
15493     }
15494
15495     /** 
15496     * @cfg {Boolean} grow 
15497     * @hide 
15498     */
15499     /** 
15500     * @cfg {Number} growMin 
15501     * @hide 
15502     */
15503     /** 
15504     * @cfg {Number} growMax 
15505     * @hide 
15506     */
15507     /**
15508      * @hide
15509      * @method autoSize
15510      */
15511 });
15512
15513 Roo.apply(Roo.bootstrap.ComboBox,  {
15514     
15515     header : {
15516         tag: 'div',
15517         cls: 'modal-header',
15518         cn: [
15519             {
15520                 tag: 'h4',
15521                 cls: 'modal-title'
15522             }
15523         ]
15524     },
15525     
15526     body : {
15527         tag: 'div',
15528         cls: 'modal-body',
15529         cn: [
15530             {
15531                 tag: 'ul',
15532                 cls: 'list-group'
15533             }
15534         ]
15535     },
15536     
15537     listItemRadio : {
15538         tag: 'li',
15539         cls: 'list-group-item',
15540         cn: [
15541             {
15542                 tag: 'span',
15543                 cls: 'roo-combobox-list-group-item-value'
15544             },
15545             {
15546                 tag: 'div',
15547                 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15548                 cn: [
15549                     {
15550                         tag: 'input',
15551                         type: 'radio'
15552                     },
15553                     {
15554                         tag: 'label'
15555                     }
15556                 ]
15557             }
15558         ]
15559     },
15560     
15561     listItemCheckbox : {
15562         tag: 'li',
15563         cls: 'list-group-item',
15564         cn: [
15565             {
15566                 tag: 'span',
15567                 cls: 'roo-combobox-list-group-item-value'
15568             },
15569             {
15570                 tag: 'div',
15571                 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15572                 cn: [
15573                     {
15574                         tag: 'input',
15575                         type: 'checkbox'
15576                     },
15577                     {
15578                         tag: 'label'
15579                     }
15580                 ]
15581             }
15582         ]
15583     },
15584     
15585     emptyResult : {
15586         tag: 'div',
15587         cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15588     },
15589     
15590     footer : {
15591         tag: 'div',
15592         cls: 'modal-footer',
15593         cn: [
15594             {
15595                 tag: 'div',
15596                 cls: 'row',
15597                 cn: [
15598                     {
15599                         tag: 'div',
15600                         cls: 'col-xs-6 text-left',
15601                         cn: {
15602                             tag: 'button',
15603                             cls: 'btn btn-danger roo-touch-view-cancel',
15604                             html: 'Cancel'
15605                         }
15606                     },
15607                     {
15608                         tag: 'div',
15609                         cls: 'col-xs-6 text-right',
15610                         cn: {
15611                             tag: 'button',
15612                             cls: 'btn btn-success roo-touch-view-ok',
15613                             html: 'OK'
15614                         }
15615                     }
15616                 ]
15617             }
15618         ]
15619         
15620     }
15621 });
15622
15623 Roo.apply(Roo.bootstrap.ComboBox,  {
15624     
15625     touchViewTemplate : {
15626         tag: 'div',
15627         cls: 'modal fade roo-combobox-touch-view',
15628         cn: [
15629             {
15630                 tag: 'div',
15631                 cls: 'modal-dialog',
15632                 style : 'position:fixed', // we have to fix position....
15633                 cn: [
15634                     {
15635                         tag: 'div',
15636                         cls: 'modal-content',
15637                         cn: [
15638                             Roo.bootstrap.ComboBox.header,
15639                             Roo.bootstrap.ComboBox.body,
15640                             Roo.bootstrap.ComboBox.footer
15641                         ]
15642                     }
15643                 ]
15644             }
15645         ]
15646     }
15647 });/*
15648  * Based on:
15649  * Ext JS Library 1.1.1
15650  * Copyright(c) 2006-2007, Ext JS, LLC.
15651  *
15652  * Originally Released Under LGPL - original licence link has changed is not relivant.
15653  *
15654  * Fork - LGPL
15655  * <script type="text/javascript">
15656  */
15657
15658 /**
15659  * @class Roo.View
15660  * @extends Roo.util.Observable
15661  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
15662  * This class also supports single and multi selection modes. <br>
15663  * Create a data model bound view:
15664  <pre><code>
15665  var store = new Roo.data.Store(...);
15666
15667  var view = new Roo.View({
15668     el : "my-element",
15669     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
15670  
15671     singleSelect: true,
15672     selectedClass: "ydataview-selected",
15673     store: store
15674  });
15675
15676  // listen for node click?
15677  view.on("click", function(vw, index, node, e){
15678  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15679  });
15680
15681  // load XML data
15682  dataModel.load("foobar.xml");
15683  </code></pre>
15684  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15685  * <br><br>
15686  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15687  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15688  * 
15689  * Note: old style constructor is still suported (container, template, config)
15690  * 
15691  * @constructor
15692  * Create a new View
15693  * @param {Object} config The config object
15694  * 
15695  */
15696 Roo.View = function(config, depreciated_tpl, depreciated_config){
15697     
15698     this.parent = false;
15699     
15700     if (typeof(depreciated_tpl) == 'undefined') {
15701         // new way.. - universal constructor.
15702         Roo.apply(this, config);
15703         this.el  = Roo.get(this.el);
15704     } else {
15705         // old format..
15706         this.el  = Roo.get(config);
15707         this.tpl = depreciated_tpl;
15708         Roo.apply(this, depreciated_config);
15709     }
15710     this.wrapEl  = this.el.wrap().wrap();
15711     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15712     
15713     
15714     if(typeof(this.tpl) == "string"){
15715         this.tpl = new Roo.Template(this.tpl);
15716     } else {
15717         // support xtype ctors..
15718         this.tpl = new Roo.factory(this.tpl, Roo);
15719     }
15720     
15721     
15722     this.tpl.compile();
15723     
15724     /** @private */
15725     this.addEvents({
15726         /**
15727          * @event beforeclick
15728          * Fires before a click is processed. Returns false to cancel the default action.
15729          * @param {Roo.View} this
15730          * @param {Number} index The index of the target node
15731          * @param {HTMLElement} node The target node
15732          * @param {Roo.EventObject} e The raw event object
15733          */
15734             "beforeclick" : true,
15735         /**
15736          * @event click
15737          * Fires when a template node is clicked.
15738          * @param {Roo.View} this
15739          * @param {Number} index The index of the target node
15740          * @param {HTMLElement} node The target node
15741          * @param {Roo.EventObject} e The raw event object
15742          */
15743             "click" : true,
15744         /**
15745          * @event dblclick
15746          * Fires when a template node is double clicked.
15747          * @param {Roo.View} this
15748          * @param {Number} index The index of the target node
15749          * @param {HTMLElement} node The target node
15750          * @param {Roo.EventObject} e The raw event object
15751          */
15752             "dblclick" : true,
15753         /**
15754          * @event contextmenu
15755          * Fires when a template node is right clicked.
15756          * @param {Roo.View} this
15757          * @param {Number} index The index of the target node
15758          * @param {HTMLElement} node The target node
15759          * @param {Roo.EventObject} e The raw event object
15760          */
15761             "contextmenu" : true,
15762         /**
15763          * @event selectionchange
15764          * Fires when the selected nodes change.
15765          * @param {Roo.View} this
15766          * @param {Array} selections Array of the selected nodes
15767          */
15768             "selectionchange" : true,
15769     
15770         /**
15771          * @event beforeselect
15772          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15773          * @param {Roo.View} this
15774          * @param {HTMLElement} node The node to be selected
15775          * @param {Array} selections Array of currently selected nodes
15776          */
15777             "beforeselect" : true,
15778         /**
15779          * @event preparedata
15780          * Fires on every row to render, to allow you to change the data.
15781          * @param {Roo.View} this
15782          * @param {Object} data to be rendered (change this)
15783          */
15784           "preparedata" : true
15785           
15786           
15787         });
15788
15789
15790
15791     this.el.on({
15792         "click": this.onClick,
15793         "dblclick": this.onDblClick,
15794         "contextmenu": this.onContextMenu,
15795         scope:this
15796     });
15797
15798     this.selections = [];
15799     this.nodes = [];
15800     this.cmp = new Roo.CompositeElementLite([]);
15801     if(this.store){
15802         this.store = Roo.factory(this.store, Roo.data);
15803         this.setStore(this.store, true);
15804     }
15805     
15806     if ( this.footer && this.footer.xtype) {
15807            
15808          var fctr = this.wrapEl.appendChild(document.createElement("div"));
15809         
15810         this.footer.dataSource = this.store;
15811         this.footer.container = fctr;
15812         this.footer = Roo.factory(this.footer, Roo);
15813         fctr.insertFirst(this.el);
15814         
15815         // this is a bit insane - as the paging toolbar seems to detach the el..
15816 //        dom.parentNode.parentNode.parentNode
15817          // they get detached?
15818     }
15819     
15820     
15821     Roo.View.superclass.constructor.call(this);
15822     
15823     
15824 };
15825
15826 Roo.extend(Roo.View, Roo.util.Observable, {
15827     
15828      /**
15829      * @cfg {Roo.data.Store} store Data store to load data from.
15830      */
15831     store : false,
15832     
15833     /**
15834      * @cfg {String|Roo.Element} el The container element.
15835      */
15836     el : '',
15837     
15838     /**
15839      * @cfg {String|Roo.Template} tpl The template used by this View 
15840      */
15841     tpl : false,
15842     /**
15843      * @cfg {String} dataName the named area of the template to use as the data area
15844      *                          Works with domtemplates roo-name="name"
15845      */
15846     dataName: false,
15847     /**
15848      * @cfg {String} selectedClass The css class to add to selected nodes
15849      */
15850     selectedClass : "x-view-selected",
15851      /**
15852      * @cfg {String} emptyText The empty text to show when nothing is loaded.
15853      */
15854     emptyText : "",
15855     
15856     /**
15857      * @cfg {String} text to display on mask (default Loading)
15858      */
15859     mask : false,
15860     /**
15861      * @cfg {Boolean} multiSelect Allow multiple selection
15862      */
15863     multiSelect : false,
15864     /**
15865      * @cfg {Boolean} singleSelect Allow single selection
15866      */
15867     singleSelect:  false,
15868     
15869     /**
15870      * @cfg {Boolean} toggleSelect - selecting 
15871      */
15872     toggleSelect : false,
15873     
15874     /**
15875      * @cfg {Boolean} tickable - selecting 
15876      */
15877     tickable : false,
15878     
15879     /**
15880      * Returns the element this view is bound to.
15881      * @return {Roo.Element}
15882      */
15883     getEl : function(){
15884         return this.wrapEl;
15885     },
15886     
15887     
15888
15889     /**
15890      * Refreshes the view. - called by datachanged on the store. - do not call directly.
15891      */
15892     refresh : function(){
15893         //Roo.log('refresh');
15894         var t = this.tpl;
15895         
15896         // if we are using something like 'domtemplate', then
15897         // the what gets used is:
15898         // t.applySubtemplate(NAME, data, wrapping data..)
15899         // the outer template then get' applied with
15900         //     the store 'extra data'
15901         // and the body get's added to the
15902         //      roo-name="data" node?
15903         //      <span class='roo-tpl-{name}'></span> ?????
15904         
15905         
15906         
15907         this.clearSelections();
15908         this.el.update("");
15909         var html = [];
15910         var records = this.store.getRange();
15911         if(records.length < 1) {
15912             
15913             // is this valid??  = should it render a template??
15914             
15915             this.el.update(this.emptyText);
15916             return;
15917         }
15918         var el = this.el;
15919         if (this.dataName) {
15920             this.el.update(t.apply(this.store.meta)); //????
15921             el = this.el.child('.roo-tpl-' + this.dataName);
15922         }
15923         
15924         for(var i = 0, len = records.length; i < len; i++){
15925             var data = this.prepareData(records[i].data, i, records[i]);
15926             this.fireEvent("preparedata", this, data, i, records[i]);
15927             
15928             var d = Roo.apply({}, data);
15929             
15930             if(this.tickable){
15931                 Roo.apply(d, {'roo-id' : Roo.id()});
15932                 
15933                 var _this = this;
15934             
15935                 Roo.each(this.parent.item, function(item){
15936                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15937                         return;
15938                     }
15939                     Roo.apply(d, {'roo-data-checked' : 'checked'});
15940                 });
15941             }
15942             
15943             html[html.length] = Roo.util.Format.trim(
15944                 this.dataName ?
15945                     t.applySubtemplate(this.dataName, d, this.store.meta) :
15946                     t.apply(d)
15947             );
15948         }
15949         
15950         
15951         
15952         el.update(html.join(""));
15953         this.nodes = el.dom.childNodes;
15954         this.updateIndexes(0);
15955     },
15956     
15957
15958     /**
15959      * Function to override to reformat the data that is sent to
15960      * the template for each node.
15961      * DEPRICATED - use the preparedata event handler.
15962      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15963      * a JSON object for an UpdateManager bound view).
15964      */
15965     prepareData : function(data, index, record)
15966     {
15967         this.fireEvent("preparedata", this, data, index, record);
15968         return data;
15969     },
15970
15971     onUpdate : function(ds, record){
15972         // Roo.log('on update');   
15973         this.clearSelections();
15974         var index = this.store.indexOf(record);
15975         var n = this.nodes[index];
15976         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15977         n.parentNode.removeChild(n);
15978         this.updateIndexes(index, index);
15979     },
15980
15981     
15982     
15983 // --------- FIXME     
15984     onAdd : function(ds, records, index)
15985     {
15986         //Roo.log(['on Add', ds, records, index] );        
15987         this.clearSelections();
15988         if(this.nodes.length == 0){
15989             this.refresh();
15990             return;
15991         }
15992         var n = this.nodes[index];
15993         for(var i = 0, len = records.length; i < len; i++){
15994             var d = this.prepareData(records[i].data, i, records[i]);
15995             if(n){
15996                 this.tpl.insertBefore(n, d);
15997             }else{
15998                 
15999                 this.tpl.append(this.el, d);
16000             }
16001         }
16002         this.updateIndexes(index);
16003     },
16004
16005     onRemove : function(ds, record, index){
16006        // Roo.log('onRemove');
16007         this.clearSelections();
16008         var el = this.dataName  ?
16009             this.el.child('.roo-tpl-' + this.dataName) :
16010             this.el; 
16011         
16012         el.dom.removeChild(this.nodes[index]);
16013         this.updateIndexes(index);
16014     },
16015
16016     /**
16017      * Refresh an individual node.
16018      * @param {Number} index
16019      */
16020     refreshNode : function(index){
16021         this.onUpdate(this.store, this.store.getAt(index));
16022     },
16023
16024     updateIndexes : function(startIndex, endIndex){
16025         var ns = this.nodes;
16026         startIndex = startIndex || 0;
16027         endIndex = endIndex || ns.length - 1;
16028         for(var i = startIndex; i <= endIndex; i++){
16029             ns[i].nodeIndex = i;
16030         }
16031     },
16032
16033     /**
16034      * Changes the data store this view uses and refresh the view.
16035      * @param {Store} store
16036      */
16037     setStore : function(store, initial){
16038         if(!initial && this.store){
16039             this.store.un("datachanged", this.refresh);
16040             this.store.un("add", this.onAdd);
16041             this.store.un("remove", this.onRemove);
16042             this.store.un("update", this.onUpdate);
16043             this.store.un("clear", this.refresh);
16044             this.store.un("beforeload", this.onBeforeLoad);
16045             this.store.un("load", this.onLoad);
16046             this.store.un("loadexception", this.onLoad);
16047         }
16048         if(store){
16049           
16050             store.on("datachanged", this.refresh, this);
16051             store.on("add", this.onAdd, this);
16052             store.on("remove", this.onRemove, this);
16053             store.on("update", this.onUpdate, this);
16054             store.on("clear", this.refresh, this);
16055             store.on("beforeload", this.onBeforeLoad, this);
16056             store.on("load", this.onLoad, this);
16057             store.on("loadexception", this.onLoad, this);
16058         }
16059         
16060         if(store){
16061             this.refresh();
16062         }
16063     },
16064     /**
16065      * onbeforeLoad - masks the loading area.
16066      *
16067      */
16068     onBeforeLoad : function(store,opts)
16069     {
16070          //Roo.log('onBeforeLoad');   
16071         if (!opts.add) {
16072             this.el.update("");
16073         }
16074         this.el.mask(this.mask ? this.mask : "Loading" ); 
16075     },
16076     onLoad : function ()
16077     {
16078         this.el.unmask();
16079     },
16080     
16081
16082     /**
16083      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16084      * @param {HTMLElement} node
16085      * @return {HTMLElement} The template node
16086      */
16087     findItemFromChild : function(node){
16088         var el = this.dataName  ?
16089             this.el.child('.roo-tpl-' + this.dataName,true) :
16090             this.el.dom; 
16091         
16092         if(!node || node.parentNode == el){
16093                     return node;
16094             }
16095             var p = node.parentNode;
16096             while(p && p != el){
16097             if(p.parentNode == el){
16098                 return p;
16099             }
16100             p = p.parentNode;
16101         }
16102             return null;
16103     },
16104
16105     /** @ignore */
16106     onClick : function(e){
16107         var item = this.findItemFromChild(e.getTarget());
16108         if(item){
16109             var index = this.indexOf(item);
16110             if(this.onItemClick(item, index, e) !== false){
16111                 this.fireEvent("click", this, index, item, e);
16112             }
16113         }else{
16114             this.clearSelections();
16115         }
16116     },
16117
16118     /** @ignore */
16119     onContextMenu : function(e){
16120         var item = this.findItemFromChild(e.getTarget());
16121         if(item){
16122             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16123         }
16124     },
16125
16126     /** @ignore */
16127     onDblClick : function(e){
16128         var item = this.findItemFromChild(e.getTarget());
16129         if(item){
16130             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16131         }
16132     },
16133
16134     onItemClick : function(item, index, e)
16135     {
16136         if(this.fireEvent("beforeclick", this, index, item, e) === false){
16137             return false;
16138         }
16139         if (this.toggleSelect) {
16140             var m = this.isSelected(item) ? 'unselect' : 'select';
16141             //Roo.log(m);
16142             var _t = this;
16143             _t[m](item, true, false);
16144             return true;
16145         }
16146         if(this.multiSelect || this.singleSelect){
16147             if(this.multiSelect && e.shiftKey && this.lastSelection){
16148                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16149             }else{
16150                 this.select(item, this.multiSelect && e.ctrlKey);
16151                 this.lastSelection = item;
16152             }
16153             
16154             if(!this.tickable){
16155                 e.preventDefault();
16156             }
16157             
16158         }
16159         return true;
16160     },
16161
16162     /**
16163      * Get the number of selected nodes.
16164      * @return {Number}
16165      */
16166     getSelectionCount : function(){
16167         return this.selections.length;
16168     },
16169
16170     /**
16171      * Get the currently selected nodes.
16172      * @return {Array} An array of HTMLElements
16173      */
16174     getSelectedNodes : function(){
16175         return this.selections;
16176     },
16177
16178     /**
16179      * Get the indexes of the selected nodes.
16180      * @return {Array}
16181      */
16182     getSelectedIndexes : function(){
16183         var indexes = [], s = this.selections;
16184         for(var i = 0, len = s.length; i < len; i++){
16185             indexes.push(s[i].nodeIndex);
16186         }
16187         return indexes;
16188     },
16189
16190     /**
16191      * Clear all selections
16192      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16193      */
16194     clearSelections : function(suppressEvent){
16195         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16196             this.cmp.elements = this.selections;
16197             this.cmp.removeClass(this.selectedClass);
16198             this.selections = [];
16199             if(!suppressEvent){
16200                 this.fireEvent("selectionchange", this, this.selections);
16201             }
16202         }
16203     },
16204
16205     /**
16206      * Returns true if the passed node is selected
16207      * @param {HTMLElement/Number} node The node or node index
16208      * @return {Boolean}
16209      */
16210     isSelected : function(node){
16211         var s = this.selections;
16212         if(s.length < 1){
16213             return false;
16214         }
16215         node = this.getNode(node);
16216         return s.indexOf(node) !== -1;
16217     },
16218
16219     /**
16220      * Selects nodes.
16221      * @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
16222      * @param {Boolean} keepExisting (optional) true to keep existing selections
16223      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16224      */
16225     select : function(nodeInfo, keepExisting, suppressEvent){
16226         if(nodeInfo instanceof Array){
16227             if(!keepExisting){
16228                 this.clearSelections(true);
16229             }
16230             for(var i = 0, len = nodeInfo.length; i < len; i++){
16231                 this.select(nodeInfo[i], true, true);
16232             }
16233             return;
16234         } 
16235         var node = this.getNode(nodeInfo);
16236         if(!node || this.isSelected(node)){
16237             return; // already selected.
16238         }
16239         if(!keepExisting){
16240             this.clearSelections(true);
16241         }
16242         
16243         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16244             Roo.fly(node).addClass(this.selectedClass);
16245             this.selections.push(node);
16246             if(!suppressEvent){
16247                 this.fireEvent("selectionchange", this, this.selections);
16248             }
16249         }
16250         
16251         
16252     },
16253       /**
16254      * Unselects nodes.
16255      * @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
16256      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16257      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16258      */
16259     unselect : function(nodeInfo, keepExisting, suppressEvent)
16260     {
16261         if(nodeInfo instanceof Array){
16262             Roo.each(this.selections, function(s) {
16263                 this.unselect(s, nodeInfo);
16264             }, this);
16265             return;
16266         }
16267         var node = this.getNode(nodeInfo);
16268         if(!node || !this.isSelected(node)){
16269             //Roo.log("not selected");
16270             return; // not selected.
16271         }
16272         // fireevent???
16273         var ns = [];
16274         Roo.each(this.selections, function(s) {
16275             if (s == node ) {
16276                 Roo.fly(node).removeClass(this.selectedClass);
16277
16278                 return;
16279             }
16280             ns.push(s);
16281         },this);
16282         
16283         this.selections= ns;
16284         this.fireEvent("selectionchange", this, this.selections);
16285     },
16286
16287     /**
16288      * Gets a template node.
16289      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16290      * @return {HTMLElement} The node or null if it wasn't found
16291      */
16292     getNode : function(nodeInfo){
16293         if(typeof nodeInfo == "string"){
16294             return document.getElementById(nodeInfo);
16295         }else if(typeof nodeInfo == "number"){
16296             return this.nodes[nodeInfo];
16297         }
16298         return nodeInfo;
16299     },
16300
16301     /**
16302      * Gets a range template nodes.
16303      * @param {Number} startIndex
16304      * @param {Number} endIndex
16305      * @return {Array} An array of nodes
16306      */
16307     getNodes : function(start, end){
16308         var ns = this.nodes;
16309         start = start || 0;
16310         end = typeof end == "undefined" ? ns.length - 1 : end;
16311         var nodes = [];
16312         if(start <= end){
16313             for(var i = start; i <= end; i++){
16314                 nodes.push(ns[i]);
16315             }
16316         } else{
16317             for(var i = start; i >= end; i--){
16318                 nodes.push(ns[i]);
16319             }
16320         }
16321         return nodes;
16322     },
16323
16324     /**
16325      * Finds the index of the passed node
16326      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16327      * @return {Number} The index of the node or -1
16328      */
16329     indexOf : function(node){
16330         node = this.getNode(node);
16331         if(typeof node.nodeIndex == "number"){
16332             return node.nodeIndex;
16333         }
16334         var ns = this.nodes;
16335         for(var i = 0, len = ns.length; i < len; i++){
16336             if(ns[i] == node){
16337                 return i;
16338             }
16339         }
16340         return -1;
16341     }
16342 });
16343 /*
16344  * - LGPL
16345  *
16346  * based on jquery fullcalendar
16347  * 
16348  */
16349
16350 Roo.bootstrap = Roo.bootstrap || {};
16351 /**
16352  * @class Roo.bootstrap.Calendar
16353  * @extends Roo.bootstrap.Component
16354  * Bootstrap Calendar class
16355  * @cfg {Boolean} loadMask (true|false) default false
16356  * @cfg {Object} header generate the user specific header of the calendar, default false
16357
16358  * @constructor
16359  * Create a new Container
16360  * @param {Object} config The config object
16361  */
16362
16363
16364
16365 Roo.bootstrap.Calendar = function(config){
16366     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16367      this.addEvents({
16368         /**
16369              * @event select
16370              * Fires when a date is selected
16371              * @param {DatePicker} this
16372              * @param {Date} date The selected date
16373              */
16374         'select': true,
16375         /**
16376              * @event monthchange
16377              * Fires when the displayed month changes 
16378              * @param {DatePicker} this
16379              * @param {Date} date The selected month
16380              */
16381         'monthchange': true,
16382         /**
16383              * @event evententer
16384              * Fires when mouse over an event
16385              * @param {Calendar} this
16386              * @param {event} Event
16387              */
16388         'evententer': true,
16389         /**
16390              * @event eventleave
16391              * Fires when the mouse leaves an
16392              * @param {Calendar} this
16393              * @param {event}
16394              */
16395         'eventleave': true,
16396         /**
16397              * @event eventclick
16398              * Fires when the mouse click an
16399              * @param {Calendar} this
16400              * @param {event}
16401              */
16402         'eventclick': true
16403         
16404     });
16405
16406 };
16407
16408 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
16409     
16410      /**
16411      * @cfg {Number} startDay
16412      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16413      */
16414     startDay : 0,
16415     
16416     loadMask : false,
16417     
16418     header : false,
16419       
16420     getAutoCreate : function(){
16421         
16422         
16423         var fc_button = function(name, corner, style, content ) {
16424             return Roo.apply({},{
16425                 tag : 'span',
16426                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
16427                          (corner.length ?
16428                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16429                             ''
16430                         ),
16431                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16432                 unselectable: 'on'
16433             });
16434         };
16435         
16436         var header = {};
16437         
16438         if(!this.header){
16439             header = {
16440                 tag : 'table',
16441                 cls : 'fc-header',
16442                 style : 'width:100%',
16443                 cn : [
16444                     {
16445                         tag: 'tr',
16446                         cn : [
16447                             {
16448                                 tag : 'td',
16449                                 cls : 'fc-header-left',
16450                                 cn : [
16451                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
16452                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
16453                                     { tag: 'span', cls: 'fc-header-space' },
16454                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
16455
16456
16457                                 ]
16458                             },
16459
16460                             {
16461                                 tag : 'td',
16462                                 cls : 'fc-header-center',
16463                                 cn : [
16464                                     {
16465                                         tag: 'span',
16466                                         cls: 'fc-header-title',
16467                                         cn : {
16468                                             tag: 'H2',
16469                                             html : 'month / year'
16470                                         }
16471                                     }
16472
16473                                 ]
16474                             },
16475                             {
16476                                 tag : 'td',
16477                                 cls : 'fc-header-right',
16478                                 cn : [
16479                               /*      fc_button('month', 'left', '', 'month' ),
16480                                     fc_button('week', '', '', 'week' ),
16481                                     fc_button('day', 'right', '', 'day' )
16482                                 */    
16483
16484                                 ]
16485                             }
16486
16487                         ]
16488                     }
16489                 ]
16490             };
16491         }
16492         
16493         header = this.header;
16494         
16495        
16496         var cal_heads = function() {
16497             var ret = [];
16498             // fixme - handle this.
16499             
16500             for (var i =0; i < Date.dayNames.length; i++) {
16501                 var d = Date.dayNames[i];
16502                 ret.push({
16503                     tag: 'th',
16504                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16505                     html : d.substring(0,3)
16506                 });
16507                 
16508             }
16509             ret[0].cls += ' fc-first';
16510             ret[6].cls += ' fc-last';
16511             return ret;
16512         };
16513         var cal_cell = function(n) {
16514             return  {
16515                 tag: 'td',
16516                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16517                 cn : [
16518                     {
16519                         cn : [
16520                             {
16521                                 cls: 'fc-day-number',
16522                                 html: 'D'
16523                             },
16524                             {
16525                                 cls: 'fc-day-content',
16526                              
16527                                 cn : [
16528                                      {
16529                                         style: 'position: relative;' // height: 17px;
16530                                     }
16531                                 ]
16532                             }
16533                             
16534                             
16535                         ]
16536                     }
16537                 ]
16538                 
16539             }
16540         };
16541         var cal_rows = function() {
16542             
16543             var ret = [];
16544             for (var r = 0; r < 6; r++) {
16545                 var row= {
16546                     tag : 'tr',
16547                     cls : 'fc-week',
16548                     cn : []
16549                 };
16550                 
16551                 for (var i =0; i < Date.dayNames.length; i++) {
16552                     var d = Date.dayNames[i];
16553                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16554
16555                 }
16556                 row.cn[0].cls+=' fc-first';
16557                 row.cn[0].cn[0].style = 'min-height:90px';
16558                 row.cn[6].cls+=' fc-last';
16559                 ret.push(row);
16560                 
16561             }
16562             ret[0].cls += ' fc-first';
16563             ret[4].cls += ' fc-prev-last';
16564             ret[5].cls += ' fc-last';
16565             return ret;
16566             
16567         };
16568         
16569         var cal_table = {
16570             tag: 'table',
16571             cls: 'fc-border-separate',
16572             style : 'width:100%',
16573             cellspacing  : 0,
16574             cn : [
16575                 { 
16576                     tag: 'thead',
16577                     cn : [
16578                         { 
16579                             tag: 'tr',
16580                             cls : 'fc-first fc-last',
16581                             cn : cal_heads()
16582                         }
16583                     ]
16584                 },
16585                 { 
16586                     tag: 'tbody',
16587                     cn : cal_rows()
16588                 }
16589                   
16590             ]
16591         };
16592          
16593          var cfg = {
16594             cls : 'fc fc-ltr',
16595             cn : [
16596                 header,
16597                 {
16598                     cls : 'fc-content',
16599                     style : "position: relative;",
16600                     cn : [
16601                         {
16602                             cls : 'fc-view fc-view-month fc-grid',
16603                             style : 'position: relative',
16604                             unselectable : 'on',
16605                             cn : [
16606                                 {
16607                                     cls : 'fc-event-container',
16608                                     style : 'position:absolute;z-index:8;top:0;left:0;'
16609                                 },
16610                                 cal_table
16611                             ]
16612                         }
16613                     ]
16614     
16615                 }
16616            ] 
16617             
16618         };
16619         
16620          
16621         
16622         return cfg;
16623     },
16624     
16625     
16626     initEvents : function()
16627     {
16628         if(!this.store){
16629             throw "can not find store for calendar";
16630         }
16631         
16632         var mark = {
16633             tag: "div",
16634             cls:"x-dlg-mask",
16635             style: "text-align:center",
16636             cn: [
16637                 {
16638                     tag: "div",
16639                     style: "background-color:white;width:50%;margin:250 auto",
16640                     cn: [
16641                         {
16642                             tag: "img",
16643                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
16644                         },
16645                         {
16646                             tag: "span",
16647                             html: "Loading"
16648                         }
16649                         
16650                     ]
16651                 }
16652             ]
16653         };
16654         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16655         
16656         var size = this.el.select('.fc-content', true).first().getSize();
16657         this.maskEl.setSize(size.width, size.height);
16658         this.maskEl.enableDisplayMode("block");
16659         if(!this.loadMask){
16660             this.maskEl.hide();
16661         }
16662         
16663         this.store = Roo.factory(this.store, Roo.data);
16664         this.store.on('load', this.onLoad, this);
16665         this.store.on('beforeload', this.onBeforeLoad, this);
16666         
16667         this.resize();
16668         
16669         this.cells = this.el.select('.fc-day',true);
16670         //Roo.log(this.cells);
16671         this.textNodes = this.el.query('.fc-day-number');
16672         this.cells.addClassOnOver('fc-state-hover');
16673         
16674         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16675         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16676         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16677         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16678         
16679         this.on('monthchange', this.onMonthChange, this);
16680         
16681         this.update(new Date().clearTime());
16682     },
16683     
16684     resize : function() {
16685         var sz  = this.el.getSize();
16686         
16687         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16688         this.el.select('.fc-day-content div',true).setHeight(34);
16689     },
16690     
16691     
16692     // private
16693     showPrevMonth : function(e){
16694         this.update(this.activeDate.add("mo", -1));
16695     },
16696     showToday : function(e){
16697         this.update(new Date().clearTime());
16698     },
16699     // private
16700     showNextMonth : function(e){
16701         this.update(this.activeDate.add("mo", 1));
16702     },
16703
16704     // private
16705     showPrevYear : function(){
16706         this.update(this.activeDate.add("y", -1));
16707     },
16708
16709     // private
16710     showNextYear : function(){
16711         this.update(this.activeDate.add("y", 1));
16712     },
16713
16714     
16715    // private
16716     update : function(date)
16717     {
16718         var vd = this.activeDate;
16719         this.activeDate = date;
16720 //        if(vd && this.el){
16721 //            var t = date.getTime();
16722 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16723 //                Roo.log('using add remove');
16724 //                
16725 //                this.fireEvent('monthchange', this, date);
16726 //                
16727 //                this.cells.removeClass("fc-state-highlight");
16728 //                this.cells.each(function(c){
16729 //                   if(c.dateValue == t){
16730 //                       c.addClass("fc-state-highlight");
16731 //                       setTimeout(function(){
16732 //                            try{c.dom.firstChild.focus();}catch(e){}
16733 //                       }, 50);
16734 //                       return false;
16735 //                   }
16736 //                   return true;
16737 //                });
16738 //                return;
16739 //            }
16740 //        }
16741         
16742         var days = date.getDaysInMonth();
16743         
16744         var firstOfMonth = date.getFirstDateOfMonth();
16745         var startingPos = firstOfMonth.getDay()-this.startDay;
16746         
16747         if(startingPos < this.startDay){
16748             startingPos += 7;
16749         }
16750         
16751         var pm = date.add(Date.MONTH, -1);
16752         var prevStart = pm.getDaysInMonth()-startingPos;
16753 //        
16754         this.cells = this.el.select('.fc-day',true);
16755         this.textNodes = this.el.query('.fc-day-number');
16756         this.cells.addClassOnOver('fc-state-hover');
16757         
16758         var cells = this.cells.elements;
16759         var textEls = this.textNodes;
16760         
16761         Roo.each(cells, function(cell){
16762             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16763         });
16764         
16765         days += startingPos;
16766
16767         // convert everything to numbers so it's fast
16768         var day = 86400000;
16769         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16770         //Roo.log(d);
16771         //Roo.log(pm);
16772         //Roo.log(prevStart);
16773         
16774         var today = new Date().clearTime().getTime();
16775         var sel = date.clearTime().getTime();
16776         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16777         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16778         var ddMatch = this.disabledDatesRE;
16779         var ddText = this.disabledDatesText;
16780         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16781         var ddaysText = this.disabledDaysText;
16782         var format = this.format;
16783         
16784         var setCellClass = function(cal, cell){
16785             cell.row = 0;
16786             cell.events = [];
16787             cell.more = [];
16788             //Roo.log('set Cell Class');
16789             cell.title = "";
16790             var t = d.getTime();
16791             
16792             //Roo.log(d);
16793             
16794             cell.dateValue = t;
16795             if(t == today){
16796                 cell.className += " fc-today";
16797                 cell.className += " fc-state-highlight";
16798                 cell.title = cal.todayText;
16799             }
16800             if(t == sel){
16801                 // disable highlight in other month..
16802                 //cell.className += " fc-state-highlight";
16803                 
16804             }
16805             // disabling
16806             if(t < min) {
16807                 cell.className = " fc-state-disabled";
16808                 cell.title = cal.minText;
16809                 return;
16810             }
16811             if(t > max) {
16812                 cell.className = " fc-state-disabled";
16813                 cell.title = cal.maxText;
16814                 return;
16815             }
16816             if(ddays){
16817                 if(ddays.indexOf(d.getDay()) != -1){
16818                     cell.title = ddaysText;
16819                     cell.className = " fc-state-disabled";
16820                 }
16821             }
16822             if(ddMatch && format){
16823                 var fvalue = d.dateFormat(format);
16824                 if(ddMatch.test(fvalue)){
16825                     cell.title = ddText.replace("%0", fvalue);
16826                     cell.className = " fc-state-disabled";
16827                 }
16828             }
16829             
16830             if (!cell.initialClassName) {
16831                 cell.initialClassName = cell.dom.className;
16832             }
16833             
16834             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
16835         };
16836
16837         var i = 0;
16838         
16839         for(; i < startingPos; i++) {
16840             textEls[i].innerHTML = (++prevStart);
16841             d.setDate(d.getDate()+1);
16842             
16843             cells[i].className = "fc-past fc-other-month";
16844             setCellClass(this, cells[i]);
16845         }
16846         
16847         var intDay = 0;
16848         
16849         for(; i < days; i++){
16850             intDay = i - startingPos + 1;
16851             textEls[i].innerHTML = (intDay);
16852             d.setDate(d.getDate()+1);
16853             
16854             cells[i].className = ''; // "x-date-active";
16855             setCellClass(this, cells[i]);
16856         }
16857         var extraDays = 0;
16858         
16859         for(; i < 42; i++) {
16860             textEls[i].innerHTML = (++extraDays);
16861             d.setDate(d.getDate()+1);
16862             
16863             cells[i].className = "fc-future fc-other-month";
16864             setCellClass(this, cells[i]);
16865         }
16866         
16867         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16868         
16869         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16870         
16871         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16872         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16873         
16874         if(totalRows != 6){
16875             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16876             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16877         }
16878         
16879         this.fireEvent('monthchange', this, date);
16880         
16881         
16882         /*
16883         if(!this.internalRender){
16884             var main = this.el.dom.firstChild;
16885             var w = main.offsetWidth;
16886             this.el.setWidth(w + this.el.getBorderWidth("lr"));
16887             Roo.fly(main).setWidth(w);
16888             this.internalRender = true;
16889             // opera does not respect the auto grow header center column
16890             // then, after it gets a width opera refuses to recalculate
16891             // without a second pass
16892             if(Roo.isOpera && !this.secondPass){
16893                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16894                 this.secondPass = true;
16895                 this.update.defer(10, this, [date]);
16896             }
16897         }
16898         */
16899         
16900     },
16901     
16902     findCell : function(dt) {
16903         dt = dt.clearTime().getTime();
16904         var ret = false;
16905         this.cells.each(function(c){
16906             //Roo.log("check " +c.dateValue + '?=' + dt);
16907             if(c.dateValue == dt){
16908                 ret = c;
16909                 return false;
16910             }
16911             return true;
16912         });
16913         
16914         return ret;
16915     },
16916     
16917     findCells : function(ev) {
16918         var s = ev.start.clone().clearTime().getTime();
16919        // Roo.log(s);
16920         var e= ev.end.clone().clearTime().getTime();
16921        // Roo.log(e);
16922         var ret = [];
16923         this.cells.each(function(c){
16924              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16925             
16926             if(c.dateValue > e){
16927                 return ;
16928             }
16929             if(c.dateValue < s){
16930                 return ;
16931             }
16932             ret.push(c);
16933         });
16934         
16935         return ret;    
16936     },
16937     
16938 //    findBestRow: function(cells)
16939 //    {
16940 //        var ret = 0;
16941 //        
16942 //        for (var i =0 ; i < cells.length;i++) {
16943 //            ret  = Math.max(cells[i].rows || 0,ret);
16944 //        }
16945 //        return ret;
16946 //        
16947 //    },
16948     
16949     
16950     addItem : function(ev)
16951     {
16952         // look for vertical location slot in
16953         var cells = this.findCells(ev);
16954         
16955 //        ev.row = this.findBestRow(cells);
16956         
16957         // work out the location.
16958         
16959         var crow = false;
16960         var rows = [];
16961         for(var i =0; i < cells.length; i++) {
16962             
16963             cells[i].row = cells[0].row;
16964             
16965             if(i == 0){
16966                 cells[i].row = cells[i].row + 1;
16967             }
16968             
16969             if (!crow) {
16970                 crow = {
16971                     start : cells[i],
16972                     end :  cells[i]
16973                 };
16974                 continue;
16975             }
16976             if (crow.start.getY() == cells[i].getY()) {
16977                 // on same row.
16978                 crow.end = cells[i];
16979                 continue;
16980             }
16981             // different row.
16982             rows.push(crow);
16983             crow = {
16984                 start: cells[i],
16985                 end : cells[i]
16986             };
16987             
16988         }
16989         
16990         rows.push(crow);
16991         ev.els = [];
16992         ev.rows = rows;
16993         ev.cells = cells;
16994         
16995         cells[0].events.push(ev);
16996         
16997         this.calevents.push(ev);
16998     },
16999     
17000     clearEvents: function() {
17001         
17002         if(!this.calevents){
17003             return;
17004         }
17005         
17006         Roo.each(this.cells.elements, function(c){
17007             c.row = 0;
17008             c.events = [];
17009             c.more = [];
17010         });
17011         
17012         Roo.each(this.calevents, function(e) {
17013             Roo.each(e.els, function(el) {
17014                 el.un('mouseenter' ,this.onEventEnter, this);
17015                 el.un('mouseleave' ,this.onEventLeave, this);
17016                 el.remove();
17017             },this);
17018         },this);
17019         
17020         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17021             e.remove();
17022         });
17023         
17024     },
17025     
17026     renderEvents: function()
17027     {   
17028         var _this = this;
17029         
17030         this.cells.each(function(c) {
17031             
17032             if(c.row < 5){
17033                 return;
17034             }
17035             
17036             var ev = c.events;
17037             
17038             var r = 4;
17039             if(c.row != c.events.length){
17040                 r = 4 - (4 - (c.row - c.events.length));
17041             }
17042             
17043             c.events = ev.slice(0, r);
17044             c.more = ev.slice(r);
17045             
17046             if(c.more.length && c.more.length == 1){
17047                 c.events.push(c.more.pop());
17048             }
17049             
17050             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17051             
17052         });
17053             
17054         this.cells.each(function(c) {
17055             
17056             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17057             
17058             
17059             for (var e = 0; e < c.events.length; e++){
17060                 var ev = c.events[e];
17061                 var rows = ev.rows;
17062                 
17063                 for(var i = 0; i < rows.length; i++) {
17064                 
17065                     // how many rows should it span..
17066
17067                     var  cfg = {
17068                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17069                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17070
17071                         unselectable : "on",
17072                         cn : [
17073                             {
17074                                 cls: 'fc-event-inner',
17075                                 cn : [
17076     //                                {
17077     //                                  tag:'span',
17078     //                                  cls: 'fc-event-time',
17079     //                                  html : cells.length > 1 ? '' : ev.time
17080     //                                },
17081                                     {
17082                                       tag:'span',
17083                                       cls: 'fc-event-title',
17084                                       html : String.format('{0}', ev.title)
17085                                     }
17086
17087
17088                                 ]
17089                             },
17090                             {
17091                                 cls: 'ui-resizable-handle ui-resizable-e',
17092                                 html : '&nbsp;&nbsp;&nbsp'
17093                             }
17094
17095                         ]
17096                     };
17097
17098                     if (i == 0) {
17099                         cfg.cls += ' fc-event-start';
17100                     }
17101                     if ((i+1) == rows.length) {
17102                         cfg.cls += ' fc-event-end';
17103                     }
17104
17105                     var ctr = _this.el.select('.fc-event-container',true).first();
17106                     var cg = ctr.createChild(cfg);
17107
17108                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17109                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17110
17111                     var r = (c.more.length) ? 1 : 0;
17112                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
17113                     cg.setWidth(ebox.right - sbox.x -2);
17114
17115                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17116                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17117                     cg.on('click', _this.onEventClick, _this, ev);
17118
17119                     ev.els.push(cg);
17120                     
17121                 }
17122                 
17123             }
17124             
17125             
17126             if(c.more.length){
17127                 var  cfg = {
17128                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17129                     style : 'position: absolute',
17130                     unselectable : "on",
17131                     cn : [
17132                         {
17133                             cls: 'fc-event-inner',
17134                             cn : [
17135                                 {
17136                                   tag:'span',
17137                                   cls: 'fc-event-title',
17138                                   html : 'More'
17139                                 }
17140
17141
17142                             ]
17143                         },
17144                         {
17145                             cls: 'ui-resizable-handle ui-resizable-e',
17146                             html : '&nbsp;&nbsp;&nbsp'
17147                         }
17148
17149                     ]
17150                 };
17151
17152                 var ctr = _this.el.select('.fc-event-container',true).first();
17153                 var cg = ctr.createChild(cfg);
17154
17155                 var sbox = c.select('.fc-day-content',true).first().getBox();
17156                 var ebox = c.select('.fc-day-content',true).first().getBox();
17157                 //Roo.log(cg);
17158                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
17159                 cg.setWidth(ebox.right - sbox.x -2);
17160
17161                 cg.on('click', _this.onMoreEventClick, _this, c.more);
17162                 
17163             }
17164             
17165         });
17166         
17167         
17168         
17169     },
17170     
17171     onEventEnter: function (e, el,event,d) {
17172         this.fireEvent('evententer', this, el, event);
17173     },
17174     
17175     onEventLeave: function (e, el,event,d) {
17176         this.fireEvent('eventleave', this, el, event);
17177     },
17178     
17179     onEventClick: function (e, el,event,d) {
17180         this.fireEvent('eventclick', this, el, event);
17181     },
17182     
17183     onMonthChange: function () {
17184         this.store.load();
17185     },
17186     
17187     onMoreEventClick: function(e, el, more)
17188     {
17189         var _this = this;
17190         
17191         this.calpopover.placement = 'right';
17192         this.calpopover.setTitle('More');
17193         
17194         this.calpopover.setContent('');
17195         
17196         var ctr = this.calpopover.el.select('.popover-content', true).first();
17197         
17198         Roo.each(more, function(m){
17199             var cfg = {
17200                 cls : 'fc-event-hori fc-event-draggable',
17201                 html : m.title
17202             };
17203             var cg = ctr.createChild(cfg);
17204             
17205             cg.on('click', _this.onEventClick, _this, m);
17206         });
17207         
17208         this.calpopover.show(el);
17209         
17210         
17211     },
17212     
17213     onLoad: function () 
17214     {   
17215         this.calevents = [];
17216         var cal = this;
17217         
17218         if(this.store.getCount() > 0){
17219             this.store.data.each(function(d){
17220                cal.addItem({
17221                     id : d.data.id,
17222                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17223                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17224                     time : d.data.start_time,
17225                     title : d.data.title,
17226                     description : d.data.description,
17227                     venue : d.data.venue
17228                 });
17229             });
17230         }
17231         
17232         this.renderEvents();
17233         
17234         if(this.calevents.length && this.loadMask){
17235             this.maskEl.hide();
17236         }
17237     },
17238     
17239     onBeforeLoad: function()
17240     {
17241         this.clearEvents();
17242         if(this.loadMask){
17243             this.maskEl.show();
17244         }
17245     }
17246 });
17247
17248  
17249  /*
17250  * - LGPL
17251  *
17252  * element
17253  * 
17254  */
17255
17256 /**
17257  * @class Roo.bootstrap.Popover
17258  * @extends Roo.bootstrap.Component
17259  * Bootstrap Popover class
17260  * @cfg {String} html contents of the popover   (or false to use children..)
17261  * @cfg {String} title of popover (or false to hide)
17262  * @cfg {String} placement how it is placed
17263  * @cfg {String} trigger click || hover (or false to trigger manually)
17264  * @cfg {String} over what (parent or false to trigger manually.)
17265  * @cfg {Number} delay - delay before showing
17266  
17267  * @constructor
17268  * Create a new Popover
17269  * @param {Object} config The config object
17270  */
17271
17272 Roo.bootstrap.Popover = function(config){
17273     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17274     
17275     this.addEvents({
17276         // raw events
17277          /**
17278          * @event show
17279          * After the popover show
17280          * 
17281          * @param {Roo.bootstrap.Popover} this
17282          */
17283         "show" : true,
17284         /**
17285          * @event hide
17286          * After the popover hide
17287          * 
17288          * @param {Roo.bootstrap.Popover} this
17289          */
17290         "hide" : true
17291     });
17292 };
17293
17294 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
17295     
17296     title: 'Fill in a title',
17297     html: false,
17298     
17299     placement : 'right',
17300     trigger : 'hover', // hover
17301     
17302     delay : 0,
17303     
17304     over: 'parent',
17305     
17306     can_build_overlaid : false,
17307     
17308     getChildContainer : function()
17309     {
17310         return this.el.select('.popover-content',true).first();
17311     },
17312     
17313     getAutoCreate : function(){
17314          
17315         var cfg = {
17316            cls : 'popover roo-dynamic',
17317            style: 'display:block',
17318            cn : [
17319                 {
17320                     cls : 'arrow'
17321                 },
17322                 {
17323                     cls : 'popover-inner',
17324                     cn : [
17325                         {
17326                             tag: 'h3',
17327                             cls: 'popover-title',
17328                             html : this.title
17329                         },
17330                         {
17331                             cls : 'popover-content',
17332                             html : this.html
17333                         }
17334                     ]
17335                     
17336                 }
17337            ]
17338         };
17339         
17340         return cfg;
17341     },
17342     setTitle: function(str)
17343     {
17344         this.title = str;
17345         this.el.select('.popover-title',true).first().dom.innerHTML = str;
17346     },
17347     setContent: function(str)
17348     {
17349         this.html = str;
17350         this.el.select('.popover-content',true).first().dom.innerHTML = str;
17351     },
17352     // as it get's added to the bottom of the page.
17353     onRender : function(ct, position)
17354     {
17355         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17356         if(!this.el){
17357             var cfg = Roo.apply({},  this.getAutoCreate());
17358             cfg.id = Roo.id();
17359             
17360             if (this.cls) {
17361                 cfg.cls += ' ' + this.cls;
17362             }
17363             if (this.style) {
17364                 cfg.style = this.style;
17365             }
17366             //Roo.log("adding to ");
17367             this.el = Roo.get(document.body).createChild(cfg, position);
17368 //            Roo.log(this.el);
17369         }
17370         this.initEvents();
17371     },
17372     
17373     initEvents : function()
17374     {
17375         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17376         this.el.enableDisplayMode('block');
17377         this.el.hide();
17378         if (this.over === false) {
17379             return; 
17380         }
17381         if (this.triggers === false) {
17382             return;
17383         }
17384         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17385         var triggers = this.trigger ? this.trigger.split(' ') : [];
17386         Roo.each(triggers, function(trigger) {
17387         
17388             if (trigger == 'click') {
17389                 on_el.on('click', this.toggle, this);
17390             } else if (trigger != 'manual') {
17391                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
17392                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17393       
17394                 on_el.on(eventIn  ,this.enter, this);
17395                 on_el.on(eventOut, this.leave, this);
17396             }
17397         }, this);
17398         
17399     },
17400     
17401     
17402     // private
17403     timeout : null,
17404     hoverState : null,
17405     
17406     toggle : function () {
17407         this.hoverState == 'in' ? this.leave() : this.enter();
17408     },
17409     
17410     enter : function () {
17411         
17412         clearTimeout(this.timeout);
17413     
17414         this.hoverState = 'in';
17415     
17416         if (!this.delay || !this.delay.show) {
17417             this.show();
17418             return;
17419         }
17420         var _t = this;
17421         this.timeout = setTimeout(function () {
17422             if (_t.hoverState == 'in') {
17423                 _t.show();
17424             }
17425         }, this.delay.show)
17426     },
17427     
17428     leave : function() {
17429         clearTimeout(this.timeout);
17430     
17431         this.hoverState = 'out';
17432     
17433         if (!this.delay || !this.delay.hide) {
17434             this.hide();
17435             return;
17436         }
17437         var _t = this;
17438         this.timeout = setTimeout(function () {
17439             if (_t.hoverState == 'out') {
17440                 _t.hide();
17441             }
17442         }, this.delay.hide)
17443     },
17444     
17445     show : function (on_el)
17446     {
17447         if (!on_el) {
17448             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17449         }
17450         
17451         // set content.
17452         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17453         if (this.html !== false) {
17454             this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17455         }
17456         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17457         if (!this.title.length) {
17458             this.el.select('.popover-title',true).hide();
17459         }
17460         
17461         var placement = typeof this.placement == 'function' ?
17462             this.placement.call(this, this.el, on_el) :
17463             this.placement;
17464             
17465         var autoToken = /\s?auto?\s?/i;
17466         var autoPlace = autoToken.test(placement);
17467         if (autoPlace) {
17468             placement = placement.replace(autoToken, '') || 'top';
17469         }
17470         
17471         //this.el.detach()
17472         //this.el.setXY([0,0]);
17473         this.el.show();
17474         this.el.dom.style.display='block';
17475         this.el.addClass(placement);
17476         
17477         //this.el.appendTo(on_el);
17478         
17479         var p = this.getPosition();
17480         var box = this.el.getBox();
17481         
17482         if (autoPlace) {
17483             // fixme..
17484         }
17485         var align = Roo.bootstrap.Popover.alignment[placement];
17486         
17487 //        Roo.log(align);
17488         this.el.alignTo(on_el, align[0],align[1]);
17489         //var arrow = this.el.select('.arrow',true).first();
17490         //arrow.set(align[2], 
17491         
17492         this.el.addClass('in');
17493         
17494         
17495         if (this.el.hasClass('fade')) {
17496             // fade it?
17497         }
17498         
17499         this.hoverState = 'in';
17500         
17501         this.fireEvent('show', this);
17502         
17503     },
17504     hide : function()
17505     {
17506         this.el.setXY([0,0]);
17507         this.el.removeClass('in');
17508         this.el.hide();
17509         this.hoverState = null;
17510         
17511         this.fireEvent('hide', this);
17512     }
17513     
17514 });
17515
17516 Roo.bootstrap.Popover.alignment = {
17517     'left' : ['r-l', [-10,0], 'right'],
17518     'right' : ['l-r', [10,0], 'left'],
17519     'bottom' : ['t-b', [0,10], 'top'],
17520     'top' : [ 'b-t', [0,-10], 'bottom']
17521 };
17522
17523  /*
17524  * - LGPL
17525  *
17526  * Progress
17527  * 
17528  */
17529
17530 /**
17531  * @class Roo.bootstrap.Progress
17532  * @extends Roo.bootstrap.Component
17533  * Bootstrap Progress class
17534  * @cfg {Boolean} striped striped of the progress bar
17535  * @cfg {Boolean} active animated of the progress bar
17536  * 
17537  * 
17538  * @constructor
17539  * Create a new Progress
17540  * @param {Object} config The config object
17541  */
17542
17543 Roo.bootstrap.Progress = function(config){
17544     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17545 };
17546
17547 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
17548     
17549     striped : false,
17550     active: false,
17551     
17552     getAutoCreate : function(){
17553         var cfg = {
17554             tag: 'div',
17555             cls: 'progress'
17556         };
17557         
17558         
17559         if(this.striped){
17560             cfg.cls += ' progress-striped';
17561         }
17562       
17563         if(this.active){
17564             cfg.cls += ' active';
17565         }
17566         
17567         
17568         return cfg;
17569     }
17570    
17571 });
17572
17573  
17574
17575  /*
17576  * - LGPL
17577  *
17578  * ProgressBar
17579  * 
17580  */
17581
17582 /**
17583  * @class Roo.bootstrap.ProgressBar
17584  * @extends Roo.bootstrap.Component
17585  * Bootstrap ProgressBar class
17586  * @cfg {Number} aria_valuenow aria-value now
17587  * @cfg {Number} aria_valuemin aria-value min
17588  * @cfg {Number} aria_valuemax aria-value max
17589  * @cfg {String} label label for the progress bar
17590  * @cfg {String} panel (success | info | warning | danger )
17591  * @cfg {String} role role of the progress bar
17592  * @cfg {String} sr_only text
17593  * 
17594  * 
17595  * @constructor
17596  * Create a new ProgressBar
17597  * @param {Object} config The config object
17598  */
17599
17600 Roo.bootstrap.ProgressBar = function(config){
17601     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17602 };
17603
17604 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
17605     
17606     aria_valuenow : 0,
17607     aria_valuemin : 0,
17608     aria_valuemax : 100,
17609     label : false,
17610     panel : false,
17611     role : false,
17612     sr_only: false,
17613     
17614     getAutoCreate : function()
17615     {
17616         
17617         var cfg = {
17618             tag: 'div',
17619             cls: 'progress-bar',
17620             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17621         };
17622         
17623         if(this.sr_only){
17624             cfg.cn = {
17625                 tag: 'span',
17626                 cls: 'sr-only',
17627                 html: this.sr_only
17628             }
17629         }
17630         
17631         if(this.role){
17632             cfg.role = this.role;
17633         }
17634         
17635         if(this.aria_valuenow){
17636             cfg['aria-valuenow'] = this.aria_valuenow;
17637         }
17638         
17639         if(this.aria_valuemin){
17640             cfg['aria-valuemin'] = this.aria_valuemin;
17641         }
17642         
17643         if(this.aria_valuemax){
17644             cfg['aria-valuemax'] = this.aria_valuemax;
17645         }
17646         
17647         if(this.label && !this.sr_only){
17648             cfg.html = this.label;
17649         }
17650         
17651         if(this.panel){
17652             cfg.cls += ' progress-bar-' + this.panel;
17653         }
17654         
17655         return cfg;
17656     },
17657     
17658     update : function(aria_valuenow)
17659     {
17660         this.aria_valuenow = aria_valuenow;
17661         
17662         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17663     }
17664    
17665 });
17666
17667  
17668
17669  /*
17670  * - LGPL
17671  *
17672  * column
17673  * 
17674  */
17675
17676 /**
17677  * @class Roo.bootstrap.TabGroup
17678  * @extends Roo.bootstrap.Column
17679  * Bootstrap Column class
17680  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17681  * @cfg {Boolean} carousel true to make the group behave like a carousel
17682  * @cfg {Boolean} bullets show bullets for the panels
17683  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17684  * @cfg {Number} timer auto slide timer .. default 0 millisecond
17685  * @cfg {Boolean} showarrow (true|false) show arrow default true
17686  * 
17687  * @constructor
17688  * Create a new TabGroup
17689  * @param {Object} config The config object
17690  */
17691
17692 Roo.bootstrap.TabGroup = function(config){
17693     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17694     if (!this.navId) {
17695         this.navId = Roo.id();
17696     }
17697     this.tabs = [];
17698     Roo.bootstrap.TabGroup.register(this);
17699     
17700 };
17701
17702 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
17703     
17704     carousel : false,
17705     transition : false,
17706     bullets : 0,
17707     timer : 0,
17708     autoslide : false,
17709     slideFn : false,
17710     slideOnTouch : false,
17711     showarrow : true,
17712     
17713     getAutoCreate : function()
17714     {
17715         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17716         
17717         cfg.cls += ' tab-content';
17718         
17719         if (this.carousel) {
17720             cfg.cls += ' carousel slide';
17721             
17722             cfg.cn = [{
17723                cls : 'carousel-inner',
17724                cn : []
17725             }];
17726         
17727             if(this.bullets  && !Roo.isTouch){
17728                 
17729                 var bullets = {
17730                     cls : 'carousel-bullets',
17731                     cn : []
17732                 };
17733                
17734                 if(this.bullets_cls){
17735                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17736                 }
17737                 
17738                 bullets.cn.push({
17739                     cls : 'clear'
17740                 });
17741                 
17742                 cfg.cn[0].cn.push(bullets);
17743             }
17744             
17745             if(this.showarrow){
17746                 cfg.cn[0].cn.push({
17747                     tag : 'div',
17748                     class : 'carousel-arrow',
17749                     cn : [
17750                         {
17751                             tag : 'div',
17752                             class : 'carousel-prev',
17753                             cn : [
17754                                 {
17755                                     tag : 'i',
17756                                     class : 'fa fa-chevron-left'
17757                                 }
17758                             ]
17759                         },
17760                         {
17761                             tag : 'div',
17762                             class : 'carousel-next',
17763                             cn : [
17764                                 {
17765                                     tag : 'i',
17766                                     class : 'fa fa-chevron-right'
17767                                 }
17768                             ]
17769                         }
17770                     ]
17771                 });
17772             }
17773             
17774         }
17775         
17776         return cfg;
17777     },
17778     
17779     initEvents:  function()
17780     {
17781 //        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17782 //            this.el.on("touchstart", this.onTouchStart, this);
17783 //        }
17784         
17785         if(this.autoslide){
17786             var _this = this;
17787             
17788             this.slideFn = window.setInterval(function() {
17789                 _this.showPanelNext();
17790             }, this.timer);
17791         }
17792         
17793         if(this.showarrow){
17794             this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17795             this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17796         }
17797         
17798         
17799     },
17800     
17801 //    onTouchStart : function(e, el, o)
17802 //    {
17803 //        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17804 //            return;
17805 //        }
17806 //        
17807 //        this.showPanelNext();
17808 //    },
17809     
17810     
17811     getChildContainer : function()
17812     {
17813         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17814     },
17815     
17816     /**
17817     * register a Navigation item
17818     * @param {Roo.bootstrap.NavItem} the navitem to add
17819     */
17820     register : function(item)
17821     {
17822         this.tabs.push( item);
17823         item.navId = this.navId; // not really needed..
17824         this.addBullet();
17825     
17826     },
17827     
17828     getActivePanel : function()
17829     {
17830         var r = false;
17831         Roo.each(this.tabs, function(t) {
17832             if (t.active) {
17833                 r = t;
17834                 return false;
17835             }
17836             return null;
17837         });
17838         return r;
17839         
17840     },
17841     getPanelByName : function(n)
17842     {
17843         var r = false;
17844         Roo.each(this.tabs, function(t) {
17845             if (t.tabId == n) {
17846                 r = t;
17847                 return false;
17848             }
17849             return null;
17850         });
17851         return r;
17852     },
17853     indexOfPanel : function(p)
17854     {
17855         var r = false;
17856         Roo.each(this.tabs, function(t,i) {
17857             if (t.tabId == p.tabId) {
17858                 r = i;
17859                 return false;
17860             }
17861             return null;
17862         });
17863         return r;
17864     },
17865     /**
17866      * show a specific panel
17867      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17868      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17869      */
17870     showPanel : function (pan)
17871     {
17872         if(this.transition || typeof(pan) == 'undefined'){
17873             Roo.log("waiting for the transitionend");
17874             return;
17875         }
17876         
17877         if (typeof(pan) == 'number') {
17878             pan = this.tabs[pan];
17879         }
17880         
17881         if (typeof(pan) == 'string') {
17882             pan = this.getPanelByName(pan);
17883         }
17884         
17885         var cur = this.getActivePanel();
17886         
17887         if(!pan || !cur){
17888             Roo.log('pan or acitve pan is undefined');
17889             return false;
17890         }
17891         
17892         if (pan.tabId == this.getActivePanel().tabId) {
17893             return true;
17894         }
17895         
17896         if (false === cur.fireEvent('beforedeactivate')) {
17897             return false;
17898         }
17899         
17900         if(this.bullets > 0 && !Roo.isTouch){
17901             this.setActiveBullet(this.indexOfPanel(pan));
17902         }
17903         
17904         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17905             
17906             this.transition = true;
17907             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
17908             var lr = dir == 'next' ? 'left' : 'right';
17909             pan.el.addClass(dir); // or prev
17910             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17911             cur.el.addClass(lr); // or right
17912             pan.el.addClass(lr);
17913             
17914             var _this = this;
17915             cur.el.on('transitionend', function() {
17916                 Roo.log("trans end?");
17917                 
17918                 pan.el.removeClass([lr,dir]);
17919                 pan.setActive(true);
17920                 
17921                 cur.el.removeClass([lr]);
17922                 cur.setActive(false);
17923                 
17924                 _this.transition = false;
17925                 
17926             }, this, { single:  true } );
17927             
17928             return true;
17929         }
17930         
17931         cur.setActive(false);
17932         pan.setActive(true);
17933         
17934         return true;
17935         
17936     },
17937     showPanelNext : function()
17938     {
17939         var i = this.indexOfPanel(this.getActivePanel());
17940         
17941         if (i >= this.tabs.length - 1 && !this.autoslide) {
17942             return;
17943         }
17944         
17945         if (i >= this.tabs.length - 1 && this.autoslide) {
17946             i = -1;
17947         }
17948         
17949         this.showPanel(this.tabs[i+1]);
17950     },
17951     
17952     showPanelPrev : function()
17953     {
17954         var i = this.indexOfPanel(this.getActivePanel());
17955         
17956         if (i  < 1 && !this.autoslide) {
17957             return;
17958         }
17959         
17960         if (i < 1 && this.autoslide) {
17961             i = this.tabs.length;
17962         }
17963         
17964         this.showPanel(this.tabs[i-1]);
17965     },
17966     
17967     
17968     addBullet: function()
17969     {
17970         if(!this.bullets || Roo.isTouch){
17971             return;
17972         }
17973         var ctr = this.el.select('.carousel-bullets',true).first();
17974         var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17975         var bullet = ctr.createChild({
17976             cls : 'bullet bullet-' + i
17977         },ctr.dom.lastChild);
17978         
17979         
17980         var _this = this;
17981         
17982         bullet.on('click', (function(e, el, o, ii, t){
17983
17984             e.preventDefault();
17985
17986             this.showPanel(ii);
17987
17988             if(this.autoslide && this.slideFn){
17989                 clearInterval(this.slideFn);
17990                 this.slideFn = window.setInterval(function() {
17991                     _this.showPanelNext();
17992                 }, this.timer);
17993             }
17994
17995         }).createDelegate(this, [i, bullet], true));
17996                 
17997         
17998     },
17999      
18000     setActiveBullet : function(i)
18001     {
18002         if(Roo.isTouch){
18003             return;
18004         }
18005         
18006         Roo.each(this.el.select('.bullet', true).elements, function(el){
18007             el.removeClass('selected');
18008         });
18009
18010         var bullet = this.el.select('.bullet-' + i, true).first();
18011         
18012         if(!bullet){
18013             return;
18014         }
18015         
18016         bullet.addClass('selected');
18017     }
18018     
18019     
18020   
18021 });
18022
18023  
18024
18025  
18026  
18027 Roo.apply(Roo.bootstrap.TabGroup, {
18028     
18029     groups: {},
18030      /**
18031     * register a Navigation Group
18032     * @param {Roo.bootstrap.NavGroup} the navgroup to add
18033     */
18034     register : function(navgrp)
18035     {
18036         this.groups[navgrp.navId] = navgrp;
18037         
18038     },
18039     /**
18040     * fetch a Navigation Group based on the navigation ID
18041     * if one does not exist , it will get created.
18042     * @param {string} the navgroup to add
18043     * @returns {Roo.bootstrap.NavGroup} the navgroup 
18044     */
18045     get: function(navId) {
18046         if (typeof(this.groups[navId]) == 'undefined') {
18047             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18048         }
18049         return this.groups[navId] ;
18050     }
18051     
18052     
18053     
18054 });
18055
18056  /*
18057  * - LGPL
18058  *
18059  * TabPanel
18060  * 
18061  */
18062
18063 /**
18064  * @class Roo.bootstrap.TabPanel
18065  * @extends Roo.bootstrap.Component
18066  * Bootstrap TabPanel class
18067  * @cfg {Boolean} active panel active
18068  * @cfg {String} html panel content
18069  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18070  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18071  * @cfg {String} href click to link..
18072  * 
18073  * 
18074  * @constructor
18075  * Create a new TabPanel
18076  * @param {Object} config The config object
18077  */
18078
18079 Roo.bootstrap.TabPanel = function(config){
18080     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18081     this.addEvents({
18082         /**
18083              * @event changed
18084              * Fires when the active status changes
18085              * @param {Roo.bootstrap.TabPanel} this
18086              * @param {Boolean} state the new state
18087             
18088          */
18089         'changed': true,
18090         /**
18091              * @event beforedeactivate
18092              * Fires before a tab is de-activated - can be used to do validation on a form.
18093              * @param {Roo.bootstrap.TabPanel} this
18094              * @return {Boolean} false if there is an error
18095             
18096          */
18097         'beforedeactivate': true
18098      });
18099     
18100     this.tabId = this.tabId || Roo.id();
18101   
18102 };
18103
18104 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
18105     
18106     active: false,
18107     html: false,
18108     tabId: false,
18109     navId : false,
18110     href : '',
18111     
18112     getAutoCreate : function(){
18113         var cfg = {
18114             tag: 'div',
18115             // item is needed for carousel - not sure if it has any effect otherwise
18116             cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18117             html: this.html || ''
18118         };
18119         
18120         if(this.active){
18121             cfg.cls += ' active';
18122         }
18123         
18124         if(this.tabId){
18125             cfg.tabId = this.tabId;
18126         }
18127         
18128         
18129         return cfg;
18130     },
18131     
18132     initEvents:  function()
18133     {
18134         var p = this.parent();
18135         
18136         this.navId = this.navId || p.navId;
18137         
18138         if (typeof(this.navId) != 'undefined') {
18139             // not really needed.. but just in case.. parent should be a NavGroup.
18140             var tg = Roo.bootstrap.TabGroup.get(this.navId);
18141             
18142             tg.register(this);
18143             
18144             var i = tg.tabs.length - 1;
18145             
18146             if(this.active && tg.bullets > 0 && i < tg.bullets){
18147                 tg.setActiveBullet(i);
18148             }
18149         }
18150         
18151         this.el.on('click', this.onClick, this);
18152         
18153         if(Roo.isTouch){
18154             this.el.on("touchstart", this.onTouchStart, this);
18155             this.el.on("touchmove", this.onTouchMove, this);
18156             this.el.on("touchend", this.onTouchEnd, this);
18157         }
18158         
18159     },
18160     
18161     onRender : function(ct, position)
18162     {
18163         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18164     },
18165     
18166     setActive : function(state)
18167     {
18168         Roo.log("panel - set active " + this.tabId + "=" + state);
18169         
18170         this.active = state;
18171         if (!state) {
18172             this.el.removeClass('active');
18173             
18174         } else  if (!this.el.hasClass('active')) {
18175             this.el.addClass('active');
18176         }
18177         
18178         this.fireEvent('changed', this, state);
18179     },
18180     
18181     onClick : function(e)
18182     {
18183         e.preventDefault();
18184         
18185         if(!this.href.length){
18186             return;
18187         }
18188         
18189         window.location.href = this.href;
18190     },
18191     
18192     startX : 0,
18193     startY : 0,
18194     endX : 0,
18195     endY : 0,
18196     swiping : false,
18197     
18198     onTouchStart : function(e)
18199     {
18200         this.swiping = false;
18201         
18202         this.startX = e.browserEvent.touches[0].clientX;
18203         this.startY = e.browserEvent.touches[0].clientY;
18204     },
18205     
18206     onTouchMove : function(e)
18207     {
18208         this.swiping = true;
18209         
18210         this.endX = e.browserEvent.touches[0].clientX;
18211         this.endY = e.browserEvent.touches[0].clientY;
18212     },
18213     
18214     onTouchEnd : function(e)
18215     {
18216         if(!this.swiping){
18217             this.onClick(e);
18218             return;
18219         }
18220         
18221         var tabGroup = this.parent();
18222         
18223         if(this.endX > this.startX){ // swiping right
18224             tabGroup.showPanelPrev();
18225             return;
18226         }
18227         
18228         if(this.startX > this.endX){ // swiping left
18229             tabGroup.showPanelNext();
18230             return;
18231         }
18232     }
18233     
18234     
18235 });
18236  
18237
18238  
18239
18240  /*
18241  * - LGPL
18242  *
18243  * DateField
18244  * 
18245  */
18246
18247 /**
18248  * @class Roo.bootstrap.DateField
18249  * @extends Roo.bootstrap.Input
18250  * Bootstrap DateField class
18251  * @cfg {Number} weekStart default 0
18252  * @cfg {String} viewMode default empty, (months|years)
18253  * @cfg {String} minViewMode default empty, (months|years)
18254  * @cfg {Number} startDate default -Infinity
18255  * @cfg {Number} endDate default Infinity
18256  * @cfg {Boolean} todayHighlight default false
18257  * @cfg {Boolean} todayBtn default false
18258  * @cfg {Boolean} calendarWeeks default false
18259  * @cfg {Object} daysOfWeekDisabled default empty
18260  * @cfg {Boolean} singleMode default false (true | false)
18261  * 
18262  * @cfg {Boolean} keyboardNavigation default true
18263  * @cfg {String} language default en
18264  * 
18265  * @constructor
18266  * Create a new DateField
18267  * @param {Object} config The config object
18268  */
18269
18270 Roo.bootstrap.DateField = function(config){
18271     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18272      this.addEvents({
18273             /**
18274              * @event show
18275              * Fires when this field show.
18276              * @param {Roo.bootstrap.DateField} this
18277              * @param {Mixed} date The date value
18278              */
18279             show : true,
18280             /**
18281              * @event show
18282              * Fires when this field hide.
18283              * @param {Roo.bootstrap.DateField} this
18284              * @param {Mixed} date The date value
18285              */
18286             hide : true,
18287             /**
18288              * @event select
18289              * Fires when select a date.
18290              * @param {Roo.bootstrap.DateField} this
18291              * @param {Mixed} date The date value
18292              */
18293             select : true,
18294             /**
18295              * @event beforeselect
18296              * Fires when before select a date.
18297              * @param {Roo.bootstrap.DateField} this
18298              * @param {Mixed} date The date value
18299              */
18300             beforeselect : true
18301         });
18302 };
18303
18304 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
18305     
18306     /**
18307      * @cfg {String} format
18308      * The default date format string which can be overriden for localization support.  The format must be
18309      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18310      */
18311     format : "m/d/y",
18312     /**
18313      * @cfg {String} altFormats
18314      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18315      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18316      */
18317     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18318     
18319     weekStart : 0,
18320     
18321     viewMode : '',
18322     
18323     minViewMode : '',
18324     
18325     todayHighlight : false,
18326     
18327     todayBtn: false,
18328     
18329     language: 'en',
18330     
18331     keyboardNavigation: true,
18332     
18333     calendarWeeks: false,
18334     
18335     startDate: -Infinity,
18336     
18337     endDate: Infinity,
18338     
18339     daysOfWeekDisabled: [],
18340     
18341     _events: [],
18342     
18343     singleMode : false,
18344     
18345     UTCDate: function()
18346     {
18347         return new Date(Date.UTC.apply(Date, arguments));
18348     },
18349     
18350     UTCToday: function()
18351     {
18352         var today = new Date();
18353         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18354     },
18355     
18356     getDate: function() {
18357             var d = this.getUTCDate();
18358             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18359     },
18360     
18361     getUTCDate: function() {
18362             return this.date;
18363     },
18364     
18365     setDate: function(d) {
18366             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18367     },
18368     
18369     setUTCDate: function(d) {
18370             this.date = d;
18371             this.setValue(this.formatDate(this.date));
18372     },
18373         
18374     onRender: function(ct, position)
18375     {
18376         
18377         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18378         
18379         this.language = this.language || 'en';
18380         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18381         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18382         
18383         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18384         this.format = this.format || 'm/d/y';
18385         this.isInline = false;
18386         this.isInput = true;
18387         this.component = this.el.select('.add-on', true).first() || false;
18388         this.component = (this.component && this.component.length === 0) ? false : this.component;
18389         this.hasInput = this.component && this.inputEl().length;
18390         
18391         if (typeof(this.minViewMode === 'string')) {
18392             switch (this.minViewMode) {
18393                 case 'months':
18394                     this.minViewMode = 1;
18395                     break;
18396                 case 'years':
18397                     this.minViewMode = 2;
18398                     break;
18399                 default:
18400                     this.minViewMode = 0;
18401                     break;
18402             }
18403         }
18404         
18405         if (typeof(this.viewMode === 'string')) {
18406             switch (this.viewMode) {
18407                 case 'months':
18408                     this.viewMode = 1;
18409                     break;
18410                 case 'years':
18411                     this.viewMode = 2;
18412                     break;
18413                 default:
18414                     this.viewMode = 0;
18415                     break;
18416             }
18417         }
18418                 
18419         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18420         
18421 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18422         
18423         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18424         
18425         this.picker().on('mousedown', this.onMousedown, this);
18426         this.picker().on('click', this.onClick, this);
18427         
18428         this.picker().addClass('datepicker-dropdown');
18429         
18430         this.startViewMode = this.viewMode;
18431         
18432         if(this.singleMode){
18433             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18434                 v.setVisibilityMode(Roo.Element.DISPLAY);
18435                 v.hide();
18436             });
18437             
18438             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18439                 v.setStyle('width', '189px');
18440             });
18441         }
18442         
18443         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18444             if(!this.calendarWeeks){
18445                 v.remove();
18446                 return;
18447             }
18448             
18449             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18450             v.attr('colspan', function(i, val){
18451                 return parseInt(val) + 1;
18452             });
18453         });
18454                         
18455         
18456         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18457         
18458         this.setStartDate(this.startDate);
18459         this.setEndDate(this.endDate);
18460         
18461         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18462         
18463         this.fillDow();
18464         this.fillMonths();
18465         this.update();
18466         this.showMode();
18467         
18468         if(this.isInline) {
18469             this.show();
18470         }
18471     },
18472     
18473     picker : function()
18474     {
18475         return this.pickerEl;
18476 //        return this.el.select('.datepicker', true).first();
18477     },
18478     
18479     fillDow: function()
18480     {
18481         var dowCnt = this.weekStart;
18482         
18483         var dow = {
18484             tag: 'tr',
18485             cn: [
18486                 
18487             ]
18488         };
18489         
18490         if(this.calendarWeeks){
18491             dow.cn.push({
18492                 tag: 'th',
18493                 cls: 'cw',
18494                 html: '&nbsp;'
18495             })
18496         }
18497         
18498         while (dowCnt < this.weekStart + 7) {
18499             dow.cn.push({
18500                 tag: 'th',
18501                 cls: 'dow',
18502                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18503             });
18504         }
18505         
18506         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18507     },
18508     
18509     fillMonths: function()
18510     {    
18511         var i = 0;
18512         var months = this.picker().select('>.datepicker-months td', true).first();
18513         
18514         months.dom.innerHTML = '';
18515         
18516         while (i < 12) {
18517             var month = {
18518                 tag: 'span',
18519                 cls: 'month',
18520                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18521             };
18522             
18523             months.createChild(month);
18524         }
18525         
18526     },
18527     
18528     update: function()
18529     {
18530         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;
18531         
18532         if (this.date < this.startDate) {
18533             this.viewDate = new Date(this.startDate);
18534         } else if (this.date > this.endDate) {
18535             this.viewDate = new Date(this.endDate);
18536         } else {
18537             this.viewDate = new Date(this.date);
18538         }
18539         
18540         this.fill();
18541     },
18542     
18543     fill: function() 
18544     {
18545         var d = new Date(this.viewDate),
18546                 year = d.getUTCFullYear(),
18547                 month = d.getUTCMonth(),
18548                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18549                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18550                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18551                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18552                 currentDate = this.date && this.date.valueOf(),
18553                 today = this.UTCToday();
18554         
18555         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18556         
18557 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18558         
18559 //        this.picker.select('>tfoot th.today').
18560 //                                              .text(dates[this.language].today)
18561 //                                              .toggle(this.todayBtn !== false);
18562     
18563         this.updateNavArrows();
18564         this.fillMonths();
18565                                                 
18566         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18567         
18568         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18569          
18570         prevMonth.setUTCDate(day);
18571         
18572         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18573         
18574         var nextMonth = new Date(prevMonth);
18575         
18576         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18577         
18578         nextMonth = nextMonth.valueOf();
18579         
18580         var fillMonths = false;
18581         
18582         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18583         
18584         while(prevMonth.valueOf() < nextMonth) {
18585             var clsName = '';
18586             
18587             if (prevMonth.getUTCDay() === this.weekStart) {
18588                 if(fillMonths){
18589                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18590                 }
18591                     
18592                 fillMonths = {
18593                     tag: 'tr',
18594                     cn: []
18595                 };
18596                 
18597                 if(this.calendarWeeks){
18598                     // ISO 8601: First week contains first thursday.
18599                     // ISO also states week starts on Monday, but we can be more abstract here.
18600                     var
18601                     // Start of current week: based on weekstart/current date
18602                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18603                     // Thursday of this week
18604                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18605                     // First Thursday of year, year from thursday
18606                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18607                     // Calendar week: ms between thursdays, div ms per day, div 7 days
18608                     calWeek =  (th - yth) / 864e5 / 7 + 1;
18609                     
18610                     fillMonths.cn.push({
18611                         tag: 'td',
18612                         cls: 'cw',
18613                         html: calWeek
18614                     });
18615                 }
18616             }
18617             
18618             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18619                 clsName += ' old';
18620             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18621                 clsName += ' new';
18622             }
18623             if (this.todayHighlight &&
18624                 prevMonth.getUTCFullYear() == today.getFullYear() &&
18625                 prevMonth.getUTCMonth() == today.getMonth() &&
18626                 prevMonth.getUTCDate() == today.getDate()) {
18627                 clsName += ' today';
18628             }
18629             
18630             if (currentDate && prevMonth.valueOf() === currentDate) {
18631                 clsName += ' active';
18632             }
18633             
18634             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18635                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18636                     clsName += ' disabled';
18637             }
18638             
18639             fillMonths.cn.push({
18640                 tag: 'td',
18641                 cls: 'day ' + clsName,
18642                 html: prevMonth.getDate()
18643             });
18644             
18645             prevMonth.setDate(prevMonth.getDate()+1);
18646         }
18647           
18648         var currentYear = this.date && this.date.getUTCFullYear();
18649         var currentMonth = this.date && this.date.getUTCMonth();
18650         
18651         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18652         
18653         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18654             v.removeClass('active');
18655             
18656             if(currentYear === year && k === currentMonth){
18657                 v.addClass('active');
18658             }
18659             
18660             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18661                 v.addClass('disabled');
18662             }
18663             
18664         });
18665         
18666         
18667         year = parseInt(year/10, 10) * 10;
18668         
18669         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18670         
18671         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18672         
18673         year -= 1;
18674         for (var i = -1; i < 11; i++) {
18675             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18676                 tag: 'span',
18677                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18678                 html: year
18679             });
18680             
18681             year += 1;
18682         }
18683     },
18684     
18685     showMode: function(dir) 
18686     {
18687         if (dir) {
18688             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18689         }
18690         
18691         Roo.each(this.picker().select('>div',true).elements, function(v){
18692             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18693             v.hide();
18694         });
18695         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18696     },
18697     
18698     place: function()
18699     {
18700         if(this.isInline) {
18701             return;
18702         }
18703         
18704         this.picker().removeClass(['bottom', 'top']);
18705         
18706         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18707             /*
18708              * place to the top of element!
18709              *
18710              */
18711             
18712             this.picker().addClass('top');
18713             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18714             
18715             return;
18716         }
18717         
18718         this.picker().addClass('bottom');
18719         
18720         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18721     },
18722     
18723     parseDate : function(value)
18724     {
18725         if(!value || value instanceof Date){
18726             return value;
18727         }
18728         var v = Date.parseDate(value, this.format);
18729         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18730             v = Date.parseDate(value, 'Y-m-d');
18731         }
18732         if(!v && this.altFormats){
18733             if(!this.altFormatsArray){
18734                 this.altFormatsArray = this.altFormats.split("|");
18735             }
18736             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18737                 v = Date.parseDate(value, this.altFormatsArray[i]);
18738             }
18739         }
18740         return v;
18741     },
18742     
18743     formatDate : function(date, fmt)
18744     {   
18745         return (!date || !(date instanceof Date)) ?
18746         date : date.dateFormat(fmt || this.format);
18747     },
18748     
18749     onFocus : function()
18750     {
18751         Roo.bootstrap.DateField.superclass.onFocus.call(this);
18752         this.show();
18753     },
18754     
18755     onBlur : function()
18756     {
18757         Roo.bootstrap.DateField.superclass.onBlur.call(this);
18758         
18759         var d = this.inputEl().getValue();
18760         
18761         this.setValue(d);
18762                 
18763         this.hide();
18764     },
18765     
18766     show : function()
18767     {
18768         this.picker().show();
18769         this.update();
18770         this.place();
18771         
18772         this.fireEvent('show', this, this.date);
18773     },
18774     
18775     hide : function()
18776     {
18777         if(this.isInline) {
18778             return;
18779         }
18780         this.picker().hide();
18781         this.viewMode = this.startViewMode;
18782         this.showMode();
18783         
18784         this.fireEvent('hide', this, this.date);
18785         
18786     },
18787     
18788     onMousedown: function(e)
18789     {
18790         e.stopPropagation();
18791         e.preventDefault();
18792     },
18793     
18794     keyup: function(e)
18795     {
18796         Roo.bootstrap.DateField.superclass.keyup.call(this);
18797         this.update();
18798     },
18799
18800     setValue: function(v)
18801     {
18802         if(this.fireEvent('beforeselect', this, v) !== false){
18803             var d = new Date(this.parseDate(v) ).clearTime();
18804         
18805             if(isNaN(d.getTime())){
18806                 this.date = this.viewDate = '';
18807                 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18808                 return;
18809             }
18810
18811             v = this.formatDate(d);
18812
18813             Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18814
18815             this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18816
18817             this.update();
18818
18819             this.fireEvent('select', this, this.date);
18820         }
18821     },
18822     
18823     getValue: function()
18824     {
18825         return this.formatDate(this.date);
18826     },
18827     
18828     fireKey: function(e)
18829     {
18830         if (!this.picker().isVisible()){
18831             if (e.keyCode == 27) { // allow escape to hide and re-show picker
18832                 this.show();
18833             }
18834             return;
18835         }
18836         
18837         var dateChanged = false,
18838         dir, day, month,
18839         newDate, newViewDate;
18840         
18841         switch(e.keyCode){
18842             case 27: // escape
18843                 this.hide();
18844                 e.preventDefault();
18845                 break;
18846             case 37: // left
18847             case 39: // right
18848                 if (!this.keyboardNavigation) {
18849                     break;
18850                 }
18851                 dir = e.keyCode == 37 ? -1 : 1;
18852                 
18853                 if (e.ctrlKey){
18854                     newDate = this.moveYear(this.date, dir);
18855                     newViewDate = this.moveYear(this.viewDate, dir);
18856                 } else if (e.shiftKey){
18857                     newDate = this.moveMonth(this.date, dir);
18858                     newViewDate = this.moveMonth(this.viewDate, dir);
18859                 } else {
18860                     newDate = new Date(this.date);
18861                     newDate.setUTCDate(this.date.getUTCDate() + dir);
18862                     newViewDate = new Date(this.viewDate);
18863                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18864                 }
18865                 if (this.dateWithinRange(newDate)){
18866                     this.date = newDate;
18867                     this.viewDate = newViewDate;
18868                     this.setValue(this.formatDate(this.date));
18869 //                    this.update();
18870                     e.preventDefault();
18871                     dateChanged = true;
18872                 }
18873                 break;
18874             case 38: // up
18875             case 40: // down
18876                 if (!this.keyboardNavigation) {
18877                     break;
18878                 }
18879                 dir = e.keyCode == 38 ? -1 : 1;
18880                 if (e.ctrlKey){
18881                     newDate = this.moveYear(this.date, dir);
18882                     newViewDate = this.moveYear(this.viewDate, dir);
18883                 } else if (e.shiftKey){
18884                     newDate = this.moveMonth(this.date, dir);
18885                     newViewDate = this.moveMonth(this.viewDate, dir);
18886                 } else {
18887                     newDate = new Date(this.date);
18888                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18889                     newViewDate = new Date(this.viewDate);
18890                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18891                 }
18892                 if (this.dateWithinRange(newDate)){
18893                     this.date = newDate;
18894                     this.viewDate = newViewDate;
18895                     this.setValue(this.formatDate(this.date));
18896 //                    this.update();
18897                     e.preventDefault();
18898                     dateChanged = true;
18899                 }
18900                 break;
18901             case 13: // enter
18902                 this.setValue(this.formatDate(this.date));
18903                 this.hide();
18904                 e.preventDefault();
18905                 break;
18906             case 9: // tab
18907                 this.setValue(this.formatDate(this.date));
18908                 this.hide();
18909                 break;
18910             case 16: // shift
18911             case 17: // ctrl
18912             case 18: // alt
18913                 break;
18914             default :
18915                 this.hide();
18916                 
18917         }
18918     },
18919     
18920     
18921     onClick: function(e) 
18922     {
18923         e.stopPropagation();
18924         e.preventDefault();
18925         
18926         var target = e.getTarget();
18927         
18928         if(target.nodeName.toLowerCase() === 'i'){
18929             target = Roo.get(target).dom.parentNode;
18930         }
18931         
18932         var nodeName = target.nodeName;
18933         var className = target.className;
18934         var html = target.innerHTML;
18935         //Roo.log(nodeName);
18936         
18937         switch(nodeName.toLowerCase()) {
18938             case 'th':
18939                 switch(className) {
18940                     case 'switch':
18941                         this.showMode(1);
18942                         break;
18943                     case 'prev':
18944                     case 'next':
18945                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18946                         switch(this.viewMode){
18947                                 case 0:
18948                                         this.viewDate = this.moveMonth(this.viewDate, dir);
18949                                         break;
18950                                 case 1:
18951                                 case 2:
18952                                         this.viewDate = this.moveYear(this.viewDate, dir);
18953                                         break;
18954                         }
18955                         this.fill();
18956                         break;
18957                     case 'today':
18958                         var date = new Date();
18959                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18960 //                        this.fill()
18961                         this.setValue(this.formatDate(this.date));
18962                         
18963                         this.hide();
18964                         break;
18965                 }
18966                 break;
18967             case 'span':
18968                 if (className.indexOf('disabled') < 0) {
18969                     this.viewDate.setUTCDate(1);
18970                     if (className.indexOf('month') > -1) {
18971                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18972                     } else {
18973                         var year = parseInt(html, 10) || 0;
18974                         this.viewDate.setUTCFullYear(year);
18975                         
18976                     }
18977                     
18978                     if(this.singleMode){
18979                         this.setValue(this.formatDate(this.viewDate));
18980                         this.hide();
18981                         return;
18982                     }
18983                     
18984                     this.showMode(-1);
18985                     this.fill();
18986                 }
18987                 break;
18988                 
18989             case 'td':
18990                 //Roo.log(className);
18991                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18992                     var day = parseInt(html, 10) || 1;
18993                     var year = this.viewDate.getUTCFullYear(),
18994                         month = this.viewDate.getUTCMonth();
18995
18996                     if (className.indexOf('old') > -1) {
18997                         if(month === 0 ){
18998                             month = 11;
18999                             year -= 1;
19000                         }else{
19001                             month -= 1;
19002                         }
19003                     } else if (className.indexOf('new') > -1) {
19004                         if (month == 11) {
19005                             month = 0;
19006                             year += 1;
19007                         } else {
19008                             month += 1;
19009                         }
19010                     }
19011                     //Roo.log([year,month,day]);
19012                     this.date = this.UTCDate(year, month, day,0,0,0,0);
19013                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19014 //                    this.fill();
19015                     //Roo.log(this.formatDate(this.date));
19016                     this.setValue(this.formatDate(this.date));
19017                     this.hide();
19018                 }
19019                 break;
19020         }
19021     },
19022     
19023     setStartDate: function(startDate)
19024     {
19025         this.startDate = startDate || -Infinity;
19026         if (this.startDate !== -Infinity) {
19027             this.startDate = this.parseDate(this.startDate);
19028         }
19029         this.update();
19030         this.updateNavArrows();
19031     },
19032
19033     setEndDate: function(endDate)
19034     {
19035         this.endDate = endDate || Infinity;
19036         if (this.endDate !== Infinity) {
19037             this.endDate = this.parseDate(this.endDate);
19038         }
19039         this.update();
19040         this.updateNavArrows();
19041     },
19042     
19043     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19044     {
19045         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19046         if (typeof(this.daysOfWeekDisabled) !== 'object') {
19047             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19048         }
19049         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19050             return parseInt(d, 10);
19051         });
19052         this.update();
19053         this.updateNavArrows();
19054     },
19055     
19056     updateNavArrows: function() 
19057     {
19058         if(this.singleMode){
19059             return;
19060         }
19061         
19062         var d = new Date(this.viewDate),
19063         year = d.getUTCFullYear(),
19064         month = d.getUTCMonth();
19065         
19066         Roo.each(this.picker().select('.prev', true).elements, function(v){
19067             v.show();
19068             switch (this.viewMode) {
19069                 case 0:
19070
19071                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19072                         v.hide();
19073                     }
19074                     break;
19075                 case 1:
19076                 case 2:
19077                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19078                         v.hide();
19079                     }
19080                     break;
19081             }
19082         });
19083         
19084         Roo.each(this.picker().select('.next', true).elements, function(v){
19085             v.show();
19086             switch (this.viewMode) {
19087                 case 0:
19088
19089                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19090                         v.hide();
19091                     }
19092                     break;
19093                 case 1:
19094                 case 2:
19095                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19096                         v.hide();
19097                     }
19098                     break;
19099             }
19100         })
19101     },
19102     
19103     moveMonth: function(date, dir)
19104     {
19105         if (!dir) {
19106             return date;
19107         }
19108         var new_date = new Date(date.valueOf()),
19109         day = new_date.getUTCDate(),
19110         month = new_date.getUTCMonth(),
19111         mag = Math.abs(dir),
19112         new_month, test;
19113         dir = dir > 0 ? 1 : -1;
19114         if (mag == 1){
19115             test = dir == -1
19116             // If going back one month, make sure month is not current month
19117             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19118             ? function(){
19119                 return new_date.getUTCMonth() == month;
19120             }
19121             // If going forward one month, make sure month is as expected
19122             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19123             : function(){
19124                 return new_date.getUTCMonth() != new_month;
19125             };
19126             new_month = month + dir;
19127             new_date.setUTCMonth(new_month);
19128             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19129             if (new_month < 0 || new_month > 11) {
19130                 new_month = (new_month + 12) % 12;
19131             }
19132         } else {
19133             // For magnitudes >1, move one month at a time...
19134             for (var i=0; i<mag; i++) {
19135                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19136                 new_date = this.moveMonth(new_date, dir);
19137             }
19138             // ...then reset the day, keeping it in the new month
19139             new_month = new_date.getUTCMonth();
19140             new_date.setUTCDate(day);
19141             test = function(){
19142                 return new_month != new_date.getUTCMonth();
19143             };
19144         }
19145         // Common date-resetting loop -- if date is beyond end of month, make it
19146         // end of month
19147         while (test()){
19148             new_date.setUTCDate(--day);
19149             new_date.setUTCMonth(new_month);
19150         }
19151         return new_date;
19152     },
19153
19154     moveYear: function(date, dir)
19155     {
19156         return this.moveMonth(date, dir*12);
19157     },
19158
19159     dateWithinRange: function(date)
19160     {
19161         return date >= this.startDate && date <= this.endDate;
19162     },
19163
19164     
19165     remove: function() 
19166     {
19167         this.picker().remove();
19168     },
19169     
19170     validateValue : function(value)
19171     {
19172         if(this.getEl().hasClass('hidden')){
19173             return true;
19174         }
19175         
19176         if(value.length < 1)  {
19177             if(this.allowBlank){
19178                 return true;
19179             }
19180             return false;
19181         }
19182         
19183         if(value.length < this.minLength){
19184             return false;
19185         }
19186         if(value.length > this.maxLength){
19187             return false;
19188         }
19189         if(this.vtype){
19190             var vt = Roo.form.VTypes;
19191             if(!vt[this.vtype](value, this)){
19192                 return false;
19193             }
19194         }
19195         if(typeof this.validator == "function"){
19196             var msg = this.validator(value);
19197             if(msg !== true){
19198                 return false;
19199             }
19200         }
19201         
19202         if(this.regex && !this.regex.test(value)){
19203             return false;
19204         }
19205         
19206         if(typeof(this.parseDate(value)) == 'undefined'){
19207             return false;
19208         }
19209         
19210         if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19211             return false;
19212         }      
19213         
19214         if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19215             return false;
19216         } 
19217         
19218         
19219         return true;
19220     },
19221     
19222     setVisible : function(visible)
19223     {
19224         if(!this.getEl()){
19225             return;
19226         }
19227         
19228         this.getEl().removeClass('hidden');
19229         
19230         if(visible){
19231             return;
19232         }
19233         
19234         this.getEl().addClass('hidden');
19235     }
19236    
19237 });
19238
19239 Roo.apply(Roo.bootstrap.DateField,  {
19240     
19241     head : {
19242         tag: 'thead',
19243         cn: [
19244         {
19245             tag: 'tr',
19246             cn: [
19247             {
19248                 tag: 'th',
19249                 cls: 'prev',
19250                 html: '<i class="fa fa-arrow-left"/>'
19251             },
19252             {
19253                 tag: 'th',
19254                 cls: 'switch',
19255                 colspan: '5'
19256             },
19257             {
19258                 tag: 'th',
19259                 cls: 'next',
19260                 html: '<i class="fa fa-arrow-right"/>'
19261             }
19262
19263             ]
19264         }
19265         ]
19266     },
19267     
19268     content : {
19269         tag: 'tbody',
19270         cn: [
19271         {
19272             tag: 'tr',
19273             cn: [
19274             {
19275                 tag: 'td',
19276                 colspan: '7'
19277             }
19278             ]
19279         }
19280         ]
19281     },
19282     
19283     footer : {
19284         tag: 'tfoot',
19285         cn: [
19286         {
19287             tag: 'tr',
19288             cn: [
19289             {
19290                 tag: 'th',
19291                 colspan: '7',
19292                 cls: 'today'
19293             }
19294                     
19295             ]
19296         }
19297         ]
19298     },
19299     
19300     dates:{
19301         en: {
19302             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19303             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19304             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19305             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19306             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19307             today: "Today"
19308         }
19309     },
19310     
19311     modes: [
19312     {
19313         clsName: 'days',
19314         navFnc: 'Month',
19315         navStep: 1
19316     },
19317     {
19318         clsName: 'months',
19319         navFnc: 'FullYear',
19320         navStep: 1
19321     },
19322     {
19323         clsName: 'years',
19324         navFnc: 'FullYear',
19325         navStep: 10
19326     }]
19327 });
19328
19329 Roo.apply(Roo.bootstrap.DateField,  {
19330   
19331     template : {
19332         tag: 'div',
19333         cls: 'datepicker dropdown-menu roo-dynamic',
19334         cn: [
19335         {
19336             tag: 'div',
19337             cls: 'datepicker-days',
19338             cn: [
19339             {
19340                 tag: 'table',
19341                 cls: 'table-condensed',
19342                 cn:[
19343                 Roo.bootstrap.DateField.head,
19344                 {
19345                     tag: 'tbody'
19346                 },
19347                 Roo.bootstrap.DateField.footer
19348                 ]
19349             }
19350             ]
19351         },
19352         {
19353             tag: 'div',
19354             cls: 'datepicker-months',
19355             cn: [
19356             {
19357                 tag: 'table',
19358                 cls: 'table-condensed',
19359                 cn:[
19360                 Roo.bootstrap.DateField.head,
19361                 Roo.bootstrap.DateField.content,
19362                 Roo.bootstrap.DateField.footer
19363                 ]
19364             }
19365             ]
19366         },
19367         {
19368             tag: 'div',
19369             cls: 'datepicker-years',
19370             cn: [
19371             {
19372                 tag: 'table',
19373                 cls: 'table-condensed',
19374                 cn:[
19375                 Roo.bootstrap.DateField.head,
19376                 Roo.bootstrap.DateField.content,
19377                 Roo.bootstrap.DateField.footer
19378                 ]
19379             }
19380             ]
19381         }
19382         ]
19383     }
19384 });
19385
19386  
19387
19388  /*
19389  * - LGPL
19390  *
19391  * TimeField
19392  * 
19393  */
19394
19395 /**
19396  * @class Roo.bootstrap.TimeField
19397  * @extends Roo.bootstrap.Input
19398  * Bootstrap DateField class
19399  * 
19400  * 
19401  * @constructor
19402  * Create a new TimeField
19403  * @param {Object} config The config object
19404  */
19405
19406 Roo.bootstrap.TimeField = function(config){
19407     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19408     this.addEvents({
19409             /**
19410              * @event show
19411              * Fires when this field show.
19412              * @param {Roo.bootstrap.DateField} thisthis
19413              * @param {Mixed} date The date value
19414              */
19415             show : true,
19416             /**
19417              * @event show
19418              * Fires when this field hide.
19419              * @param {Roo.bootstrap.DateField} this
19420              * @param {Mixed} date The date value
19421              */
19422             hide : true,
19423             /**
19424              * @event select
19425              * Fires when select a date.
19426              * @param {Roo.bootstrap.DateField} this
19427              * @param {Mixed} date The date value
19428              */
19429             select : true
19430         });
19431 };
19432
19433 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
19434     
19435     /**
19436      * @cfg {String} format
19437      * The default time format string which can be overriden for localization support.  The format must be
19438      * valid according to {@link Date#parseDate} (defaults to 'H:i').
19439      */
19440     format : "H:i",
19441        
19442     onRender: function(ct, position)
19443     {
19444         
19445         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19446                 
19447         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19448         
19449         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19450         
19451         this.pop = this.picker().select('>.datepicker-time',true).first();
19452         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19453         
19454         this.picker().on('mousedown', this.onMousedown, this);
19455         this.picker().on('click', this.onClick, this);
19456         
19457         this.picker().addClass('datepicker-dropdown');
19458     
19459         this.fillTime();
19460         this.update();
19461             
19462         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19463         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19464         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19465         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19466         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19467         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19468
19469     },
19470     
19471     fireKey: function(e){
19472         if (!this.picker().isVisible()){
19473             if (e.keyCode == 27) { // allow escape to hide and re-show picker
19474                 this.show();
19475             }
19476             return;
19477         }
19478
19479         e.preventDefault();
19480         
19481         switch(e.keyCode){
19482             case 27: // escape
19483                 this.hide();
19484                 break;
19485             case 37: // left
19486             case 39: // right
19487                 this.onTogglePeriod();
19488                 break;
19489             case 38: // up
19490                 this.onIncrementMinutes();
19491                 break;
19492             case 40: // down
19493                 this.onDecrementMinutes();
19494                 break;
19495             case 13: // enter
19496             case 9: // tab
19497                 this.setTime();
19498                 break;
19499         }
19500     },
19501     
19502     onClick: function(e) {
19503         e.stopPropagation();
19504         e.preventDefault();
19505     },
19506     
19507     picker : function()
19508     {
19509         return this.el.select('.datepicker', true).first();
19510     },
19511     
19512     fillTime: function()
19513     {    
19514         var time = this.pop.select('tbody', true).first();
19515         
19516         time.dom.innerHTML = '';
19517         
19518         time.createChild({
19519             tag: 'tr',
19520             cn: [
19521                 {
19522                     tag: 'td',
19523                     cn: [
19524                         {
19525                             tag: 'a',
19526                             href: '#',
19527                             cls: 'btn',
19528                             cn: [
19529                                 {
19530                                     tag: 'span',
19531                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
19532                                 }
19533                             ]
19534                         } 
19535                     ]
19536                 },
19537                 {
19538                     tag: 'td',
19539                     cls: 'separator'
19540                 },
19541                 {
19542                     tag: 'td',
19543                     cn: [
19544                         {
19545                             tag: 'a',
19546                             href: '#',
19547                             cls: 'btn',
19548                             cn: [
19549                                 {
19550                                     tag: 'span',
19551                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
19552                                 }
19553                             ]
19554                         }
19555                     ]
19556                 },
19557                 {
19558                     tag: 'td',
19559                     cls: 'separator'
19560                 }
19561             ]
19562         });
19563         
19564         time.createChild({
19565             tag: 'tr',
19566             cn: [
19567                 {
19568                     tag: 'td',
19569                     cn: [
19570                         {
19571                             tag: 'span',
19572                             cls: 'timepicker-hour',
19573                             html: '00'
19574                         }  
19575                     ]
19576                 },
19577                 {
19578                     tag: 'td',
19579                     cls: 'separator',
19580                     html: ':'
19581                 },
19582                 {
19583                     tag: 'td',
19584                     cn: [
19585                         {
19586                             tag: 'span',
19587                             cls: 'timepicker-minute',
19588                             html: '00'
19589                         }  
19590                     ]
19591                 },
19592                 {
19593                     tag: 'td',
19594                     cls: 'separator'
19595                 },
19596                 {
19597                     tag: 'td',
19598                     cn: [
19599                         {
19600                             tag: 'button',
19601                             type: 'button',
19602                             cls: 'btn btn-primary period',
19603                             html: 'AM'
19604                             
19605                         }
19606                     ]
19607                 }
19608             ]
19609         });
19610         
19611         time.createChild({
19612             tag: 'tr',
19613             cn: [
19614                 {
19615                     tag: 'td',
19616                     cn: [
19617                         {
19618                             tag: 'a',
19619                             href: '#',
19620                             cls: 'btn',
19621                             cn: [
19622                                 {
19623                                     tag: 'span',
19624                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
19625                                 }
19626                             ]
19627                         }
19628                     ]
19629                 },
19630                 {
19631                     tag: 'td',
19632                     cls: 'separator'
19633                 },
19634                 {
19635                     tag: 'td',
19636                     cn: [
19637                         {
19638                             tag: 'a',
19639                             href: '#',
19640                             cls: 'btn',
19641                             cn: [
19642                                 {
19643                                     tag: 'span',
19644                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
19645                                 }
19646                             ]
19647                         }
19648                     ]
19649                 },
19650                 {
19651                     tag: 'td',
19652                     cls: 'separator'
19653                 }
19654             ]
19655         });
19656         
19657     },
19658     
19659     update: function()
19660     {
19661         
19662         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19663         
19664         this.fill();
19665     },
19666     
19667     fill: function() 
19668     {
19669         var hours = this.time.getHours();
19670         var minutes = this.time.getMinutes();
19671         var period = 'AM';
19672         
19673         if(hours > 11){
19674             period = 'PM';
19675         }
19676         
19677         if(hours == 0){
19678             hours = 12;
19679         }
19680         
19681         
19682         if(hours > 12){
19683             hours = hours - 12;
19684         }
19685         
19686         if(hours < 10){
19687             hours = '0' + hours;
19688         }
19689         
19690         if(minutes < 10){
19691             minutes = '0' + minutes;
19692         }
19693         
19694         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19695         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19696         this.pop.select('button', true).first().dom.innerHTML = period;
19697         
19698     },
19699     
19700     place: function()
19701     {   
19702         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19703         
19704         var cls = ['bottom'];
19705         
19706         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19707             cls.pop();
19708             cls.push('top');
19709         }
19710         
19711         cls.push('right');
19712         
19713         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19714             cls.pop();
19715             cls.push('left');
19716         }
19717         
19718         this.picker().addClass(cls.join('-'));
19719         
19720         var _this = this;
19721         
19722         Roo.each(cls, function(c){
19723             if(c == 'bottom'){
19724                 _this.picker().setTop(_this.inputEl().getHeight());
19725                 return;
19726             }
19727             if(c == 'top'){
19728                 _this.picker().setTop(0 - _this.picker().getHeight());
19729                 return;
19730             }
19731             
19732             if(c == 'left'){
19733                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19734                 return;
19735             }
19736             if(c == 'right'){
19737                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19738                 return;
19739             }
19740         });
19741         
19742     },
19743   
19744     onFocus : function()
19745     {
19746         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19747         this.show();
19748     },
19749     
19750     onBlur : function()
19751     {
19752         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19753         this.hide();
19754     },
19755     
19756     show : function()
19757     {
19758         this.picker().show();
19759         this.pop.show();
19760         this.update();
19761         this.place();
19762         
19763         this.fireEvent('show', this, this.date);
19764     },
19765     
19766     hide : function()
19767     {
19768         this.picker().hide();
19769         this.pop.hide();
19770         
19771         this.fireEvent('hide', this, this.date);
19772     },
19773     
19774     setTime : function()
19775     {
19776         this.hide();
19777         this.setValue(this.time.format(this.format));
19778         
19779         this.fireEvent('select', this, this.date);
19780         
19781         
19782     },
19783     
19784     onMousedown: function(e){
19785         e.stopPropagation();
19786         e.preventDefault();
19787     },
19788     
19789     onIncrementHours: function()
19790     {
19791         Roo.log('onIncrementHours');
19792         this.time = this.time.add(Date.HOUR, 1);
19793         this.update();
19794         
19795     },
19796     
19797     onDecrementHours: function()
19798     {
19799         Roo.log('onDecrementHours');
19800         this.time = this.time.add(Date.HOUR, -1);
19801         this.update();
19802     },
19803     
19804     onIncrementMinutes: function()
19805     {
19806         Roo.log('onIncrementMinutes');
19807         this.time = this.time.add(Date.MINUTE, 1);
19808         this.update();
19809     },
19810     
19811     onDecrementMinutes: function()
19812     {
19813         Roo.log('onDecrementMinutes');
19814         this.time = this.time.add(Date.MINUTE, -1);
19815         this.update();
19816     },
19817     
19818     onTogglePeriod: function()
19819     {
19820         Roo.log('onTogglePeriod');
19821         this.time = this.time.add(Date.HOUR, 12);
19822         this.update();
19823     }
19824     
19825    
19826 });
19827
19828 Roo.apply(Roo.bootstrap.TimeField,  {
19829     
19830     content : {
19831         tag: 'tbody',
19832         cn: [
19833             {
19834                 tag: 'tr',
19835                 cn: [
19836                 {
19837                     tag: 'td',
19838                     colspan: '7'
19839                 }
19840                 ]
19841             }
19842         ]
19843     },
19844     
19845     footer : {
19846         tag: 'tfoot',
19847         cn: [
19848             {
19849                 tag: 'tr',
19850                 cn: [
19851                 {
19852                     tag: 'th',
19853                     colspan: '7',
19854                     cls: '',
19855                     cn: [
19856                         {
19857                             tag: 'button',
19858                             cls: 'btn btn-info ok',
19859                             html: 'OK'
19860                         }
19861                     ]
19862                 }
19863
19864                 ]
19865             }
19866         ]
19867     }
19868 });
19869
19870 Roo.apply(Roo.bootstrap.TimeField,  {
19871   
19872     template : {
19873         tag: 'div',
19874         cls: 'datepicker dropdown-menu',
19875         cn: [
19876             {
19877                 tag: 'div',
19878                 cls: 'datepicker-time',
19879                 cn: [
19880                 {
19881                     tag: 'table',
19882                     cls: 'table-condensed',
19883                     cn:[
19884                     Roo.bootstrap.TimeField.content,
19885                     Roo.bootstrap.TimeField.footer
19886                     ]
19887                 }
19888                 ]
19889             }
19890         ]
19891     }
19892 });
19893
19894  
19895
19896  /*
19897  * - LGPL
19898  *
19899  * MonthField
19900  * 
19901  */
19902
19903 /**
19904  * @class Roo.bootstrap.MonthField
19905  * @extends Roo.bootstrap.Input
19906  * Bootstrap MonthField class
19907  * 
19908  * @cfg {String} language default en
19909  * 
19910  * @constructor
19911  * Create a new MonthField
19912  * @param {Object} config The config object
19913  */
19914
19915 Roo.bootstrap.MonthField = function(config){
19916     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19917     
19918     this.addEvents({
19919         /**
19920          * @event show
19921          * Fires when this field show.
19922          * @param {Roo.bootstrap.MonthField} this
19923          * @param {Mixed} date The date value
19924          */
19925         show : true,
19926         /**
19927          * @event show
19928          * Fires when this field hide.
19929          * @param {Roo.bootstrap.MonthField} this
19930          * @param {Mixed} date The date value
19931          */
19932         hide : true,
19933         /**
19934          * @event select
19935          * Fires when select a date.
19936          * @param {Roo.bootstrap.MonthField} this
19937          * @param {String} oldvalue The old value
19938          * @param {String} newvalue The new value
19939          */
19940         select : true
19941     });
19942 };
19943
19944 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
19945     
19946     onRender: function(ct, position)
19947     {
19948         
19949         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19950         
19951         this.language = this.language || 'en';
19952         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19953         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19954         
19955         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19956         this.isInline = false;
19957         this.isInput = true;
19958         this.component = this.el.select('.add-on', true).first() || false;
19959         this.component = (this.component && this.component.length === 0) ? false : this.component;
19960         this.hasInput = this.component && this.inputEL().length;
19961         
19962         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19963         
19964         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19965         
19966         this.picker().on('mousedown', this.onMousedown, this);
19967         this.picker().on('click', this.onClick, this);
19968         
19969         this.picker().addClass('datepicker-dropdown');
19970         
19971         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19972             v.setStyle('width', '189px');
19973         });
19974         
19975         this.fillMonths();
19976         
19977         this.update();
19978         
19979         if(this.isInline) {
19980             this.show();
19981         }
19982         
19983     },
19984     
19985     setValue: function(v, suppressEvent)
19986     {   
19987         var o = this.getValue();
19988         
19989         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19990         
19991         this.update();
19992
19993         if(suppressEvent !== true){
19994             this.fireEvent('select', this, o, v);
19995         }
19996         
19997     },
19998     
19999     getValue: function()
20000     {
20001         return this.value;
20002     },
20003     
20004     onClick: function(e) 
20005     {
20006         e.stopPropagation();
20007         e.preventDefault();
20008         
20009         var target = e.getTarget();
20010         
20011         if(target.nodeName.toLowerCase() === 'i'){
20012             target = Roo.get(target).dom.parentNode;
20013         }
20014         
20015         var nodeName = target.nodeName;
20016         var className = target.className;
20017         var html = target.innerHTML;
20018         
20019         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20020             return;
20021         }
20022         
20023         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20024         
20025         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20026         
20027         this.hide();
20028                         
20029     },
20030     
20031     picker : function()
20032     {
20033         return this.pickerEl;
20034     },
20035     
20036     fillMonths: function()
20037     {    
20038         var i = 0;
20039         var months = this.picker().select('>.datepicker-months td', true).first();
20040         
20041         months.dom.innerHTML = '';
20042         
20043         while (i < 12) {
20044             var month = {
20045                 tag: 'span',
20046                 cls: 'month',
20047                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20048             };
20049             
20050             months.createChild(month);
20051         }
20052         
20053     },
20054     
20055     update: function()
20056     {
20057         var _this = this;
20058         
20059         if(typeof(this.vIndex) == 'undefined' && this.value.length){
20060             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20061         }
20062         
20063         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20064             e.removeClass('active');
20065             
20066             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20067                 e.addClass('active');
20068             }
20069         })
20070     },
20071     
20072     place: function()
20073     {
20074         if(this.isInline) {
20075             return;
20076         }
20077         
20078         this.picker().removeClass(['bottom', 'top']);
20079         
20080         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20081             /*
20082              * place to the top of element!
20083              *
20084              */
20085             
20086             this.picker().addClass('top');
20087             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20088             
20089             return;
20090         }
20091         
20092         this.picker().addClass('bottom');
20093         
20094         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20095     },
20096     
20097     onFocus : function()
20098     {
20099         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20100         this.show();
20101     },
20102     
20103     onBlur : function()
20104     {
20105         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20106         
20107         var d = this.inputEl().getValue();
20108         
20109         this.setValue(d);
20110                 
20111         this.hide();
20112     },
20113     
20114     show : function()
20115     {
20116         this.picker().show();
20117         this.picker().select('>.datepicker-months', true).first().show();
20118         this.update();
20119         this.place();
20120         
20121         this.fireEvent('show', this, this.date);
20122     },
20123     
20124     hide : function()
20125     {
20126         if(this.isInline) {
20127             return;
20128         }
20129         this.picker().hide();
20130         this.fireEvent('hide', this, this.date);
20131         
20132     },
20133     
20134     onMousedown: function(e)
20135     {
20136         e.stopPropagation();
20137         e.preventDefault();
20138     },
20139     
20140     keyup: function(e)
20141     {
20142         Roo.bootstrap.MonthField.superclass.keyup.call(this);
20143         this.update();
20144     },
20145
20146     fireKey: function(e)
20147     {
20148         if (!this.picker().isVisible()){
20149             if (e.keyCode == 27)   {// allow escape to hide and re-show picker
20150                 this.show();
20151             }
20152             return;
20153         }
20154         
20155         var dir;
20156         
20157         switch(e.keyCode){
20158             case 27: // escape
20159                 this.hide();
20160                 e.preventDefault();
20161                 break;
20162             case 37: // left
20163             case 39: // right
20164                 dir = e.keyCode == 37 ? -1 : 1;
20165                 
20166                 this.vIndex = this.vIndex + dir;
20167                 
20168                 if(this.vIndex < 0){
20169                     this.vIndex = 0;
20170                 }
20171                 
20172                 if(this.vIndex > 11){
20173                     this.vIndex = 11;
20174                 }
20175                 
20176                 if(isNaN(this.vIndex)){
20177                     this.vIndex = 0;
20178                 }
20179                 
20180                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20181                 
20182                 break;
20183             case 38: // up
20184             case 40: // down
20185                 
20186                 dir = e.keyCode == 38 ? -1 : 1;
20187                 
20188                 this.vIndex = this.vIndex + dir * 4;
20189                 
20190                 if(this.vIndex < 0){
20191                     this.vIndex = 0;
20192                 }
20193                 
20194                 if(this.vIndex > 11){
20195                     this.vIndex = 11;
20196                 }
20197                 
20198                 if(isNaN(this.vIndex)){
20199                     this.vIndex = 0;
20200                 }
20201                 
20202                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20203                 break;
20204                 
20205             case 13: // enter
20206                 
20207                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20208                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20209                 }
20210                 
20211                 this.hide();
20212                 e.preventDefault();
20213                 break;
20214             case 9: // tab
20215                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20216                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20217                 }
20218                 this.hide();
20219                 break;
20220             case 16: // shift
20221             case 17: // ctrl
20222             case 18: // alt
20223                 break;
20224             default :
20225                 this.hide();
20226                 
20227         }
20228     },
20229     
20230     remove: function() 
20231     {
20232         this.picker().remove();
20233     }
20234    
20235 });
20236
20237 Roo.apply(Roo.bootstrap.MonthField,  {
20238     
20239     content : {
20240         tag: 'tbody',
20241         cn: [
20242         {
20243             tag: 'tr',
20244             cn: [
20245             {
20246                 tag: 'td',
20247                 colspan: '7'
20248             }
20249             ]
20250         }
20251         ]
20252     },
20253     
20254     dates:{
20255         en: {
20256             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20257             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20258         }
20259     }
20260 });
20261
20262 Roo.apply(Roo.bootstrap.MonthField,  {
20263   
20264     template : {
20265         tag: 'div',
20266         cls: 'datepicker dropdown-menu roo-dynamic',
20267         cn: [
20268             {
20269                 tag: 'div',
20270                 cls: 'datepicker-months',
20271                 cn: [
20272                 {
20273                     tag: 'table',
20274                     cls: 'table-condensed',
20275                     cn:[
20276                         Roo.bootstrap.DateField.content
20277                     ]
20278                 }
20279                 ]
20280             }
20281         ]
20282     }
20283 });
20284
20285  
20286
20287  
20288  /*
20289  * - LGPL
20290  *
20291  * CheckBox
20292  * 
20293  */
20294
20295 /**
20296  * @class Roo.bootstrap.CheckBox
20297  * @extends Roo.bootstrap.Input
20298  * Bootstrap CheckBox class
20299  * 
20300  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20301  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20302  * @cfg {String} boxLabel The text that appears beside the checkbox
20303  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20304  * @cfg {Boolean} checked initnal the element
20305  * @cfg {Boolean} inline inline the element (default false)
20306  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20307  * @cfg {String} tooltip label tooltip
20308  * 
20309  * @constructor
20310  * Create a new CheckBox
20311  * @param {Object} config The config object
20312  */
20313
20314 Roo.bootstrap.CheckBox = function(config){
20315     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20316    
20317     this.addEvents({
20318         /**
20319         * @event check
20320         * Fires when the element is checked or unchecked.
20321         * @param {Roo.bootstrap.CheckBox} this This input
20322         * @param {Boolean} checked The new checked value
20323         */
20324        check : true,
20325        /**
20326         * @event click
20327         * Fires when the element is click.
20328         * @param {Roo.bootstrap.CheckBox} this This input
20329         */
20330        click : true
20331     });
20332     
20333 };
20334
20335 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
20336   
20337     inputType: 'checkbox',
20338     inputValue: 1,
20339     valueOff: 0,
20340     boxLabel: false,
20341     checked: false,
20342     weight : false,
20343     inline: false,
20344     tooltip : '',
20345     
20346     getAutoCreate : function()
20347     {
20348         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20349         
20350         var id = Roo.id();
20351         
20352         var cfg = {};
20353         
20354         cfg.cls = 'form-group ' + this.inputType; //input-group
20355         
20356         if(this.inline){
20357             cfg.cls += ' ' + this.inputType + '-inline';
20358         }
20359         
20360         var input =  {
20361             tag: 'input',
20362             id : id,
20363             type : this.inputType,
20364             value : this.inputValue,
20365             cls : 'roo-' + this.inputType, //'form-box',
20366             placeholder : this.placeholder || ''
20367             
20368         };
20369         
20370         if(this.inputType != 'radio'){
20371             var hidden =  {
20372                 tag: 'input',
20373                 type : 'hidden',
20374                 cls : 'roo-hidden-value',
20375                 value : this.checked ? this.inputValue : this.valueOff
20376             };
20377         }
20378         
20379             
20380         if (this.weight) { // Validity check?
20381             cfg.cls += " " + this.inputType + "-" + this.weight;
20382         }
20383         
20384         if (this.disabled) {
20385             input.disabled=true;
20386         }
20387         
20388         if(this.checked){
20389             input.checked = this.checked;
20390         }
20391         
20392         if (this.name) {
20393             
20394             input.name = this.name;
20395             
20396             if(this.inputType != 'radio'){
20397                 hidden.name = this.name;
20398                 input.name = '_hidden_' + this.name;
20399             }
20400         }
20401         
20402         if (this.size) {
20403             input.cls += ' input-' + this.size;
20404         }
20405         
20406         var settings=this;
20407         
20408         ['xs','sm','md','lg'].map(function(size){
20409             if (settings[size]) {
20410                 cfg.cls += ' col-' + size + '-' + settings[size];
20411             }
20412         });
20413         
20414         var inputblock = input;
20415          
20416         if (this.before || this.after) {
20417             
20418             inputblock = {
20419                 cls : 'input-group',
20420                 cn :  [] 
20421             };
20422             
20423             if (this.before) {
20424                 inputblock.cn.push({
20425                     tag :'span',
20426                     cls : 'input-group-addon',
20427                     html : this.before
20428                 });
20429             }
20430             
20431             inputblock.cn.push(input);
20432             
20433             if(this.inputType != 'radio'){
20434                 inputblock.cn.push(hidden);
20435             }
20436             
20437             if (this.after) {
20438                 inputblock.cn.push({
20439                     tag :'span',
20440                     cls : 'input-group-addon',
20441                     html : this.after
20442                 });
20443             }
20444             
20445         }
20446         
20447         if (align ==='left' && this.fieldLabel.length) {
20448 //                Roo.log("left and has label");
20449             cfg.cn = [
20450                 {
20451                     tag: 'label',
20452                     'for' :  id,
20453                     cls : 'control-label',
20454                     html : this.fieldLabel
20455                 },
20456                 {
20457                     cls : "", 
20458                     cn: [
20459                         inputblock
20460                     ]
20461                 }
20462             ];
20463             
20464             if(this.labelWidth > 12){
20465                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20466             }
20467             
20468             if(this.labelWidth < 13 && this.labelmd == 0){
20469                 this.labelmd = this.labelWidth;
20470             }
20471             
20472             if(this.labellg > 0){
20473                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20474                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20475             }
20476             
20477             if(this.labelmd > 0){
20478                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20479                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20480             }
20481             
20482             if(this.labelsm > 0){
20483                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20484                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20485             }
20486             
20487             if(this.labelxs > 0){
20488                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20489                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20490             }
20491             
20492         } else if ( this.fieldLabel.length) {
20493 //                Roo.log(" label");
20494                 cfg.cn = [
20495                    
20496                     {
20497                         tag: this.boxLabel ? 'span' : 'label',
20498                         'for': id,
20499                         cls: 'control-label box-input-label',
20500                         //cls : 'input-group-addon',
20501                         html : this.fieldLabel
20502                     },
20503                     
20504                     inputblock
20505                     
20506                 ];
20507
20508         } else {
20509             
20510 //                Roo.log(" no label && no align");
20511                 cfg.cn = [  inputblock ] ;
20512                 
20513                 
20514         }
20515         
20516         if(this.boxLabel){
20517              var boxLabelCfg = {
20518                 tag: 'label',
20519                 //'for': id, // box label is handled by onclick - so no for...
20520                 cls: 'box-label',
20521                 html: this.boxLabel
20522             };
20523             
20524             if(this.tooltip){
20525                 boxLabelCfg.tooltip = this.tooltip;
20526             }
20527              
20528             cfg.cn.push(boxLabelCfg);
20529         }
20530         
20531         if(this.inputType != 'radio'){
20532             cfg.cn.push(hidden);
20533         }
20534         
20535         return cfg;
20536         
20537     },
20538     
20539     /**
20540      * return the real input element.
20541      */
20542     inputEl: function ()
20543     {
20544         return this.el.select('input.roo-' + this.inputType,true).first();
20545     },
20546     hiddenEl: function ()
20547     {
20548         return this.el.select('input.roo-hidden-value',true).first();
20549     },
20550     
20551     labelEl: function()
20552     {
20553         return this.el.select('label.control-label',true).first();
20554     },
20555     /* depricated... */
20556     
20557     label: function()
20558     {
20559         return this.labelEl();
20560     },
20561     
20562     boxLabelEl: function()
20563     {
20564         return this.el.select('label.box-label',true).first();
20565     },
20566     
20567     initEvents : function()
20568     {
20569 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20570         
20571         this.inputEl().on('click', this.onClick,  this);
20572         
20573         if (this.boxLabel) { 
20574             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
20575         }
20576         
20577         this.startValue = this.getValue();
20578         
20579         if(this.groupId){
20580             Roo.bootstrap.CheckBox.register(this);
20581         }
20582     },
20583     
20584     onClick : function(e)
20585     {   
20586         if(this.fireEvent('click', this, e) !== false){
20587             this.setChecked(!this.checked);
20588         }
20589         
20590     },
20591     
20592     setChecked : function(state,suppressEvent)
20593     {
20594         this.startValue = this.getValue();
20595
20596         if(this.inputType == 'radio'){
20597             
20598             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20599                 e.dom.checked = false;
20600             });
20601             
20602             this.inputEl().dom.checked = true;
20603             
20604             this.inputEl().dom.value = this.inputValue;
20605             
20606             if(suppressEvent !== true){
20607                 this.fireEvent('check', this, true);
20608             }
20609             
20610             this.validate();
20611             
20612             return;
20613         }
20614         
20615         this.checked = state;
20616         
20617         this.inputEl().dom.checked = state;
20618         
20619         
20620         this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20621         
20622         if(suppressEvent !== true){
20623             this.fireEvent('check', this, state);
20624         }
20625         
20626         this.validate();
20627     },
20628     
20629     getValue : function()
20630     {
20631         if(this.inputType == 'radio'){
20632             return this.getGroupValue();
20633         }
20634         
20635         return this.hiddenEl().dom.value;
20636         
20637     },
20638     
20639     getGroupValue : function()
20640     {
20641         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20642             return '';
20643         }
20644         
20645         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20646     },
20647     
20648     setValue : function(v,suppressEvent)
20649     {
20650         if(this.inputType == 'radio'){
20651             this.setGroupValue(v, suppressEvent);
20652             return;
20653         }
20654         
20655         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20656         
20657         this.validate();
20658     },
20659     
20660     setGroupValue : function(v, suppressEvent)
20661     {
20662         this.startValue = this.getValue();
20663         
20664         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20665             e.dom.checked = false;
20666             
20667             if(e.dom.value == v){
20668                 e.dom.checked = true;
20669             }
20670         });
20671         
20672         if(suppressEvent !== true){
20673             this.fireEvent('check', this, true);
20674         }
20675
20676         this.validate();
20677         
20678         return;
20679     },
20680     
20681     validate : function()
20682     {
20683         if(
20684                 this.disabled || 
20685                 (this.inputType == 'radio' && this.validateRadio()) ||
20686                 (this.inputType == 'checkbox' && this.validateCheckbox())
20687         ){
20688             this.markValid();
20689             return true;
20690         }
20691         
20692         this.markInvalid();
20693         return false;
20694     },
20695     
20696     validateRadio : function()
20697     {
20698         if(this.allowBlank){
20699             return true;
20700         }
20701         
20702         var valid = false;
20703         
20704         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20705             if(!e.dom.checked){
20706                 return;
20707             }
20708             
20709             valid = true;
20710             
20711             return false;
20712         });
20713         
20714         return valid;
20715     },
20716     
20717     validateCheckbox : function()
20718     {
20719         if(!this.groupId){
20720             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20721             //return (this.getValue() == this.inputValue) ? true : false;
20722         }
20723         
20724         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20725         
20726         if(!group){
20727             return false;
20728         }
20729         
20730         var r = false;
20731         
20732         for(var i in group){
20733             if(group[i].el.isVisible(true)){
20734                 r = false;
20735                 break;
20736             }
20737             
20738             r = true;
20739         }
20740         
20741         for(var i in group){
20742             if(r){
20743                 break;
20744             }
20745             
20746             r = (group[i].getValue() == group[i].inputValue) ? true : false;
20747         }
20748         
20749         return r;
20750     },
20751     
20752     /**
20753      * Mark this field as valid
20754      */
20755     markValid : function()
20756     {
20757         var _this = this;
20758         
20759         this.fireEvent('valid', this);
20760         
20761         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20762         
20763         if(this.groupId){
20764             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20765         }
20766         
20767         if(label){
20768             label.markValid();
20769         }
20770
20771         if(this.inputType == 'radio'){
20772             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20773                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20774                 e.findParent('.form-group', false, true).addClass(_this.validClass);
20775             });
20776             
20777             return;
20778         }
20779
20780         if(!this.groupId){
20781             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20782             this.el.findParent('.form-group', false, true).addClass(this.validClass);
20783             return;
20784         }
20785         
20786         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20787         
20788         if(!group){
20789             return;
20790         }
20791         
20792         for(var i in group){
20793             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20794             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20795         }
20796     },
20797     
20798      /**
20799      * Mark this field as invalid
20800      * @param {String} msg The validation message
20801      */
20802     markInvalid : function(msg)
20803     {
20804         if(this.allowBlank){
20805             return;
20806         }
20807         
20808         var _this = this;
20809         
20810         this.fireEvent('invalid', this, msg);
20811         
20812         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20813         
20814         if(this.groupId){
20815             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20816         }
20817         
20818         if(label){
20819             label.markInvalid();
20820         }
20821             
20822         if(this.inputType == 'radio'){
20823             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20824                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20825                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20826             });
20827             
20828             return;
20829         }
20830         
20831         if(!this.groupId){
20832             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20833             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20834             return;
20835         }
20836         
20837         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20838         
20839         if(!group){
20840             return;
20841         }
20842         
20843         for(var i in group){
20844             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20845             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20846         }
20847         
20848     },
20849     
20850     clearInvalid : function()
20851     {
20852         Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20853         
20854         // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20855         
20856         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20857         
20858         if (label && label.iconEl) {
20859             label.iconEl.removeClass(label.validClass);
20860             label.iconEl.removeClass(label.invalidClass);
20861         }
20862     },
20863     
20864     disable : function()
20865     {
20866         if(this.inputType != 'radio'){
20867             Roo.bootstrap.CheckBox.superclass.disable.call(this);
20868             return;
20869         }
20870         
20871         var _this = this;
20872         
20873         if(this.rendered){
20874             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20875                 _this.getActionEl().addClass(this.disabledClass);
20876                 e.dom.disabled = true;
20877             });
20878         }
20879         
20880         this.disabled = true;
20881         this.fireEvent("disable", this);
20882         return this;
20883     },
20884
20885     enable : function()
20886     {
20887         if(this.inputType != 'radio'){
20888             Roo.bootstrap.CheckBox.superclass.enable.call(this);
20889             return;
20890         }
20891         
20892         var _this = this;
20893         
20894         if(this.rendered){
20895             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20896                 _this.getActionEl().removeClass(this.disabledClass);
20897                 e.dom.disabled = false;
20898             });
20899         }
20900         
20901         this.disabled = false;
20902         this.fireEvent("enable", this);
20903         return this;
20904     },
20905     
20906     setBoxLabel : function(v)
20907     {
20908         this.boxLabel = v;
20909         
20910         if(this.rendered){
20911             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20912         }
20913     }
20914
20915 });
20916
20917 Roo.apply(Roo.bootstrap.CheckBox, {
20918     
20919     groups: {},
20920     
20921      /**
20922     * register a CheckBox Group
20923     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20924     */
20925     register : function(checkbox)
20926     {
20927         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20928             this.groups[checkbox.groupId] = {};
20929         }
20930         
20931         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20932             return;
20933         }
20934         
20935         this.groups[checkbox.groupId][checkbox.name] = checkbox;
20936         
20937     },
20938     /**
20939     * fetch a CheckBox Group based on the group ID
20940     * @param {string} the group ID
20941     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20942     */
20943     get: function(groupId) {
20944         if (typeof(this.groups[groupId]) == 'undefined') {
20945             return false;
20946         }
20947         
20948         return this.groups[groupId] ;
20949     }
20950     
20951     
20952 });
20953 /*
20954  * - LGPL
20955  *
20956  * RadioItem
20957  * 
20958  */
20959
20960 /**
20961  * @class Roo.bootstrap.Radio
20962  * @extends Roo.bootstrap.Component
20963  * Bootstrap Radio class
20964  * @cfg {String} boxLabel - the label associated
20965  * @cfg {String} value - the value of radio
20966  * 
20967  * @constructor
20968  * Create a new Radio
20969  * @param {Object} config The config object
20970  */
20971 Roo.bootstrap.Radio = function(config){
20972     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20973     
20974 };
20975
20976 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20977     
20978     boxLabel : '',
20979     
20980     value : '',
20981     
20982     getAutoCreate : function()
20983     {
20984         var cfg = {
20985             tag : 'div',
20986             cls : 'form-group radio',
20987             cn : [
20988                 {
20989                     tag : 'label',
20990                     cls : 'box-label',
20991                     html : this.boxLabel
20992                 }
20993             ]
20994         };
20995         
20996         return cfg;
20997     },
20998     
20999     initEvents : function() 
21000     {
21001         this.parent().register(this);
21002         
21003         this.el.on('click', this.onClick, this);
21004         
21005     },
21006     
21007     onClick : function(e)
21008     {
21009         if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21010             this.setChecked(true);
21011         }
21012     },
21013     
21014     setChecked : function(state, suppressEvent)
21015     {
21016         this.parent().setValue(this.value, suppressEvent);
21017         
21018     },
21019     
21020     setBoxLabel : function(v)
21021     {
21022         this.boxLabel = v;
21023         
21024         if(this.rendered){
21025             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21026         }
21027     }
21028     
21029 });
21030  
21031
21032  /*
21033  * - LGPL
21034  *
21035  * Input
21036  * 
21037  */
21038
21039 /**
21040  * @class Roo.bootstrap.SecurePass
21041  * @extends Roo.bootstrap.Input
21042  * Bootstrap SecurePass class
21043  *
21044  * 
21045  * @constructor
21046  * Create a new SecurePass
21047  * @param {Object} config The config object
21048  */
21049  
21050 Roo.bootstrap.SecurePass = function (config) {
21051     // these go here, so the translation tool can replace them..
21052     this.errors = {
21053         PwdEmpty: "Please type a password, and then retype it to confirm.",
21054         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21055         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21056         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21057         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21058         FNInPwd: "Your password can't contain your first name. Please type a different password.",
21059         LNInPwd: "Your password can't contain your last name. Please type a different password.",
21060         TooWeak: "Your password is Too Weak."
21061     },
21062     this.meterLabel = "Password strength:";
21063     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21064     this.meterClass = [
21065         "roo-password-meter-tooweak", 
21066         "roo-password-meter-weak", 
21067         "roo-password-meter-medium", 
21068         "roo-password-meter-strong", 
21069         "roo-password-meter-grey"
21070     ];
21071     
21072     this.errors = {};
21073     
21074     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21075 }
21076
21077 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21078     /**
21079      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21080      * {
21081      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
21082      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21083      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21084      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21085      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21086      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
21087      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
21088      * })
21089      */
21090     // private
21091     
21092     meterWidth: 300,
21093     errorMsg :'',    
21094     errors: false,
21095     imageRoot: '/',
21096     /**
21097      * @cfg {String/Object} Label for the strength meter (defaults to
21098      * 'Password strength:')
21099      */
21100     // private
21101     meterLabel: '',
21102     /**
21103      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21104      * ['Weak', 'Medium', 'Strong'])
21105      */
21106     // private    
21107     pwdStrengths: false,    
21108     // private
21109     strength: 0,
21110     // private
21111     _lastPwd: null,
21112     // private
21113     kCapitalLetter: 0,
21114     kSmallLetter: 1,
21115     kDigit: 2,
21116     kPunctuation: 3,
21117     
21118     insecure: false,
21119     // private
21120     initEvents: function ()
21121     {
21122         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21123
21124         if (this.el.is('input[type=password]') && Roo.isSafari) {
21125             this.el.on('keydown', this.SafariOnKeyDown, this);
21126         }
21127
21128         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21129     },
21130     // private
21131     onRender: function (ct, position)
21132     {
21133         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21134         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21135         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21136
21137         this.trigger.createChild({
21138                    cn: [
21139                     {
21140                     //id: 'PwdMeter',
21141                     tag: 'div',
21142                     cls: 'roo-password-meter-grey col-xs-12',
21143                     style: {
21144                         //width: 0,
21145                         //width: this.meterWidth + 'px'                                                
21146                         }
21147                     },
21148                     {                            
21149                          cls: 'roo-password-meter-text'                          
21150                     }
21151                 ]            
21152         });
21153
21154          
21155         if (this.hideTrigger) {
21156             this.trigger.setDisplayed(false);
21157         }
21158         this.setSize(this.width || '', this.height || '');
21159     },
21160     // private
21161     onDestroy: function ()
21162     {
21163         if (this.trigger) {
21164             this.trigger.removeAllListeners();
21165             this.trigger.remove();
21166         }
21167         if (this.wrap) {
21168             this.wrap.remove();
21169         }
21170         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21171     },
21172     // private
21173     checkStrength: function ()
21174     {
21175         var pwd = this.inputEl().getValue();
21176         if (pwd == this._lastPwd) {
21177             return;
21178         }
21179
21180         var strength;
21181         if (this.ClientSideStrongPassword(pwd)) {
21182             strength = 3;
21183         } else if (this.ClientSideMediumPassword(pwd)) {
21184             strength = 2;
21185         } else if (this.ClientSideWeakPassword(pwd)) {
21186             strength = 1;
21187         } else {
21188             strength = 0;
21189         }
21190         
21191         Roo.log('strength1: ' + strength);
21192         
21193         //var pm = this.trigger.child('div/div/div').dom;
21194         var pm = this.trigger.child('div/div');
21195         pm.removeClass(this.meterClass);
21196         pm.addClass(this.meterClass[strength]);
21197                 
21198         
21199         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21200                 
21201         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21202         
21203         this._lastPwd = pwd;
21204     },
21205     reset: function ()
21206     {
21207         Roo.bootstrap.SecurePass.superclass.reset.call(this);
21208         
21209         this._lastPwd = '';
21210         
21211         var pm = this.trigger.child('div/div');
21212         pm.removeClass(this.meterClass);
21213         pm.addClass('roo-password-meter-grey');        
21214         
21215         
21216         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21217         
21218         pt.innerHTML = '';
21219         this.inputEl().dom.type='password';
21220     },
21221     // private
21222     validateValue: function (value)
21223     {
21224         
21225         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21226             return false;
21227         }
21228         if (value.length == 0) {
21229             if (this.allowBlank) {
21230                 this.clearInvalid();
21231                 return true;
21232             }
21233
21234             this.markInvalid(this.errors.PwdEmpty);
21235             this.errorMsg = this.errors.PwdEmpty;
21236             return false;
21237         }
21238         
21239         if(this.insecure){
21240             return true;
21241         }
21242         
21243         if ('[\x21-\x7e]*'.match(value)) {
21244             this.markInvalid(this.errors.PwdBadChar);
21245             this.errorMsg = this.errors.PwdBadChar;
21246             return false;
21247         }
21248         if (value.length < 6) {
21249             this.markInvalid(this.errors.PwdShort);
21250             this.errorMsg = this.errors.PwdShort;
21251             return false;
21252         }
21253         if (value.length > 16) {
21254             this.markInvalid(this.errors.PwdLong);
21255             this.errorMsg = this.errors.PwdLong;
21256             return false;
21257         }
21258         var strength;
21259         if (this.ClientSideStrongPassword(value)) {
21260             strength = 3;
21261         } else if (this.ClientSideMediumPassword(value)) {
21262             strength = 2;
21263         } else if (this.ClientSideWeakPassword(value)) {
21264             strength = 1;
21265         } else {
21266             strength = 0;
21267         }
21268
21269         
21270         if (strength < 2) {
21271             //this.markInvalid(this.errors.TooWeak);
21272             this.errorMsg = this.errors.TooWeak;
21273             //return false;
21274         }
21275         
21276         
21277         console.log('strength2: ' + strength);
21278         
21279         //var pm = this.trigger.child('div/div/div').dom;
21280         
21281         var pm = this.trigger.child('div/div');
21282         pm.removeClass(this.meterClass);
21283         pm.addClass(this.meterClass[strength]);
21284                 
21285         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21286                 
21287         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21288         
21289         this.errorMsg = ''; 
21290         return true;
21291     },
21292     // private
21293     CharacterSetChecks: function (type)
21294     {
21295         this.type = type;
21296         this.fResult = false;
21297     },
21298     // private
21299     isctype: function (character, type)
21300     {
21301         switch (type) {  
21302             case this.kCapitalLetter:
21303                 if (character >= 'A' && character <= 'Z') {
21304                     return true;
21305                 }
21306                 break;
21307             
21308             case this.kSmallLetter:
21309                 if (character >= 'a' && character <= 'z') {
21310                     return true;
21311                 }
21312                 break;
21313             
21314             case this.kDigit:
21315                 if (character >= '0' && character <= '9') {
21316                     return true;
21317                 }
21318                 break;
21319             
21320             case this.kPunctuation:
21321                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21322                     return true;
21323                 }
21324                 break;
21325             
21326             default:
21327                 return false;
21328         }
21329
21330     },
21331     // private
21332     IsLongEnough: function (pwd, size)
21333     {
21334         return !(pwd == null || isNaN(size) || pwd.length < size);
21335     },
21336     // private
21337     SpansEnoughCharacterSets: function (word, nb)
21338     {
21339         if (!this.IsLongEnough(word, nb))
21340         {
21341             return false;
21342         }
21343
21344         var characterSetChecks = new Array(
21345             new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21346             new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21347         );
21348         
21349         for (var index = 0; index < word.length; ++index) {
21350             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21351                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21352                     characterSetChecks[nCharSet].fResult = true;
21353                     break;
21354                 }
21355             }
21356         }
21357
21358         var nCharSets = 0;
21359         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21360             if (characterSetChecks[nCharSet].fResult) {
21361                 ++nCharSets;
21362             }
21363         }
21364
21365         if (nCharSets < nb) {
21366             return false;
21367         }
21368         return true;
21369     },
21370     // private
21371     ClientSideStrongPassword: function (pwd)
21372     {
21373         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21374     },
21375     // private
21376     ClientSideMediumPassword: function (pwd)
21377     {
21378         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21379     },
21380     // private
21381     ClientSideWeakPassword: function (pwd)
21382     {
21383         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21384     }
21385           
21386 })//<script type="text/javascript">
21387
21388 /*
21389  * Based  Ext JS Library 1.1.1
21390  * Copyright(c) 2006-2007, Ext JS, LLC.
21391  * LGPL
21392  *
21393  */
21394  
21395 /**
21396  * @class Roo.HtmlEditorCore
21397  * @extends Roo.Component
21398  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21399  *
21400  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21401  */
21402
21403 Roo.HtmlEditorCore = function(config){
21404     
21405     
21406     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21407     
21408     
21409     this.addEvents({
21410         /**
21411          * @event initialize
21412          * Fires when the editor is fully initialized (including the iframe)
21413          * @param {Roo.HtmlEditorCore} this
21414          */
21415         initialize: true,
21416         /**
21417          * @event activate
21418          * Fires when the editor is first receives the focus. Any insertion must wait
21419          * until after this event.
21420          * @param {Roo.HtmlEditorCore} this
21421          */
21422         activate: true,
21423          /**
21424          * @event beforesync
21425          * Fires before the textarea is updated with content from the editor iframe. Return false
21426          * to cancel the sync.
21427          * @param {Roo.HtmlEditorCore} this
21428          * @param {String} html
21429          */
21430         beforesync: true,
21431          /**
21432          * @event beforepush
21433          * Fires before the iframe editor is updated with content from the textarea. Return false
21434          * to cancel the push.
21435          * @param {Roo.HtmlEditorCore} this
21436          * @param {String} html
21437          */
21438         beforepush: true,
21439          /**
21440          * @event sync
21441          * Fires when the textarea is updated with content from the editor iframe.
21442          * @param {Roo.HtmlEditorCore} this
21443          * @param {String} html
21444          */
21445         sync: true,
21446          /**
21447          * @event push
21448          * Fires when the iframe editor is updated with content from the textarea.
21449          * @param {Roo.HtmlEditorCore} this
21450          * @param {String} html
21451          */
21452         push: true,
21453         
21454         /**
21455          * @event editorevent
21456          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21457          * @param {Roo.HtmlEditorCore} this
21458          */
21459         editorevent: true
21460         
21461     });
21462     
21463     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21464     
21465     // defaults : white / black...
21466     this.applyBlacklists();
21467     
21468     
21469     
21470 };
21471
21472
21473 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
21474
21475
21476      /**
21477      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
21478      */
21479     
21480     owner : false,
21481     
21482      /**
21483      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
21484      *                        Roo.resizable.
21485      */
21486     resizable : false,
21487      /**
21488      * @cfg {Number} height (in pixels)
21489      */   
21490     height: 300,
21491    /**
21492      * @cfg {Number} width (in pixels)
21493      */   
21494     width: 500,
21495     
21496     /**
21497      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21498      * 
21499      */
21500     stylesheets: false,
21501     
21502     // id of frame..
21503     frameId: false,
21504     
21505     // private properties
21506     validationEvent : false,
21507     deferHeight: true,
21508     initialized : false,
21509     activated : false,
21510     sourceEditMode : false,
21511     onFocus : Roo.emptyFn,
21512     iframePad:3,
21513     hideMode:'offsets',
21514     
21515     clearUp: true,
21516     
21517     // blacklist + whitelisted elements..
21518     black: false,
21519     white: false,
21520      
21521     bodyCls : '',
21522
21523     /**
21524      * Protected method that will not generally be called directly. It
21525      * is called when the editor initializes the iframe with HTML contents. Override this method if you
21526      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21527      */
21528     getDocMarkup : function(){
21529         // body styles..
21530         var st = '';
21531         
21532         // inherit styels from page...?? 
21533         if (this.stylesheets === false) {
21534             
21535             Roo.get(document.head).select('style').each(function(node) {
21536                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21537             });
21538             
21539             Roo.get(document.head).select('link').each(function(node) { 
21540                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21541             });
21542             
21543         } else if (!this.stylesheets.length) {
21544                 // simple..
21545                 st = '<style type="text/css">' +
21546                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21547                    '</style>';
21548         } else { 
21549             st = '<style type="text/css">' +
21550                     this.stylesheets +
21551                 '</style>';
21552         }
21553         
21554         st +=  '<style type="text/css">' +
21555             'IMG { cursor: pointer } ' +
21556         '</style>';
21557
21558         var cls = 'roo-htmleditor-body';
21559         
21560         if(this.bodyCls.length){
21561             cls += ' ' + this.bodyCls;
21562         }
21563         
21564         return '<html><head>' + st  +
21565             //<style type="text/css">' +
21566             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21567             //'</style>' +
21568             ' </head><body class="' +  cls + '"></body></html>';
21569     },
21570
21571     // private
21572     onRender : function(ct, position)
21573     {
21574         var _t = this;
21575         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21576         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21577         
21578         
21579         this.el.dom.style.border = '0 none';
21580         this.el.dom.setAttribute('tabIndex', -1);
21581         this.el.addClass('x-hidden hide');
21582         
21583         
21584         
21585         if(Roo.isIE){ // fix IE 1px bogus margin
21586             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21587         }
21588        
21589         
21590         this.frameId = Roo.id();
21591         
21592          
21593         
21594         var iframe = this.owner.wrap.createChild({
21595             tag: 'iframe',
21596             cls: 'form-control', // bootstrap..
21597             id: this.frameId,
21598             name: this.frameId,
21599             frameBorder : 'no',
21600             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
21601         }, this.el
21602         );
21603         
21604         
21605         this.iframe = iframe.dom;
21606
21607          this.assignDocWin();
21608         
21609         this.doc.designMode = 'on';
21610        
21611         this.doc.open();
21612         this.doc.write(this.getDocMarkup());
21613         this.doc.close();
21614
21615         
21616         var task = { // must defer to wait for browser to be ready
21617             run : function(){
21618                 //console.log("run task?" + this.doc.readyState);
21619                 this.assignDocWin();
21620                 if(this.doc.body || this.doc.readyState == 'complete'){
21621                     try {
21622                         this.doc.designMode="on";
21623                     } catch (e) {
21624                         return;
21625                     }
21626                     Roo.TaskMgr.stop(task);
21627                     this.initEditor.defer(10, this);
21628                 }
21629             },
21630             interval : 10,
21631             duration: 10000,
21632             scope: this
21633         };
21634         Roo.TaskMgr.start(task);
21635
21636     },
21637
21638     // private
21639     onResize : function(w, h)
21640     {
21641          Roo.log('resize: ' +w + ',' + h );
21642         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21643         if(!this.iframe){
21644             return;
21645         }
21646         if(typeof w == 'number'){
21647             
21648             this.iframe.style.width = w + 'px';
21649         }
21650         if(typeof h == 'number'){
21651             
21652             this.iframe.style.height = h + 'px';
21653             if(this.doc){
21654                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21655             }
21656         }
21657         
21658     },
21659
21660     /**
21661      * Toggles the editor between standard and source edit mode.
21662      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21663      */
21664     toggleSourceEdit : function(sourceEditMode){
21665         
21666         this.sourceEditMode = sourceEditMode === true;
21667         
21668         if(this.sourceEditMode){
21669  
21670             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
21671             
21672         }else{
21673             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21674             //this.iframe.className = '';
21675             this.deferFocus();
21676         }
21677         //this.setSize(this.owner.wrap.getSize());
21678         //this.fireEvent('editmodechange', this, this.sourceEditMode);
21679     },
21680
21681     
21682   
21683
21684     /**
21685      * Protected method that will not generally be called directly. If you need/want
21686      * custom HTML cleanup, this is the method you should override.
21687      * @param {String} html The HTML to be cleaned
21688      * return {String} The cleaned HTML
21689      */
21690     cleanHtml : function(html){
21691         html = String(html);
21692         if(html.length > 5){
21693             if(Roo.isSafari){ // strip safari nonsense
21694                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21695             }
21696         }
21697         if(html == '&nbsp;'){
21698             html = '';
21699         }
21700         return html;
21701     },
21702
21703     /**
21704      * HTML Editor -> Textarea
21705      * Protected method that will not generally be called directly. Syncs the contents
21706      * of the editor iframe with the textarea.
21707      */
21708     syncValue : function(){
21709         if(this.initialized){
21710             var bd = (this.doc.body || this.doc.documentElement);
21711             //this.cleanUpPaste(); -- this is done else where and causes havoc..
21712             var html = bd.innerHTML;
21713             if(Roo.isSafari){
21714                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21715                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21716                 if(m && m[1]){
21717                     html = '<div style="'+m[0]+'">' + html + '</div>';
21718                 }
21719             }
21720             html = this.cleanHtml(html);
21721             // fix up the special chars.. normaly like back quotes in word...
21722             // however we do not want to do this with chinese..
21723             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21724                 var cc = b.charCodeAt();
21725                 if (
21726                     (cc >= 0x4E00 && cc < 0xA000 ) ||
21727                     (cc >= 0x3400 && cc < 0x4E00 ) ||
21728                     (cc >= 0xf900 && cc < 0xfb00 )
21729                 ) {
21730                         return b;
21731                 }
21732                 return "&#"+cc+";" 
21733             });
21734             if(this.owner.fireEvent('beforesync', this, html) !== false){
21735                 this.el.dom.value = html;
21736                 this.owner.fireEvent('sync', this, html);
21737             }
21738         }
21739     },
21740
21741     /**
21742      * Protected method that will not generally be called directly. Pushes the value of the textarea
21743      * into the iframe editor.
21744      */
21745     pushValue : function(){
21746         if(this.initialized){
21747             var v = this.el.dom.value.trim();
21748             
21749 //            if(v.length < 1){
21750 //                v = '&#160;';
21751 //            }
21752             
21753             if(this.owner.fireEvent('beforepush', this, v) !== false){
21754                 var d = (this.doc.body || this.doc.documentElement);
21755                 d.innerHTML = v;
21756                 this.cleanUpPaste();
21757                 this.el.dom.value = d.innerHTML;
21758                 this.owner.fireEvent('push', this, v);
21759             }
21760         }
21761     },
21762
21763     // private
21764     deferFocus : function(){
21765         this.focus.defer(10, this);
21766     },
21767
21768     // doc'ed in Field
21769     focus : function(){
21770         if(this.win && !this.sourceEditMode){
21771             this.win.focus();
21772         }else{
21773             this.el.focus();
21774         }
21775     },
21776     
21777     assignDocWin: function()
21778     {
21779         var iframe = this.iframe;
21780         
21781          if(Roo.isIE){
21782             this.doc = iframe.contentWindow.document;
21783             this.win = iframe.contentWindow;
21784         } else {
21785 //            if (!Roo.get(this.frameId)) {
21786 //                return;
21787 //            }
21788 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21789 //            this.win = Roo.get(this.frameId).dom.contentWindow;
21790             
21791             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21792                 return;
21793             }
21794             
21795             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21796             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21797         }
21798     },
21799     
21800     // private
21801     initEditor : function(){
21802         //console.log("INIT EDITOR");
21803         this.assignDocWin();
21804         
21805         
21806         
21807         this.doc.designMode="on";
21808         this.doc.open();
21809         this.doc.write(this.getDocMarkup());
21810         this.doc.close();
21811         
21812         var dbody = (this.doc.body || this.doc.documentElement);
21813         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21814         // this copies styles from the containing element into thsi one..
21815         // not sure why we need all of this..
21816         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21817         
21818         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21819         //ss['background-attachment'] = 'fixed'; // w3c
21820         dbody.bgProperties = 'fixed'; // ie
21821         //Roo.DomHelper.applyStyles(dbody, ss);
21822         Roo.EventManager.on(this.doc, {
21823             //'mousedown': this.onEditorEvent,
21824             'mouseup': this.onEditorEvent,
21825             'dblclick': this.onEditorEvent,
21826             'click': this.onEditorEvent,
21827             'keyup': this.onEditorEvent,
21828             buffer:100,
21829             scope: this
21830         });
21831         if(Roo.isGecko){
21832             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21833         }
21834         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21835             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21836         }
21837         this.initialized = true;
21838
21839         this.owner.fireEvent('initialize', this);
21840         this.pushValue();
21841     },
21842
21843     // private
21844     onDestroy : function(){
21845         
21846         
21847         
21848         if(this.rendered){
21849             
21850             //for (var i =0; i < this.toolbars.length;i++) {
21851             //    // fixme - ask toolbars for heights?
21852             //    this.toolbars[i].onDestroy();
21853            // }
21854             
21855             //this.wrap.dom.innerHTML = '';
21856             //this.wrap.remove();
21857         }
21858     },
21859
21860     // private
21861     onFirstFocus : function(){
21862         
21863         this.assignDocWin();
21864         
21865         
21866         this.activated = true;
21867          
21868     
21869         if(Roo.isGecko){ // prevent silly gecko errors
21870             this.win.focus();
21871             var s = this.win.getSelection();
21872             if(!s.focusNode || s.focusNode.nodeType != 3){
21873                 var r = s.getRangeAt(0);
21874                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21875                 r.collapse(true);
21876                 this.deferFocus();
21877             }
21878             try{
21879                 this.execCmd('useCSS', true);
21880                 this.execCmd('styleWithCSS', false);
21881             }catch(e){}
21882         }
21883         this.owner.fireEvent('activate', this);
21884     },
21885
21886     // private
21887     adjustFont: function(btn){
21888         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21889         //if(Roo.isSafari){ // safari
21890         //    adjust *= 2;
21891        // }
21892         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21893         if(Roo.isSafari){ // safari
21894             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21895             v =  (v < 10) ? 10 : v;
21896             v =  (v > 48) ? 48 : v;
21897             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21898             
21899         }
21900         
21901         
21902         v = Math.max(1, v+adjust);
21903         
21904         this.execCmd('FontSize', v  );
21905     },
21906
21907     onEditorEvent : function(e)
21908     {
21909         this.owner.fireEvent('editorevent', this, e);
21910       //  this.updateToolbar();
21911         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21912     },
21913
21914     insertTag : function(tg)
21915     {
21916         // could be a bit smarter... -> wrap the current selected tRoo..
21917         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21918             
21919             range = this.createRange(this.getSelection());
21920             var wrappingNode = this.doc.createElement(tg.toLowerCase());
21921             wrappingNode.appendChild(range.extractContents());
21922             range.insertNode(wrappingNode);
21923
21924             return;
21925             
21926             
21927             
21928         }
21929         this.execCmd("formatblock",   tg);
21930         
21931     },
21932     
21933     insertText : function(txt)
21934     {
21935         
21936         
21937         var range = this.createRange();
21938         range.deleteContents();
21939                //alert(Sender.getAttribute('label'));
21940                
21941         range.insertNode(this.doc.createTextNode(txt));
21942     } ,
21943     
21944      
21945
21946     /**
21947      * Executes a Midas editor command on the editor document and performs necessary focus and
21948      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21949      * @param {String} cmd The Midas command
21950      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21951      */
21952     relayCmd : function(cmd, value){
21953         this.win.focus();
21954         this.execCmd(cmd, value);
21955         this.owner.fireEvent('editorevent', this);
21956         //this.updateToolbar();
21957         this.owner.deferFocus();
21958     },
21959
21960     /**
21961      * Executes a Midas editor command directly on the editor document.
21962      * For visual commands, you should use {@link #relayCmd} instead.
21963      * <b>This should only be called after the editor is initialized.</b>
21964      * @param {String} cmd The Midas command
21965      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21966      */
21967     execCmd : function(cmd, value){
21968         this.doc.execCommand(cmd, false, value === undefined ? null : value);
21969         this.syncValue();
21970     },
21971  
21972  
21973    
21974     /**
21975      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21976      * to insert tRoo.
21977      * @param {String} text | dom node.. 
21978      */
21979     insertAtCursor : function(text)
21980     {
21981         
21982         if(!this.activated){
21983             return;
21984         }
21985         /*
21986         if(Roo.isIE){
21987             this.win.focus();
21988             var r = this.doc.selection.createRange();
21989             if(r){
21990                 r.collapse(true);
21991                 r.pasteHTML(text);
21992                 this.syncValue();
21993                 this.deferFocus();
21994             
21995             }
21996             return;
21997         }
21998         */
21999         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22000             this.win.focus();
22001             
22002             
22003             // from jquery ui (MIT licenced)
22004             var range, node;
22005             var win = this.win;
22006             
22007             if (win.getSelection && win.getSelection().getRangeAt) {
22008                 range = win.getSelection().getRangeAt(0);
22009                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22010                 range.insertNode(node);
22011             } else if (win.document.selection && win.document.selection.createRange) {
22012                 // no firefox support
22013                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22014                 win.document.selection.createRange().pasteHTML(txt);
22015             } else {
22016                 // no firefox support
22017                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22018                 this.execCmd('InsertHTML', txt);
22019             } 
22020             
22021             this.syncValue();
22022             
22023             this.deferFocus();
22024         }
22025     },
22026  // private
22027     mozKeyPress : function(e){
22028         if(e.ctrlKey){
22029             var c = e.getCharCode(), cmd;
22030           
22031             if(c > 0){
22032                 c = String.fromCharCode(c).toLowerCase();
22033                 switch(c){
22034                     case 'b':
22035                         cmd = 'bold';
22036                         break;
22037                     case 'i':
22038                         cmd = 'italic';
22039                         break;
22040                     
22041                     case 'u':
22042                         cmd = 'underline';
22043                         break;
22044                     
22045                     case 'v':
22046                         this.cleanUpPaste.defer(100, this);
22047                         return;
22048                         
22049                 }
22050                 if(cmd){
22051                     this.win.focus();
22052                     this.execCmd(cmd);
22053                     this.deferFocus();
22054                     e.preventDefault();
22055                 }
22056                 
22057             }
22058         }
22059     },
22060
22061     // private
22062     fixKeys : function(){ // load time branching for fastest keydown performance
22063         if(Roo.isIE){
22064             return function(e){
22065                 var k = e.getKey(), r;
22066                 if(k == e.TAB){
22067                     e.stopEvent();
22068                     r = this.doc.selection.createRange();
22069                     if(r){
22070                         r.collapse(true);
22071                         r.pasteHTML('&#160;&#160;&#160;&#160;');
22072                         this.deferFocus();
22073                     }
22074                     return;
22075                 }
22076                 
22077                 if(k == e.ENTER){
22078                     r = this.doc.selection.createRange();
22079                     if(r){
22080                         var target = r.parentElement();
22081                         if(!target || target.tagName.toLowerCase() != 'li'){
22082                             e.stopEvent();
22083                             r.pasteHTML('<br />');
22084                             r.collapse(false);
22085                             r.select();
22086                         }
22087                     }
22088                 }
22089                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22090                     this.cleanUpPaste.defer(100, this);
22091                     return;
22092                 }
22093                 
22094                 
22095             };
22096         }else if(Roo.isOpera){
22097             return function(e){
22098                 var k = e.getKey();
22099                 if(k == e.TAB){
22100                     e.stopEvent();
22101                     this.win.focus();
22102                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
22103                     this.deferFocus();
22104                 }
22105                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22106                     this.cleanUpPaste.defer(100, this);
22107                     return;
22108                 }
22109                 
22110             };
22111         }else if(Roo.isSafari){
22112             return function(e){
22113                 var k = e.getKey();
22114                 
22115                 if(k == e.TAB){
22116                     e.stopEvent();
22117                     this.execCmd('InsertText','\t');
22118                     this.deferFocus();
22119                     return;
22120                 }
22121                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22122                     this.cleanUpPaste.defer(100, this);
22123                     return;
22124                 }
22125                 
22126              };
22127         }
22128     }(),
22129     
22130     getAllAncestors: function()
22131     {
22132         var p = this.getSelectedNode();
22133         var a = [];
22134         if (!p) {
22135             a.push(p); // push blank onto stack..
22136             p = this.getParentElement();
22137         }
22138         
22139         
22140         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22141             a.push(p);
22142             p = p.parentNode;
22143         }
22144         a.push(this.doc.body);
22145         return a;
22146     },
22147     lastSel : false,
22148     lastSelNode : false,
22149     
22150     
22151     getSelection : function() 
22152     {
22153         this.assignDocWin();
22154         return Roo.isIE ? this.doc.selection : this.win.getSelection();
22155     },
22156     
22157     getSelectedNode: function() 
22158     {
22159         // this may only work on Gecko!!!
22160         
22161         // should we cache this!!!!
22162         
22163         
22164         
22165          
22166         var range = this.createRange(this.getSelection()).cloneRange();
22167         
22168         if (Roo.isIE) {
22169             var parent = range.parentElement();
22170             while (true) {
22171                 var testRange = range.duplicate();
22172                 testRange.moveToElementText(parent);
22173                 if (testRange.inRange(range)) {
22174                     break;
22175                 }
22176                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22177                     break;
22178                 }
22179                 parent = parent.parentElement;
22180             }
22181             return parent;
22182         }
22183         
22184         // is ancestor a text element.
22185         var ac =  range.commonAncestorContainer;
22186         if (ac.nodeType == 3) {
22187             ac = ac.parentNode;
22188         }
22189         
22190         var ar = ac.childNodes;
22191          
22192         var nodes = [];
22193         var other_nodes = [];
22194         var has_other_nodes = false;
22195         for (var i=0;i<ar.length;i++) {
22196             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
22197                 continue;
22198             }
22199             // fullly contained node.
22200             
22201             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22202                 nodes.push(ar[i]);
22203                 continue;
22204             }
22205             
22206             // probably selected..
22207             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22208                 other_nodes.push(ar[i]);
22209                 continue;
22210             }
22211             // outer..
22212             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
22213                 continue;
22214             }
22215             
22216             
22217             has_other_nodes = true;
22218         }
22219         if (!nodes.length && other_nodes.length) {
22220             nodes= other_nodes;
22221         }
22222         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22223             return false;
22224         }
22225         
22226         return nodes[0];
22227     },
22228     createRange: function(sel)
22229     {
22230         // this has strange effects when using with 
22231         // top toolbar - not sure if it's a great idea.
22232         //this.editor.contentWindow.focus();
22233         if (typeof sel != "undefined") {
22234             try {
22235                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22236             } catch(e) {
22237                 return this.doc.createRange();
22238             }
22239         } else {
22240             return this.doc.createRange();
22241         }
22242     },
22243     getParentElement: function()
22244     {
22245         
22246         this.assignDocWin();
22247         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22248         
22249         var range = this.createRange(sel);
22250          
22251         try {
22252             var p = range.commonAncestorContainer;
22253             while (p.nodeType == 3) { // text node
22254                 p = p.parentNode;
22255             }
22256             return p;
22257         } catch (e) {
22258             return null;
22259         }
22260     
22261     },
22262     /***
22263      *
22264      * Range intersection.. the hard stuff...
22265      *  '-1' = before
22266      *  '0' = hits..
22267      *  '1' = after.
22268      *         [ -- selected range --- ]
22269      *   [fail]                        [fail]
22270      *
22271      *    basically..
22272      *      if end is before start or  hits it. fail.
22273      *      if start is after end or hits it fail.
22274      *
22275      *   if either hits (but other is outside. - then it's not 
22276      *   
22277      *    
22278      **/
22279     
22280     
22281     // @see http://www.thismuchiknow.co.uk/?p=64.
22282     rangeIntersectsNode : function(range, node)
22283     {
22284         var nodeRange = node.ownerDocument.createRange();
22285         try {
22286             nodeRange.selectNode(node);
22287         } catch (e) {
22288             nodeRange.selectNodeContents(node);
22289         }
22290     
22291         var rangeStartRange = range.cloneRange();
22292         rangeStartRange.collapse(true);
22293     
22294         var rangeEndRange = range.cloneRange();
22295         rangeEndRange.collapse(false);
22296     
22297         var nodeStartRange = nodeRange.cloneRange();
22298         nodeStartRange.collapse(true);
22299     
22300         var nodeEndRange = nodeRange.cloneRange();
22301         nodeEndRange.collapse(false);
22302     
22303         return rangeStartRange.compareBoundaryPoints(
22304                  Range.START_TO_START, nodeEndRange) == -1 &&
22305                rangeEndRange.compareBoundaryPoints(
22306                  Range.START_TO_START, nodeStartRange) == 1;
22307         
22308          
22309     },
22310     rangeCompareNode : function(range, node)
22311     {
22312         var nodeRange = node.ownerDocument.createRange();
22313         try {
22314             nodeRange.selectNode(node);
22315         } catch (e) {
22316             nodeRange.selectNodeContents(node);
22317         }
22318         
22319         
22320         range.collapse(true);
22321     
22322         nodeRange.collapse(true);
22323      
22324         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22325         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
22326          
22327         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22328         
22329         var nodeIsBefore   =  ss == 1;
22330         var nodeIsAfter    = ee == -1;
22331         
22332         if (nodeIsBefore && nodeIsAfter) {
22333             return 0; // outer
22334         }
22335         if (!nodeIsBefore && nodeIsAfter) {
22336             return 1; //right trailed.
22337         }
22338         
22339         if (nodeIsBefore && !nodeIsAfter) {
22340             return 2;  // left trailed.
22341         }
22342         // fully contined.
22343         return 3;
22344     },
22345
22346     // private? - in a new class?
22347     cleanUpPaste :  function()
22348     {
22349         // cleans up the whole document..
22350         Roo.log('cleanuppaste');
22351         
22352         this.cleanUpChildren(this.doc.body);
22353         var clean = this.cleanWordChars(this.doc.body.innerHTML);
22354         if (clean != this.doc.body.innerHTML) {
22355             this.doc.body.innerHTML = clean;
22356         }
22357         
22358     },
22359     
22360     cleanWordChars : function(input) {// change the chars to hex code
22361         var he = Roo.HtmlEditorCore;
22362         
22363         var output = input;
22364         Roo.each(he.swapCodes, function(sw) { 
22365             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22366             
22367             output = output.replace(swapper, sw[1]);
22368         });
22369         
22370         return output;
22371     },
22372     
22373     
22374     cleanUpChildren : function (n)
22375     {
22376         if (!n.childNodes.length) {
22377             return;
22378         }
22379         for (var i = n.childNodes.length-1; i > -1 ; i--) {
22380            this.cleanUpChild(n.childNodes[i]);
22381         }
22382     },
22383     
22384     
22385         
22386     
22387     cleanUpChild : function (node)
22388     {
22389         var ed = this;
22390         //console.log(node);
22391         if (node.nodeName == "#text") {
22392             // clean up silly Windows -- stuff?
22393             return; 
22394         }
22395         if (node.nodeName == "#comment") {
22396             node.parentNode.removeChild(node);
22397             // clean up silly Windows -- stuff?
22398             return; 
22399         }
22400         var lcname = node.tagName.toLowerCase();
22401         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22402         // whitelist of tags..
22403         
22404         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22405             // remove node.
22406             node.parentNode.removeChild(node);
22407             return;
22408             
22409         }
22410         
22411         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22412         
22413         // remove <a name=....> as rendering on yahoo mailer is borked with this.
22414         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22415         
22416         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22417         //    remove_keep_children = true;
22418         //}
22419         
22420         if (remove_keep_children) {
22421             this.cleanUpChildren(node);
22422             // inserts everything just before this node...
22423             while (node.childNodes.length) {
22424                 var cn = node.childNodes[0];
22425                 node.removeChild(cn);
22426                 node.parentNode.insertBefore(cn, node);
22427             }
22428             node.parentNode.removeChild(node);
22429             return;
22430         }
22431         
22432         if (!node.attributes || !node.attributes.length) {
22433             this.cleanUpChildren(node);
22434             return;
22435         }
22436         
22437         function cleanAttr(n,v)
22438         {
22439             
22440             if (v.match(/^\./) || v.match(/^\//)) {
22441                 return;
22442             }
22443             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22444                 return;
22445             }
22446             if (v.match(/^#/)) {
22447                 return;
22448             }
22449 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22450             node.removeAttribute(n);
22451             
22452         }
22453         
22454         var cwhite = this.cwhite;
22455         var cblack = this.cblack;
22456             
22457         function cleanStyle(n,v)
22458         {
22459             if (v.match(/expression/)) { //XSS?? should we even bother..
22460                 node.removeAttribute(n);
22461                 return;
22462             }
22463             
22464             var parts = v.split(/;/);
22465             var clean = [];
22466             
22467             Roo.each(parts, function(p) {
22468                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22469                 if (!p.length) {
22470                     return true;
22471                 }
22472                 var l = p.split(':').shift().replace(/\s+/g,'');
22473                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22474                 
22475                 if ( cwhite.length && cblack.indexOf(l) > -1) {
22476 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22477                     //node.removeAttribute(n);
22478                     return true;
22479                 }
22480                 //Roo.log()
22481                 // only allow 'c whitelisted system attributes'
22482                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
22483 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22484                     //node.removeAttribute(n);
22485                     return true;
22486                 }
22487                 
22488                 
22489                  
22490                 
22491                 clean.push(p);
22492                 return true;
22493             });
22494             if (clean.length) { 
22495                 node.setAttribute(n, clean.join(';'));
22496             } else {
22497                 node.removeAttribute(n);
22498             }
22499             
22500         }
22501         
22502         
22503         for (var i = node.attributes.length-1; i > -1 ; i--) {
22504             var a = node.attributes[i];
22505             //console.log(a);
22506             
22507             if (a.name.toLowerCase().substr(0,2)=='on')  {
22508                 node.removeAttribute(a.name);
22509                 continue;
22510             }
22511             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22512                 node.removeAttribute(a.name);
22513                 continue;
22514             }
22515             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22516                 cleanAttr(a.name,a.value); // fixme..
22517                 continue;
22518             }
22519             if (a.name == 'style') {
22520                 cleanStyle(a.name,a.value);
22521                 continue;
22522             }
22523             /// clean up MS crap..
22524             // tecnically this should be a list of valid class'es..
22525             
22526             
22527             if (a.name == 'class') {
22528                 if (a.value.match(/^Mso/)) {
22529                     node.className = '';
22530                 }
22531                 
22532                 if (a.value.match(/^body$/)) {
22533                     node.className = '';
22534                 }
22535                 continue;
22536             }
22537             
22538             // style cleanup!?
22539             // class cleanup?
22540             
22541         }
22542         
22543         
22544         this.cleanUpChildren(node);
22545         
22546         
22547     },
22548     
22549     /**
22550      * Clean up MS wordisms...
22551      */
22552     cleanWord : function(node)
22553     {
22554         
22555         
22556         if (!node) {
22557             this.cleanWord(this.doc.body);
22558             return;
22559         }
22560         if (node.nodeName == "#text") {
22561             // clean up silly Windows -- stuff?
22562             return; 
22563         }
22564         if (node.nodeName == "#comment") {
22565             node.parentNode.removeChild(node);
22566             // clean up silly Windows -- stuff?
22567             return; 
22568         }
22569         
22570         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22571             node.parentNode.removeChild(node);
22572             return;
22573         }
22574         
22575         // remove - but keep children..
22576         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22577             while (node.childNodes.length) {
22578                 var cn = node.childNodes[0];
22579                 node.removeChild(cn);
22580                 node.parentNode.insertBefore(cn, node);
22581             }
22582             node.parentNode.removeChild(node);
22583             this.iterateChildren(node, this.cleanWord);
22584             return;
22585         }
22586         // clean styles
22587         if (node.className.length) {
22588             
22589             var cn = node.className.split(/\W+/);
22590             var cna = [];
22591             Roo.each(cn, function(cls) {
22592                 if (cls.match(/Mso[a-zA-Z]+/)) {
22593                     return;
22594                 }
22595                 cna.push(cls);
22596             });
22597             node.className = cna.length ? cna.join(' ') : '';
22598             if (!cna.length) {
22599                 node.removeAttribute("class");
22600             }
22601         }
22602         
22603         if (node.hasAttribute("lang")) {
22604             node.removeAttribute("lang");
22605         }
22606         
22607         if (node.hasAttribute("style")) {
22608             
22609             var styles = node.getAttribute("style").split(";");
22610             var nstyle = [];
22611             Roo.each(styles, function(s) {
22612                 if (!s.match(/:/)) {
22613                     return;
22614                 }
22615                 var kv = s.split(":");
22616                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22617                     return;
22618                 }
22619                 // what ever is left... we allow.
22620                 nstyle.push(s);
22621             });
22622             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22623             if (!nstyle.length) {
22624                 node.removeAttribute('style');
22625             }
22626         }
22627         this.iterateChildren(node, this.cleanWord);
22628         
22629         
22630         
22631     },
22632     /**
22633      * iterateChildren of a Node, calling fn each time, using this as the scole..
22634      * @param {DomNode} node node to iterate children of.
22635      * @param {Function} fn method of this class to call on each item.
22636      */
22637     iterateChildren : function(node, fn)
22638     {
22639         if (!node.childNodes.length) {
22640                 return;
22641         }
22642         for (var i = node.childNodes.length-1; i > -1 ; i--) {
22643            fn.call(this, node.childNodes[i])
22644         }
22645     },
22646     
22647     
22648     /**
22649      * cleanTableWidths.
22650      *
22651      * Quite often pasting from word etc.. results in tables with column and widths.
22652      * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22653      *
22654      */
22655     cleanTableWidths : function(node)
22656     {
22657          
22658          
22659         if (!node) {
22660             this.cleanTableWidths(this.doc.body);
22661             return;
22662         }
22663         
22664         // ignore list...
22665         if (node.nodeName == "#text" || node.nodeName == "#comment") {
22666             return; 
22667         }
22668         Roo.log(node.tagName);
22669         if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22670             this.iterateChildren(node, this.cleanTableWidths);
22671             return;
22672         }
22673         if (node.hasAttribute('width')) {
22674             node.removeAttribute('width');
22675         }
22676         
22677          
22678         if (node.hasAttribute("style")) {
22679             // pretty basic...
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(/^\s*(width|min-width)\s*$/)) {
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         
22700         this.iterateChildren(node, this.cleanTableWidths);
22701         
22702         
22703     },
22704     
22705     
22706     
22707     
22708     domToHTML : function(currentElement, depth, nopadtext) {
22709         
22710         depth = depth || 0;
22711         nopadtext = nopadtext || false;
22712     
22713         if (!currentElement) {
22714             return this.domToHTML(this.doc.body);
22715         }
22716         
22717         //Roo.log(currentElement);
22718         var j;
22719         var allText = false;
22720         var nodeName = currentElement.nodeName;
22721         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22722         
22723         if  (nodeName == '#text') {
22724             
22725             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22726         }
22727         
22728         
22729         var ret = '';
22730         if (nodeName != 'BODY') {
22731              
22732             var i = 0;
22733             // Prints the node tagName, such as <A>, <IMG>, etc
22734             if (tagName) {
22735                 var attr = [];
22736                 for(i = 0; i < currentElement.attributes.length;i++) {
22737                     // quoting?
22738                     var aname = currentElement.attributes.item(i).name;
22739                     if (!currentElement.attributes.item(i).value.length) {
22740                         continue;
22741                     }
22742                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22743                 }
22744                 
22745                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22746             } 
22747             else {
22748                 
22749                 // eack
22750             }
22751         } else {
22752             tagName = false;
22753         }
22754         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22755             return ret;
22756         }
22757         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22758             nopadtext = true;
22759         }
22760         
22761         
22762         // Traverse the tree
22763         i = 0;
22764         var currentElementChild = currentElement.childNodes.item(i);
22765         var allText = true;
22766         var innerHTML  = '';
22767         lastnode = '';
22768         while (currentElementChild) {
22769             // Formatting code (indent the tree so it looks nice on the screen)
22770             var nopad = nopadtext;
22771             if (lastnode == 'SPAN') {
22772                 nopad  = true;
22773             }
22774             // text
22775             if  (currentElementChild.nodeName == '#text') {
22776                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22777                 toadd = nopadtext ? toadd : toadd.trim();
22778                 if (!nopad && toadd.length > 80) {
22779                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
22780                 }
22781                 innerHTML  += toadd;
22782                 
22783                 i++;
22784                 currentElementChild = currentElement.childNodes.item(i);
22785                 lastNode = '';
22786                 continue;
22787             }
22788             allText = false;
22789             
22790             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
22791                 
22792             // Recursively traverse the tree structure of the child node
22793             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
22794             lastnode = currentElementChild.nodeName;
22795             i++;
22796             currentElementChild=currentElement.childNodes.item(i);
22797         }
22798         
22799         ret += innerHTML;
22800         
22801         if (!allText) {
22802                 // The remaining code is mostly for formatting the tree
22803             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
22804         }
22805         
22806         
22807         if (tagName) {
22808             ret+= "</"+tagName+">";
22809         }
22810         return ret;
22811         
22812     },
22813         
22814     applyBlacklists : function()
22815     {
22816         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
22817         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
22818         
22819         this.white = [];
22820         this.black = [];
22821         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22822             if (b.indexOf(tag) > -1) {
22823                 return;
22824             }
22825             this.white.push(tag);
22826             
22827         }, this);
22828         
22829         Roo.each(w, function(tag) {
22830             if (b.indexOf(tag) > -1) {
22831                 return;
22832             }
22833             if (this.white.indexOf(tag) > -1) {
22834                 return;
22835             }
22836             this.white.push(tag);
22837             
22838         }, this);
22839         
22840         
22841         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22842             if (w.indexOf(tag) > -1) {
22843                 return;
22844             }
22845             this.black.push(tag);
22846             
22847         }, this);
22848         
22849         Roo.each(b, function(tag) {
22850             if (w.indexOf(tag) > -1) {
22851                 return;
22852             }
22853             if (this.black.indexOf(tag) > -1) {
22854                 return;
22855             }
22856             this.black.push(tag);
22857             
22858         }, this);
22859         
22860         
22861         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
22862         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
22863         
22864         this.cwhite = [];
22865         this.cblack = [];
22866         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22867             if (b.indexOf(tag) > -1) {
22868                 return;
22869             }
22870             this.cwhite.push(tag);
22871             
22872         }, this);
22873         
22874         Roo.each(w, function(tag) {
22875             if (b.indexOf(tag) > -1) {
22876                 return;
22877             }
22878             if (this.cwhite.indexOf(tag) > -1) {
22879                 return;
22880             }
22881             this.cwhite.push(tag);
22882             
22883         }, this);
22884         
22885         
22886         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22887             if (w.indexOf(tag) > -1) {
22888                 return;
22889             }
22890             this.cblack.push(tag);
22891             
22892         }, this);
22893         
22894         Roo.each(b, function(tag) {
22895             if (w.indexOf(tag) > -1) {
22896                 return;
22897             }
22898             if (this.cblack.indexOf(tag) > -1) {
22899                 return;
22900             }
22901             this.cblack.push(tag);
22902             
22903         }, this);
22904     },
22905     
22906     setStylesheets : function(stylesheets)
22907     {
22908         if(typeof(stylesheets) == 'string'){
22909             Roo.get(this.iframe.contentDocument.head).createChild({
22910                 tag : 'link',
22911                 rel : 'stylesheet',
22912                 type : 'text/css',
22913                 href : stylesheets
22914             });
22915             
22916             return;
22917         }
22918         var _this = this;
22919      
22920         Roo.each(stylesheets, function(s) {
22921             if(!s.length){
22922                 return;
22923             }
22924             
22925             Roo.get(_this.iframe.contentDocument.head).createChild({
22926                 tag : 'link',
22927                 rel : 'stylesheet',
22928                 type : 'text/css',
22929                 href : s
22930             });
22931         });
22932
22933         
22934     },
22935     
22936     removeStylesheets : function()
22937     {
22938         var _this = this;
22939         
22940         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22941             s.remove();
22942         });
22943     },
22944     
22945     setStyle : function(style)
22946     {
22947         Roo.get(this.iframe.contentDocument.head).createChild({
22948             tag : 'style',
22949             type : 'text/css',
22950             html : style
22951         });
22952
22953         return;
22954     }
22955     
22956     // hide stuff that is not compatible
22957     /**
22958      * @event blur
22959      * @hide
22960      */
22961     /**
22962      * @event change
22963      * @hide
22964      */
22965     /**
22966      * @event focus
22967      * @hide
22968      */
22969     /**
22970      * @event specialkey
22971      * @hide
22972      */
22973     /**
22974      * @cfg {String} fieldClass @hide
22975      */
22976     /**
22977      * @cfg {String} focusClass @hide
22978      */
22979     /**
22980      * @cfg {String} autoCreate @hide
22981      */
22982     /**
22983      * @cfg {String} inputType @hide
22984      */
22985     /**
22986      * @cfg {String} invalidClass @hide
22987      */
22988     /**
22989      * @cfg {String} invalidText @hide
22990      */
22991     /**
22992      * @cfg {String} msgFx @hide
22993      */
22994     /**
22995      * @cfg {String} validateOnBlur @hide
22996      */
22997 });
22998
22999 Roo.HtmlEditorCore.white = [
23000         'area', 'br', 'img', 'input', 'hr', 'wbr',
23001         
23002        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
23003        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
23004        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
23005        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
23006        'table',   'ul',         'xmp', 
23007        
23008        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
23009       'thead',   'tr', 
23010      
23011       'dir', 'menu', 'ol', 'ul', 'dl',
23012        
23013       'embed',  'object'
23014 ];
23015
23016
23017 Roo.HtmlEditorCore.black = [
23018     //    'embed',  'object', // enable - backend responsiblity to clean thiese
23019         'applet', // 
23020         'base',   'basefont', 'bgsound', 'blink',  'body', 
23021         'frame',  'frameset', 'head',    'html',   'ilayer', 
23022         'iframe', 'layer',  'link',     'meta',    'object',   
23023         'script', 'style' ,'title',  'xml' // clean later..
23024 ];
23025 Roo.HtmlEditorCore.clean = [
23026     'script', 'style', 'title', 'xml'
23027 ];
23028 Roo.HtmlEditorCore.remove = [
23029     'font'
23030 ];
23031 // attributes..
23032
23033 Roo.HtmlEditorCore.ablack = [
23034     'on'
23035 ];
23036     
23037 Roo.HtmlEditorCore.aclean = [ 
23038     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
23039 ];
23040
23041 // protocols..
23042 Roo.HtmlEditorCore.pwhite= [
23043         'http',  'https',  'mailto'
23044 ];
23045
23046 // white listed style attributes.
23047 Roo.HtmlEditorCore.cwhite= [
23048       //  'text-align', /// default is to allow most things..
23049       
23050          
23051 //        'font-size'//??
23052 ];
23053
23054 // black listed style attributes.
23055 Roo.HtmlEditorCore.cblack= [
23056       //  'font-size' -- this can be set by the project 
23057 ];
23058
23059
23060 Roo.HtmlEditorCore.swapCodes   =[ 
23061     [    8211, "--" ], 
23062     [    8212, "--" ], 
23063     [    8216,  "'" ],  
23064     [    8217, "'" ],  
23065     [    8220, '"' ],  
23066     [    8221, '"' ],  
23067     [    8226, "*" ],  
23068     [    8230, "..." ]
23069 ]; 
23070
23071     /*
23072  * - LGPL
23073  *
23074  * HtmlEditor
23075  * 
23076  */
23077
23078 /**
23079  * @class Roo.bootstrap.HtmlEditor
23080  * @extends Roo.bootstrap.TextArea
23081  * Bootstrap HtmlEditor class
23082
23083  * @constructor
23084  * Create a new HtmlEditor
23085  * @param {Object} config The config object
23086  */
23087
23088 Roo.bootstrap.HtmlEditor = function(config){
23089     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23090     if (!this.toolbars) {
23091         this.toolbars = [];
23092     }
23093     
23094     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23095     this.addEvents({
23096             /**
23097              * @event initialize
23098              * Fires when the editor is fully initialized (including the iframe)
23099              * @param {HtmlEditor} this
23100              */
23101             initialize: true,
23102             /**
23103              * @event activate
23104              * Fires when the editor is first receives the focus. Any insertion must wait
23105              * until after this event.
23106              * @param {HtmlEditor} this
23107              */
23108             activate: true,
23109              /**
23110              * @event beforesync
23111              * Fires before the textarea is updated with content from the editor iframe. Return false
23112              * to cancel the sync.
23113              * @param {HtmlEditor} this
23114              * @param {String} html
23115              */
23116             beforesync: true,
23117              /**
23118              * @event beforepush
23119              * Fires before the iframe editor is updated with content from the textarea. Return false
23120              * to cancel the push.
23121              * @param {HtmlEditor} this
23122              * @param {String} html
23123              */
23124             beforepush: true,
23125              /**
23126              * @event sync
23127              * Fires when the textarea is updated with content from the editor iframe.
23128              * @param {HtmlEditor} this
23129              * @param {String} html
23130              */
23131             sync: true,
23132              /**
23133              * @event push
23134              * Fires when the iframe editor is updated with content from the textarea.
23135              * @param {HtmlEditor} this
23136              * @param {String} html
23137              */
23138             push: true,
23139              /**
23140              * @event editmodechange
23141              * Fires when the editor switches edit modes
23142              * @param {HtmlEditor} this
23143              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23144              */
23145             editmodechange: true,
23146             /**
23147              * @event editorevent
23148              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23149              * @param {HtmlEditor} this
23150              */
23151             editorevent: true,
23152             /**
23153              * @event firstfocus
23154              * Fires when on first focus - needed by toolbars..
23155              * @param {HtmlEditor} this
23156              */
23157             firstfocus: true,
23158             /**
23159              * @event autosave
23160              * Auto save the htmlEditor value as a file into Events
23161              * @param {HtmlEditor} this
23162              */
23163             autosave: true,
23164             /**
23165              * @event savedpreview
23166              * preview the saved version of htmlEditor
23167              * @param {HtmlEditor} this
23168              */
23169             savedpreview: true
23170         });
23171 };
23172
23173
23174 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
23175     
23176     
23177       /**
23178      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23179      */
23180     toolbars : false,
23181     
23182      /**
23183     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23184     */
23185     btns : [],
23186    
23187      /**
23188      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
23189      *                        Roo.resizable.
23190      */
23191     resizable : false,
23192      /**
23193      * @cfg {Number} height (in pixels)
23194      */   
23195     height: 300,
23196    /**
23197      * @cfg {Number} width (in pixels)
23198      */   
23199     width: false,
23200     
23201     /**
23202      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23203      * 
23204      */
23205     stylesheets: false,
23206     
23207     // id of frame..
23208     frameId: false,
23209     
23210     // private properties
23211     validationEvent : false,
23212     deferHeight: true,
23213     initialized : false,
23214     activated : false,
23215     
23216     onFocus : Roo.emptyFn,
23217     iframePad:3,
23218     hideMode:'offsets',
23219     
23220     tbContainer : false,
23221     
23222     bodyCls : '',
23223     
23224     toolbarContainer :function() {
23225         return this.wrap.select('.x-html-editor-tb',true).first();
23226     },
23227
23228     /**
23229      * Protected method that will not generally be called directly. It
23230      * is called when the editor creates its toolbar. Override this method if you need to
23231      * add custom toolbar buttons.
23232      * @param {HtmlEditor} editor
23233      */
23234     createToolbar : function(){
23235         Roo.log('renewing');
23236         Roo.log("create toolbars");
23237         
23238         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23239         this.toolbars[0].render(this.toolbarContainer());
23240         
23241         return;
23242         
23243 //        if (!editor.toolbars || !editor.toolbars.length) {
23244 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23245 //        }
23246 //        
23247 //        for (var i =0 ; i < editor.toolbars.length;i++) {
23248 //            editor.toolbars[i] = Roo.factory(
23249 //                    typeof(editor.toolbars[i]) == 'string' ?
23250 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
23251 //                Roo.bootstrap.HtmlEditor);
23252 //            editor.toolbars[i].init(editor);
23253 //        }
23254     },
23255
23256      
23257     // private
23258     onRender : function(ct, position)
23259     {
23260        // Roo.log("Call onRender: " + this.xtype);
23261         var _t = this;
23262         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23263       
23264         this.wrap = this.inputEl().wrap({
23265             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23266         });
23267         
23268         this.editorcore.onRender(ct, position);
23269          
23270         if (this.resizable) {
23271             this.resizeEl = new Roo.Resizable(this.wrap, {
23272                 pinned : true,
23273                 wrap: true,
23274                 dynamic : true,
23275                 minHeight : this.height,
23276                 height: this.height,
23277                 handles : this.resizable,
23278                 width: this.width,
23279                 listeners : {
23280                     resize : function(r, w, h) {
23281                         _t.onResize(w,h); // -something
23282                     }
23283                 }
23284             });
23285             
23286         }
23287         this.createToolbar(this);
23288        
23289         
23290         if(!this.width && this.resizable){
23291             this.setSize(this.wrap.getSize());
23292         }
23293         if (this.resizeEl) {
23294             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23295             // should trigger onReize..
23296         }
23297         
23298     },
23299
23300     // private
23301     onResize : function(w, h)
23302     {
23303         Roo.log('resize: ' +w + ',' + h );
23304         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23305         var ew = false;
23306         var eh = false;
23307         
23308         if(this.inputEl() ){
23309             if(typeof w == 'number'){
23310                 var aw = w - this.wrap.getFrameWidth('lr');
23311                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23312                 ew = aw;
23313             }
23314             if(typeof h == 'number'){
23315                  var tbh = -11;  // fixme it needs to tool bar size!
23316                 for (var i =0; i < this.toolbars.length;i++) {
23317                     // fixme - ask toolbars for heights?
23318                     tbh += this.toolbars[i].el.getHeight();
23319                     //if (this.toolbars[i].footer) {
23320                     //    tbh += this.toolbars[i].footer.el.getHeight();
23321                     //}
23322                 }
23323               
23324                 
23325                 
23326                 
23327                 
23328                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23329                 ah -= 5; // knock a few pixes off for look..
23330                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23331                 var eh = ah;
23332             }
23333         }
23334         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23335         this.editorcore.onResize(ew,eh);
23336         
23337     },
23338
23339     /**
23340      * Toggles the editor between standard and source edit mode.
23341      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23342      */
23343     toggleSourceEdit : function(sourceEditMode)
23344     {
23345         this.editorcore.toggleSourceEdit(sourceEditMode);
23346         
23347         if(this.editorcore.sourceEditMode){
23348             Roo.log('editor - showing textarea');
23349             
23350 //            Roo.log('in');
23351 //            Roo.log(this.syncValue());
23352             this.syncValue();
23353             this.inputEl().removeClass(['hide', 'x-hidden']);
23354             this.inputEl().dom.removeAttribute('tabIndex');
23355             this.inputEl().focus();
23356         }else{
23357             Roo.log('editor - hiding textarea');
23358 //            Roo.log('out')
23359 //            Roo.log(this.pushValue()); 
23360             this.pushValue();
23361             
23362             this.inputEl().addClass(['hide', 'x-hidden']);
23363             this.inputEl().dom.setAttribute('tabIndex', -1);
23364             //this.deferFocus();
23365         }
23366          
23367         if(this.resizable){
23368             this.setSize(this.wrap.getSize());
23369         }
23370         
23371         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23372     },
23373  
23374     // private (for BoxComponent)
23375     adjustSize : Roo.BoxComponent.prototype.adjustSize,
23376
23377     // private (for BoxComponent)
23378     getResizeEl : function(){
23379         return this.wrap;
23380     },
23381
23382     // private (for BoxComponent)
23383     getPositionEl : function(){
23384         return this.wrap;
23385     },
23386
23387     // private
23388     initEvents : function(){
23389         this.originalValue = this.getValue();
23390     },
23391
23392 //    /**
23393 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23394 //     * @method
23395 //     */
23396 //    markInvalid : Roo.emptyFn,
23397 //    /**
23398 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23399 //     * @method
23400 //     */
23401 //    clearInvalid : Roo.emptyFn,
23402
23403     setValue : function(v){
23404         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23405         this.editorcore.pushValue();
23406     },
23407
23408      
23409     // private
23410     deferFocus : function(){
23411         this.focus.defer(10, this);
23412     },
23413
23414     // doc'ed in Field
23415     focus : function(){
23416         this.editorcore.focus();
23417         
23418     },
23419       
23420
23421     // private
23422     onDestroy : function(){
23423         
23424         
23425         
23426         if(this.rendered){
23427             
23428             for (var i =0; i < this.toolbars.length;i++) {
23429                 // fixme - ask toolbars for heights?
23430                 this.toolbars[i].onDestroy();
23431             }
23432             
23433             this.wrap.dom.innerHTML = '';
23434             this.wrap.remove();
23435         }
23436     },
23437
23438     // private
23439     onFirstFocus : function(){
23440         //Roo.log("onFirstFocus");
23441         this.editorcore.onFirstFocus();
23442          for (var i =0; i < this.toolbars.length;i++) {
23443             this.toolbars[i].onFirstFocus();
23444         }
23445         
23446     },
23447     
23448     // private
23449     syncValue : function()
23450     {   
23451         this.editorcore.syncValue();
23452     },
23453     
23454     pushValue : function()
23455     {   
23456         this.editorcore.pushValue();
23457     }
23458      
23459     
23460     // hide stuff that is not compatible
23461     /**
23462      * @event blur
23463      * @hide
23464      */
23465     /**
23466      * @event change
23467      * @hide
23468      */
23469     /**
23470      * @event focus
23471      * @hide
23472      */
23473     /**
23474      * @event specialkey
23475      * @hide
23476      */
23477     /**
23478      * @cfg {String} fieldClass @hide
23479      */
23480     /**
23481      * @cfg {String} focusClass @hide
23482      */
23483     /**
23484      * @cfg {String} autoCreate @hide
23485      */
23486     /**
23487      * @cfg {String} inputType @hide
23488      */
23489     /**
23490      * @cfg {String} invalidClass @hide
23491      */
23492     /**
23493      * @cfg {String} invalidText @hide
23494      */
23495     /**
23496      * @cfg {String} msgFx @hide
23497      */
23498     /**
23499      * @cfg {String} validateOnBlur @hide
23500      */
23501 });
23502  
23503     
23504    
23505    
23506    
23507       
23508 Roo.namespace('Roo.bootstrap.htmleditor');
23509 /**
23510  * @class Roo.bootstrap.HtmlEditorToolbar1
23511  * Basic Toolbar
23512  * 
23513  * Usage:
23514  *
23515  new Roo.bootstrap.HtmlEditor({
23516     ....
23517     toolbars : [
23518         new Roo.bootstrap.HtmlEditorToolbar1({
23519             disable : { fonts: 1 , format: 1, ..., ... , ...],
23520             btns : [ .... ]
23521         })
23522     }
23523      
23524  * 
23525  * @cfg {Object} disable List of elements to disable..
23526  * @cfg {Array} btns List of additional buttons.
23527  * 
23528  * 
23529  * NEEDS Extra CSS? 
23530  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23531  */
23532  
23533 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23534 {
23535     
23536     Roo.apply(this, config);
23537     
23538     // default disabled, based on 'good practice'..
23539     this.disable = this.disable || {};
23540     Roo.applyIf(this.disable, {
23541         fontSize : true,
23542         colors : true,
23543         specialElements : true
23544     });
23545     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23546     
23547     this.editor = config.editor;
23548     this.editorcore = config.editor.editorcore;
23549     
23550     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23551     
23552     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23553     // dont call parent... till later.
23554 }
23555 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
23556      
23557     bar : true,
23558     
23559     editor : false,
23560     editorcore : false,
23561     
23562     
23563     formats : [
23564         "p" ,  
23565         "h1","h2","h3","h4","h5","h6", 
23566         "pre", "code", 
23567         "abbr", "acronym", "address", "cite", "samp", "var",
23568         'div','span'
23569     ],
23570     
23571     onRender : function(ct, position)
23572     {
23573        // Roo.log("Call onRender: " + this.xtype);
23574         
23575        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23576        Roo.log(this.el);
23577        this.el.dom.style.marginBottom = '0';
23578        var _this = this;
23579        var editorcore = this.editorcore;
23580        var editor= this.editor;
23581        
23582        var children = [];
23583        var btn = function(id,cmd , toggle, handler, html){
23584        
23585             var  event = toggle ? 'toggle' : 'click';
23586        
23587             var a = {
23588                 size : 'sm',
23589                 xtype: 'Button',
23590                 xns: Roo.bootstrap,
23591                 glyphicon : id,
23592                 cmd : id || cmd,
23593                 enableToggle:toggle !== false,
23594                 html : html || '',
23595                 pressed : toggle ? false : null,
23596                 listeners : {}
23597             };
23598             a.listeners[toggle ? 'toggle' : 'click'] = function() {
23599                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
23600             };
23601             children.push(a);
23602             return a;
23603        }
23604        
23605     //    var cb_box = function...
23606         
23607         var style = {
23608                 xtype: 'Button',
23609                 size : 'sm',
23610                 xns: Roo.bootstrap,
23611                 glyphicon : 'font',
23612                 //html : 'submit'
23613                 menu : {
23614                     xtype: 'Menu',
23615                     xns: Roo.bootstrap,
23616                     items:  []
23617                 }
23618         };
23619         Roo.each(this.formats, function(f) {
23620             style.menu.items.push({
23621                 xtype :'MenuItem',
23622                 xns: Roo.bootstrap,
23623                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23624                 tagname : f,
23625                 listeners : {
23626                     click : function()
23627                     {
23628                         editorcore.insertTag(this.tagname);
23629                         editor.focus();
23630                     }
23631                 }
23632                 
23633             });
23634         });
23635         children.push(style);   
23636         
23637         btn('bold',false,true);
23638         btn('italic',false,true);
23639         btn('align-left', 'justifyleft',true);
23640         btn('align-center', 'justifycenter',true);
23641         btn('align-right' , 'justifyright',true);
23642         btn('link', false, false, function(btn) {
23643             //Roo.log("create link?");
23644             var url = prompt(this.createLinkText, this.defaultLinkValue);
23645             if(url && url != 'http:/'+'/'){
23646                 this.editorcore.relayCmd('createlink', url);
23647             }
23648         }),
23649         btn('list','insertunorderedlist',true);
23650         btn('pencil', false,true, function(btn){
23651                 Roo.log(this);
23652                 this.toggleSourceEdit(btn.pressed);
23653         });
23654         
23655         if (this.editor.btns.length > 0) {
23656             for (var i = 0; i<this.editor.btns.length; i++) {
23657                 children.push(this.editor.btns[i]);
23658             }
23659         }
23660         
23661         /*
23662         var cog = {
23663                 xtype: 'Button',
23664                 size : 'sm',
23665                 xns: Roo.bootstrap,
23666                 glyphicon : 'cog',
23667                 //html : 'submit'
23668                 menu : {
23669                     xtype: 'Menu',
23670                     xns: Roo.bootstrap,
23671                     items:  []
23672                 }
23673         };
23674         
23675         cog.menu.items.push({
23676             xtype :'MenuItem',
23677             xns: Roo.bootstrap,
23678             html : Clean styles,
23679             tagname : f,
23680             listeners : {
23681                 click : function()
23682                 {
23683                     editorcore.insertTag(this.tagname);
23684                     editor.focus();
23685                 }
23686             }
23687             
23688         });
23689        */
23690         
23691          
23692        this.xtype = 'NavSimplebar';
23693         
23694         for(var i=0;i< children.length;i++) {
23695             
23696             this.buttons.add(this.addxtypeChild(children[i]));
23697             
23698         }
23699         
23700         editor.on('editorevent', this.updateToolbar, this);
23701     },
23702     onBtnClick : function(id)
23703     {
23704        this.editorcore.relayCmd(id);
23705        this.editorcore.focus();
23706     },
23707     
23708     /**
23709      * Protected method that will not generally be called directly. It triggers
23710      * a toolbar update by reading the markup state of the current selection in the editor.
23711      */
23712     updateToolbar: function(){
23713
23714         if(!this.editorcore.activated){
23715             this.editor.onFirstFocus(); // is this neeed?
23716             return;
23717         }
23718
23719         var btns = this.buttons; 
23720         var doc = this.editorcore.doc;
23721         btns.get('bold').setActive(doc.queryCommandState('bold'));
23722         btns.get('italic').setActive(doc.queryCommandState('italic'));
23723         //btns.get('underline').setActive(doc.queryCommandState('underline'));
23724         
23725         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23726         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23727         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23728         
23729         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23730         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23731          /*
23732         
23733         var ans = this.editorcore.getAllAncestors();
23734         if (this.formatCombo) {
23735             
23736             
23737             var store = this.formatCombo.store;
23738             this.formatCombo.setValue("");
23739             for (var i =0; i < ans.length;i++) {
23740                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23741                     // select it..
23742                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23743                     break;
23744                 }
23745             }
23746         }
23747         
23748         
23749         
23750         // hides menus... - so this cant be on a menu...
23751         Roo.bootstrap.MenuMgr.hideAll();
23752         */
23753         Roo.bootstrap.MenuMgr.hideAll();
23754         //this.editorsyncValue();
23755     },
23756     onFirstFocus: function() {
23757         this.buttons.each(function(item){
23758            item.enable();
23759         });
23760     },
23761     toggleSourceEdit : function(sourceEditMode){
23762         
23763           
23764         if(sourceEditMode){
23765             Roo.log("disabling buttons");
23766            this.buttons.each( function(item){
23767                 if(item.cmd != 'pencil'){
23768                     item.disable();
23769                 }
23770             });
23771           
23772         }else{
23773             Roo.log("enabling buttons");
23774             if(this.editorcore.initialized){
23775                 this.buttons.each( function(item){
23776                     item.enable();
23777                 });
23778             }
23779             
23780         }
23781         Roo.log("calling toggole on editor");
23782         // tell the editor that it's been pressed..
23783         this.editor.toggleSourceEdit(sourceEditMode);
23784        
23785     }
23786 });
23787
23788
23789
23790
23791
23792 /**
23793  * @class Roo.bootstrap.Table.AbstractSelectionModel
23794  * @extends Roo.util.Observable
23795  * Abstract base class for grid SelectionModels.  It provides the interface that should be
23796  * implemented by descendant classes.  This class should not be directly instantiated.
23797  * @constructor
23798  */
23799 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23800     this.locked = false;
23801     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23802 };
23803
23804
23805 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
23806     /** @ignore Called by the grid automatically. Do not call directly. */
23807     init : function(grid){
23808         this.grid = grid;
23809         this.initEvents();
23810     },
23811
23812     /**
23813      * Locks the selections.
23814      */
23815     lock : function(){
23816         this.locked = true;
23817     },
23818
23819     /**
23820      * Unlocks the selections.
23821      */
23822     unlock : function(){
23823         this.locked = false;
23824     },
23825
23826     /**
23827      * Returns true if the selections are locked.
23828      * @return {Boolean}
23829      */
23830     isLocked : function(){
23831         return this.locked;
23832     }
23833 });
23834 /**
23835  * @extends Roo.bootstrap.Table.AbstractSelectionModel
23836  * @class Roo.bootstrap.Table.RowSelectionModel
23837  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23838  * It supports multiple selections and keyboard selection/navigation. 
23839  * @constructor
23840  * @param {Object} config
23841  */
23842
23843 Roo.bootstrap.Table.RowSelectionModel = function(config){
23844     Roo.apply(this, config);
23845     this.selections = new Roo.util.MixedCollection(false, function(o){
23846         return o.id;
23847     });
23848
23849     this.last = false;
23850     this.lastActive = false;
23851
23852     this.addEvents({
23853         /**
23854              * @event selectionchange
23855              * Fires when the selection changes
23856              * @param {SelectionModel} this
23857              */
23858             "selectionchange" : true,
23859         /**
23860              * @event afterselectionchange
23861              * Fires after the selection changes (eg. by key press or clicking)
23862              * @param {SelectionModel} this
23863              */
23864             "afterselectionchange" : true,
23865         /**
23866              * @event beforerowselect
23867              * Fires when a row is selected being selected, return false to cancel.
23868              * @param {SelectionModel} this
23869              * @param {Number} rowIndex The selected index
23870              * @param {Boolean} keepExisting False if other selections will be cleared
23871              */
23872             "beforerowselect" : true,
23873         /**
23874              * @event rowselect
23875              * Fires when a row is selected.
23876              * @param {SelectionModel} this
23877              * @param {Number} rowIndex The selected index
23878              * @param {Roo.data.Record} r The record
23879              */
23880             "rowselect" : true,
23881         /**
23882              * @event rowdeselect
23883              * Fires when a row is deselected.
23884              * @param {SelectionModel} this
23885              * @param {Number} rowIndex The selected index
23886              */
23887         "rowdeselect" : true
23888     });
23889     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23890     this.locked = false;
23891  };
23892
23893 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
23894     /**
23895      * @cfg {Boolean} singleSelect
23896      * True to allow selection of only one row at a time (defaults to false)
23897      */
23898     singleSelect : false,
23899
23900     // private
23901     initEvents : function()
23902     {
23903
23904         //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23905         //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
23906         //}else{ // allow click to work like normal
23907          //   this.grid.on("rowclick", this.handleDragableRowClick, this);
23908         //}
23909         //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23910         this.grid.on("rowclick", this.handleMouseDown, this);
23911         
23912         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23913             "up" : function(e){
23914                 if(!e.shiftKey){
23915                     this.selectPrevious(e.shiftKey);
23916                 }else if(this.last !== false && this.lastActive !== false){
23917                     var last = this.last;
23918                     this.selectRange(this.last,  this.lastActive-1);
23919                     this.grid.getView().focusRow(this.lastActive);
23920                     if(last !== false){
23921                         this.last = last;
23922                     }
23923                 }else{
23924                     this.selectFirstRow();
23925                 }
23926                 this.fireEvent("afterselectionchange", this);
23927             },
23928             "down" : function(e){
23929                 if(!e.shiftKey){
23930                     this.selectNext(e.shiftKey);
23931                 }else if(this.last !== false && this.lastActive !== false){
23932                     var last = this.last;
23933                     this.selectRange(this.last,  this.lastActive+1);
23934                     this.grid.getView().focusRow(this.lastActive);
23935                     if(last !== false){
23936                         this.last = last;
23937                     }
23938                 }else{
23939                     this.selectFirstRow();
23940                 }
23941                 this.fireEvent("afterselectionchange", this);
23942             },
23943             scope: this
23944         });
23945         this.grid.store.on('load', function(){
23946             this.selections.clear();
23947         },this);
23948         /*
23949         var view = this.grid.view;
23950         view.on("refresh", this.onRefresh, this);
23951         view.on("rowupdated", this.onRowUpdated, this);
23952         view.on("rowremoved", this.onRemove, this);
23953         */
23954     },
23955
23956     // private
23957     onRefresh : function()
23958     {
23959         var ds = this.grid.store, i, v = this.grid.view;
23960         var s = this.selections;
23961         s.each(function(r){
23962             if((i = ds.indexOfId(r.id)) != -1){
23963                 v.onRowSelect(i);
23964             }else{
23965                 s.remove(r);
23966             }
23967         });
23968     },
23969
23970     // private
23971     onRemove : function(v, index, r){
23972         this.selections.remove(r);
23973     },
23974
23975     // private
23976     onRowUpdated : function(v, index, r){
23977         if(this.isSelected(r)){
23978             v.onRowSelect(index);
23979         }
23980     },
23981
23982     /**
23983      * Select records.
23984      * @param {Array} records The records to select
23985      * @param {Boolean} keepExisting (optional) True to keep existing selections
23986      */
23987     selectRecords : function(records, keepExisting)
23988     {
23989         if(!keepExisting){
23990             this.clearSelections();
23991         }
23992             var ds = this.grid.store;
23993         for(var i = 0, len = records.length; i < len; i++){
23994             this.selectRow(ds.indexOf(records[i]), true);
23995         }
23996     },
23997
23998     /**
23999      * Gets the number of selected rows.
24000      * @return {Number}
24001      */
24002     getCount : function(){
24003         return this.selections.length;
24004     },
24005
24006     /**
24007      * Selects the first row in the grid.
24008      */
24009     selectFirstRow : function(){
24010         this.selectRow(0);
24011     },
24012
24013     /**
24014      * Select the last row.
24015      * @param {Boolean} keepExisting (optional) True to keep existing selections
24016      */
24017     selectLastRow : function(keepExisting){
24018         //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24019         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24020     },
24021
24022     /**
24023      * Selects the row immediately following the last selected row.
24024      * @param {Boolean} keepExisting (optional) True to keep existing selections
24025      */
24026     selectNext : function(keepExisting)
24027     {
24028             if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24029             this.selectRow(this.last+1, keepExisting);
24030             this.grid.getView().focusRow(this.last);
24031         }
24032     },
24033
24034     /**
24035      * Selects the row that precedes the last selected row.
24036      * @param {Boolean} keepExisting (optional) True to keep existing selections
24037      */
24038     selectPrevious : function(keepExisting){
24039         if(this.last){
24040             this.selectRow(this.last-1, keepExisting);
24041             this.grid.getView().focusRow(this.last);
24042         }
24043     },
24044
24045     /**
24046      * Returns the selected records
24047      * @return {Array} Array of selected records
24048      */
24049     getSelections : function(){
24050         return [].concat(this.selections.items);
24051     },
24052
24053     /**
24054      * Returns the first selected record.
24055      * @return {Record}
24056      */
24057     getSelected : function(){
24058         return this.selections.itemAt(0);
24059     },
24060
24061
24062     /**
24063      * Clears all selections.
24064      */
24065     clearSelections : function(fast)
24066     {
24067         if(this.locked) {
24068             return;
24069         }
24070         if(fast !== true){
24071                 var ds = this.grid.store;
24072             var s = this.selections;
24073             s.each(function(r){
24074                 this.deselectRow(ds.indexOfId(r.id));
24075             }, this);
24076             s.clear();
24077         }else{
24078             this.selections.clear();
24079         }
24080         this.last = false;
24081     },
24082
24083
24084     /**
24085      * Selects all rows.
24086      */
24087     selectAll : function(){
24088         if(this.locked) {
24089             return;
24090         }
24091         this.selections.clear();
24092         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24093             this.selectRow(i, true);
24094         }
24095     },
24096
24097     /**
24098      * Returns True if there is a selection.
24099      * @return {Boolean}
24100      */
24101     hasSelection : function(){
24102         return this.selections.length > 0;
24103     },
24104
24105     /**
24106      * Returns True if the specified row is selected.
24107      * @param {Number/Record} record The record or index of the record to check
24108      * @return {Boolean}
24109      */
24110     isSelected : function(index){
24111             var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24112         return (r && this.selections.key(r.id) ? true : false);
24113     },
24114
24115     /**
24116      * Returns True if the specified record id is selected.
24117      * @param {String} id The id of record to check
24118      * @return {Boolean}
24119      */
24120     isIdSelected : function(id){
24121         return (this.selections.key(id) ? true : false);
24122     },
24123
24124
24125     // private
24126     handleMouseDBClick : function(e, t){
24127         
24128     },
24129     // private
24130     handleMouseDown : function(e, t)
24131     {
24132             var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24133         if(this.isLocked() || rowIndex < 0 ){
24134             return;
24135         };
24136         if(e.shiftKey && this.last !== false){
24137             var last = this.last;
24138             this.selectRange(last, rowIndex, e.ctrlKey);
24139             this.last = last; // reset the last
24140             t.focus();
24141     
24142         }else{
24143             var isSelected = this.isSelected(rowIndex);
24144             //Roo.log("select row:" + rowIndex);
24145             if(isSelected){
24146                 this.deselectRow(rowIndex);
24147             } else {
24148                         this.selectRow(rowIndex, true);
24149             }
24150     
24151             /*
24152                 if(e.button !== 0 && isSelected){
24153                 alert('rowIndex 2: ' + rowIndex);
24154                     view.focusRow(rowIndex);
24155                 }else if(e.ctrlKey && isSelected){
24156                     this.deselectRow(rowIndex);
24157                 }else if(!isSelected){
24158                     this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24159                     view.focusRow(rowIndex);
24160                 }
24161             */
24162         }
24163         this.fireEvent("afterselectionchange", this);
24164     },
24165     // private
24166     handleDragableRowClick :  function(grid, rowIndex, e) 
24167     {
24168         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24169             this.selectRow(rowIndex, false);
24170             grid.view.focusRow(rowIndex);
24171              this.fireEvent("afterselectionchange", this);
24172         }
24173     },
24174     
24175     /**
24176      * Selects multiple rows.
24177      * @param {Array} rows Array of the indexes of the row to select
24178      * @param {Boolean} keepExisting (optional) True to keep existing selections
24179      */
24180     selectRows : function(rows, keepExisting){
24181         if(!keepExisting){
24182             this.clearSelections();
24183         }
24184         for(var i = 0, len = rows.length; i < len; i++){
24185             this.selectRow(rows[i], true);
24186         }
24187     },
24188
24189     /**
24190      * Selects a range of rows. All rows in between startRow and endRow are also selected.
24191      * @param {Number} startRow The index of the first row in the range
24192      * @param {Number} endRow The index of the last row in the range
24193      * @param {Boolean} keepExisting (optional) True to retain existing selections
24194      */
24195     selectRange : function(startRow, endRow, keepExisting){
24196         if(this.locked) {
24197             return;
24198         }
24199         if(!keepExisting){
24200             this.clearSelections();
24201         }
24202         if(startRow <= endRow){
24203             for(var i = startRow; i <= endRow; i++){
24204                 this.selectRow(i, true);
24205             }
24206         }else{
24207             for(var i = startRow; i >= endRow; i--){
24208                 this.selectRow(i, true);
24209             }
24210         }
24211     },
24212
24213     /**
24214      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24215      * @param {Number} startRow The index of the first row in the range
24216      * @param {Number} endRow The index of the last row in the range
24217      */
24218     deselectRange : function(startRow, endRow, preventViewNotify){
24219         if(this.locked) {
24220             return;
24221         }
24222         for(var i = startRow; i <= endRow; i++){
24223             this.deselectRow(i, preventViewNotify);
24224         }
24225     },
24226
24227     /**
24228      * Selects a row.
24229      * @param {Number} row The index of the row to select
24230      * @param {Boolean} keepExisting (optional) True to keep existing selections
24231      */
24232     selectRow : function(index, keepExisting, preventViewNotify)
24233     {
24234             if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24235             return;
24236         }
24237         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24238             if(!keepExisting || this.singleSelect){
24239                 this.clearSelections();
24240             }
24241             
24242             var r = this.grid.store.getAt(index);
24243             //console.log('selectRow - record id :' + r.id);
24244             
24245             this.selections.add(r);
24246             this.last = this.lastActive = index;
24247             if(!preventViewNotify){
24248                 var proxy = new Roo.Element(
24249                                 this.grid.getRowDom(index)
24250                 );
24251                 proxy.addClass('bg-info info');
24252             }
24253             this.fireEvent("rowselect", this, index, r);
24254             this.fireEvent("selectionchange", this);
24255         }
24256     },
24257
24258     /**
24259      * Deselects a row.
24260      * @param {Number} row The index of the row to deselect
24261      */
24262     deselectRow : function(index, preventViewNotify)
24263     {
24264         if(this.locked) {
24265             return;
24266         }
24267         if(this.last == index){
24268             this.last = false;
24269         }
24270         if(this.lastActive == index){
24271             this.lastActive = false;
24272         }
24273         
24274         var r = this.grid.store.getAt(index);
24275         if (!r) {
24276             return;
24277         }
24278         
24279         this.selections.remove(r);
24280         //.console.log('deselectRow - record id :' + r.id);
24281         if(!preventViewNotify){
24282         
24283             var proxy = new Roo.Element(
24284                 this.grid.getRowDom(index)
24285             );
24286             proxy.removeClass('bg-info info');
24287         }
24288         this.fireEvent("rowdeselect", this, index);
24289         this.fireEvent("selectionchange", this);
24290     },
24291
24292     // private
24293     restoreLast : function(){
24294         if(this._last){
24295             this.last = this._last;
24296         }
24297     },
24298
24299     // private
24300     acceptsNav : function(row, col, cm){
24301         return !cm.isHidden(col) && cm.isCellEditable(col, row);
24302     },
24303
24304     // private
24305     onEditorKey : function(field, e){
24306         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24307         if(k == e.TAB){
24308             e.stopEvent();
24309             ed.completeEdit();
24310             if(e.shiftKey){
24311                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24312             }else{
24313                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24314             }
24315         }else if(k == e.ENTER && !e.ctrlKey){
24316             e.stopEvent();
24317             ed.completeEdit();
24318             if(e.shiftKey){
24319                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24320             }else{
24321                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24322             }
24323         }else if(k == e.ESC){
24324             ed.cancelEdit();
24325         }
24326         if(newCell){
24327             g.startEditing(newCell[0], newCell[1]);
24328         }
24329     }
24330 });
24331 /*
24332  * Based on:
24333  * Ext JS Library 1.1.1
24334  * Copyright(c) 2006-2007, Ext JS, LLC.
24335  *
24336  * Originally Released Under LGPL - original licence link has changed is not relivant.
24337  *
24338  * Fork - LGPL
24339  * <script type="text/javascript">
24340  */
24341  
24342 /**
24343  * @class Roo.bootstrap.PagingToolbar
24344  * @extends Roo.bootstrap.NavSimplebar
24345  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24346  * @constructor
24347  * Create a new PagingToolbar
24348  * @param {Object} config The config object
24349  * @param {Roo.data.Store} store
24350  */
24351 Roo.bootstrap.PagingToolbar = function(config)
24352 {
24353     // old args format still supported... - xtype is prefered..
24354         // created from xtype...
24355     
24356     this.ds = config.dataSource;
24357     
24358     if (config.store && !this.ds) {
24359         this.store= Roo.factory(config.store, Roo.data);
24360         this.ds = this.store;
24361         this.ds.xmodule = this.xmodule || false;
24362     }
24363     
24364     this.toolbarItems = [];
24365     if (config.items) {
24366         this.toolbarItems = config.items;
24367     }
24368     
24369     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24370     
24371     this.cursor = 0;
24372     
24373     if (this.ds) { 
24374         this.bind(this.ds);
24375     }
24376     
24377     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24378     
24379 };
24380
24381 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24382     /**
24383      * @cfg {Roo.data.Store} dataSource
24384      * The underlying data store providing the paged data
24385      */
24386     /**
24387      * @cfg {String/HTMLElement/Element} container
24388      * container The id or element that will contain the toolbar
24389      */
24390     /**
24391      * @cfg {Boolean} displayInfo
24392      * True to display the displayMsg (defaults to false)
24393      */
24394     /**
24395      * @cfg {Number} pageSize
24396      * The number of records to display per page (defaults to 20)
24397      */
24398     pageSize: 20,
24399     /**
24400      * @cfg {String} displayMsg
24401      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24402      */
24403     displayMsg : 'Displaying {0} - {1} of {2}',
24404     /**
24405      * @cfg {String} emptyMsg
24406      * The message to display when no records are found (defaults to "No data to display")
24407      */
24408     emptyMsg : 'No data to display',
24409     /**
24410      * Customizable piece of the default paging text (defaults to "Page")
24411      * @type String
24412      */
24413     beforePageText : "Page",
24414     /**
24415      * Customizable piece of the default paging text (defaults to "of %0")
24416      * @type String
24417      */
24418     afterPageText : "of {0}",
24419     /**
24420      * Customizable piece of the default paging text (defaults to "First Page")
24421      * @type String
24422      */
24423     firstText : "First Page",
24424     /**
24425      * Customizable piece of the default paging text (defaults to "Previous Page")
24426      * @type String
24427      */
24428     prevText : "Previous Page",
24429     /**
24430      * Customizable piece of the default paging text (defaults to "Next Page")
24431      * @type String
24432      */
24433     nextText : "Next Page",
24434     /**
24435      * Customizable piece of the default paging text (defaults to "Last Page")
24436      * @type String
24437      */
24438     lastText : "Last Page",
24439     /**
24440      * Customizable piece of the default paging text (defaults to "Refresh")
24441      * @type String
24442      */
24443     refreshText : "Refresh",
24444
24445     buttons : false,
24446     // private
24447     onRender : function(ct, position) 
24448     {
24449         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24450         this.navgroup.parentId = this.id;
24451         this.navgroup.onRender(this.el, null);
24452         // add the buttons to the navgroup
24453         
24454         if(this.displayInfo){
24455             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24456             this.displayEl = this.el.select('.x-paging-info', true).first();
24457 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24458 //            this.displayEl = navel.el.select('span',true).first();
24459         }
24460         
24461         var _this = this;
24462         
24463         if(this.buttons){
24464             Roo.each(_this.buttons, function(e){ // this might need to use render????
24465                Roo.factory(e).onRender(_this.el, null);
24466             });
24467         }
24468             
24469         Roo.each(_this.toolbarItems, function(e) {
24470             _this.navgroup.addItem(e);
24471         });
24472         
24473         
24474         this.first = this.navgroup.addItem({
24475             tooltip: this.firstText,
24476             cls: "prev",
24477             icon : 'fa fa-backward',
24478             disabled: true,
24479             preventDefault: true,
24480             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24481         });
24482         
24483         this.prev =  this.navgroup.addItem({
24484             tooltip: this.prevText,
24485             cls: "prev",
24486             icon : 'fa fa-step-backward',
24487             disabled: true,
24488             preventDefault: true,
24489             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
24490         });
24491     //this.addSeparator();
24492         
24493         
24494         var field = this.navgroup.addItem( {
24495             tagtype : 'span',
24496             cls : 'x-paging-position',
24497             
24498             html : this.beforePageText  +
24499                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24500                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
24501          } ); //?? escaped?
24502         
24503         this.field = field.el.select('input', true).first();
24504         this.field.on("keydown", this.onPagingKeydown, this);
24505         this.field.on("focus", function(){this.dom.select();});
24506     
24507     
24508         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
24509         //this.field.setHeight(18);
24510         //this.addSeparator();
24511         this.next = this.navgroup.addItem({
24512             tooltip: this.nextText,
24513             cls: "next",
24514             html : ' <i class="fa fa-step-forward">',
24515             disabled: true,
24516             preventDefault: true,
24517             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
24518         });
24519         this.last = this.navgroup.addItem({
24520             tooltip: this.lastText,
24521             icon : 'fa fa-forward',
24522             cls: "next",
24523             disabled: true,
24524             preventDefault: true,
24525             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
24526         });
24527     //this.addSeparator();
24528         this.loading = this.navgroup.addItem({
24529             tooltip: this.refreshText,
24530             icon: 'fa fa-refresh',
24531             preventDefault: true,
24532             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24533         });
24534         
24535     },
24536
24537     // private
24538     updateInfo : function(){
24539         if(this.displayEl){
24540             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24541             var msg = count == 0 ?
24542                 this.emptyMsg :
24543                 String.format(
24544                     this.displayMsg,
24545                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
24546                 );
24547             this.displayEl.update(msg);
24548         }
24549     },
24550
24551     // private
24552     onLoad : function(ds, r, o)
24553     {
24554         this.cursor = o.params.start ? o.params.start : 0;
24555         
24556         var d = this.getPageData(),
24557             ap = d.activePage,
24558             ps = d.pages;
24559         
24560         
24561         this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24562         this.field.dom.value = ap;
24563         this.first.setDisabled(ap == 1);
24564         this.prev.setDisabled(ap == 1);
24565         this.next.setDisabled(ap == ps);
24566         this.last.setDisabled(ap == ps);
24567         this.loading.enable();
24568         this.updateInfo();
24569     },
24570
24571     // private
24572     getPageData : function(){
24573         var total = this.ds.getTotalCount();
24574         return {
24575             total : total,
24576             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24577             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24578         };
24579     },
24580
24581     // private
24582     onLoadError : function(){
24583         this.loading.enable();
24584     },
24585
24586     // private
24587     onPagingKeydown : function(e){
24588         var k = e.getKey();
24589         var d = this.getPageData();
24590         if(k == e.RETURN){
24591             var v = this.field.dom.value, pageNum;
24592             if(!v || isNaN(pageNum = parseInt(v, 10))){
24593                 this.field.dom.value = d.activePage;
24594                 return;
24595             }
24596             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24597             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24598             e.stopEvent();
24599         }
24600         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))
24601         {
24602           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24603           this.field.dom.value = pageNum;
24604           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24605           e.stopEvent();
24606         }
24607         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24608         {
24609           var v = this.field.dom.value, pageNum; 
24610           var increment = (e.shiftKey) ? 10 : 1;
24611           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24612                 increment *= -1;
24613           }
24614           if(!v || isNaN(pageNum = parseInt(v, 10))) {
24615             this.field.dom.value = d.activePage;
24616             return;
24617           }
24618           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24619           {
24620             this.field.dom.value = parseInt(v, 10) + increment;
24621             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24622             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24623           }
24624           e.stopEvent();
24625         }
24626     },
24627
24628     // private
24629     beforeLoad : function(){
24630         if(this.loading){
24631             this.loading.disable();
24632         }
24633     },
24634
24635     // private
24636     onClick : function(which){
24637         
24638         var ds = this.ds;
24639         if (!ds) {
24640             return;
24641         }
24642         
24643         switch(which){
24644             case "first":
24645                 ds.load({params:{start: 0, limit: this.pageSize}});
24646             break;
24647             case "prev":
24648                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24649             break;
24650             case "next":
24651                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24652             break;
24653             case "last":
24654                 var total = ds.getTotalCount();
24655                 var extra = total % this.pageSize;
24656                 var lastStart = extra ? (total - extra) : total-this.pageSize;
24657                 ds.load({params:{start: lastStart, limit: this.pageSize}});
24658             break;
24659             case "refresh":
24660                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24661             break;
24662         }
24663     },
24664
24665     /**
24666      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24667      * @param {Roo.data.Store} store The data store to unbind
24668      */
24669     unbind : function(ds){
24670         ds.un("beforeload", this.beforeLoad, this);
24671         ds.un("load", this.onLoad, this);
24672         ds.un("loadexception", this.onLoadError, this);
24673         ds.un("remove", this.updateInfo, this);
24674         ds.un("add", this.updateInfo, this);
24675         this.ds = undefined;
24676     },
24677
24678     /**
24679      * Binds the paging toolbar to the specified {@link Roo.data.Store}
24680      * @param {Roo.data.Store} store The data store to bind
24681      */
24682     bind : function(ds){
24683         ds.on("beforeload", this.beforeLoad, this);
24684         ds.on("load", this.onLoad, this);
24685         ds.on("loadexception", this.onLoadError, this);
24686         ds.on("remove", this.updateInfo, this);
24687         ds.on("add", this.updateInfo, this);
24688         this.ds = ds;
24689     }
24690 });/*
24691  * - LGPL
24692  *
24693  * element
24694  * 
24695  */
24696
24697 /**
24698  * @class Roo.bootstrap.MessageBar
24699  * @extends Roo.bootstrap.Component
24700  * Bootstrap MessageBar class
24701  * @cfg {String} html contents of the MessageBar
24702  * @cfg {String} weight (info | success | warning | danger) default info
24703  * @cfg {String} beforeClass insert the bar before the given class
24704  * @cfg {Boolean} closable (true | false) default false
24705  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24706  * 
24707  * @constructor
24708  * Create a new Element
24709  * @param {Object} config The config object
24710  */
24711
24712 Roo.bootstrap.MessageBar = function(config){
24713     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24714 };
24715
24716 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
24717     
24718     html: '',
24719     weight: 'info',
24720     closable: false,
24721     fixed: false,
24722     beforeClass: 'bootstrap-sticky-wrap',
24723     
24724     getAutoCreate : function(){
24725         
24726         var cfg = {
24727             tag: 'div',
24728             cls: 'alert alert-dismissable alert-' + this.weight,
24729             cn: [
24730                 {
24731                     tag: 'span',
24732                     cls: 'message',
24733                     html: this.html || ''
24734                 }
24735             ]
24736         };
24737         
24738         if(this.fixed){
24739             cfg.cls += ' alert-messages-fixed';
24740         }
24741         
24742         if(this.closable){
24743             cfg.cn.push({
24744                 tag: 'button',
24745                 cls: 'close',
24746                 html: 'x'
24747             });
24748         }
24749         
24750         return cfg;
24751     },
24752     
24753     onRender : function(ct, position)
24754     {
24755         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24756         
24757         if(!this.el){
24758             var cfg = Roo.apply({},  this.getAutoCreate());
24759             cfg.id = Roo.id();
24760             
24761             if (this.cls) {
24762                 cfg.cls += ' ' + this.cls;
24763             }
24764             if (this.style) {
24765                 cfg.style = this.style;
24766             }
24767             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24768             
24769             this.el.setVisibilityMode(Roo.Element.DISPLAY);
24770         }
24771         
24772         this.el.select('>button.close').on('click', this.hide, this);
24773         
24774     },
24775     
24776     show : function()
24777     {
24778         if (!this.rendered) {
24779             this.render();
24780         }
24781         
24782         this.el.show();
24783         
24784         this.fireEvent('show', this);
24785         
24786     },
24787     
24788     hide : function()
24789     {
24790         if (!this.rendered) {
24791             this.render();
24792         }
24793         
24794         this.el.hide();
24795         
24796         this.fireEvent('hide', this);
24797     },
24798     
24799     update : function()
24800     {
24801 //        var e = this.el.dom.firstChild;
24802 //        
24803 //        if(this.closable){
24804 //            e = e.nextSibling;
24805 //        }
24806 //        
24807 //        e.data = this.html || '';
24808
24809         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24810     }
24811    
24812 });
24813
24814  
24815
24816      /*
24817  * - LGPL
24818  *
24819  * Graph
24820  * 
24821  */
24822
24823
24824 /**
24825  * @class Roo.bootstrap.Graph
24826  * @extends Roo.bootstrap.Component
24827  * Bootstrap Graph class
24828 > Prameters
24829  -sm {number} sm 4
24830  -md {number} md 5
24831  @cfg {String} graphtype  bar | vbar | pie
24832  @cfg {number} g_x coodinator | centre x (pie)
24833  @cfg {number} g_y coodinator | centre y (pie)
24834  @cfg {number} g_r radius (pie)
24835  @cfg {number} g_height height of the chart (respected by all elements in the set)
24836  @cfg {number} g_width width of the chart (respected by all elements in the set)
24837  @cfg {Object} title The title of the chart
24838     
24839  -{Array}  values
24840  -opts (object) options for the chart 
24841      o {
24842      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24843      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24844      o vgutter (number)
24845      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.
24846      o stacked (boolean) whether or not to tread values as in a stacked bar chart
24847      o to
24848      o stretch (boolean)
24849      o }
24850  -opts (object) options for the pie
24851      o{
24852      o cut
24853      o startAngle (number)
24854      o endAngle (number)
24855      } 
24856  *
24857  * @constructor
24858  * Create a new Input
24859  * @param {Object} config The config object
24860  */
24861
24862 Roo.bootstrap.Graph = function(config){
24863     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24864     
24865     this.addEvents({
24866         // img events
24867         /**
24868          * @event click
24869          * The img click event for the img.
24870          * @param {Roo.EventObject} e
24871          */
24872         "click" : true
24873     });
24874 };
24875
24876 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
24877     
24878     sm: 4,
24879     md: 5,
24880     graphtype: 'bar',
24881     g_height: 250,
24882     g_width: 400,
24883     g_x: 50,
24884     g_y: 50,
24885     g_r: 30,
24886     opts:{
24887         //g_colors: this.colors,
24888         g_type: 'soft',
24889         g_gutter: '20%'
24890
24891     },
24892     title : false,
24893
24894     getAutoCreate : function(){
24895         
24896         var cfg = {
24897             tag: 'div',
24898             html : null
24899         };
24900         
24901         
24902         return  cfg;
24903     },
24904
24905     onRender : function(ct,position){
24906         
24907         
24908         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24909         
24910         if (typeof(Raphael) == 'undefined') {
24911             Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24912             return;
24913         }
24914         
24915         this.raphael = Raphael(this.el.dom);
24916         
24917                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24918                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24919                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24920                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24921                 /*
24922                 r.text(160, 10, "Single Series Chart").attr(txtattr);
24923                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24924                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24925                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24926                 
24927                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24928                 r.barchart(330, 10, 300, 220, data1);
24929                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24930                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24931                 */
24932                 
24933                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24934                 // r.barchart(30, 30, 560, 250,  xdata, {
24935                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24936                 //     axis : "0 0 1 1",
24937                 //     axisxlabels :  xdata
24938                 //     //yvalues : cols,
24939                    
24940                 // });
24941 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24942 //        
24943 //        this.load(null,xdata,{
24944 //                axis : "0 0 1 1",
24945 //                axisxlabels :  xdata
24946 //                });
24947
24948     },
24949
24950     load : function(graphtype,xdata,opts)
24951     {
24952         this.raphael.clear();
24953         if(!graphtype) {
24954             graphtype = this.graphtype;
24955         }
24956         if(!opts){
24957             opts = this.opts;
24958         }
24959         var r = this.raphael,
24960             fin = function () {
24961                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24962             },
24963             fout = function () {
24964                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24965             },
24966             pfin = function() {
24967                 this.sector.stop();
24968                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24969
24970                 if (this.label) {
24971                     this.label[0].stop();
24972                     this.label[0].attr({ r: 7.5 });
24973                     this.label[1].attr({ "font-weight": 800 });
24974                 }
24975             },
24976             pfout = function() {
24977                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24978
24979                 if (this.label) {
24980                     this.label[0].animate({ r: 5 }, 500, "bounce");
24981                     this.label[1].attr({ "font-weight": 400 });
24982                 }
24983             };
24984
24985         switch(graphtype){
24986             case 'bar':
24987                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24988                 break;
24989             case 'hbar':
24990                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24991                 break;
24992             case 'pie':
24993 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
24994 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24995 //            
24996                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24997                 
24998                 break;
24999
25000         }
25001         
25002         if(this.title){
25003             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25004         }
25005         
25006     },
25007     
25008     setTitle: function(o)
25009     {
25010         this.title = o;
25011     },
25012     
25013     initEvents: function() {
25014         
25015         if(!this.href){
25016             this.el.on('click', this.onClick, this);
25017         }
25018     },
25019     
25020     onClick : function(e)
25021     {
25022         Roo.log('img onclick');
25023         this.fireEvent('click', this, e);
25024     }
25025    
25026 });
25027
25028  
25029 /*
25030  * - LGPL
25031  *
25032  * numberBox
25033  * 
25034  */
25035 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25036
25037 /**
25038  * @class Roo.bootstrap.dash.NumberBox
25039  * @extends Roo.bootstrap.Component
25040  * Bootstrap NumberBox class
25041  * @cfg {String} headline Box headline
25042  * @cfg {String} content Box content
25043  * @cfg {String} icon Box icon
25044  * @cfg {String} footer Footer text
25045  * @cfg {String} fhref Footer href
25046  * 
25047  * @constructor
25048  * Create a new NumberBox
25049  * @param {Object} config The config object
25050  */
25051
25052
25053 Roo.bootstrap.dash.NumberBox = function(config){
25054     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25055     
25056 };
25057
25058 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
25059     
25060     headline : '',
25061     content : '',
25062     icon : '',
25063     footer : '',
25064     fhref : '',
25065     ficon : '',
25066     
25067     getAutoCreate : function(){
25068         
25069         var cfg = {
25070             tag : 'div',
25071             cls : 'small-box ',
25072             cn : [
25073                 {
25074                     tag : 'div',
25075                     cls : 'inner',
25076                     cn :[
25077                         {
25078                             tag : 'h3',
25079                             cls : 'roo-headline',
25080                             html : this.headline
25081                         },
25082                         {
25083                             tag : 'p',
25084                             cls : 'roo-content',
25085                             html : this.content
25086                         }
25087                     ]
25088                 }
25089             ]
25090         };
25091         
25092         if(this.icon){
25093             cfg.cn.push({
25094                 tag : 'div',
25095                 cls : 'icon',
25096                 cn :[
25097                     {
25098                         tag : 'i',
25099                         cls : 'ion ' + this.icon
25100                     }
25101                 ]
25102             });
25103         }
25104         
25105         if(this.footer){
25106             var footer = {
25107                 tag : 'a',
25108                 cls : 'small-box-footer',
25109                 href : this.fhref || '#',
25110                 html : this.footer
25111             };
25112             
25113             cfg.cn.push(footer);
25114             
25115         }
25116         
25117         return  cfg;
25118     },
25119
25120     onRender : function(ct,position){
25121         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25122
25123
25124        
25125                 
25126     },
25127
25128     setHeadline: function (value)
25129     {
25130         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25131     },
25132     
25133     setFooter: function (value, href)
25134     {
25135         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25136         
25137         if(href){
25138             this.el.select('a.small-box-footer',true).first().attr('href', href);
25139         }
25140         
25141     },
25142
25143     setContent: function (value)
25144     {
25145         this.el.select('.roo-content',true).first().dom.innerHTML = value;
25146     },
25147
25148     initEvents: function() 
25149     {   
25150         
25151     }
25152     
25153 });
25154
25155  
25156 /*
25157  * - LGPL
25158  *
25159  * TabBox
25160  * 
25161  */
25162 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25163
25164 /**
25165  * @class Roo.bootstrap.dash.TabBox
25166  * @extends Roo.bootstrap.Component
25167  * Bootstrap TabBox class
25168  * @cfg {String} title Title of the TabBox
25169  * @cfg {String} icon Icon of the TabBox
25170  * @cfg {Boolean} showtabs (true|false) show the tabs default true
25171  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25172  * 
25173  * @constructor
25174  * Create a new TabBox
25175  * @param {Object} config The config object
25176  */
25177
25178
25179 Roo.bootstrap.dash.TabBox = function(config){
25180     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25181     this.addEvents({
25182         // raw events
25183         /**
25184          * @event addpane
25185          * When a pane is added
25186          * @param {Roo.bootstrap.dash.TabPane} pane
25187          */
25188         "addpane" : true,
25189         /**
25190          * @event activatepane
25191          * When a pane is activated
25192          * @param {Roo.bootstrap.dash.TabPane} pane
25193          */
25194         "activatepane" : true
25195         
25196          
25197     });
25198     
25199     this.panes = [];
25200 };
25201
25202 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
25203
25204     title : '',
25205     icon : false,
25206     showtabs : true,
25207     tabScrollable : false,
25208     
25209     getChildContainer : function()
25210     {
25211         return this.el.select('.tab-content', true).first();
25212     },
25213     
25214     getAutoCreate : function(){
25215         
25216         var header = {
25217             tag: 'li',
25218             cls: 'pull-left header',
25219             html: this.title,
25220             cn : []
25221         };
25222         
25223         if(this.icon){
25224             header.cn.push({
25225                 tag: 'i',
25226                 cls: 'fa ' + this.icon
25227             });
25228         }
25229         
25230         var h = {
25231             tag: 'ul',
25232             cls: 'nav nav-tabs pull-right',
25233             cn: [
25234                 header
25235             ]
25236         };
25237         
25238         if(this.tabScrollable){
25239             h = {
25240                 tag: 'div',
25241                 cls: 'tab-header',
25242                 cn: [
25243                     {
25244                         tag: 'ul',
25245                         cls: 'nav nav-tabs pull-right',
25246                         cn: [
25247                             header
25248                         ]
25249                     }
25250                 ]
25251             };
25252         }
25253         
25254         var cfg = {
25255             tag: 'div',
25256             cls: 'nav-tabs-custom',
25257             cn: [
25258                 h,
25259                 {
25260                     tag: 'div',
25261                     cls: 'tab-content no-padding',
25262                     cn: []
25263                 }
25264             ]
25265         };
25266
25267         return  cfg;
25268     },
25269     initEvents : function()
25270     {
25271         //Roo.log('add add pane handler');
25272         this.on('addpane', this.onAddPane, this);
25273     },
25274      /**
25275      * Updates the box title
25276      * @param {String} html to set the title to.
25277      */
25278     setTitle : function(value)
25279     {
25280         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25281     },
25282     onAddPane : function(pane)
25283     {
25284         this.panes.push(pane);
25285         //Roo.log('addpane');
25286         //Roo.log(pane);
25287         // tabs are rendere left to right..
25288         if(!this.showtabs){
25289             return;
25290         }
25291         
25292         var ctr = this.el.select('.nav-tabs', true).first();
25293          
25294          
25295         var existing = ctr.select('.nav-tab',true);
25296         var qty = existing.getCount();;
25297         
25298         
25299         var tab = ctr.createChild({
25300             tag : 'li',
25301             cls : 'nav-tab' + (qty ? '' : ' active'),
25302             cn : [
25303                 {
25304                     tag : 'a',
25305                     href:'#',
25306                     html : pane.title
25307                 }
25308             ]
25309         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25310         pane.tab = tab;
25311         
25312         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25313         if (!qty) {
25314             pane.el.addClass('active');
25315         }
25316         
25317                 
25318     },
25319     onTabClick : function(ev,un,ob,pane)
25320     {
25321         //Roo.log('tab - prev default');
25322         ev.preventDefault();
25323         
25324         
25325         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25326         pane.tab.addClass('active');
25327         //Roo.log(pane.title);
25328         this.getChildContainer().select('.tab-pane',true).removeClass('active');
25329         // technically we should have a deactivate event.. but maybe add later.
25330         // and it should not de-activate the selected tab...
25331         this.fireEvent('activatepane', pane);
25332         pane.el.addClass('active');
25333         pane.fireEvent('activate');
25334         
25335         
25336     },
25337     
25338     getActivePane : function()
25339     {
25340         var r = false;
25341         Roo.each(this.panes, function(p) {
25342             if(p.el.hasClass('active')){
25343                 r = p;
25344                 return false;
25345             }
25346             
25347             return;
25348         });
25349         
25350         return r;
25351     }
25352     
25353     
25354 });
25355
25356  
25357 /*
25358  * - LGPL
25359  *
25360  * Tab pane
25361  * 
25362  */
25363 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25364 /**
25365  * @class Roo.bootstrap.TabPane
25366  * @extends Roo.bootstrap.Component
25367  * Bootstrap TabPane class
25368  * @cfg {Boolean} active (false | true) Default false
25369  * @cfg {String} title title of panel
25370
25371  * 
25372  * @constructor
25373  * Create a new TabPane
25374  * @param {Object} config The config object
25375  */
25376
25377 Roo.bootstrap.dash.TabPane = function(config){
25378     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25379     
25380     this.addEvents({
25381         // raw events
25382         /**
25383          * @event activate
25384          * When a pane is activated
25385          * @param {Roo.bootstrap.dash.TabPane} pane
25386          */
25387         "activate" : true
25388          
25389     });
25390 };
25391
25392 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
25393     
25394     active : false,
25395     title : '',
25396     
25397     // the tabBox that this is attached to.
25398     tab : false,
25399      
25400     getAutoCreate : function() 
25401     {
25402         var cfg = {
25403             tag: 'div',
25404             cls: 'tab-pane'
25405         };
25406         
25407         if(this.active){
25408             cfg.cls += ' active';
25409         }
25410         
25411         return cfg;
25412     },
25413     initEvents  : function()
25414     {
25415         //Roo.log('trigger add pane handler');
25416         this.parent().fireEvent('addpane', this)
25417     },
25418     
25419      /**
25420      * Updates the tab title 
25421      * @param {String} html to set the title to.
25422      */
25423     setTitle: function(str)
25424     {
25425         if (!this.tab) {
25426             return;
25427         }
25428         this.title = str;
25429         this.tab.select('a', true).first().dom.innerHTML = str;
25430         
25431     }
25432     
25433     
25434     
25435 });
25436
25437  
25438
25439
25440  /*
25441  * - LGPL
25442  *
25443  * menu
25444  * 
25445  */
25446 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25447
25448 /**
25449  * @class Roo.bootstrap.menu.Menu
25450  * @extends Roo.bootstrap.Component
25451  * Bootstrap Menu class - container for Menu
25452  * @cfg {String} html Text of the menu
25453  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25454  * @cfg {String} icon Font awesome icon
25455  * @cfg {String} pos Menu align to (top | bottom) default bottom
25456  * 
25457  * 
25458  * @constructor
25459  * Create a new Menu
25460  * @param {Object} config The config object
25461  */
25462
25463
25464 Roo.bootstrap.menu.Menu = function(config){
25465     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25466     
25467     this.addEvents({
25468         /**
25469          * @event beforeshow
25470          * Fires before this menu is displayed
25471          * @param {Roo.bootstrap.menu.Menu} this
25472          */
25473         beforeshow : true,
25474         /**
25475          * @event beforehide
25476          * Fires before this menu is hidden
25477          * @param {Roo.bootstrap.menu.Menu} this
25478          */
25479         beforehide : true,
25480         /**
25481          * @event show
25482          * Fires after this menu is displayed
25483          * @param {Roo.bootstrap.menu.Menu} this
25484          */
25485         show : true,
25486         /**
25487          * @event hide
25488          * Fires after this menu is hidden
25489          * @param {Roo.bootstrap.menu.Menu} this
25490          */
25491         hide : true,
25492         /**
25493          * @event click
25494          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25495          * @param {Roo.bootstrap.menu.Menu} this
25496          * @param {Roo.EventObject} e
25497          */
25498         click : true
25499     });
25500     
25501 };
25502
25503 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
25504     
25505     submenu : false,
25506     html : '',
25507     weight : 'default',
25508     icon : false,
25509     pos : 'bottom',
25510     
25511     
25512     getChildContainer : function() {
25513         if(this.isSubMenu){
25514             return this.el;
25515         }
25516         
25517         return this.el.select('ul.dropdown-menu', true).first();  
25518     },
25519     
25520     getAutoCreate : function()
25521     {
25522         var text = [
25523             {
25524                 tag : 'span',
25525                 cls : 'roo-menu-text',
25526                 html : this.html
25527             }
25528         ];
25529         
25530         if(this.icon){
25531             text.unshift({
25532                 tag : 'i',
25533                 cls : 'fa ' + this.icon
25534             })
25535         }
25536         
25537         
25538         var cfg = {
25539             tag : 'div',
25540             cls : 'btn-group',
25541             cn : [
25542                 {
25543                     tag : 'button',
25544                     cls : 'dropdown-button btn btn-' + this.weight,
25545                     cn : text
25546                 },
25547                 {
25548                     tag : 'button',
25549                     cls : 'dropdown-toggle btn btn-' + this.weight,
25550                     cn : [
25551                         {
25552                             tag : 'span',
25553                             cls : 'caret'
25554                         }
25555                     ]
25556                 },
25557                 {
25558                     tag : 'ul',
25559                     cls : 'dropdown-menu'
25560                 }
25561             ]
25562             
25563         };
25564         
25565         if(this.pos == 'top'){
25566             cfg.cls += ' dropup';
25567         }
25568         
25569         if(this.isSubMenu){
25570             cfg = {
25571                 tag : 'ul',
25572                 cls : 'dropdown-menu'
25573             }
25574         }
25575         
25576         return cfg;
25577     },
25578     
25579     onRender : function(ct, position)
25580     {
25581         this.isSubMenu = ct.hasClass('dropdown-submenu');
25582         
25583         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25584     },
25585     
25586     initEvents : function() 
25587     {
25588         if(this.isSubMenu){
25589             return;
25590         }
25591         
25592         this.hidden = true;
25593         
25594         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25595         this.triggerEl.on('click', this.onTriggerPress, this);
25596         
25597         this.buttonEl = this.el.select('button.dropdown-button', true).first();
25598         this.buttonEl.on('click', this.onClick, this);
25599         
25600     },
25601     
25602     list : function()
25603     {
25604         if(this.isSubMenu){
25605             return this.el;
25606         }
25607         
25608         return this.el.select('ul.dropdown-menu', true).first();
25609     },
25610     
25611     onClick : function(e)
25612     {
25613         this.fireEvent("click", this, e);
25614     },
25615     
25616     onTriggerPress  : function(e)
25617     {   
25618         if (this.isVisible()) {
25619             this.hide();
25620         } else {
25621             this.show();
25622         }
25623     },
25624     
25625     isVisible : function(){
25626         return !this.hidden;
25627     },
25628     
25629     show : function()
25630     {
25631         this.fireEvent("beforeshow", this);
25632         
25633         this.hidden = false;
25634         this.el.addClass('open');
25635         
25636         Roo.get(document).on("mouseup", this.onMouseUp, this);
25637         
25638         this.fireEvent("show", this);
25639         
25640         
25641     },
25642     
25643     hide : function()
25644     {
25645         this.fireEvent("beforehide", this);
25646         
25647         this.hidden = true;
25648         this.el.removeClass('open');
25649         
25650         Roo.get(document).un("mouseup", this.onMouseUp);
25651         
25652         this.fireEvent("hide", this);
25653     },
25654     
25655     onMouseUp : function()
25656     {
25657         this.hide();
25658     }
25659     
25660 });
25661
25662  
25663  /*
25664  * - LGPL
25665  *
25666  * menu item
25667  * 
25668  */
25669 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25670
25671 /**
25672  * @class Roo.bootstrap.menu.Item
25673  * @extends Roo.bootstrap.Component
25674  * Bootstrap MenuItem class
25675  * @cfg {Boolean} submenu (true | false) default false
25676  * @cfg {String} html text of the item
25677  * @cfg {String} href the link
25678  * @cfg {Boolean} disable (true | false) default false
25679  * @cfg {Boolean} preventDefault (true | false) default true
25680  * @cfg {String} icon Font awesome icon
25681  * @cfg {String} pos Submenu align to (left | right) default right 
25682  * 
25683  * 
25684  * @constructor
25685  * Create a new Item
25686  * @param {Object} config The config object
25687  */
25688
25689
25690 Roo.bootstrap.menu.Item = function(config){
25691     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25692     this.addEvents({
25693         /**
25694          * @event mouseover
25695          * Fires when the mouse is hovering over this menu
25696          * @param {Roo.bootstrap.menu.Item} this
25697          * @param {Roo.EventObject} e
25698          */
25699         mouseover : true,
25700         /**
25701          * @event mouseout
25702          * Fires when the mouse exits this menu
25703          * @param {Roo.bootstrap.menu.Item} this
25704          * @param {Roo.EventObject} e
25705          */
25706         mouseout : true,
25707         // raw events
25708         /**
25709          * @event click
25710          * The raw click event for the entire grid.
25711          * @param {Roo.EventObject} e
25712          */
25713         click : true
25714     });
25715 };
25716
25717 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
25718     
25719     submenu : false,
25720     href : '',
25721     html : '',
25722     preventDefault: true,
25723     disable : false,
25724     icon : false,
25725     pos : 'right',
25726     
25727     getAutoCreate : function()
25728     {
25729         var text = [
25730             {
25731                 tag : 'span',
25732                 cls : 'roo-menu-item-text',
25733                 html : this.html
25734             }
25735         ];
25736         
25737         if(this.icon){
25738             text.unshift({
25739                 tag : 'i',
25740                 cls : 'fa ' + this.icon
25741             })
25742         }
25743         
25744         var cfg = {
25745             tag : 'li',
25746             cn : [
25747                 {
25748                     tag : 'a',
25749                     href : this.href || '#',
25750                     cn : text
25751                 }
25752             ]
25753         };
25754         
25755         if(this.disable){
25756             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25757         }
25758         
25759         if(this.submenu){
25760             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25761             
25762             if(this.pos == 'left'){
25763                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25764             }
25765         }
25766         
25767         return cfg;
25768     },
25769     
25770     initEvents : function() 
25771     {
25772         this.el.on('mouseover', this.onMouseOver, this);
25773         this.el.on('mouseout', this.onMouseOut, this);
25774         
25775         this.el.select('a', true).first().on('click', this.onClick, this);
25776         
25777     },
25778     
25779     onClick : function(e)
25780     {
25781         if(this.preventDefault){
25782             e.preventDefault();
25783         }
25784         
25785         this.fireEvent("click", this, e);
25786     },
25787     
25788     onMouseOver : function(e)
25789     {
25790         if(this.submenu && this.pos == 'left'){
25791             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25792         }
25793         
25794         this.fireEvent("mouseover", this, e);
25795     },
25796     
25797     onMouseOut : function(e)
25798     {
25799         this.fireEvent("mouseout", this, e);
25800     }
25801 });
25802
25803  
25804
25805  /*
25806  * - LGPL
25807  *
25808  * menu separator
25809  * 
25810  */
25811 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25812
25813 /**
25814  * @class Roo.bootstrap.menu.Separator
25815  * @extends Roo.bootstrap.Component
25816  * Bootstrap Separator class
25817  * 
25818  * @constructor
25819  * Create a new Separator
25820  * @param {Object} config The config object
25821  */
25822
25823
25824 Roo.bootstrap.menu.Separator = function(config){
25825     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25826 };
25827
25828 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
25829     
25830     getAutoCreate : function(){
25831         var cfg = {
25832             tag : 'li',
25833             cls: 'divider'
25834         };
25835         
25836         return cfg;
25837     }
25838    
25839 });
25840
25841  
25842
25843  /*
25844  * - LGPL
25845  *
25846  * Tooltip
25847  * 
25848  */
25849
25850 /**
25851  * @class Roo.bootstrap.Tooltip
25852  * Bootstrap Tooltip class
25853  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25854  * to determine which dom element triggers the tooltip.
25855  * 
25856  * It needs to add support for additional attributes like tooltip-position
25857  * 
25858  * @constructor
25859  * Create a new Toolti
25860  * @param {Object} config The config object
25861  */
25862
25863 Roo.bootstrap.Tooltip = function(config){
25864     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25865     
25866     this.alignment = Roo.bootstrap.Tooltip.alignment;
25867     
25868     if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25869         this.alignment = config.alignment;
25870     }
25871     
25872 };
25873
25874 Roo.apply(Roo.bootstrap.Tooltip, {
25875     /**
25876      * @function init initialize tooltip monitoring.
25877      * @static
25878      */
25879     currentEl : false,
25880     currentTip : false,
25881     currentRegion : false,
25882     
25883     //  init : delay?
25884     
25885     init : function()
25886     {
25887         Roo.get(document).on('mouseover', this.enter ,this);
25888         Roo.get(document).on('mouseout', this.leave, this);
25889          
25890         
25891         this.currentTip = new Roo.bootstrap.Tooltip();
25892     },
25893     
25894     enter : function(ev)
25895     {
25896         var dom = ev.getTarget();
25897         
25898         //Roo.log(['enter',dom]);
25899         var el = Roo.fly(dom);
25900         if (this.currentEl) {
25901             //Roo.log(dom);
25902             //Roo.log(this.currentEl);
25903             //Roo.log(this.currentEl.contains(dom));
25904             if (this.currentEl == el) {
25905                 return;
25906             }
25907             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25908                 return;
25909             }
25910
25911         }
25912         
25913         if (this.currentTip.el) {
25914             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25915         }    
25916         //Roo.log(ev);
25917         
25918         if(!el || el.dom == document){
25919             return;
25920         }
25921         
25922         var bindEl = el;
25923         
25924         // you can not look for children, as if el is the body.. then everythign is the child..
25925         if (!el.attr('tooltip')) { //
25926             if (!el.select("[tooltip]").elements.length) {
25927                 return;
25928             }
25929             // is the mouse over this child...?
25930             bindEl = el.select("[tooltip]").first();
25931             var xy = ev.getXY();
25932             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25933                 //Roo.log("not in region.");
25934                 return;
25935             }
25936             //Roo.log("child element over..");
25937             
25938         }
25939         this.currentEl = bindEl;
25940         this.currentTip.bind(bindEl);
25941         this.currentRegion = Roo.lib.Region.getRegion(dom);
25942         this.currentTip.enter();
25943         
25944     },
25945     leave : function(ev)
25946     {
25947         var dom = ev.getTarget();
25948         //Roo.log(['leave',dom]);
25949         if (!this.currentEl) {
25950             return;
25951         }
25952         
25953         
25954         if (dom != this.currentEl.dom) {
25955             return;
25956         }
25957         var xy = ev.getXY();
25958         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
25959             return;
25960         }
25961         // only activate leave if mouse cursor is outside... bounding box..
25962         
25963         
25964         
25965         
25966         if (this.currentTip) {
25967             this.currentTip.leave();
25968         }
25969         //Roo.log('clear currentEl');
25970         this.currentEl = false;
25971         
25972         
25973     },
25974     alignment : {
25975         'left' : ['r-l', [-2,0], 'right'],
25976         'right' : ['l-r', [2,0], 'left'],
25977         'bottom' : ['t-b', [0,2], 'top'],
25978         'top' : [ 'b-t', [0,-2], 'bottom']
25979     }
25980     
25981 });
25982
25983
25984 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
25985     
25986     
25987     bindEl : false,
25988     
25989     delay : null, // can be { show : 300 , hide: 500}
25990     
25991     timeout : null,
25992     
25993     hoverState : null, //???
25994     
25995     placement : 'bottom', 
25996     
25997     alignment : false,
25998     
25999     getAutoCreate : function(){
26000     
26001         var cfg = {
26002            cls : 'tooltip',
26003            role : 'tooltip',
26004            cn : [
26005                 {
26006                     cls : 'tooltip-arrow'
26007                 },
26008                 {
26009                     cls : 'tooltip-inner'
26010                 }
26011            ]
26012         };
26013         
26014         return cfg;
26015     },
26016     bind : function(el)
26017     {
26018         this.bindEl = el;
26019     },
26020       
26021     
26022     enter : function () {
26023        
26024         if (this.timeout != null) {
26025             clearTimeout(this.timeout);
26026         }
26027         
26028         this.hoverState = 'in';
26029          //Roo.log("enter - show");
26030         if (!this.delay || !this.delay.show) {
26031             this.show();
26032             return;
26033         }
26034         var _t = this;
26035         this.timeout = setTimeout(function () {
26036             if (_t.hoverState == 'in') {
26037                 _t.show();
26038             }
26039         }, this.delay.show);
26040     },
26041     leave : function()
26042     {
26043         clearTimeout(this.timeout);
26044     
26045         this.hoverState = 'out';
26046          if (!this.delay || !this.delay.hide) {
26047             this.hide();
26048             return;
26049         }
26050        
26051         var _t = this;
26052         this.timeout = setTimeout(function () {
26053             //Roo.log("leave - timeout");
26054             
26055             if (_t.hoverState == 'out') {
26056                 _t.hide();
26057                 Roo.bootstrap.Tooltip.currentEl = false;
26058             }
26059         }, delay);
26060     },
26061     
26062     show : function (msg)
26063     {
26064         if (!this.el) {
26065             this.render(document.body);
26066         }
26067         // set content.
26068         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26069         
26070         var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26071         
26072         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26073         
26074         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26075         
26076         var placement = typeof this.placement == 'function' ?
26077             this.placement.call(this, this.el, on_el) :
26078             this.placement;
26079             
26080         var autoToken = /\s?auto?\s?/i;
26081         var autoPlace = autoToken.test(placement);
26082         if (autoPlace) {
26083             placement = placement.replace(autoToken, '') || 'top';
26084         }
26085         
26086         //this.el.detach()
26087         //this.el.setXY([0,0]);
26088         this.el.show();
26089         //this.el.dom.style.display='block';
26090         
26091         //this.el.appendTo(on_el);
26092         
26093         var p = this.getPosition();
26094         var box = this.el.getBox();
26095         
26096         if (autoPlace) {
26097             // fixme..
26098         }
26099         
26100         var align = this.alignment[placement];
26101         
26102         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26103         
26104         if(placement == 'top' || placement == 'bottom'){
26105             if(xy[0] < 0){
26106                 placement = 'right';
26107             }
26108             
26109             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26110                 placement = 'left';
26111             }
26112             
26113             var scroll = Roo.select('body', true).first().getScroll();
26114             
26115             if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26116                 placement = 'top';
26117             }
26118             
26119         }
26120         
26121         this.el.alignTo(this.bindEl, align[0],align[1]);
26122         //var arrow = this.el.select('.arrow',true).first();
26123         //arrow.set(align[2], 
26124         
26125         this.el.addClass(placement);
26126         
26127         this.el.addClass('in fade');
26128         
26129         this.hoverState = null;
26130         
26131         if (this.el.hasClass('fade')) {
26132             // fade it?
26133         }
26134         
26135     },
26136     hide : function()
26137     {
26138          
26139         if (!this.el) {
26140             return;
26141         }
26142         //this.el.setXY([0,0]);
26143         this.el.removeClass('in');
26144         //this.el.hide();
26145         
26146     }
26147     
26148 });
26149  
26150
26151  /*
26152  * - LGPL
26153  *
26154  * Location Picker
26155  * 
26156  */
26157
26158 /**
26159  * @class Roo.bootstrap.LocationPicker
26160  * @extends Roo.bootstrap.Component
26161  * Bootstrap LocationPicker class
26162  * @cfg {Number} latitude Position when init default 0
26163  * @cfg {Number} longitude Position when init default 0
26164  * @cfg {Number} zoom default 15
26165  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26166  * @cfg {Boolean} mapTypeControl default false
26167  * @cfg {Boolean} disableDoubleClickZoom default false
26168  * @cfg {Boolean} scrollwheel default true
26169  * @cfg {Boolean} streetViewControl default false
26170  * @cfg {Number} radius default 0
26171  * @cfg {String} locationName
26172  * @cfg {Boolean} draggable default true
26173  * @cfg {Boolean} enableAutocomplete default false
26174  * @cfg {Boolean} enableReverseGeocode default true
26175  * @cfg {String} markerTitle
26176  * 
26177  * @constructor
26178  * Create a new LocationPicker
26179  * @param {Object} config The config object
26180  */
26181
26182
26183 Roo.bootstrap.LocationPicker = function(config){
26184     
26185     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26186     
26187     this.addEvents({
26188         /**
26189          * @event initial
26190          * Fires when the picker initialized.
26191          * @param {Roo.bootstrap.LocationPicker} this
26192          * @param {Google Location} location
26193          */
26194         initial : true,
26195         /**
26196          * @event positionchanged
26197          * Fires when the picker position changed.
26198          * @param {Roo.bootstrap.LocationPicker} this
26199          * @param {Google Location} location
26200          */
26201         positionchanged : true,
26202         /**
26203          * @event resize
26204          * Fires when the map resize.
26205          * @param {Roo.bootstrap.LocationPicker} this
26206          */
26207         resize : true,
26208         /**
26209          * @event show
26210          * Fires when the map show.
26211          * @param {Roo.bootstrap.LocationPicker} this
26212          */
26213         show : true,
26214         /**
26215          * @event hide
26216          * Fires when the map hide.
26217          * @param {Roo.bootstrap.LocationPicker} this
26218          */
26219         hide : true,
26220         /**
26221          * @event mapClick
26222          * Fires when click the map.
26223          * @param {Roo.bootstrap.LocationPicker} this
26224          * @param {Map event} e
26225          */
26226         mapClick : true,
26227         /**
26228          * @event mapRightClick
26229          * Fires when right click the map.
26230          * @param {Roo.bootstrap.LocationPicker} this
26231          * @param {Map event} e
26232          */
26233         mapRightClick : true,
26234         /**
26235          * @event markerClick
26236          * Fires when click the marker.
26237          * @param {Roo.bootstrap.LocationPicker} this
26238          * @param {Map event} e
26239          */
26240         markerClick : true,
26241         /**
26242          * @event markerRightClick
26243          * Fires when right click the marker.
26244          * @param {Roo.bootstrap.LocationPicker} this
26245          * @param {Map event} e
26246          */
26247         markerRightClick : true,
26248         /**
26249          * @event OverlayViewDraw
26250          * Fires when OverlayView Draw
26251          * @param {Roo.bootstrap.LocationPicker} this
26252          */
26253         OverlayViewDraw : true,
26254         /**
26255          * @event OverlayViewOnAdd
26256          * Fires when OverlayView Draw
26257          * @param {Roo.bootstrap.LocationPicker} this
26258          */
26259         OverlayViewOnAdd : true,
26260         /**
26261          * @event OverlayViewOnRemove
26262          * Fires when OverlayView Draw
26263          * @param {Roo.bootstrap.LocationPicker} this
26264          */
26265         OverlayViewOnRemove : true,
26266         /**
26267          * @event OverlayViewShow
26268          * Fires when OverlayView Draw
26269          * @param {Roo.bootstrap.LocationPicker} this
26270          * @param {Pixel} cpx
26271          */
26272         OverlayViewShow : true,
26273         /**
26274          * @event OverlayViewHide
26275          * Fires when OverlayView Draw
26276          * @param {Roo.bootstrap.LocationPicker} this
26277          */
26278         OverlayViewHide : true,
26279         /**
26280          * @event loadexception
26281          * Fires when load google lib failed.
26282          * @param {Roo.bootstrap.LocationPicker} this
26283          */
26284         loadexception : true
26285     });
26286         
26287 };
26288
26289 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
26290     
26291     gMapContext: false,
26292     
26293     latitude: 0,
26294     longitude: 0,
26295     zoom: 15,
26296     mapTypeId: false,
26297     mapTypeControl: false,
26298     disableDoubleClickZoom: false,
26299     scrollwheel: true,
26300     streetViewControl: false,
26301     radius: 0,
26302     locationName: '',
26303     draggable: true,
26304     enableAutocomplete: false,
26305     enableReverseGeocode: true,
26306     markerTitle: '',
26307     
26308     getAutoCreate: function()
26309     {
26310
26311         var cfg = {
26312             tag: 'div',
26313             cls: 'roo-location-picker'
26314         };
26315         
26316         return cfg
26317     },
26318     
26319     initEvents: function(ct, position)
26320     {       
26321         if(!this.el.getWidth() || this.isApplied()){
26322             return;
26323         }
26324         
26325         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26326         
26327         this.initial();
26328     },
26329     
26330     initial: function()
26331     {
26332         if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26333             this.fireEvent('loadexception', this);
26334             return;
26335         }
26336         
26337         if(!this.mapTypeId){
26338             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26339         }
26340         
26341         this.gMapContext = this.GMapContext();
26342         
26343         this.initOverlayView();
26344         
26345         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26346         
26347         var _this = this;
26348                 
26349         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26350             _this.setPosition(_this.gMapContext.marker.position);
26351         });
26352         
26353         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26354             _this.fireEvent('mapClick', this, event);
26355             
26356         });
26357
26358         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26359             _this.fireEvent('mapRightClick', this, event);
26360             
26361         });
26362         
26363         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26364             _this.fireEvent('markerClick', this, event);
26365             
26366         });
26367
26368         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26369             _this.fireEvent('markerRightClick', this, event);
26370             
26371         });
26372         
26373         this.setPosition(this.gMapContext.location);
26374         
26375         this.fireEvent('initial', this, this.gMapContext.location);
26376     },
26377     
26378     initOverlayView: function()
26379     {
26380         var _this = this;
26381         
26382         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26383             
26384             draw: function()
26385             {
26386                 _this.fireEvent('OverlayViewDraw', _this);
26387             },
26388             
26389             onAdd: function()
26390             {
26391                 _this.fireEvent('OverlayViewOnAdd', _this);
26392             },
26393             
26394             onRemove: function()
26395             {
26396                 _this.fireEvent('OverlayViewOnRemove', _this);
26397             },
26398             
26399             show: function(cpx)
26400             {
26401                 _this.fireEvent('OverlayViewShow', _this, cpx);
26402             },
26403             
26404             hide: function()
26405             {
26406                 _this.fireEvent('OverlayViewHide', _this);
26407             }
26408             
26409         });
26410     },
26411     
26412     fromLatLngToContainerPixel: function(event)
26413     {
26414         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26415     },
26416     
26417     isApplied: function() 
26418     {
26419         return this.getGmapContext() == false ? false : true;
26420     },
26421     
26422     getGmapContext: function() 
26423     {
26424         return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26425     },
26426     
26427     GMapContext: function() 
26428     {
26429         var position = new google.maps.LatLng(this.latitude, this.longitude);
26430         
26431         var _map = new google.maps.Map(this.el.dom, {
26432             center: position,
26433             zoom: this.zoom,
26434             mapTypeId: this.mapTypeId,
26435             mapTypeControl: this.mapTypeControl,
26436             disableDoubleClickZoom: this.disableDoubleClickZoom,
26437             scrollwheel: this.scrollwheel,
26438             streetViewControl: this.streetViewControl,
26439             locationName: this.locationName,
26440             draggable: this.draggable,
26441             enableAutocomplete: this.enableAutocomplete,
26442             enableReverseGeocode: this.enableReverseGeocode
26443         });
26444         
26445         var _marker = new google.maps.Marker({
26446             position: position,
26447             map: _map,
26448             title: this.markerTitle,
26449             draggable: this.draggable
26450         });
26451         
26452         return {
26453             map: _map,
26454             marker: _marker,
26455             circle: null,
26456             location: position,
26457             radius: this.radius,
26458             locationName: this.locationName,
26459             addressComponents: {
26460                 formatted_address: null,
26461                 addressLine1: null,
26462                 addressLine2: null,
26463                 streetName: null,
26464                 streetNumber: null,
26465                 city: null,
26466                 district: null,
26467                 state: null,
26468                 stateOrProvince: null
26469             },
26470             settings: this,
26471             domContainer: this.el.dom,
26472             geodecoder: new google.maps.Geocoder()
26473         };
26474     },
26475     
26476     drawCircle: function(center, radius, options) 
26477     {
26478         if (this.gMapContext.circle != null) {
26479             this.gMapContext.circle.setMap(null);
26480         }
26481         if (radius > 0) {
26482             radius *= 1;
26483             options = Roo.apply({}, options, {
26484                 strokeColor: "#0000FF",
26485                 strokeOpacity: .35,
26486                 strokeWeight: 2,
26487                 fillColor: "#0000FF",
26488                 fillOpacity: .2
26489             });
26490             
26491             options.map = this.gMapContext.map;
26492             options.radius = radius;
26493             options.center = center;
26494             this.gMapContext.circle = new google.maps.Circle(options);
26495             return this.gMapContext.circle;
26496         }
26497         
26498         return null;
26499     },
26500     
26501     setPosition: function(location) 
26502     {
26503         this.gMapContext.location = location;
26504         this.gMapContext.marker.setPosition(location);
26505         this.gMapContext.map.panTo(location);
26506         this.drawCircle(location, this.gMapContext.radius, {});
26507         
26508         var _this = this;
26509         
26510         if (this.gMapContext.settings.enableReverseGeocode) {
26511             this.gMapContext.geodecoder.geocode({
26512                 latLng: this.gMapContext.location
26513             }, function(results, status) {
26514                 
26515                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26516                     _this.gMapContext.locationName = results[0].formatted_address;
26517                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26518                     
26519                     _this.fireEvent('positionchanged', this, location);
26520                 }
26521             });
26522             
26523             return;
26524         }
26525         
26526         this.fireEvent('positionchanged', this, location);
26527     },
26528     
26529     resize: function()
26530     {
26531         google.maps.event.trigger(this.gMapContext.map, "resize");
26532         
26533         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26534         
26535         this.fireEvent('resize', this);
26536     },
26537     
26538     setPositionByLatLng: function(latitude, longitude)
26539     {
26540         this.setPosition(new google.maps.LatLng(latitude, longitude));
26541     },
26542     
26543     getCurrentPosition: function() 
26544     {
26545         return {
26546             latitude: this.gMapContext.location.lat(),
26547             longitude: this.gMapContext.location.lng()
26548         };
26549     },
26550     
26551     getAddressName: function() 
26552     {
26553         return this.gMapContext.locationName;
26554     },
26555     
26556     getAddressComponents: function() 
26557     {
26558         return this.gMapContext.addressComponents;
26559     },
26560     
26561     address_component_from_google_geocode: function(address_components) 
26562     {
26563         var result = {};
26564         
26565         for (var i = 0; i < address_components.length; i++) {
26566             var component = address_components[i];
26567             if (component.types.indexOf("postal_code") >= 0) {
26568                 result.postalCode = component.short_name;
26569             } else if (component.types.indexOf("street_number") >= 0) {
26570                 result.streetNumber = component.short_name;
26571             } else if (component.types.indexOf("route") >= 0) {
26572                 result.streetName = component.short_name;
26573             } else if (component.types.indexOf("neighborhood") >= 0) {
26574                 result.city = component.short_name;
26575             } else if (component.types.indexOf("locality") >= 0) {
26576                 result.city = component.short_name;
26577             } else if (component.types.indexOf("sublocality") >= 0) {
26578                 result.district = component.short_name;
26579             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26580                 result.stateOrProvince = component.short_name;
26581             } else if (component.types.indexOf("country") >= 0) {
26582                 result.country = component.short_name;
26583             }
26584         }
26585         
26586         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26587         result.addressLine2 = "";
26588         return result;
26589     },
26590     
26591     setZoomLevel: function(zoom)
26592     {
26593         this.gMapContext.map.setZoom(zoom);
26594     },
26595     
26596     show: function()
26597     {
26598         if(!this.el){
26599             return;
26600         }
26601         
26602         this.el.show();
26603         
26604         this.resize();
26605         
26606         this.fireEvent('show', this);
26607     },
26608     
26609     hide: function()
26610     {
26611         if(!this.el){
26612             return;
26613         }
26614         
26615         this.el.hide();
26616         
26617         this.fireEvent('hide', this);
26618     }
26619     
26620 });
26621
26622 Roo.apply(Roo.bootstrap.LocationPicker, {
26623     
26624     OverlayView : function(map, options)
26625     {
26626         options = options || {};
26627         
26628         this.setMap(map);
26629     }
26630     
26631     
26632 });/*
26633  * - LGPL
26634  *
26635  * Alert
26636  * 
26637  */
26638
26639 /**
26640  * @class Roo.bootstrap.Alert
26641  * @extends Roo.bootstrap.Component
26642  * Bootstrap Alert class
26643  * @cfg {String} title The title of alert
26644  * @cfg {String} html The content of alert
26645  * @cfg {String} weight (  success | info | warning | danger )
26646  * @cfg {String} faicon font-awesomeicon
26647  * 
26648  * @constructor
26649  * Create a new alert
26650  * @param {Object} config The config object
26651  */
26652
26653
26654 Roo.bootstrap.Alert = function(config){
26655     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26656     
26657 };
26658
26659 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
26660     
26661     title: '',
26662     html: '',
26663     weight: false,
26664     faicon: false,
26665     
26666     getAutoCreate : function()
26667     {
26668         
26669         var cfg = {
26670             tag : 'div',
26671             cls : 'alert',
26672             cn : [
26673                 {
26674                     tag : 'i',
26675                     cls : 'roo-alert-icon'
26676                     
26677                 },
26678                 {
26679                     tag : 'b',
26680                     cls : 'roo-alert-title',
26681                     html : this.title
26682                 },
26683                 {
26684                     tag : 'span',
26685                     cls : 'roo-alert-text',
26686                     html : this.html
26687                 }
26688             ]
26689         };
26690         
26691         if(this.faicon){
26692             cfg.cn[0].cls += ' fa ' + this.faicon;
26693         }
26694         
26695         if(this.weight){
26696             cfg.cls += ' alert-' + this.weight;
26697         }
26698         
26699         return cfg;
26700     },
26701     
26702     initEvents: function() 
26703     {
26704         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26705     },
26706     
26707     setTitle : function(str)
26708     {
26709         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26710     },
26711     
26712     setText : function(str)
26713     {
26714         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26715     },
26716     
26717     setWeight : function(weight)
26718     {
26719         if(this.weight){
26720             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26721         }
26722         
26723         this.weight = weight;
26724         
26725         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26726     },
26727     
26728     setIcon : function(icon)
26729     {
26730         if(this.faicon){
26731             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26732         }
26733         
26734         this.faicon = icon;
26735         
26736         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26737     },
26738     
26739     hide: function() 
26740     {
26741         this.el.hide();   
26742     },
26743     
26744     show: function() 
26745     {  
26746         this.el.show();   
26747     }
26748     
26749 });
26750
26751  
26752 /*
26753 * Licence: LGPL
26754 */
26755
26756 /**
26757  * @class Roo.bootstrap.UploadCropbox
26758  * @extends Roo.bootstrap.Component
26759  * Bootstrap UploadCropbox class
26760  * @cfg {String} emptyText show when image has been loaded
26761  * @cfg {String} rotateNotify show when image too small to rotate
26762  * @cfg {Number} errorTimeout default 3000
26763  * @cfg {Number} minWidth default 300
26764  * @cfg {Number} minHeight default 300
26765  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26766  * @cfg {Boolean} isDocument (true|false) default false
26767  * @cfg {String} url action url
26768  * @cfg {String} paramName default 'imageUpload'
26769  * @cfg {String} method default POST
26770  * @cfg {Boolean} loadMask (true|false) default true
26771  * @cfg {Boolean} loadingText default 'Loading...'
26772  * 
26773  * @constructor
26774  * Create a new UploadCropbox
26775  * @param {Object} config The config object
26776  */
26777
26778 Roo.bootstrap.UploadCropbox = function(config){
26779     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26780     
26781     this.addEvents({
26782         /**
26783          * @event beforeselectfile
26784          * Fire before select file
26785          * @param {Roo.bootstrap.UploadCropbox} this
26786          */
26787         "beforeselectfile" : true,
26788         /**
26789          * @event initial
26790          * Fire after initEvent
26791          * @param {Roo.bootstrap.UploadCropbox} this
26792          */
26793         "initial" : true,
26794         /**
26795          * @event crop
26796          * Fire after initEvent
26797          * @param {Roo.bootstrap.UploadCropbox} this
26798          * @param {String} data
26799          */
26800         "crop" : true,
26801         /**
26802          * @event prepare
26803          * Fire when preparing the file data
26804          * @param {Roo.bootstrap.UploadCropbox} this
26805          * @param {Object} file
26806          */
26807         "prepare" : true,
26808         /**
26809          * @event exception
26810          * Fire when get exception
26811          * @param {Roo.bootstrap.UploadCropbox} this
26812          * @param {XMLHttpRequest} xhr
26813          */
26814         "exception" : true,
26815         /**
26816          * @event beforeloadcanvas
26817          * Fire before load the canvas
26818          * @param {Roo.bootstrap.UploadCropbox} this
26819          * @param {String} src
26820          */
26821         "beforeloadcanvas" : true,
26822         /**
26823          * @event trash
26824          * Fire when trash image
26825          * @param {Roo.bootstrap.UploadCropbox} this
26826          */
26827         "trash" : true,
26828         /**
26829          * @event download
26830          * Fire when download the image
26831          * @param {Roo.bootstrap.UploadCropbox} this
26832          */
26833         "download" : true,
26834         /**
26835          * @event footerbuttonclick
26836          * Fire when footerbuttonclick
26837          * @param {Roo.bootstrap.UploadCropbox} this
26838          * @param {String} type
26839          */
26840         "footerbuttonclick" : true,
26841         /**
26842          * @event resize
26843          * Fire when resize
26844          * @param {Roo.bootstrap.UploadCropbox} this
26845          */
26846         "resize" : true,
26847         /**
26848          * @event rotate
26849          * Fire when rotate the image
26850          * @param {Roo.bootstrap.UploadCropbox} this
26851          * @param {String} pos
26852          */
26853         "rotate" : true,
26854         /**
26855          * @event inspect
26856          * Fire when inspect the file
26857          * @param {Roo.bootstrap.UploadCropbox} this
26858          * @param {Object} file
26859          */
26860         "inspect" : true,
26861         /**
26862          * @event upload
26863          * Fire when xhr upload the file
26864          * @param {Roo.bootstrap.UploadCropbox} this
26865          * @param {Object} data
26866          */
26867         "upload" : true,
26868         /**
26869          * @event arrange
26870          * Fire when arrange the file data
26871          * @param {Roo.bootstrap.UploadCropbox} this
26872          * @param {Object} formData
26873          */
26874         "arrange" : true
26875     });
26876     
26877     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26878 };
26879
26880 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
26881     
26882     emptyText : 'Click to upload image',
26883     rotateNotify : 'Image is too small to rotate',
26884     errorTimeout : 3000,
26885     scale : 0,
26886     baseScale : 1,
26887     rotate : 0,
26888     dragable : false,
26889     pinching : false,
26890     mouseX : 0,
26891     mouseY : 0,
26892     cropData : false,
26893     minWidth : 300,
26894     minHeight : 300,
26895     file : false,
26896     exif : {},
26897     baseRotate : 1,
26898     cropType : 'image/jpeg',
26899     buttons : false,
26900     canvasLoaded : false,
26901     isDocument : false,
26902     method : 'POST',
26903     paramName : 'imageUpload',
26904     loadMask : true,
26905     loadingText : 'Loading...',
26906     maskEl : false,
26907     
26908     getAutoCreate : function()
26909     {
26910         var cfg = {
26911             tag : 'div',
26912             cls : 'roo-upload-cropbox',
26913             cn : [
26914                 {
26915                     tag : 'input',
26916                     cls : 'roo-upload-cropbox-selector',
26917                     type : 'file'
26918                 },
26919                 {
26920                     tag : 'div',
26921                     cls : 'roo-upload-cropbox-body',
26922                     style : 'cursor:pointer',
26923                     cn : [
26924                         {
26925                             tag : 'div',
26926                             cls : 'roo-upload-cropbox-preview'
26927                         },
26928                         {
26929                             tag : 'div',
26930                             cls : 'roo-upload-cropbox-thumb'
26931                         },
26932                         {
26933                             tag : 'div',
26934                             cls : 'roo-upload-cropbox-empty-notify',
26935                             html : this.emptyText
26936                         },
26937                         {
26938                             tag : 'div',
26939                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26940                             html : this.rotateNotify
26941                         }
26942                     ]
26943                 },
26944                 {
26945                     tag : 'div',
26946                     cls : 'roo-upload-cropbox-footer',
26947                     cn : {
26948                         tag : 'div',
26949                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26950                         cn : []
26951                     }
26952                 }
26953             ]
26954         };
26955         
26956         return cfg;
26957     },
26958     
26959     onRender : function(ct, position)
26960     {
26961         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26962         
26963         if (this.buttons.length) {
26964             
26965             Roo.each(this.buttons, function(bb) {
26966                 
26967                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26968                 
26969                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26970                 
26971             }, this);
26972         }
26973         
26974         if(this.loadMask){
26975             this.maskEl = this.el;
26976         }
26977     },
26978     
26979     initEvents : function()
26980     {
26981         this.urlAPI = (window.createObjectURL && window) || 
26982                                 (window.URL && URL.revokeObjectURL && URL) || 
26983                                 (window.webkitURL && webkitURL);
26984                         
26985         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26986         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26987         
26988         this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26989         this.selectorEl.hide();
26990         
26991         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26992         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26993         
26994         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26995         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26996         this.thumbEl.hide();
26997         
26998         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26999         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27000         
27001         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27002         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27003         this.errorEl.hide();
27004         
27005         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27006         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27007         this.footerEl.hide();
27008         
27009         this.setThumbBoxSize();
27010         
27011         this.bind();
27012         
27013         this.resize();
27014         
27015         this.fireEvent('initial', this);
27016     },
27017
27018     bind : function()
27019     {
27020         var _this = this;
27021         
27022         window.addEventListener("resize", function() { _this.resize(); } );
27023         
27024         this.bodyEl.on('click', this.beforeSelectFile, this);
27025         
27026         if(Roo.isTouch){
27027             this.bodyEl.on('touchstart', this.onTouchStart, this);
27028             this.bodyEl.on('touchmove', this.onTouchMove, this);
27029             this.bodyEl.on('touchend', this.onTouchEnd, this);
27030         }
27031         
27032         if(!Roo.isTouch){
27033             this.bodyEl.on('mousedown', this.onMouseDown, this);
27034             this.bodyEl.on('mousemove', this.onMouseMove, this);
27035             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27036             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27037             Roo.get(document).on('mouseup', this.onMouseUp, this);
27038         }
27039         
27040         this.selectorEl.on('change', this.onFileSelected, this);
27041     },
27042     
27043     reset : function()
27044     {    
27045         this.scale = 0;
27046         this.baseScale = 1;
27047         this.rotate = 0;
27048         this.baseRotate = 1;
27049         this.dragable = false;
27050         this.pinching = false;
27051         this.mouseX = 0;
27052         this.mouseY = 0;
27053         this.cropData = false;
27054         this.notifyEl.dom.innerHTML = this.emptyText;
27055         
27056         this.selectorEl.dom.value = '';
27057         
27058     },
27059     
27060     resize : function()
27061     {
27062         if(this.fireEvent('resize', this) != false){
27063             this.setThumbBoxPosition();
27064             this.setCanvasPosition();
27065         }
27066     },
27067     
27068     onFooterButtonClick : function(e, el, o, type)
27069     {
27070         switch (type) {
27071             case 'rotate-left' :
27072                 this.onRotateLeft(e);
27073                 break;
27074             case 'rotate-right' :
27075                 this.onRotateRight(e);
27076                 break;
27077             case 'picture' :
27078                 this.beforeSelectFile(e);
27079                 break;
27080             case 'trash' :
27081                 this.trash(e);
27082                 break;
27083             case 'crop' :
27084                 this.crop(e);
27085                 break;
27086             case 'download' :
27087                 this.download(e);
27088                 break;
27089             default :
27090                 break;
27091         }
27092         
27093         this.fireEvent('footerbuttonclick', this, type);
27094     },
27095     
27096     beforeSelectFile : function(e)
27097     {
27098         e.preventDefault();
27099         
27100         if(this.fireEvent('beforeselectfile', this) != false){
27101             this.selectorEl.dom.click();
27102         }
27103     },
27104     
27105     onFileSelected : function(e)
27106     {
27107         e.preventDefault();
27108         
27109         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27110             return;
27111         }
27112         
27113         var file = this.selectorEl.dom.files[0];
27114         
27115         if(this.fireEvent('inspect', this, file) != false){
27116             this.prepare(file);
27117         }
27118         
27119     },
27120     
27121     trash : function(e)
27122     {
27123         this.fireEvent('trash', this);
27124     },
27125     
27126     download : function(e)
27127     {
27128         this.fireEvent('download', this);
27129     },
27130     
27131     loadCanvas : function(src)
27132     {   
27133         if(this.fireEvent('beforeloadcanvas', this, src) != false){
27134             
27135             this.reset();
27136             
27137             this.imageEl = document.createElement('img');
27138             
27139             var _this = this;
27140             
27141             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27142             
27143             this.imageEl.src = src;
27144         }
27145     },
27146     
27147     onLoadCanvas : function()
27148     {   
27149         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27150         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27151         
27152         this.bodyEl.un('click', this.beforeSelectFile, this);
27153         
27154         this.notifyEl.hide();
27155         this.thumbEl.show();
27156         this.footerEl.show();
27157         
27158         this.baseRotateLevel();
27159         
27160         if(this.isDocument){
27161             this.setThumbBoxSize();
27162         }
27163         
27164         this.setThumbBoxPosition();
27165         
27166         this.baseScaleLevel();
27167         
27168         this.draw();
27169         
27170         this.resize();
27171         
27172         this.canvasLoaded = true;
27173         
27174         if(this.loadMask){
27175             this.maskEl.unmask();
27176         }
27177         
27178     },
27179     
27180     setCanvasPosition : function()
27181     {   
27182         if(!this.canvasEl){
27183             return;
27184         }
27185         
27186         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27187         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27188         
27189         this.previewEl.setLeft(pw);
27190         this.previewEl.setTop(ph);
27191         
27192     },
27193     
27194     onMouseDown : function(e)
27195     {   
27196         e.stopEvent();
27197         
27198         this.dragable = true;
27199         this.pinching = false;
27200         
27201         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27202             this.dragable = false;
27203             return;
27204         }
27205         
27206         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27207         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27208         
27209     },
27210     
27211     onMouseMove : function(e)
27212     {   
27213         e.stopEvent();
27214         
27215         if(!this.canvasLoaded){
27216             return;
27217         }
27218         
27219         if (!this.dragable){
27220             return;
27221         }
27222         
27223         var minX = Math.ceil(this.thumbEl.getLeft(true));
27224         var minY = Math.ceil(this.thumbEl.getTop(true));
27225         
27226         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27227         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27228         
27229         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27230         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27231         
27232         x = x - this.mouseX;
27233         y = y - this.mouseY;
27234         
27235         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27236         var bgY = Math.ceil(y + this.previewEl.getTop(true));
27237         
27238         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27239         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27240         
27241         this.previewEl.setLeft(bgX);
27242         this.previewEl.setTop(bgY);
27243         
27244         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27245         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27246     },
27247     
27248     onMouseUp : function(e)
27249     {   
27250         e.stopEvent();
27251         
27252         this.dragable = false;
27253     },
27254     
27255     onMouseWheel : function(e)
27256     {   
27257         e.stopEvent();
27258         
27259         this.startScale = this.scale;
27260         
27261         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27262         
27263         if(!this.zoomable()){
27264             this.scale = this.startScale;
27265             return;
27266         }
27267         
27268         this.draw();
27269         
27270         return;
27271     },
27272     
27273     zoomable : function()
27274     {
27275         var minScale = this.thumbEl.getWidth() / this.minWidth;
27276         
27277         if(this.minWidth < this.minHeight){
27278             minScale = this.thumbEl.getHeight() / this.minHeight;
27279         }
27280         
27281         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27282         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27283         
27284         if(
27285                 this.isDocument &&
27286                 (this.rotate == 0 || this.rotate == 180) && 
27287                 (
27288                     width > this.imageEl.OriginWidth || 
27289                     height > this.imageEl.OriginHeight ||
27290                     (width < this.minWidth && height < this.minHeight)
27291                 )
27292         ){
27293             return false;
27294         }
27295         
27296         if(
27297                 this.isDocument &&
27298                 (this.rotate == 90 || this.rotate == 270) && 
27299                 (
27300                     width > this.imageEl.OriginWidth || 
27301                     height > this.imageEl.OriginHeight ||
27302                     (width < this.minHeight && height < this.minWidth)
27303                 )
27304         ){
27305             return false;
27306         }
27307         
27308         if(
27309                 !this.isDocument &&
27310                 (this.rotate == 0 || this.rotate == 180) && 
27311                 (
27312                     width < this.minWidth || 
27313                     width > this.imageEl.OriginWidth || 
27314                     height < this.minHeight || 
27315                     height > this.imageEl.OriginHeight
27316                 )
27317         ){
27318             return false;
27319         }
27320         
27321         if(
27322                 !this.isDocument &&
27323                 (this.rotate == 90 || this.rotate == 270) && 
27324                 (
27325                     width < this.minHeight || 
27326                     width > this.imageEl.OriginWidth || 
27327                     height < this.minWidth || 
27328                     height > this.imageEl.OriginHeight
27329                 )
27330         ){
27331             return false;
27332         }
27333         
27334         return true;
27335         
27336     },
27337     
27338     onRotateLeft : function(e)
27339     {   
27340         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27341             
27342             var minScale = this.thumbEl.getWidth() / this.minWidth;
27343             
27344             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27345             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27346             
27347             this.startScale = this.scale;
27348             
27349             while (this.getScaleLevel() < minScale){
27350             
27351                 this.scale = this.scale + 1;
27352                 
27353                 if(!this.zoomable()){
27354                     break;
27355                 }
27356                 
27357                 if(
27358                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27359                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27360                 ){
27361                     continue;
27362                 }
27363                 
27364                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27365
27366                 this.draw();
27367                 
27368                 return;
27369             }
27370             
27371             this.scale = this.startScale;
27372             
27373             this.onRotateFail();
27374             
27375             return false;
27376         }
27377         
27378         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27379
27380         if(this.isDocument){
27381             this.setThumbBoxSize();
27382             this.setThumbBoxPosition();
27383             this.setCanvasPosition();
27384         }
27385         
27386         this.draw();
27387         
27388         this.fireEvent('rotate', this, 'left');
27389         
27390     },
27391     
27392     onRotateRight : function(e)
27393     {
27394         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27395             
27396             var minScale = this.thumbEl.getWidth() / this.minWidth;
27397         
27398             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27399             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27400             
27401             this.startScale = this.scale;
27402             
27403             while (this.getScaleLevel() < minScale){
27404             
27405                 this.scale = this.scale + 1;
27406                 
27407                 if(!this.zoomable()){
27408                     break;
27409                 }
27410                 
27411                 if(
27412                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27413                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27414                 ){
27415                     continue;
27416                 }
27417                 
27418                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27419
27420                 this.draw();
27421                 
27422                 return;
27423             }
27424             
27425             this.scale = this.startScale;
27426             
27427             this.onRotateFail();
27428             
27429             return false;
27430         }
27431         
27432         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27433
27434         if(this.isDocument){
27435             this.setThumbBoxSize();
27436             this.setThumbBoxPosition();
27437             this.setCanvasPosition();
27438         }
27439         
27440         this.draw();
27441         
27442         this.fireEvent('rotate', this, 'right');
27443     },
27444     
27445     onRotateFail : function()
27446     {
27447         this.errorEl.show(true);
27448         
27449         var _this = this;
27450         
27451         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27452     },
27453     
27454     draw : function()
27455     {
27456         this.previewEl.dom.innerHTML = '';
27457         
27458         var canvasEl = document.createElement("canvas");
27459         
27460         var contextEl = canvasEl.getContext("2d");
27461         
27462         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27463         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27464         var center = this.imageEl.OriginWidth / 2;
27465         
27466         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27467             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27468             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27469             center = this.imageEl.OriginHeight / 2;
27470         }
27471         
27472         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27473         
27474         contextEl.translate(center, center);
27475         contextEl.rotate(this.rotate * Math.PI / 180);
27476
27477         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27478         
27479         this.canvasEl = document.createElement("canvas");
27480         
27481         this.contextEl = this.canvasEl.getContext("2d");
27482         
27483         switch (this.rotate) {
27484             case 0 :
27485                 
27486                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27487                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27488                 
27489                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27490                 
27491                 break;
27492             case 90 : 
27493                 
27494                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27495                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27496                 
27497                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27498                     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);
27499                     break;
27500                 }
27501                 
27502                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27503                 
27504                 break;
27505             case 180 :
27506                 
27507                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27508                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27509                 
27510                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27511                     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);
27512                     break;
27513                 }
27514                 
27515                 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);
27516                 
27517                 break;
27518             case 270 :
27519                 
27520                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27521                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27522         
27523                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27524                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27525                     break;
27526                 }
27527                 
27528                 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);
27529                 
27530                 break;
27531             default : 
27532                 break;
27533         }
27534         
27535         this.previewEl.appendChild(this.canvasEl);
27536         
27537         this.setCanvasPosition();
27538     },
27539     
27540     crop : function()
27541     {
27542         if(!this.canvasLoaded){
27543             return;
27544         }
27545         
27546         var imageCanvas = document.createElement("canvas");
27547         
27548         var imageContext = imageCanvas.getContext("2d");
27549         
27550         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27551         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27552         
27553         var center = imageCanvas.width / 2;
27554         
27555         imageContext.translate(center, center);
27556         
27557         imageContext.rotate(this.rotate * Math.PI / 180);
27558         
27559         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27560         
27561         var canvas = document.createElement("canvas");
27562         
27563         var context = canvas.getContext("2d");
27564                 
27565         canvas.width = this.minWidth;
27566         canvas.height = this.minHeight;
27567
27568         switch (this.rotate) {
27569             case 0 :
27570                 
27571                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27572                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27573                 
27574                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27575                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27576                 
27577                 var targetWidth = this.minWidth - 2 * x;
27578                 var targetHeight = this.minHeight - 2 * y;
27579                 
27580                 var scale = 1;
27581                 
27582                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27583                     scale = targetWidth / width;
27584                 }
27585                 
27586                 if(x > 0 && y == 0){
27587                     scale = targetHeight / height;
27588                 }
27589                 
27590                 if(x > 0 && y > 0){
27591                     scale = targetWidth / width;
27592                     
27593                     if(width < height){
27594                         scale = targetHeight / height;
27595                     }
27596                 }
27597                 
27598                 context.scale(scale, scale);
27599                 
27600                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27601                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27602
27603                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27604                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27605
27606                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27607                 
27608                 break;
27609             case 90 : 
27610                 
27611                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27612                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27613                 
27614                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27615                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27616                 
27617                 var targetWidth = this.minWidth - 2 * x;
27618                 var targetHeight = this.minHeight - 2 * y;
27619                 
27620                 var scale = 1;
27621                 
27622                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27623                     scale = targetWidth / width;
27624                 }
27625                 
27626                 if(x > 0 && y == 0){
27627                     scale = targetHeight / height;
27628                 }
27629                 
27630                 if(x > 0 && y > 0){
27631                     scale = targetWidth / width;
27632                     
27633                     if(width < height){
27634                         scale = targetHeight / height;
27635                     }
27636                 }
27637                 
27638                 context.scale(scale, scale);
27639                 
27640                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27641                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27642
27643                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27644                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27645                 
27646                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27647                 
27648                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27649                 
27650                 break;
27651             case 180 :
27652                 
27653                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27654                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27655                 
27656                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27657                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27658                 
27659                 var targetWidth = this.minWidth - 2 * x;
27660                 var targetHeight = this.minHeight - 2 * y;
27661                 
27662                 var scale = 1;
27663                 
27664                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27665                     scale = targetWidth / width;
27666                 }
27667                 
27668                 if(x > 0 && y == 0){
27669                     scale = targetHeight / height;
27670                 }
27671                 
27672                 if(x > 0 && y > 0){
27673                     scale = targetWidth / width;
27674                     
27675                     if(width < height){
27676                         scale = targetHeight / height;
27677                     }
27678                 }
27679                 
27680                 context.scale(scale, scale);
27681                 
27682                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27683                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27684
27685                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27686                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27687
27688                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27689                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27690                 
27691                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27692                 
27693                 break;
27694             case 270 :
27695                 
27696                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27697                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27698                 
27699                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27700                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27701                 
27702                 var targetWidth = this.minWidth - 2 * x;
27703                 var targetHeight = this.minHeight - 2 * y;
27704                 
27705                 var scale = 1;
27706                 
27707                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27708                     scale = targetWidth / width;
27709                 }
27710                 
27711                 if(x > 0 && y == 0){
27712                     scale = targetHeight / height;
27713                 }
27714                 
27715                 if(x > 0 && y > 0){
27716                     scale = targetWidth / width;
27717                     
27718                     if(width < height){
27719                         scale = targetHeight / height;
27720                     }
27721                 }
27722                 
27723                 context.scale(scale, scale);
27724                 
27725                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27726                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27727
27728                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27729                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27730                 
27731                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27732                 
27733                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27734                 
27735                 break;
27736             default : 
27737                 break;
27738         }
27739         
27740         this.cropData = canvas.toDataURL(this.cropType);
27741         
27742         if(this.fireEvent('crop', this, this.cropData) !== false){
27743             this.process(this.file, this.cropData);
27744         }
27745         
27746         return;
27747         
27748     },
27749     
27750     setThumbBoxSize : function()
27751     {
27752         var width, height;
27753         
27754         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27755             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27756             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27757             
27758             this.minWidth = width;
27759             this.minHeight = height;
27760             
27761             if(this.rotate == 90 || this.rotate == 270){
27762                 this.minWidth = height;
27763                 this.minHeight = width;
27764             }
27765         }
27766         
27767         height = 300;
27768         width = Math.ceil(this.minWidth * height / this.minHeight);
27769         
27770         if(this.minWidth > this.minHeight){
27771             width = 300;
27772             height = Math.ceil(this.minHeight * width / this.minWidth);
27773         }
27774         
27775         this.thumbEl.setStyle({
27776             width : width + 'px',
27777             height : height + 'px'
27778         });
27779
27780         return;
27781             
27782     },
27783     
27784     setThumbBoxPosition : function()
27785     {
27786         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27787         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27788         
27789         this.thumbEl.setLeft(x);
27790         this.thumbEl.setTop(y);
27791         
27792     },
27793     
27794     baseRotateLevel : function()
27795     {
27796         this.baseRotate = 1;
27797         
27798         if(
27799                 typeof(this.exif) != 'undefined' &&
27800                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27801                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27802         ){
27803             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27804         }
27805         
27806         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27807         
27808     },
27809     
27810     baseScaleLevel : function()
27811     {
27812         var width, height;
27813         
27814         if(this.isDocument){
27815             
27816             if(this.baseRotate == 6 || this.baseRotate == 8){
27817             
27818                 height = this.thumbEl.getHeight();
27819                 this.baseScale = height / this.imageEl.OriginWidth;
27820
27821                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27822                     width = this.thumbEl.getWidth();
27823                     this.baseScale = width / this.imageEl.OriginHeight;
27824                 }
27825
27826                 return;
27827             }
27828
27829             height = this.thumbEl.getHeight();
27830             this.baseScale = height / this.imageEl.OriginHeight;
27831
27832             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27833                 width = this.thumbEl.getWidth();
27834                 this.baseScale = width / this.imageEl.OriginWidth;
27835             }
27836
27837             return;
27838         }
27839         
27840         if(this.baseRotate == 6 || this.baseRotate == 8){
27841             
27842             width = this.thumbEl.getHeight();
27843             this.baseScale = width / this.imageEl.OriginHeight;
27844             
27845             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27846                 height = this.thumbEl.getWidth();
27847                 this.baseScale = height / this.imageEl.OriginHeight;
27848             }
27849             
27850             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27851                 height = this.thumbEl.getWidth();
27852                 this.baseScale = height / this.imageEl.OriginHeight;
27853                 
27854                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27855                     width = this.thumbEl.getHeight();
27856                     this.baseScale = width / this.imageEl.OriginWidth;
27857                 }
27858             }
27859             
27860             return;
27861         }
27862         
27863         width = this.thumbEl.getWidth();
27864         this.baseScale = width / this.imageEl.OriginWidth;
27865         
27866         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27867             height = this.thumbEl.getHeight();
27868             this.baseScale = height / this.imageEl.OriginHeight;
27869         }
27870         
27871         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27872             
27873             height = this.thumbEl.getHeight();
27874             this.baseScale = height / this.imageEl.OriginHeight;
27875             
27876             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27877                 width = this.thumbEl.getWidth();
27878                 this.baseScale = width / this.imageEl.OriginWidth;
27879             }
27880             
27881         }
27882         
27883         return;
27884     },
27885     
27886     getScaleLevel : function()
27887     {
27888         return this.baseScale * Math.pow(1.1, this.scale);
27889     },
27890     
27891     onTouchStart : function(e)
27892     {
27893         if(!this.canvasLoaded){
27894             this.beforeSelectFile(e);
27895             return;
27896         }
27897         
27898         var touches = e.browserEvent.touches;
27899         
27900         if(!touches){
27901             return;
27902         }
27903         
27904         if(touches.length == 1){
27905             this.onMouseDown(e);
27906             return;
27907         }
27908         
27909         if(touches.length != 2){
27910             return;
27911         }
27912         
27913         var coords = [];
27914         
27915         for(var i = 0, finger; finger = touches[i]; i++){
27916             coords.push(finger.pageX, finger.pageY);
27917         }
27918         
27919         var x = Math.pow(coords[0] - coords[2], 2);
27920         var y = Math.pow(coords[1] - coords[3], 2);
27921         
27922         this.startDistance = Math.sqrt(x + y);
27923         
27924         this.startScale = this.scale;
27925         
27926         this.pinching = true;
27927         this.dragable = false;
27928         
27929     },
27930     
27931     onTouchMove : function(e)
27932     {
27933         if(!this.pinching && !this.dragable){
27934             return;
27935         }
27936         
27937         var touches = e.browserEvent.touches;
27938         
27939         if(!touches){
27940             return;
27941         }
27942         
27943         if(this.dragable){
27944             this.onMouseMove(e);
27945             return;
27946         }
27947         
27948         var coords = [];
27949         
27950         for(var i = 0, finger; finger = touches[i]; i++){
27951             coords.push(finger.pageX, finger.pageY);
27952         }
27953         
27954         var x = Math.pow(coords[0] - coords[2], 2);
27955         var y = Math.pow(coords[1] - coords[3], 2);
27956         
27957         this.endDistance = Math.sqrt(x + y);
27958         
27959         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27960         
27961         if(!this.zoomable()){
27962             this.scale = this.startScale;
27963             return;
27964         }
27965         
27966         this.draw();
27967         
27968     },
27969     
27970     onTouchEnd : function(e)
27971     {
27972         this.pinching = false;
27973         this.dragable = false;
27974         
27975     },
27976     
27977     process : function(file, crop)
27978     {
27979         if(this.loadMask){
27980             this.maskEl.mask(this.loadingText);
27981         }
27982         
27983         this.xhr = new XMLHttpRequest();
27984         
27985         file.xhr = this.xhr;
27986
27987         this.xhr.open(this.method, this.url, true);
27988         
27989         var headers = {
27990             "Accept": "application/json",
27991             "Cache-Control": "no-cache",
27992             "X-Requested-With": "XMLHttpRequest"
27993         };
27994         
27995         for (var headerName in headers) {
27996             var headerValue = headers[headerName];
27997             if (headerValue) {
27998                 this.xhr.setRequestHeader(headerName, headerValue);
27999             }
28000         }
28001         
28002         var _this = this;
28003         
28004         this.xhr.onload = function()
28005         {
28006             _this.xhrOnLoad(_this.xhr);
28007         }
28008         
28009         this.xhr.onerror = function()
28010         {
28011             _this.xhrOnError(_this.xhr);
28012         }
28013         
28014         var formData = new FormData();
28015
28016         formData.append('returnHTML', 'NO');
28017         
28018         if(crop){
28019             formData.append('crop', crop);
28020         }
28021         
28022         if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28023             formData.append(this.paramName, file, file.name);
28024         }
28025         
28026         if(typeof(file.filename) != 'undefined'){
28027             formData.append('filename', file.filename);
28028         }
28029         
28030         if(typeof(file.mimetype) != 'undefined'){
28031             formData.append('mimetype', file.mimetype);
28032         }
28033         
28034         if(this.fireEvent('arrange', this, formData) != false){
28035             this.xhr.send(formData);
28036         };
28037     },
28038     
28039     xhrOnLoad : function(xhr)
28040     {
28041         if(this.loadMask){
28042             this.maskEl.unmask();
28043         }
28044         
28045         if (xhr.readyState !== 4) {
28046             this.fireEvent('exception', this, xhr);
28047             return;
28048         }
28049
28050         var response = Roo.decode(xhr.responseText);
28051         
28052         if(!response.success){
28053             this.fireEvent('exception', this, xhr);
28054             return;
28055         }
28056         
28057         var response = Roo.decode(xhr.responseText);
28058         
28059         this.fireEvent('upload', this, response);
28060         
28061     },
28062     
28063     xhrOnError : function()
28064     {
28065         if(this.loadMask){
28066             this.maskEl.unmask();
28067         }
28068         
28069         Roo.log('xhr on error');
28070         
28071         var response = Roo.decode(xhr.responseText);
28072           
28073         Roo.log(response);
28074         
28075     },
28076     
28077     prepare : function(file)
28078     {   
28079         if(this.loadMask){
28080             this.maskEl.mask(this.loadingText);
28081         }
28082         
28083         this.file = false;
28084         this.exif = {};
28085         
28086         if(typeof(file) === 'string'){
28087             this.loadCanvas(file);
28088             return;
28089         }
28090         
28091         if(!file || !this.urlAPI){
28092             return;
28093         }
28094         
28095         this.file = file;
28096         this.cropType = file.type;
28097         
28098         var _this = this;
28099         
28100         if(this.fireEvent('prepare', this, this.file) != false){
28101             
28102             var reader = new FileReader();
28103             
28104             reader.onload = function (e) {
28105                 if (e.target.error) {
28106                     Roo.log(e.target.error);
28107                     return;
28108                 }
28109                 
28110                 var buffer = e.target.result,
28111                     dataView = new DataView(buffer),
28112                     offset = 2,
28113                     maxOffset = dataView.byteLength - 4,
28114                     markerBytes,
28115                     markerLength;
28116                 
28117                 if (dataView.getUint16(0) === 0xffd8) {
28118                     while (offset < maxOffset) {
28119                         markerBytes = dataView.getUint16(offset);
28120                         
28121                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28122                             markerLength = dataView.getUint16(offset + 2) + 2;
28123                             if (offset + markerLength > dataView.byteLength) {
28124                                 Roo.log('Invalid meta data: Invalid segment size.');
28125                                 break;
28126                             }
28127                             
28128                             if(markerBytes == 0xffe1){
28129                                 _this.parseExifData(
28130                                     dataView,
28131                                     offset,
28132                                     markerLength
28133                                 );
28134                             }
28135                             
28136                             offset += markerLength;
28137                             
28138                             continue;
28139                         }
28140                         
28141                         break;
28142                     }
28143                     
28144                 }
28145                 
28146                 var url = _this.urlAPI.createObjectURL(_this.file);
28147                 
28148                 _this.loadCanvas(url);
28149                 
28150                 return;
28151             }
28152             
28153             reader.readAsArrayBuffer(this.file);
28154             
28155         }
28156         
28157     },
28158     
28159     parseExifData : function(dataView, offset, length)
28160     {
28161         var tiffOffset = offset + 10,
28162             littleEndian,
28163             dirOffset;
28164     
28165         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28166             // No Exif data, might be XMP data instead
28167             return;
28168         }
28169         
28170         // Check for the ASCII code for "Exif" (0x45786966):
28171         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28172             // No Exif data, might be XMP data instead
28173             return;
28174         }
28175         if (tiffOffset + 8 > dataView.byteLength) {
28176             Roo.log('Invalid Exif data: Invalid segment size.');
28177             return;
28178         }
28179         // Check for the two null bytes:
28180         if (dataView.getUint16(offset + 8) !== 0x0000) {
28181             Roo.log('Invalid Exif data: Missing byte alignment offset.');
28182             return;
28183         }
28184         // Check the byte alignment:
28185         switch (dataView.getUint16(tiffOffset)) {
28186         case 0x4949:
28187             littleEndian = true;
28188             break;
28189         case 0x4D4D:
28190             littleEndian = false;
28191             break;
28192         default:
28193             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28194             return;
28195         }
28196         // Check for the TIFF tag marker (0x002A):
28197         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28198             Roo.log('Invalid Exif data: Missing TIFF marker.');
28199             return;
28200         }
28201         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28202         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28203         
28204         this.parseExifTags(
28205             dataView,
28206             tiffOffset,
28207             tiffOffset + dirOffset,
28208             littleEndian
28209         );
28210     },
28211     
28212     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28213     {
28214         var tagsNumber,
28215             dirEndOffset,
28216             i;
28217         if (dirOffset + 6 > dataView.byteLength) {
28218             Roo.log('Invalid Exif data: Invalid directory offset.');
28219             return;
28220         }
28221         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28222         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28223         if (dirEndOffset + 4 > dataView.byteLength) {
28224             Roo.log('Invalid Exif data: Invalid directory size.');
28225             return;
28226         }
28227         for (i = 0; i < tagsNumber; i += 1) {
28228             this.parseExifTag(
28229                 dataView,
28230                 tiffOffset,
28231                 dirOffset + 2 + 12 * i, // tag offset
28232                 littleEndian
28233             );
28234         }
28235         // Return the offset to the next directory:
28236         return dataView.getUint32(dirEndOffset, littleEndian);
28237     },
28238     
28239     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
28240     {
28241         var tag = dataView.getUint16(offset, littleEndian);
28242         
28243         this.exif[tag] = this.getExifValue(
28244             dataView,
28245             tiffOffset,
28246             offset,
28247             dataView.getUint16(offset + 2, littleEndian), // tag type
28248             dataView.getUint32(offset + 4, littleEndian), // tag length
28249             littleEndian
28250         );
28251     },
28252     
28253     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28254     {
28255         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28256             tagSize,
28257             dataOffset,
28258             values,
28259             i,
28260             str,
28261             c;
28262     
28263         if (!tagType) {
28264             Roo.log('Invalid Exif data: Invalid tag type.');
28265             return;
28266         }
28267         
28268         tagSize = tagType.size * length;
28269         // Determine if the value is contained in the dataOffset bytes,
28270         // or if the value at the dataOffset is a pointer to the actual data:
28271         dataOffset = tagSize > 4 ?
28272                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28273         if (dataOffset + tagSize > dataView.byteLength) {
28274             Roo.log('Invalid Exif data: Invalid data offset.');
28275             return;
28276         }
28277         if (length === 1) {
28278             return tagType.getValue(dataView, dataOffset, littleEndian);
28279         }
28280         values = [];
28281         for (i = 0; i < length; i += 1) {
28282             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28283         }
28284         
28285         if (tagType.ascii) {
28286             str = '';
28287             // Concatenate the chars:
28288             for (i = 0; i < values.length; i += 1) {
28289                 c = values[i];
28290                 // Ignore the terminating NULL byte(s):
28291                 if (c === '\u0000') {
28292                     break;
28293                 }
28294                 str += c;
28295             }
28296             return str;
28297         }
28298         return values;
28299     }
28300     
28301 });
28302
28303 Roo.apply(Roo.bootstrap.UploadCropbox, {
28304     tags : {
28305         'Orientation': 0x0112
28306     },
28307     
28308     Orientation: {
28309             1: 0, //'top-left',
28310 //            2: 'top-right',
28311             3: 180, //'bottom-right',
28312 //            4: 'bottom-left',
28313 //            5: 'left-top',
28314             6: 90, //'right-top',
28315 //            7: 'right-bottom',
28316             8: 270 //'left-bottom'
28317     },
28318     
28319     exifTagTypes : {
28320         // byte, 8-bit unsigned int:
28321         1: {
28322             getValue: function (dataView, dataOffset) {
28323                 return dataView.getUint8(dataOffset);
28324             },
28325             size: 1
28326         },
28327         // ascii, 8-bit byte:
28328         2: {
28329             getValue: function (dataView, dataOffset) {
28330                 return String.fromCharCode(dataView.getUint8(dataOffset));
28331             },
28332             size: 1,
28333             ascii: true
28334         },
28335         // short, 16 bit int:
28336         3: {
28337             getValue: function (dataView, dataOffset, littleEndian) {
28338                 return dataView.getUint16(dataOffset, littleEndian);
28339             },
28340             size: 2
28341         },
28342         // long, 32 bit int:
28343         4: {
28344             getValue: function (dataView, dataOffset, littleEndian) {
28345                 return dataView.getUint32(dataOffset, littleEndian);
28346             },
28347             size: 4
28348         },
28349         // rational = two long values, first is numerator, second is denominator:
28350         5: {
28351             getValue: function (dataView, dataOffset, littleEndian) {
28352                 return dataView.getUint32(dataOffset, littleEndian) /
28353                     dataView.getUint32(dataOffset + 4, littleEndian);
28354             },
28355             size: 8
28356         },
28357         // slong, 32 bit signed int:
28358         9: {
28359             getValue: function (dataView, dataOffset, littleEndian) {
28360                 return dataView.getInt32(dataOffset, littleEndian);
28361             },
28362             size: 4
28363         },
28364         // srational, two slongs, first is numerator, second is denominator:
28365         10: {
28366             getValue: function (dataView, dataOffset, littleEndian) {
28367                 return dataView.getInt32(dataOffset, littleEndian) /
28368                     dataView.getInt32(dataOffset + 4, littleEndian);
28369             },
28370             size: 8
28371         }
28372     },
28373     
28374     footer : {
28375         STANDARD : [
28376             {
28377                 tag : 'div',
28378                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28379                 action : 'rotate-left',
28380                 cn : [
28381                     {
28382                         tag : 'button',
28383                         cls : 'btn btn-default',
28384                         html : '<i class="fa fa-undo"></i>'
28385                     }
28386                 ]
28387             },
28388             {
28389                 tag : 'div',
28390                 cls : 'btn-group roo-upload-cropbox-picture',
28391                 action : 'picture',
28392                 cn : [
28393                     {
28394                         tag : 'button',
28395                         cls : 'btn btn-default',
28396                         html : '<i class="fa fa-picture-o"></i>'
28397                     }
28398                 ]
28399             },
28400             {
28401                 tag : 'div',
28402                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28403                 action : 'rotate-right',
28404                 cn : [
28405                     {
28406                         tag : 'button',
28407                         cls : 'btn btn-default',
28408                         html : '<i class="fa fa-repeat"></i>'
28409                     }
28410                 ]
28411             }
28412         ],
28413         DOCUMENT : [
28414             {
28415                 tag : 'div',
28416                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28417                 action : 'rotate-left',
28418                 cn : [
28419                     {
28420                         tag : 'button',
28421                         cls : 'btn btn-default',
28422                         html : '<i class="fa fa-undo"></i>'
28423                     }
28424                 ]
28425             },
28426             {
28427                 tag : 'div',
28428                 cls : 'btn-group roo-upload-cropbox-download',
28429                 action : 'download',
28430                 cn : [
28431                     {
28432                         tag : 'button',
28433                         cls : 'btn btn-default',
28434                         html : '<i class="fa fa-download"></i>'
28435                     }
28436                 ]
28437             },
28438             {
28439                 tag : 'div',
28440                 cls : 'btn-group roo-upload-cropbox-crop',
28441                 action : 'crop',
28442                 cn : [
28443                     {
28444                         tag : 'button',
28445                         cls : 'btn btn-default',
28446                         html : '<i class="fa fa-crop"></i>'
28447                     }
28448                 ]
28449             },
28450             {
28451                 tag : 'div',
28452                 cls : 'btn-group roo-upload-cropbox-trash',
28453                 action : 'trash',
28454                 cn : [
28455                     {
28456                         tag : 'button',
28457                         cls : 'btn btn-default',
28458                         html : '<i class="fa fa-trash"></i>'
28459                     }
28460                 ]
28461             },
28462             {
28463                 tag : 'div',
28464                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28465                 action : 'rotate-right',
28466                 cn : [
28467                     {
28468                         tag : 'button',
28469                         cls : 'btn btn-default',
28470                         html : '<i class="fa fa-repeat"></i>'
28471                     }
28472                 ]
28473             }
28474         ],
28475         ROTATOR : [
28476             {
28477                 tag : 'div',
28478                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28479                 action : 'rotate-left',
28480                 cn : [
28481                     {
28482                         tag : 'button',
28483                         cls : 'btn btn-default',
28484                         html : '<i class="fa fa-undo"></i>'
28485                     }
28486                 ]
28487             },
28488             {
28489                 tag : 'div',
28490                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28491                 action : 'rotate-right',
28492                 cn : [
28493                     {
28494                         tag : 'button',
28495                         cls : 'btn btn-default',
28496                         html : '<i class="fa fa-repeat"></i>'
28497                     }
28498                 ]
28499             }
28500         ]
28501     }
28502 });
28503
28504 /*
28505 * Licence: LGPL
28506 */
28507
28508 /**
28509  * @class Roo.bootstrap.DocumentManager
28510  * @extends Roo.bootstrap.Component
28511  * Bootstrap DocumentManager class
28512  * @cfg {String} paramName default 'imageUpload'
28513  * @cfg {String} toolTipName default 'filename'
28514  * @cfg {String} method default POST
28515  * @cfg {String} url action url
28516  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28517  * @cfg {Boolean} multiple multiple upload default true
28518  * @cfg {Number} thumbSize default 300
28519  * @cfg {String} fieldLabel
28520  * @cfg {Number} labelWidth default 4
28521  * @cfg {String} labelAlign (left|top) default left
28522  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28523 * @cfg {Number} labellg set the width of label (1-12)
28524  * @cfg {Number} labelmd set the width of label (1-12)
28525  * @cfg {Number} labelsm set the width of label (1-12)
28526  * @cfg {Number} labelxs set the width of label (1-12)
28527  * 
28528  * @constructor
28529  * Create a new DocumentManager
28530  * @param {Object} config The config object
28531  */
28532
28533 Roo.bootstrap.DocumentManager = function(config){
28534     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28535     
28536     this.files = [];
28537     this.delegates = [];
28538     
28539     this.addEvents({
28540         /**
28541          * @event initial
28542          * Fire when initial the DocumentManager
28543          * @param {Roo.bootstrap.DocumentManager} this
28544          */
28545         "initial" : true,
28546         /**
28547          * @event inspect
28548          * inspect selected file
28549          * @param {Roo.bootstrap.DocumentManager} this
28550          * @param {File} file
28551          */
28552         "inspect" : true,
28553         /**
28554          * @event exception
28555          * Fire when xhr load exception
28556          * @param {Roo.bootstrap.DocumentManager} this
28557          * @param {XMLHttpRequest} xhr
28558          */
28559         "exception" : true,
28560         /**
28561          * @event afterupload
28562          * Fire when xhr load exception
28563          * @param {Roo.bootstrap.DocumentManager} this
28564          * @param {XMLHttpRequest} xhr
28565          */
28566         "afterupload" : true,
28567         /**
28568          * @event prepare
28569          * prepare the form data
28570          * @param {Roo.bootstrap.DocumentManager} this
28571          * @param {Object} formData
28572          */
28573         "prepare" : true,
28574         /**
28575          * @event remove
28576          * Fire when remove the file
28577          * @param {Roo.bootstrap.DocumentManager} this
28578          * @param {Object} file
28579          */
28580         "remove" : true,
28581         /**
28582          * @event refresh
28583          * Fire after refresh the file
28584          * @param {Roo.bootstrap.DocumentManager} this
28585          */
28586         "refresh" : true,
28587         /**
28588          * @event click
28589          * Fire after click the image
28590          * @param {Roo.bootstrap.DocumentManager} this
28591          * @param {Object} file
28592          */
28593         "click" : true,
28594         /**
28595          * @event edit
28596          * Fire when upload a image and editable set to true
28597          * @param {Roo.bootstrap.DocumentManager} this
28598          * @param {Object} file
28599          */
28600         "edit" : true,
28601         /**
28602          * @event beforeselectfile
28603          * Fire before select file
28604          * @param {Roo.bootstrap.DocumentManager} this
28605          */
28606         "beforeselectfile" : true,
28607         /**
28608          * @event process
28609          * Fire before process file
28610          * @param {Roo.bootstrap.DocumentManager} this
28611          * @param {Object} file
28612          */
28613         "process" : true,
28614         /**
28615          * @event previewrendered
28616          * Fire when preview rendered
28617          * @param {Roo.bootstrap.DocumentManager} this
28618          * @param {Object} file
28619          */
28620         "previewrendered" : true
28621         
28622     });
28623 };
28624
28625 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
28626     
28627     boxes : 0,
28628     inputName : '',
28629     thumbSize : 300,
28630     multiple : true,
28631     files : false,
28632     method : 'POST',
28633     url : '',
28634     paramName : 'imageUpload',
28635     toolTipName : 'filename',
28636     fieldLabel : '',
28637     labelWidth : 4,
28638     labelAlign : 'left',
28639     editable : true,
28640     delegates : false,
28641     xhr : false, 
28642     
28643     labellg : 0,
28644     labelmd : 0,
28645     labelsm : 0,
28646     labelxs : 0,
28647     
28648     getAutoCreate : function()
28649     {   
28650         var managerWidget = {
28651             tag : 'div',
28652             cls : 'roo-document-manager',
28653             cn : [
28654                 {
28655                     tag : 'input',
28656                     cls : 'roo-document-manager-selector',
28657                     type : 'file'
28658                 },
28659                 {
28660                     tag : 'div',
28661                     cls : 'roo-document-manager-uploader',
28662                     cn : [
28663                         {
28664                             tag : 'div',
28665                             cls : 'roo-document-manager-upload-btn',
28666                             html : '<i class="fa fa-plus"></i>'
28667                         }
28668                     ]
28669                     
28670                 }
28671             ]
28672         };
28673         
28674         var content = [
28675             {
28676                 tag : 'div',
28677                 cls : 'column col-md-12',
28678                 cn : managerWidget
28679             }
28680         ];
28681         
28682         if(this.fieldLabel.length){
28683             
28684             content = [
28685                 {
28686                     tag : 'div',
28687                     cls : 'column col-md-12',
28688                     html : this.fieldLabel
28689                 },
28690                 {
28691                     tag : 'div',
28692                     cls : 'column col-md-12',
28693                     cn : managerWidget
28694                 }
28695             ];
28696
28697             if(this.labelAlign == 'left'){
28698                 content = [
28699                     {
28700                         tag : 'div',
28701                         cls : 'column',
28702                         html : this.fieldLabel
28703                     },
28704                     {
28705                         tag : 'div',
28706                         cls : 'column',
28707                         cn : managerWidget
28708                     }
28709                 ];
28710                 
28711                 if(this.labelWidth > 12){
28712                     content[0].style = "width: " + this.labelWidth + 'px';
28713                 }
28714
28715                 if(this.labelWidth < 13 && this.labelmd == 0){
28716                     this.labelmd = this.labelWidth;
28717                 }
28718
28719                 if(this.labellg > 0){
28720                     content[0].cls += ' col-lg-' + this.labellg;
28721                     content[1].cls += ' col-lg-' + (12 - this.labellg);
28722                 }
28723
28724                 if(this.labelmd > 0){
28725                     content[0].cls += ' col-md-' + this.labelmd;
28726                     content[1].cls += ' col-md-' + (12 - this.labelmd);
28727                 }
28728
28729                 if(this.labelsm > 0){
28730                     content[0].cls += ' col-sm-' + this.labelsm;
28731                     content[1].cls += ' col-sm-' + (12 - this.labelsm);
28732                 }
28733
28734                 if(this.labelxs > 0){
28735                     content[0].cls += ' col-xs-' + this.labelxs;
28736                     content[1].cls += ' col-xs-' + (12 - this.labelxs);
28737                 }
28738                 
28739             }
28740         }
28741         
28742         var cfg = {
28743             tag : 'div',
28744             cls : 'row clearfix',
28745             cn : content
28746         };
28747         
28748         return cfg;
28749         
28750     },
28751     
28752     initEvents : function()
28753     {
28754         this.managerEl = this.el.select('.roo-document-manager', true).first();
28755         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28756         
28757         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28758         this.selectorEl.hide();
28759         
28760         if(this.multiple){
28761             this.selectorEl.attr('multiple', 'multiple');
28762         }
28763         
28764         this.selectorEl.on('change', this.onFileSelected, this);
28765         
28766         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28767         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28768         
28769         this.uploader.on('click', this.onUploaderClick, this);
28770         
28771         this.renderProgressDialog();
28772         
28773         var _this = this;
28774         
28775         window.addEventListener("resize", function() { _this.refresh(); } );
28776         
28777         this.fireEvent('initial', this);
28778     },
28779     
28780     renderProgressDialog : function()
28781     {
28782         var _this = this;
28783         
28784         this.progressDialog = new Roo.bootstrap.Modal({
28785             cls : 'roo-document-manager-progress-dialog',
28786             allow_close : false,
28787             title : '',
28788             buttons : [
28789                 {
28790                     name  :'cancel',
28791                     weight : 'danger',
28792                     html : 'Cancel'
28793                 }
28794             ], 
28795             listeners : { 
28796                 btnclick : function() {
28797                     _this.uploadCancel();
28798                     this.hide();
28799                 }
28800             }
28801         });
28802          
28803         this.progressDialog.render(Roo.get(document.body));
28804          
28805         this.progress = new Roo.bootstrap.Progress({
28806             cls : 'roo-document-manager-progress',
28807             active : true,
28808             striped : true
28809         });
28810         
28811         this.progress.render(this.progressDialog.getChildContainer());
28812         
28813         this.progressBar = new Roo.bootstrap.ProgressBar({
28814             cls : 'roo-document-manager-progress-bar',
28815             aria_valuenow : 0,
28816             aria_valuemin : 0,
28817             aria_valuemax : 12,
28818             panel : 'success'
28819         });
28820         
28821         this.progressBar.render(this.progress.getChildContainer());
28822     },
28823     
28824     onUploaderClick : function(e)
28825     {
28826         e.preventDefault();
28827      
28828         if(this.fireEvent('beforeselectfile', this) != false){
28829             this.selectorEl.dom.click();
28830         }
28831         
28832     },
28833     
28834     onFileSelected : function(e)
28835     {
28836         e.preventDefault();
28837         
28838         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28839             return;
28840         }
28841         
28842         Roo.each(this.selectorEl.dom.files, function(file){
28843             if(this.fireEvent('inspect', this, file) != false){
28844                 this.files.push(file);
28845             }
28846         }, this);
28847         
28848         this.queue();
28849         
28850     },
28851     
28852     queue : function()
28853     {
28854         this.selectorEl.dom.value = '';
28855         
28856         if(!this.files || !this.files.length){
28857             return;
28858         }
28859         
28860         if(this.boxes > 0 && this.files.length > this.boxes){
28861             this.files = this.files.slice(0, this.boxes);
28862         }
28863         
28864         this.uploader.show();
28865         
28866         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28867             this.uploader.hide();
28868         }
28869         
28870         var _this = this;
28871         
28872         var files = [];
28873         
28874         var docs = [];
28875         
28876         Roo.each(this.files, function(file){
28877             
28878             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28879                 var f = this.renderPreview(file);
28880                 files.push(f);
28881                 return;
28882             }
28883             
28884             if(file.type.indexOf('image') != -1){
28885                 this.delegates.push(
28886                     (function(){
28887                         _this.process(file);
28888                     }).createDelegate(this)
28889                 );
28890         
28891                 return;
28892             }
28893             
28894             docs.push(
28895                 (function(){
28896                     _this.process(file);
28897                 }).createDelegate(this)
28898             );
28899             
28900         }, this);
28901         
28902         this.files = files;
28903         
28904         this.delegates = this.delegates.concat(docs);
28905         
28906         if(!this.delegates.length){
28907             this.refresh();
28908             return;
28909         }
28910         
28911         this.progressBar.aria_valuemax = this.delegates.length;
28912         
28913         this.arrange();
28914         
28915         return;
28916     },
28917     
28918     arrange : function()
28919     {
28920         if(!this.delegates.length){
28921             this.progressDialog.hide();
28922             this.refresh();
28923             return;
28924         }
28925         
28926         var delegate = this.delegates.shift();
28927         
28928         this.progressDialog.show();
28929         
28930         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28931         
28932         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28933         
28934         delegate();
28935     },
28936     
28937     refresh : function()
28938     {
28939         this.uploader.show();
28940         
28941         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28942             this.uploader.hide();
28943         }
28944         
28945         Roo.isTouch ? this.closable(false) : this.closable(true);
28946         
28947         this.fireEvent('refresh', this);
28948     },
28949     
28950     onRemove : function(e, el, o)
28951     {
28952         e.preventDefault();
28953         
28954         this.fireEvent('remove', this, o);
28955         
28956     },
28957     
28958     remove : function(o)
28959     {
28960         var files = [];
28961         
28962         Roo.each(this.files, function(file){
28963             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28964                 files.push(file);
28965                 return;
28966             }
28967
28968             o.target.remove();
28969
28970         }, this);
28971         
28972         this.files = files;
28973         
28974         this.refresh();
28975     },
28976     
28977     clear : function()
28978     {
28979         Roo.each(this.files, function(file){
28980             if(!file.target){
28981                 return;
28982             }
28983             
28984             file.target.remove();
28985
28986         }, this);
28987         
28988         this.files = [];
28989         
28990         this.refresh();
28991     },
28992     
28993     onClick : function(e, el, o)
28994     {
28995         e.preventDefault();
28996         
28997         this.fireEvent('click', this, o);
28998         
28999     },
29000     
29001     closable : function(closable)
29002     {
29003         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29004             
29005             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29006             
29007             if(closable){
29008                 el.show();
29009                 return;
29010             }
29011             
29012             el.hide();
29013             
29014         }, this);
29015     },
29016     
29017     xhrOnLoad : function(xhr)
29018     {
29019         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29020             el.remove();
29021         }, this);
29022         
29023         if (xhr.readyState !== 4) {
29024             this.arrange();
29025             this.fireEvent('exception', this, xhr);
29026             return;
29027         }
29028
29029         var response = Roo.decode(xhr.responseText);
29030         
29031         if(!response.success){
29032             this.arrange();
29033             this.fireEvent('exception', this, xhr);
29034             return;
29035         }
29036         
29037         var file = this.renderPreview(response.data);
29038         
29039         this.files.push(file);
29040         
29041         this.arrange();
29042         
29043         this.fireEvent('afterupload', this, xhr);
29044         
29045     },
29046     
29047     xhrOnError : function(xhr)
29048     {
29049         Roo.log('xhr on error');
29050         
29051         var response = Roo.decode(xhr.responseText);
29052           
29053         Roo.log(response);
29054         
29055         this.arrange();
29056     },
29057     
29058     process : function(file)
29059     {
29060         if(this.fireEvent('process', this, file) !== false){
29061             if(this.editable && file.type.indexOf('image') != -1){
29062                 this.fireEvent('edit', this, file);
29063                 return;
29064             }
29065
29066             this.uploadStart(file, false);
29067
29068             return;
29069         }
29070         
29071     },
29072     
29073     uploadStart : function(file, crop)
29074     {
29075         this.xhr = new XMLHttpRequest();
29076         
29077         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29078             this.arrange();
29079             return;
29080         }
29081         
29082         file.xhr = this.xhr;
29083             
29084         this.managerEl.createChild({
29085             tag : 'div',
29086             cls : 'roo-document-manager-loading',
29087             cn : [
29088                 {
29089                     tag : 'div',
29090                     tooltip : file.name,
29091                     cls : 'roo-document-manager-thumb',
29092                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29093                 }
29094             ]
29095
29096         });
29097
29098         this.xhr.open(this.method, this.url, true);
29099         
29100         var headers = {
29101             "Accept": "application/json",
29102             "Cache-Control": "no-cache",
29103             "X-Requested-With": "XMLHttpRequest"
29104         };
29105         
29106         for (var headerName in headers) {
29107             var headerValue = headers[headerName];
29108             if (headerValue) {
29109                 this.xhr.setRequestHeader(headerName, headerValue);
29110             }
29111         }
29112         
29113         var _this = this;
29114         
29115         this.xhr.onload = function()
29116         {
29117             _this.xhrOnLoad(_this.xhr);
29118         }
29119         
29120         this.xhr.onerror = function()
29121         {
29122             _this.xhrOnError(_this.xhr);
29123         }
29124         
29125         var formData = new FormData();
29126
29127         formData.append('returnHTML', 'NO');
29128         
29129         if(crop){
29130             formData.append('crop', crop);
29131         }
29132         
29133         formData.append(this.paramName, file, file.name);
29134         
29135         var options = {
29136             file : file, 
29137             manually : false
29138         };
29139         
29140         if(this.fireEvent('prepare', this, formData, options) != false){
29141             
29142             if(options.manually){
29143                 return;
29144             }
29145             
29146             this.xhr.send(formData);
29147             return;
29148         };
29149         
29150         this.uploadCancel();
29151     },
29152     
29153     uploadCancel : function()
29154     {
29155         if (this.xhr) {
29156             this.xhr.abort();
29157         }
29158         
29159         this.delegates = [];
29160         
29161         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29162             el.remove();
29163         }, this);
29164         
29165         this.arrange();
29166     },
29167     
29168     renderPreview : function(file)
29169     {
29170         if(typeof(file.target) != 'undefined' && file.target){
29171             return file;
29172         }
29173         
29174         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29175         
29176         var previewEl = this.managerEl.createChild({
29177             tag : 'div',
29178             cls : 'roo-document-manager-preview',
29179             cn : [
29180                 {
29181                     tag : 'div',
29182                     tooltip : file[this.toolTipName],
29183                     cls : 'roo-document-manager-thumb',
29184                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29185                 },
29186                 {
29187                     tag : 'button',
29188                     cls : 'close',
29189                     html : '<i class="fa fa-times-circle"></i>'
29190                 }
29191             ]
29192         });
29193
29194         var close = previewEl.select('button.close', true).first();
29195
29196         close.on('click', this.onRemove, this, file);
29197
29198         file.target = previewEl;
29199
29200         var image = previewEl.select('img', true).first();
29201         
29202         var _this = this;
29203         
29204         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29205         
29206         image.on('click', this.onClick, this, file);
29207         
29208         this.fireEvent('previewrendered', this, file);
29209         
29210         return file;
29211         
29212     },
29213     
29214     onPreviewLoad : function(file, image)
29215     {
29216         if(typeof(file.target) == 'undefined' || !file.target){
29217             return;
29218         }
29219         
29220         var width = image.dom.naturalWidth || image.dom.width;
29221         var height = image.dom.naturalHeight || image.dom.height;
29222         
29223         if(width > height){
29224             file.target.addClass('wide');
29225             return;
29226         }
29227         
29228         file.target.addClass('tall');
29229         return;
29230         
29231     },
29232     
29233     uploadFromSource : function(file, crop)
29234     {
29235         this.xhr = new XMLHttpRequest();
29236         
29237         this.managerEl.createChild({
29238             tag : 'div',
29239             cls : 'roo-document-manager-loading',
29240             cn : [
29241                 {
29242                     tag : 'div',
29243                     tooltip : file.name,
29244                     cls : 'roo-document-manager-thumb',
29245                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29246                 }
29247             ]
29248
29249         });
29250
29251         this.xhr.open(this.method, this.url, true);
29252         
29253         var headers = {
29254             "Accept": "application/json",
29255             "Cache-Control": "no-cache",
29256             "X-Requested-With": "XMLHttpRequest"
29257         };
29258         
29259         for (var headerName in headers) {
29260             var headerValue = headers[headerName];
29261             if (headerValue) {
29262                 this.xhr.setRequestHeader(headerName, headerValue);
29263             }
29264         }
29265         
29266         var _this = this;
29267         
29268         this.xhr.onload = function()
29269         {
29270             _this.xhrOnLoad(_this.xhr);
29271         }
29272         
29273         this.xhr.onerror = function()
29274         {
29275             _this.xhrOnError(_this.xhr);
29276         }
29277         
29278         var formData = new FormData();
29279
29280         formData.append('returnHTML', 'NO');
29281         
29282         formData.append('crop', crop);
29283         
29284         if(typeof(file.filename) != 'undefined'){
29285             formData.append('filename', file.filename);
29286         }
29287         
29288         if(typeof(file.mimetype) != 'undefined'){
29289             formData.append('mimetype', file.mimetype);
29290         }
29291         
29292         Roo.log(formData);
29293         
29294         if(this.fireEvent('prepare', this, formData) != false){
29295             this.xhr.send(formData);
29296         };
29297     }
29298 });
29299
29300 /*
29301 * Licence: LGPL
29302 */
29303
29304 /**
29305  * @class Roo.bootstrap.DocumentViewer
29306  * @extends Roo.bootstrap.Component
29307  * Bootstrap DocumentViewer class
29308  * @cfg {Boolean} showDownload (true|false) show download button (default true)
29309  * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29310  * 
29311  * @constructor
29312  * Create a new DocumentViewer
29313  * @param {Object} config The config object
29314  */
29315
29316 Roo.bootstrap.DocumentViewer = function(config){
29317     Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29318     
29319     this.addEvents({
29320         /**
29321          * @event initial
29322          * Fire after initEvent
29323          * @param {Roo.bootstrap.DocumentViewer} this
29324          */
29325         "initial" : true,
29326         /**
29327          * @event click
29328          * Fire after click
29329          * @param {Roo.bootstrap.DocumentViewer} this
29330          */
29331         "click" : true,
29332         /**
29333          * @event download
29334          * Fire after download button
29335          * @param {Roo.bootstrap.DocumentViewer} this
29336          */
29337         "download" : true,
29338         /**
29339          * @event trash
29340          * Fire after trash button
29341          * @param {Roo.bootstrap.DocumentViewer} this
29342          */
29343         "trash" : true
29344         
29345     });
29346 };
29347
29348 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
29349     
29350     showDownload : true,
29351     
29352     showTrash : true,
29353     
29354     getAutoCreate : function()
29355     {
29356         var cfg = {
29357             tag : 'div',
29358             cls : 'roo-document-viewer',
29359             cn : [
29360                 {
29361                     tag : 'div',
29362                     cls : 'roo-document-viewer-body',
29363                     cn : [
29364                         {
29365                             tag : 'div',
29366                             cls : 'roo-document-viewer-thumb',
29367                             cn : [
29368                                 {
29369                                     tag : 'img',
29370                                     cls : 'roo-document-viewer-image'
29371                                 }
29372                             ]
29373                         }
29374                     ]
29375                 },
29376                 {
29377                     tag : 'div',
29378                     cls : 'roo-document-viewer-footer',
29379                     cn : {
29380                         tag : 'div',
29381                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29382                         cn : [
29383                             {
29384                                 tag : 'div',
29385                                 cls : 'btn-group roo-document-viewer-download',
29386                                 cn : [
29387                                     {
29388                                         tag : 'button',
29389                                         cls : 'btn btn-default',
29390                                         html : '<i class="fa fa-download"></i>'
29391                                     }
29392                                 ]
29393                             },
29394                             {
29395                                 tag : 'div',
29396                                 cls : 'btn-group roo-document-viewer-trash',
29397                                 cn : [
29398                                     {
29399                                         tag : 'button',
29400                                         cls : 'btn btn-default',
29401                                         html : '<i class="fa fa-trash"></i>'
29402                                     }
29403                                 ]
29404                             }
29405                         ]
29406                     }
29407                 }
29408             ]
29409         };
29410         
29411         return cfg;
29412     },
29413     
29414     initEvents : function()
29415     {
29416         this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29417         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29418         
29419         this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29420         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29421         
29422         this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29423         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29424         
29425         this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29426         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29427         
29428         this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29429         this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29430         
29431         this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29432         this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29433         
29434         this.bodyEl.on('click', this.onClick, this);
29435         this.downloadBtn.on('click', this.onDownload, this);
29436         this.trashBtn.on('click', this.onTrash, this);
29437         
29438         this.downloadBtn.hide();
29439         this.trashBtn.hide();
29440         
29441         if(this.showDownload){
29442             this.downloadBtn.show();
29443         }
29444         
29445         if(this.showTrash){
29446             this.trashBtn.show();
29447         }
29448         
29449         if(!this.showDownload && !this.showTrash) {
29450             this.footerEl.hide();
29451         }
29452         
29453     },
29454     
29455     initial : function()
29456     {
29457         this.fireEvent('initial', this);
29458         
29459     },
29460     
29461     onClick : function(e)
29462     {
29463         e.preventDefault();
29464         
29465         this.fireEvent('click', this);
29466     },
29467     
29468     onDownload : function(e)
29469     {
29470         e.preventDefault();
29471         
29472         this.fireEvent('download', this);
29473     },
29474     
29475     onTrash : function(e)
29476     {
29477         e.preventDefault();
29478         
29479         this.fireEvent('trash', this);
29480     }
29481     
29482 });
29483 /*
29484  * - LGPL
29485  *
29486  * nav progress bar
29487  * 
29488  */
29489
29490 /**
29491  * @class Roo.bootstrap.NavProgressBar
29492  * @extends Roo.bootstrap.Component
29493  * Bootstrap NavProgressBar class
29494  * 
29495  * @constructor
29496  * Create a new nav progress bar
29497  * @param {Object} config The config object
29498  */
29499
29500 Roo.bootstrap.NavProgressBar = function(config){
29501     Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29502
29503     this.bullets = this.bullets || [];
29504    
29505 //    Roo.bootstrap.NavProgressBar.register(this);
29506      this.addEvents({
29507         /**
29508              * @event changed
29509              * Fires when the active item changes
29510              * @param {Roo.bootstrap.NavProgressBar} this
29511              * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29512              * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
29513          */
29514         'changed': true
29515      });
29516     
29517 };
29518
29519 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
29520     
29521     bullets : [],
29522     barItems : [],
29523     
29524     getAutoCreate : function()
29525     {
29526         var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29527         
29528         cfg = {
29529             tag : 'div',
29530             cls : 'roo-navigation-bar-group',
29531             cn : [
29532                 {
29533                     tag : 'div',
29534                     cls : 'roo-navigation-top-bar'
29535                 },
29536                 {
29537                     tag : 'div',
29538                     cls : 'roo-navigation-bullets-bar',
29539                     cn : [
29540                         {
29541                             tag : 'ul',
29542                             cls : 'roo-navigation-bar'
29543                         }
29544                     ]
29545                 },
29546                 
29547                 {
29548                     tag : 'div',
29549                     cls : 'roo-navigation-bottom-bar'
29550                 }
29551             ]
29552             
29553         };
29554         
29555         return cfg;
29556         
29557     },
29558     
29559     initEvents: function() 
29560     {
29561         
29562     },
29563     
29564     onRender : function(ct, position) 
29565     {
29566         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29567         
29568         if(this.bullets.length){
29569             Roo.each(this.bullets, function(b){
29570                this.addItem(b);
29571             }, this);
29572         }
29573         
29574         this.format();
29575         
29576     },
29577     
29578     addItem : function(cfg)
29579     {
29580         var item = new Roo.bootstrap.NavProgressItem(cfg);
29581         
29582         item.parentId = this.id;
29583         item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29584         
29585         if(cfg.html){
29586             var top = new Roo.bootstrap.Element({
29587                 tag : 'div',
29588                 cls : 'roo-navigation-bar-text'
29589             });
29590             
29591             var bottom = new Roo.bootstrap.Element({
29592                 tag : 'div',
29593                 cls : 'roo-navigation-bar-text'
29594             });
29595             
29596             top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29597             bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29598             
29599             var topText = new Roo.bootstrap.Element({
29600                 tag : 'span',
29601                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29602             });
29603             
29604             var bottomText = new Roo.bootstrap.Element({
29605                 tag : 'span',
29606                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29607             });
29608             
29609             topText.onRender(top.el, null);
29610             bottomText.onRender(bottom.el, null);
29611             
29612             item.topEl = top;
29613             item.bottomEl = bottom;
29614         }
29615         
29616         this.barItems.push(item);
29617         
29618         return item;
29619     },
29620     
29621     getActive : function()
29622     {
29623         var active = false;
29624         
29625         Roo.each(this.barItems, function(v){
29626             
29627             if (!v.isActive()) {
29628                 return;
29629             }
29630             
29631             active = v;
29632             return false;
29633             
29634         });
29635         
29636         return active;
29637     },
29638     
29639     setActiveItem : function(item)
29640     {
29641         var prev = false;
29642         
29643         Roo.each(this.barItems, function(v){
29644             if (v.rid == item.rid) {
29645                 return ;
29646             }
29647             
29648             if (v.isActive()) {
29649                 v.setActive(false);
29650                 prev = v;
29651             }
29652         });
29653
29654         item.setActive(true);
29655         
29656         this.fireEvent('changed', this, item, prev);
29657     },
29658     
29659     getBarItem: function(rid)
29660     {
29661         var ret = false;
29662         
29663         Roo.each(this.barItems, function(e) {
29664             if (e.rid != rid) {
29665                 return;
29666             }
29667             
29668             ret =  e;
29669             return false;
29670         });
29671         
29672         return ret;
29673     },
29674     
29675     indexOfItem : function(item)
29676     {
29677         var index = false;
29678         
29679         Roo.each(this.barItems, function(v, i){
29680             
29681             if (v.rid != item.rid) {
29682                 return;
29683             }
29684             
29685             index = i;
29686             return false
29687         });
29688         
29689         return index;
29690     },
29691     
29692     setActiveNext : function()
29693     {
29694         var i = this.indexOfItem(this.getActive());
29695         
29696         if (i > this.barItems.length) {
29697             return;
29698         }
29699         
29700         this.setActiveItem(this.barItems[i+1]);
29701     },
29702     
29703     setActivePrev : function()
29704     {
29705         var i = this.indexOfItem(this.getActive());
29706         
29707         if (i  < 1) {
29708             return;
29709         }
29710         
29711         this.setActiveItem(this.barItems[i-1]);
29712     },
29713     
29714     format : function()
29715     {
29716         if(!this.barItems.length){
29717             return;
29718         }
29719      
29720         var width = 100 / this.barItems.length;
29721         
29722         Roo.each(this.barItems, function(i){
29723             i.el.setStyle('width', width + '%');
29724             i.topEl.el.setStyle('width', width + '%');
29725             i.bottomEl.el.setStyle('width', width + '%');
29726         }, this);
29727         
29728     }
29729     
29730 });
29731 /*
29732  * - LGPL
29733  *
29734  * Nav Progress Item
29735  * 
29736  */
29737
29738 /**
29739  * @class Roo.bootstrap.NavProgressItem
29740  * @extends Roo.bootstrap.Component
29741  * Bootstrap NavProgressItem class
29742  * @cfg {String} rid the reference id
29743  * @cfg {Boolean} active (true|false) Is item active default false
29744  * @cfg {Boolean} disabled (true|false) Is item active default false
29745  * @cfg {String} html
29746  * @cfg {String} position (top|bottom) text position default bottom
29747  * @cfg {String} icon show icon instead of number
29748  * 
29749  * @constructor
29750  * Create a new NavProgressItem
29751  * @param {Object} config The config object
29752  */
29753 Roo.bootstrap.NavProgressItem = function(config){
29754     Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29755     this.addEvents({
29756         // raw events
29757         /**
29758          * @event click
29759          * The raw click event for the entire grid.
29760          * @param {Roo.bootstrap.NavProgressItem} this
29761          * @param {Roo.EventObject} e
29762          */
29763         "click" : true
29764     });
29765    
29766 };
29767
29768 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
29769     
29770     rid : '',
29771     active : false,
29772     disabled : false,
29773     html : '',
29774     position : 'bottom',
29775     icon : false,
29776     
29777     getAutoCreate : function()
29778     {
29779         var iconCls = 'roo-navigation-bar-item-icon';
29780         
29781         iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29782         
29783         var cfg = {
29784             tag: 'li',
29785             cls: 'roo-navigation-bar-item',
29786             cn : [
29787                 {
29788                     tag : 'i',
29789                     cls : iconCls
29790                 }
29791             ]
29792         };
29793         
29794         if(this.active){
29795             cfg.cls += ' active';
29796         }
29797         if(this.disabled){
29798             cfg.cls += ' disabled';
29799         }
29800         
29801         return cfg;
29802     },
29803     
29804     disable : function()
29805     {
29806         this.setDisabled(true);
29807     },
29808     
29809     enable : function()
29810     {
29811         this.setDisabled(false);
29812     },
29813     
29814     initEvents: function() 
29815     {
29816         this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29817         
29818         this.iconEl.on('click', this.onClick, this);
29819     },
29820     
29821     onClick : function(e)
29822     {
29823         e.preventDefault();
29824         
29825         if(this.disabled){
29826             return;
29827         }
29828         
29829         if(this.fireEvent('click', this, e) === false){
29830             return;
29831         };
29832         
29833         this.parent().setActiveItem(this);
29834     },
29835     
29836     isActive: function () 
29837     {
29838         return this.active;
29839     },
29840     
29841     setActive : function(state)
29842     {
29843         if(this.active == state){
29844             return;
29845         }
29846         
29847         this.active = state;
29848         
29849         if (state) {
29850             this.el.addClass('active');
29851             return;
29852         }
29853         
29854         this.el.removeClass('active');
29855         
29856         return;
29857     },
29858     
29859     setDisabled : function(state)
29860     {
29861         if(this.disabled == state){
29862             return;
29863         }
29864         
29865         this.disabled = state;
29866         
29867         if (state) {
29868             this.el.addClass('disabled');
29869             return;
29870         }
29871         
29872         this.el.removeClass('disabled');
29873     },
29874     
29875     tooltipEl : function()
29876     {
29877         return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29878     }
29879 });
29880  
29881
29882  /*
29883  * - LGPL
29884  *
29885  * FieldLabel
29886  * 
29887  */
29888
29889 /**
29890  * @class Roo.bootstrap.FieldLabel
29891  * @extends Roo.bootstrap.Component
29892  * Bootstrap FieldLabel class
29893  * @cfg {String} html contents of the element
29894  * @cfg {String} tag tag of the element default label
29895  * @cfg {String} cls class of the element
29896  * @cfg {String} target label target 
29897  * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29898  * @cfg {String} invalidClass default "text-warning"
29899  * @cfg {String} validClass default "text-success"
29900  * @cfg {String} iconTooltip default "This field is required"
29901  * @cfg {String} indicatorpos (left|right) default left
29902  * 
29903  * @constructor
29904  * Create a new FieldLabel
29905  * @param {Object} config The config object
29906  */
29907
29908 Roo.bootstrap.FieldLabel = function(config){
29909     Roo.bootstrap.Element.superclass.constructor.call(this, config);
29910     
29911     this.addEvents({
29912             /**
29913              * @event invalid
29914              * Fires after the field has been marked as invalid.
29915              * @param {Roo.form.FieldLabel} this
29916              * @param {String} msg The validation message
29917              */
29918             invalid : true,
29919             /**
29920              * @event valid
29921              * Fires after the field has been validated with no errors.
29922              * @param {Roo.form.FieldLabel} this
29923              */
29924             valid : true
29925         });
29926 };
29927
29928 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
29929     
29930     tag: 'label',
29931     cls: '',
29932     html: '',
29933     target: '',
29934     allowBlank : true,
29935     invalidClass : 'has-warning',
29936     validClass : 'has-success',
29937     iconTooltip : 'This field is required',
29938     indicatorpos : 'left',
29939     
29940     getAutoCreate : function(){
29941         
29942         var cfg = {
29943             tag : this.tag,
29944             cls : 'roo-bootstrap-field-label ' + this.cls,
29945             for : this.target,
29946             cn : [
29947                 {
29948                     tag : 'i',
29949                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29950                     tooltip : this.iconTooltip
29951                 },
29952                 {
29953                     tag : 'span',
29954                     html : this.html
29955                 }
29956             ] 
29957         };
29958         
29959         if(this.indicatorpos == 'right'){
29960             var cfg = {
29961                 tag : this.tag,
29962                 cls : 'roo-bootstrap-field-label ' + this.cls,
29963                 for : this.target,
29964                 cn : [
29965                     {
29966                         tag : 'span',
29967                         html : this.html
29968                     },
29969                     {
29970                         tag : 'i',
29971                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29972                         tooltip : this.iconTooltip
29973                     }
29974                 ] 
29975             };
29976         }
29977         
29978         return cfg;
29979     },
29980     
29981     initEvents: function() 
29982     {
29983         Roo.bootstrap.Element.superclass.initEvents.call(this);
29984         
29985         this.indicator = this.indicatorEl();
29986         
29987         if(this.indicator){
29988             this.indicator.removeClass('visible');
29989             this.indicator.addClass('invisible');
29990         }
29991         
29992         Roo.bootstrap.FieldLabel.register(this);
29993     },
29994     
29995     indicatorEl : function()
29996     {
29997         var indicator = this.el.select('i.roo-required-indicator',true).first();
29998         
29999         if(!indicator){
30000             return false;
30001         }
30002         
30003         return indicator;
30004         
30005     },
30006     
30007     /**
30008      * Mark this field as valid
30009      */
30010     markValid : function()
30011     {
30012         if(this.indicator){
30013             this.indicator.removeClass('visible');
30014             this.indicator.addClass('invisible');
30015         }
30016         
30017         this.el.removeClass(this.invalidClass);
30018         
30019         this.el.addClass(this.validClass);
30020         
30021         this.fireEvent('valid', this);
30022     },
30023     
30024     /**
30025      * Mark this field as invalid
30026      * @param {String} msg The validation message
30027      */
30028     markInvalid : function(msg)
30029     {
30030         if(this.indicator){
30031             this.indicator.removeClass('invisible');
30032             this.indicator.addClass('visible');
30033         }
30034         
30035         this.el.removeClass(this.validClass);
30036         
30037         this.el.addClass(this.invalidClass);
30038         
30039         this.fireEvent('invalid', this, msg);
30040     }
30041     
30042    
30043 });
30044
30045 Roo.apply(Roo.bootstrap.FieldLabel, {
30046     
30047     groups: {},
30048     
30049      /**
30050     * register a FieldLabel Group
30051     * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30052     */
30053     register : function(label)
30054     {
30055         if(this.groups.hasOwnProperty(label.target)){
30056             return;
30057         }
30058      
30059         this.groups[label.target] = label;
30060         
30061     },
30062     /**
30063     * fetch a FieldLabel Group based on the target
30064     * @param {string} target
30065     * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30066     */
30067     get: function(target) {
30068         if (typeof(this.groups[target]) == 'undefined') {
30069             return false;
30070         }
30071         
30072         return this.groups[target] ;
30073     }
30074 });
30075
30076  
30077
30078  /*
30079  * - LGPL
30080  *
30081  * page DateSplitField.
30082  * 
30083  */
30084
30085
30086 /**
30087  * @class Roo.bootstrap.DateSplitField
30088  * @extends Roo.bootstrap.Component
30089  * Bootstrap DateSplitField class
30090  * @cfg {string} fieldLabel - the label associated
30091  * @cfg {Number} labelWidth set the width of label (0-12)
30092  * @cfg {String} labelAlign (top|left)
30093  * @cfg {Boolean} dayAllowBlank (true|false) default false
30094  * @cfg {Boolean} monthAllowBlank (true|false) default false
30095  * @cfg {Boolean} yearAllowBlank (true|false) default false
30096  * @cfg {string} dayPlaceholder 
30097  * @cfg {string} monthPlaceholder
30098  * @cfg {string} yearPlaceholder
30099  * @cfg {string} dayFormat default 'd'
30100  * @cfg {string} monthFormat default 'm'
30101  * @cfg {string} yearFormat default 'Y'
30102  * @cfg {Number} labellg set the width of label (1-12)
30103  * @cfg {Number} labelmd set the width of label (1-12)
30104  * @cfg {Number} labelsm set the width of label (1-12)
30105  * @cfg {Number} labelxs set the width of label (1-12)
30106
30107  *     
30108  * @constructor
30109  * Create a new DateSplitField
30110  * @param {Object} config The config object
30111  */
30112
30113 Roo.bootstrap.DateSplitField = function(config){
30114     Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30115     
30116     this.addEvents({
30117         // raw events
30118          /**
30119          * @event years
30120          * getting the data of years
30121          * @param {Roo.bootstrap.DateSplitField} this
30122          * @param {Object} years
30123          */
30124         "years" : true,
30125         /**
30126          * @event days
30127          * getting the data of days
30128          * @param {Roo.bootstrap.DateSplitField} this
30129          * @param {Object} days
30130          */
30131         "days" : true,
30132         /**
30133          * @event invalid
30134          * Fires after the field has been marked as invalid.
30135          * @param {Roo.form.Field} this
30136          * @param {String} msg The validation message
30137          */
30138         invalid : true,
30139        /**
30140          * @event valid
30141          * Fires after the field has been validated with no errors.
30142          * @param {Roo.form.Field} this
30143          */
30144         valid : true
30145     });
30146 };
30147
30148 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
30149     
30150     fieldLabel : '',
30151     labelAlign : 'top',
30152     labelWidth : 3,
30153     dayAllowBlank : false,
30154     monthAllowBlank : false,
30155     yearAllowBlank : false,
30156     dayPlaceholder : '',
30157     monthPlaceholder : '',
30158     yearPlaceholder : '',
30159     dayFormat : 'd',
30160     monthFormat : 'm',
30161     yearFormat : 'Y',
30162     isFormField : true,
30163     labellg : 0,
30164     labelmd : 0,
30165     labelsm : 0,
30166     labelxs : 0,
30167     
30168     getAutoCreate : function()
30169     {
30170         var cfg = {
30171             tag : 'div',
30172             cls : 'row roo-date-split-field-group',
30173             cn : [
30174                 {
30175                     tag : 'input',
30176                     type : 'hidden',
30177                     cls : 'form-hidden-field roo-date-split-field-group-value',
30178                     name : this.name
30179                 }
30180             ]
30181         };
30182         
30183         var labelCls = 'col-md-12';
30184         var contentCls = 'col-md-4';
30185         
30186         if(this.fieldLabel){
30187             
30188             var label = {
30189                 tag : 'div',
30190                 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30191                 cn : [
30192                     {
30193                         tag : 'label',
30194                         html : this.fieldLabel
30195                     }
30196                 ]
30197             };
30198             
30199             if(this.labelAlign == 'left'){
30200             
30201                 if(this.labelWidth > 12){
30202                     label.style = "width: " + this.labelWidth + 'px';
30203                 }
30204
30205                 if(this.labelWidth < 13 && this.labelmd == 0){
30206                     this.labelmd = this.labelWidth;
30207                 }
30208
30209                 if(this.labellg > 0){
30210                     labelCls = ' col-lg-' + this.labellg;
30211                     contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30212                 }
30213
30214                 if(this.labelmd > 0){
30215                     labelCls = ' col-md-' + this.labelmd;
30216                     contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30217                 }
30218
30219                 if(this.labelsm > 0){
30220                     labelCls = ' col-sm-' + this.labelsm;
30221                     contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30222                 }
30223
30224                 if(this.labelxs > 0){
30225                     labelCls = ' col-xs-' + this.labelxs;
30226                     contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30227                 }
30228             }
30229             
30230             label.cls += ' ' + labelCls;
30231             
30232             cfg.cn.push(label);
30233         }
30234         
30235         Roo.each(['day', 'month', 'year'], function(t){
30236             cfg.cn.push({
30237                 tag : 'div',
30238                 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30239             });
30240         }, this);
30241         
30242         return cfg;
30243     },
30244     
30245     inputEl: function ()
30246     {
30247         return this.el.select('.roo-date-split-field-group-value', true).first();
30248     },
30249     
30250     onRender : function(ct, position) 
30251     {
30252         var _this = this;
30253         
30254         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30255         
30256         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30257         
30258         this.dayField = new Roo.bootstrap.ComboBox({
30259             allowBlank : this.dayAllowBlank,
30260             alwaysQuery : true,
30261             displayField : 'value',
30262             editable : false,
30263             fieldLabel : '',
30264             forceSelection : true,
30265             mode : 'local',
30266             placeholder : this.dayPlaceholder,
30267             selectOnFocus : true,
30268             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30269             triggerAction : 'all',
30270             typeAhead : true,
30271             valueField : 'value',
30272             store : new Roo.data.SimpleStore({
30273                 data : (function() {    
30274                     var days = [];
30275                     _this.fireEvent('days', _this, days);
30276                     return days;
30277                 })(),
30278                 fields : [ 'value' ]
30279             }),
30280             listeners : {
30281                 select : function (_self, record, index)
30282                 {
30283                     _this.setValue(_this.getValue());
30284                 }
30285             }
30286         });
30287
30288         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30289         
30290         this.monthField = new Roo.bootstrap.MonthField({
30291             after : '<i class=\"fa fa-calendar\"></i>',
30292             allowBlank : this.monthAllowBlank,
30293             placeholder : this.monthPlaceholder,
30294             readOnly : true,
30295             listeners : {
30296                 render : function (_self)
30297                 {
30298                     this.el.select('span.input-group-addon', true).first().on('click', function(e){
30299                         e.preventDefault();
30300                         _self.focus();
30301                     });
30302                 },
30303                 select : function (_self, oldvalue, newvalue)
30304                 {
30305                     _this.setValue(_this.getValue());
30306                 }
30307             }
30308         });
30309         
30310         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30311         
30312         this.yearField = new Roo.bootstrap.ComboBox({
30313             allowBlank : this.yearAllowBlank,
30314             alwaysQuery : true,
30315             displayField : 'value',
30316             editable : false,
30317             fieldLabel : '',
30318             forceSelection : true,
30319             mode : 'local',
30320             placeholder : this.yearPlaceholder,
30321             selectOnFocus : true,
30322             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30323             triggerAction : 'all',
30324             typeAhead : true,
30325             valueField : 'value',
30326             store : new Roo.data.SimpleStore({
30327                 data : (function() {
30328                     var years = [];
30329                     _this.fireEvent('years', _this, years);
30330                     return years;
30331                 })(),
30332                 fields : [ 'value' ]
30333             }),
30334             listeners : {
30335                 select : function (_self, record, index)
30336                 {
30337                     _this.setValue(_this.getValue());
30338                 }
30339             }
30340         });
30341
30342         this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30343     },
30344     
30345     setValue : function(v, format)
30346     {
30347         this.inputEl.dom.value = v;
30348         
30349         var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30350         
30351         var d = Date.parseDate(v, f);
30352         
30353         if(!d){
30354             this.validate();
30355             return;
30356         }
30357         
30358         this.setDay(d.format(this.dayFormat));
30359         this.setMonth(d.format(this.monthFormat));
30360         this.setYear(d.format(this.yearFormat));
30361         
30362         this.validate();
30363         
30364         return;
30365     },
30366     
30367     setDay : function(v)
30368     {
30369         this.dayField.setValue(v);
30370         this.inputEl.dom.value = this.getValue();
30371         this.validate();
30372         return;
30373     },
30374     
30375     setMonth : function(v)
30376     {
30377         this.monthField.setValue(v, true);
30378         this.inputEl.dom.value = this.getValue();
30379         this.validate();
30380         return;
30381     },
30382     
30383     setYear : function(v)
30384     {
30385         this.yearField.setValue(v);
30386         this.inputEl.dom.value = this.getValue();
30387         this.validate();
30388         return;
30389     },
30390     
30391     getDay : function()
30392     {
30393         return this.dayField.getValue();
30394     },
30395     
30396     getMonth : function()
30397     {
30398         return this.monthField.getValue();
30399     },
30400     
30401     getYear : function()
30402     {
30403         return this.yearField.getValue();
30404     },
30405     
30406     getValue : function()
30407     {
30408         var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30409         
30410         var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30411         
30412         return date;
30413     },
30414     
30415     reset : function()
30416     {
30417         this.setDay('');
30418         this.setMonth('');
30419         this.setYear('');
30420         this.inputEl.dom.value = '';
30421         this.validate();
30422         return;
30423     },
30424     
30425     validate : function()
30426     {
30427         var d = this.dayField.validate();
30428         var m = this.monthField.validate();
30429         var y = this.yearField.validate();
30430         
30431         var valid = true;
30432         
30433         if(
30434                 (!this.dayAllowBlank && !d) ||
30435                 (!this.monthAllowBlank && !m) ||
30436                 (!this.yearAllowBlank && !y)
30437         ){
30438             valid = false;
30439         }
30440         
30441         if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30442             return valid;
30443         }
30444         
30445         if(valid){
30446             this.markValid();
30447             return valid;
30448         }
30449         
30450         this.markInvalid();
30451         
30452         return valid;
30453     },
30454     
30455     markValid : function()
30456     {
30457         
30458         var label = this.el.select('label', true).first();
30459         var icon = this.el.select('i.fa-star', true).first();
30460
30461         if(label && icon){
30462             icon.remove();
30463         }
30464         
30465         this.fireEvent('valid', this);
30466     },
30467     
30468      /**
30469      * Mark this field as invalid
30470      * @param {String} msg The validation message
30471      */
30472     markInvalid : function(msg)
30473     {
30474         
30475         var label = this.el.select('label', true).first();
30476         var icon = this.el.select('i.fa-star', true).first();
30477
30478         if(label && !icon){
30479             this.el.select('.roo-date-split-field-label', true).createChild({
30480                 tag : 'i',
30481                 cls : 'text-danger fa fa-lg fa-star',
30482                 tooltip : 'This field is required',
30483                 style : 'margin-right:5px;'
30484             }, label, true);
30485         }
30486         
30487         this.fireEvent('invalid', this, msg);
30488     },
30489     
30490     clearInvalid : function()
30491     {
30492         var label = this.el.select('label', true).first();
30493         var icon = this.el.select('i.fa-star', true).first();
30494
30495         if(label && icon){
30496             icon.remove();
30497         }
30498         
30499         this.fireEvent('valid', this);
30500     },
30501     
30502     getName: function()
30503     {
30504         return this.name;
30505     }
30506     
30507 });
30508
30509  /**
30510  *
30511  * This is based on 
30512  * http://masonry.desandro.com
30513  *
30514  * The idea is to render all the bricks based on vertical width...
30515  *
30516  * The original code extends 'outlayer' - we might need to use that....
30517  * 
30518  */
30519
30520
30521 /**
30522  * @class Roo.bootstrap.LayoutMasonry
30523  * @extends Roo.bootstrap.Component
30524  * Bootstrap Layout Masonry class
30525  * 
30526  * @constructor
30527  * Create a new Element
30528  * @param {Object} config The config object
30529  */
30530
30531 Roo.bootstrap.LayoutMasonry = function(config){
30532     
30533     Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30534     
30535     this.bricks = [];
30536     
30537     Roo.bootstrap.LayoutMasonry.register(this);
30538     
30539     this.addEvents({
30540         // raw events
30541         /**
30542          * @event layout
30543          * Fire after layout the items
30544          * @param {Roo.bootstrap.LayoutMasonry} this
30545          * @param {Roo.EventObject} e
30546          */
30547         "layout" : true
30548     });
30549     
30550 };
30551
30552 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component,  {
30553     
30554     /**
30555      * @cfg {Boolean} isLayoutInstant = no animation?
30556      */   
30557     isLayoutInstant : false, // needed?
30558    
30559     /**
30560      * @cfg {Number} boxWidth  width of the columns
30561      */   
30562     boxWidth : 450,
30563     
30564       /**
30565      * @cfg {Number} boxHeight  - 0 for square, or fix it at a certian height
30566      */   
30567     boxHeight : 0,
30568     
30569     /**
30570      * @cfg {Number} padWidth padding below box..
30571      */   
30572     padWidth : 10, 
30573     
30574     /**
30575      * @cfg {Number} gutter gutter width..
30576      */   
30577     gutter : 10,
30578     
30579      /**
30580      * @cfg {Number} maxCols maximum number of columns
30581      */   
30582     
30583     maxCols: 0,
30584     
30585     /**
30586      * @cfg {Boolean} isAutoInitial defalut true
30587      */   
30588     isAutoInitial : true, 
30589     
30590     containerWidth: 0,
30591     
30592     /**
30593      * @cfg {Boolean} isHorizontal defalut false
30594      */   
30595     isHorizontal : false, 
30596
30597     currentSize : null,
30598     
30599     tag: 'div',
30600     
30601     cls: '',
30602     
30603     bricks: null, //CompositeElement
30604     
30605     cols : 1,
30606     
30607     _isLayoutInited : false,
30608     
30609 //    isAlternative : false, // only use for vertical layout...
30610     
30611     /**
30612      * @cfg {Number} alternativePadWidth padding below box..
30613      */   
30614     alternativePadWidth : 50,
30615     
30616     selectedBrick : [],
30617     
30618     getAutoCreate : function(){
30619         
30620         var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30621         
30622         var cfg = {
30623             tag: this.tag,
30624             cls: 'blog-masonary-wrapper ' + this.cls,
30625             cn : {
30626                 cls : 'mas-boxes masonary'
30627             }
30628         };
30629         
30630         return cfg;
30631     },
30632     
30633     getChildContainer: function( )
30634     {
30635         if (this.boxesEl) {
30636             return this.boxesEl;
30637         }
30638         
30639         this.boxesEl = this.el.select('.mas-boxes').first();
30640         
30641         return this.boxesEl;
30642     },
30643     
30644     
30645     initEvents : function()
30646     {
30647         var _this = this;
30648         
30649         if(this.isAutoInitial){
30650             Roo.log('hook children rendered');
30651             this.on('childrenrendered', function() {
30652                 Roo.log('children rendered');
30653                 _this.initial();
30654             } ,this);
30655         }
30656     },
30657     
30658     initial : function()
30659     {
30660         this.selectedBrick = [];
30661         
30662         this.currentSize = this.el.getBox(true);
30663         
30664         Roo.EventManager.onWindowResize(this.resize, this); 
30665
30666         if(!this.isAutoInitial){
30667             this.layout();
30668             return;
30669         }
30670         
30671         this.layout();
30672         
30673         return;
30674         //this.layout.defer(500,this);
30675         
30676     },
30677     
30678     resize : function()
30679     {
30680         var cs = this.el.getBox(true);
30681         
30682         if (
30683                 this.currentSize.width == cs.width && 
30684                 this.currentSize.x == cs.x && 
30685                 this.currentSize.height == cs.height && 
30686                 this.currentSize.y == cs.y 
30687         ) {
30688             Roo.log("no change in with or X or Y");
30689             return;
30690         }
30691         
30692         this.currentSize = cs;
30693         
30694         this.layout();
30695         
30696     },
30697     
30698     layout : function()
30699     {   
30700         this._resetLayout();
30701         
30702         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30703         
30704         this.layoutItems( isInstant );
30705       
30706         this._isLayoutInited = true;
30707         
30708         this.fireEvent('layout', this);
30709         
30710     },
30711     
30712     _resetLayout : function()
30713     {
30714         if(this.isHorizontal){
30715             this.horizontalMeasureColumns();
30716             return;
30717         }
30718         
30719         this.verticalMeasureColumns();
30720         
30721     },
30722     
30723     verticalMeasureColumns : function()
30724     {
30725         this.getContainerWidth();
30726         
30727 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30728 //            this.colWidth = Math.floor(this.containerWidth * 0.8);
30729 //            return;
30730 //        }
30731         
30732         var boxWidth = this.boxWidth + this.padWidth;
30733         
30734         if(this.containerWidth < this.boxWidth){
30735             boxWidth = this.containerWidth
30736         }
30737         
30738         var containerWidth = this.containerWidth;
30739         
30740         var cols = Math.floor(containerWidth / boxWidth);
30741         
30742         this.cols = Math.max( cols, 1 );
30743         
30744         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30745         
30746         var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30747         
30748         var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30749         
30750         this.colWidth = boxWidth + avail - this.padWidth;
30751         
30752         this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30753         this.unitHeight = this.boxHeight > 0 ? this.boxHeight  : this.unitWidth;
30754     },
30755     
30756     horizontalMeasureColumns : function()
30757     {
30758         this.getContainerWidth();
30759         
30760         var boxWidth = this.boxWidth;
30761         
30762         if(this.containerWidth < boxWidth){
30763             boxWidth = this.containerWidth;
30764         }
30765         
30766         this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30767         
30768         this.el.setHeight(boxWidth);
30769         
30770     },
30771     
30772     getContainerWidth : function()
30773     {
30774         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
30775     },
30776     
30777     layoutItems : function( isInstant )
30778     {
30779         Roo.log(this.bricks);
30780         
30781         var items = Roo.apply([], this.bricks);
30782         
30783         if(this.isHorizontal){
30784             this._horizontalLayoutItems( items , isInstant );
30785             return;
30786         }
30787         
30788 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30789 //            this._verticalAlternativeLayoutItems( items , isInstant );
30790 //            return;
30791 //        }
30792         
30793         this._verticalLayoutItems( items , isInstant );
30794         
30795     },
30796     
30797     _verticalLayoutItems : function ( items , isInstant)
30798     {
30799         if ( !items || !items.length ) {
30800             return;
30801         }
30802         
30803         var standard = [
30804             ['xs', 'xs', 'xs', 'tall'],
30805             ['xs', 'xs', 'tall'],
30806             ['xs', 'xs', 'sm'],
30807             ['xs', 'xs', 'xs'],
30808             ['xs', 'tall'],
30809             ['xs', 'sm'],
30810             ['xs', 'xs'],
30811             ['xs'],
30812             
30813             ['sm', 'xs', 'xs'],
30814             ['sm', 'xs'],
30815             ['sm'],
30816             
30817             ['tall', 'xs', 'xs', 'xs'],
30818             ['tall', 'xs', 'xs'],
30819             ['tall', 'xs'],
30820             ['tall']
30821             
30822         ];
30823         
30824         var queue = [];
30825         
30826         var boxes = [];
30827         
30828         var box = [];
30829         
30830         Roo.each(items, function(item, k){
30831             
30832             switch (item.size) {
30833                 // these layouts take up a full box,
30834                 case 'md' :
30835                 case 'md-left' :
30836                 case 'md-right' :
30837                 case 'wide' :
30838                     
30839                     if(box.length){
30840                         boxes.push(box);
30841                         box = [];
30842                     }
30843                     
30844                     boxes.push([item]);
30845                     
30846                     break;
30847                     
30848                 case 'xs' :
30849                 case 'sm' :
30850                 case 'tall' :
30851                     
30852                     box.push(item);
30853                     
30854                     break;
30855                 default :
30856                     break;
30857                     
30858             }
30859             
30860         }, this);
30861         
30862         if(box.length){
30863             boxes.push(box);
30864             box = [];
30865         }
30866         
30867         var filterPattern = function(box, length)
30868         {
30869             if(!box.length){
30870                 return;
30871             }
30872             
30873             var match = false;
30874             
30875             var pattern = box.slice(0, length);
30876             
30877             var format = [];
30878             
30879             Roo.each(pattern, function(i){
30880                 format.push(i.size);
30881             }, this);
30882             
30883             Roo.each(standard, function(s){
30884                 
30885                 if(String(s) != String(format)){
30886                     return;
30887                 }
30888                 
30889                 match = true;
30890                 return false;
30891                 
30892             }, this);
30893             
30894             if(!match && length == 1){
30895                 return;
30896             }
30897             
30898             if(!match){
30899                 filterPattern(box, length - 1);
30900                 return;
30901             }
30902                 
30903             queue.push(pattern);
30904
30905             box = box.slice(length, box.length);
30906
30907             filterPattern(box, 4);
30908
30909             return;
30910             
30911         }
30912         
30913         Roo.each(boxes, function(box, k){
30914             
30915             if(!box.length){
30916                 return;
30917             }
30918             
30919             if(box.length == 1){
30920                 queue.push(box);
30921                 return;
30922             }
30923             
30924             filterPattern(box, 4);
30925             
30926         }, this);
30927         
30928         this._processVerticalLayoutQueue( queue, isInstant );
30929         
30930     },
30931     
30932 //    _verticalAlternativeLayoutItems : function( items , isInstant )
30933 //    {
30934 //        if ( !items || !items.length ) {
30935 //            return;
30936 //        }
30937 //
30938 //        this._processVerticalAlternativeLayoutQueue( items, isInstant );
30939 //        
30940 //    },
30941     
30942     _horizontalLayoutItems : function ( items , isInstant)
30943     {
30944         if ( !items || !items.length || items.length < 3) {
30945             return;
30946         }
30947         
30948         items.reverse();
30949         
30950         var eItems = items.slice(0, 3);
30951         
30952         items = items.slice(3, items.length);
30953         
30954         var standard = [
30955             ['xs', 'xs', 'xs', 'wide'],
30956             ['xs', 'xs', 'wide'],
30957             ['xs', 'xs', 'sm'],
30958             ['xs', 'xs', 'xs'],
30959             ['xs', 'wide'],
30960             ['xs', 'sm'],
30961             ['xs', 'xs'],
30962             ['xs'],
30963             
30964             ['sm', 'xs', 'xs'],
30965             ['sm', 'xs'],
30966             ['sm'],
30967             
30968             ['wide', 'xs', 'xs', 'xs'],
30969             ['wide', 'xs', 'xs'],
30970             ['wide', 'xs'],
30971             ['wide'],
30972             
30973             ['wide-thin']
30974         ];
30975         
30976         var queue = [];
30977         
30978         var boxes = [];
30979         
30980         var box = [];
30981         
30982         Roo.each(items, function(item, k){
30983             
30984             switch (item.size) {
30985                 case 'md' :
30986                 case 'md-left' :
30987                 case 'md-right' :
30988                 case 'tall' :
30989                     
30990                     if(box.length){
30991                         boxes.push(box);
30992                         box = [];
30993                     }
30994                     
30995                     boxes.push([item]);
30996                     
30997                     break;
30998                     
30999                 case 'xs' :
31000                 case 'sm' :
31001                 case 'wide' :
31002                 case 'wide-thin' :
31003                     
31004                     box.push(item);
31005                     
31006                     break;
31007                 default :
31008                     break;
31009                     
31010             }
31011             
31012         }, this);
31013         
31014         if(box.length){
31015             boxes.push(box);
31016             box = [];
31017         }
31018         
31019         var filterPattern = function(box, length)
31020         {
31021             if(!box.length){
31022                 return;
31023             }
31024             
31025             var match = false;
31026             
31027             var pattern = box.slice(0, length);
31028             
31029             var format = [];
31030             
31031             Roo.each(pattern, function(i){
31032                 format.push(i.size);
31033             }, this);
31034             
31035             Roo.each(standard, function(s){
31036                 
31037                 if(String(s) != String(format)){
31038                     return;
31039                 }
31040                 
31041                 match = true;
31042                 return false;
31043                 
31044             }, this);
31045             
31046             if(!match && length == 1){
31047                 return;
31048             }
31049             
31050             if(!match){
31051                 filterPattern(box, length - 1);
31052                 return;
31053             }
31054                 
31055             queue.push(pattern);
31056
31057             box = box.slice(length, box.length);
31058
31059             filterPattern(box, 4);
31060
31061             return;
31062             
31063         }
31064         
31065         Roo.each(boxes, function(box, k){
31066             
31067             if(!box.length){
31068                 return;
31069             }
31070             
31071             if(box.length == 1){
31072                 queue.push(box);
31073                 return;
31074             }
31075             
31076             filterPattern(box, 4);
31077             
31078         }, this);
31079         
31080         
31081         var prune = [];
31082         
31083         var pos = this.el.getBox(true);
31084         
31085         var minX = pos.x;
31086         
31087         var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31088         
31089         var hit_end = false;
31090         
31091         Roo.each(queue, function(box){
31092             
31093             if(hit_end){
31094                 
31095                 Roo.each(box, function(b){
31096                 
31097                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31098                     b.el.hide();
31099
31100                 }, this);
31101
31102                 return;
31103             }
31104             
31105             var mx = 0;
31106             
31107             Roo.each(box, function(b){
31108                 
31109                 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31110                 b.el.show();
31111
31112                 mx = Math.max(mx, b.x);
31113                 
31114             }, this);
31115             
31116             maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31117             
31118             if(maxX < minX){
31119                 
31120                 Roo.each(box, function(b){
31121                 
31122                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31123                     b.el.hide();
31124                     
31125                 }, this);
31126                 
31127                 hit_end = true;
31128                 
31129                 return;
31130             }
31131             
31132             prune.push(box);
31133             
31134         }, this);
31135         
31136         this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31137     },
31138     
31139     /** Sets position of item in DOM
31140     * @param {Element} item
31141     * @param {Number} x - horizontal position
31142     * @param {Number} y - vertical position
31143     * @param {Boolean} isInstant - disables transitions
31144     */
31145     _processVerticalLayoutQueue : function( queue, isInstant )
31146     {
31147         var pos = this.el.getBox(true);
31148         var x = pos.x;
31149         var y = pos.y;
31150         var maxY = [];
31151         
31152         for (var i = 0; i < this.cols; i++){
31153             maxY[i] = pos.y;
31154         }
31155         
31156         Roo.each(queue, function(box, k){
31157             
31158             var col = k % this.cols;
31159             
31160             Roo.each(box, function(b,kk){
31161                 
31162                 b.el.position('absolute');
31163                 
31164                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31165                 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31166                 
31167                 if(b.size == 'md-left' || b.size == 'md-right'){
31168                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31169                     height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31170                 }
31171                 
31172                 b.el.setWidth(width);
31173                 b.el.setHeight(height);
31174                 // iframe?
31175                 b.el.select('iframe',true).setSize(width,height);
31176                 
31177             }, this);
31178             
31179             for (var i = 0; i < this.cols; i++){
31180                 
31181                 if(maxY[i] < maxY[col]){
31182                     col = i;
31183                     continue;
31184                 }
31185                 
31186                 col = Math.min(col, i);
31187                 
31188             }
31189             
31190             x = pos.x + col * (this.colWidth + this.padWidth);
31191             
31192             y = maxY[col];
31193             
31194             var positions = [];
31195             
31196             switch (box.length){
31197                 case 1 :
31198                     positions = this.getVerticalOneBoxColPositions(x, y, box);
31199                     break;
31200                 case 2 :
31201                     positions = this.getVerticalTwoBoxColPositions(x, y, box);
31202                     break;
31203                 case 3 :
31204                     positions = this.getVerticalThreeBoxColPositions(x, y, box);
31205                     break;
31206                 case 4 :
31207                     positions = this.getVerticalFourBoxColPositions(x, y, box);
31208                     break;
31209                 default :
31210                     break;
31211             }
31212             
31213             Roo.each(box, function(b,kk){
31214                 
31215                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31216                 
31217                 var sz = b.el.getSize();
31218                 
31219                 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31220                 
31221             }, this);
31222             
31223         }, this);
31224         
31225         var mY = 0;
31226         
31227         for (var i = 0; i < this.cols; i++){
31228             mY = Math.max(mY, maxY[i]);
31229         }
31230         
31231         this.el.setHeight(mY - pos.y);
31232         
31233     },
31234     
31235 //    _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31236 //    {
31237 //        var pos = this.el.getBox(true);
31238 //        var x = pos.x;
31239 //        var y = pos.y;
31240 //        var maxX = pos.right;
31241 //        
31242 //        var maxHeight = 0;
31243 //        
31244 //        Roo.each(items, function(item, k){
31245 //            
31246 //            var c = k % 2;
31247 //            
31248 //            item.el.position('absolute');
31249 //                
31250 //            var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31251 //
31252 //            item.el.setWidth(width);
31253 //
31254 //            var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31255 //
31256 //            item.el.setHeight(height);
31257 //            
31258 //            if(c == 0){
31259 //                item.el.setXY([x, y], isInstant ? false : true);
31260 //            } else {
31261 //                item.el.setXY([maxX - width, y], isInstant ? false : true);
31262 //            }
31263 //            
31264 //            y = y + height + this.alternativePadWidth;
31265 //            
31266 //            maxHeight = maxHeight + height + this.alternativePadWidth;
31267 //            
31268 //        }, this);
31269 //        
31270 //        this.el.setHeight(maxHeight);
31271 //        
31272 //    },
31273     
31274     _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31275     {
31276         var pos = this.el.getBox(true);
31277         
31278         var minX = pos.x;
31279         var minY = pos.y;
31280         
31281         var maxX = pos.right;
31282         
31283         this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31284         
31285         var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31286         
31287         Roo.each(queue, function(box, k){
31288             
31289             Roo.each(box, function(b, kk){
31290                 
31291                 b.el.position('absolute');
31292                 
31293                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31294                 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31295                 
31296                 if(b.size == 'md-left' || b.size == 'md-right'){
31297                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31298                     height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31299                 }
31300                 
31301                 b.el.setWidth(width);
31302                 b.el.setHeight(height);
31303                 
31304             }, this);
31305             
31306             if(!box.length){
31307                 return;
31308             }
31309             
31310             var positions = [];
31311             
31312             switch (box.length){
31313                 case 1 :
31314                     positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31315                     break;
31316                 case 2 :
31317                     positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31318                     break;
31319                 case 3 :
31320                     positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31321                     break;
31322                 case 4 :
31323                     positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31324                     break;
31325                 default :
31326                     break;
31327             }
31328             
31329             Roo.each(box, function(b,kk){
31330                 
31331                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31332                 
31333                 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31334                 
31335             }, this);
31336             
31337         }, this);
31338         
31339     },
31340     
31341     _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31342     {
31343         Roo.each(eItems, function(b,k){
31344             
31345             b.size = (k == 0) ? 'sm' : 'xs';
31346             b.x = (k == 0) ? 2 : 1;
31347             b.y = (k == 0) ? 2 : 1;
31348             
31349             b.el.position('absolute');
31350             
31351             var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31352                 
31353             b.el.setWidth(width);
31354             
31355             var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31356             
31357             b.el.setHeight(height);
31358             
31359         }, this);
31360
31361         var positions = [];
31362         
31363         positions.push({
31364             x : maxX - this.unitWidth * 2 - this.gutter,
31365             y : minY
31366         });
31367         
31368         positions.push({
31369             x : maxX - this.unitWidth,
31370             y : minY + (this.unitWidth + this.gutter) * 2
31371         });
31372         
31373         positions.push({
31374             x : maxX - this.unitWidth * 3 - this.gutter * 2,
31375             y : minY
31376         });
31377         
31378         Roo.each(eItems, function(b,k){
31379             
31380             b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31381
31382         }, this);
31383         
31384     },
31385     
31386     getVerticalOneBoxColPositions : function(x, y, box)
31387     {
31388         var pos = [];
31389         
31390         var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31391         
31392         if(box[0].size == 'md-left'){
31393             rand = 0;
31394         }
31395         
31396         if(box[0].size == 'md-right'){
31397             rand = 1;
31398         }
31399         
31400         pos.push({
31401             x : x + (this.unitWidth + this.gutter) * rand,
31402             y : y
31403         });
31404         
31405         return pos;
31406     },
31407     
31408     getVerticalTwoBoxColPositions : function(x, y, box)
31409     {
31410         var pos = [];
31411         
31412         if(box[0].size == 'xs'){
31413             
31414             pos.push({
31415                 x : x,
31416                 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31417             });
31418
31419             pos.push({
31420                 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31421                 y : y
31422             });
31423             
31424             return pos;
31425             
31426         }
31427         
31428         pos.push({
31429             x : x,
31430             y : y
31431         });
31432
31433         pos.push({
31434             x : x + (this.unitWidth + this.gutter) * 2,
31435             y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31436         });
31437         
31438         return pos;
31439         
31440     },
31441     
31442     getVerticalThreeBoxColPositions : function(x, y, box)
31443     {
31444         var pos = [];
31445         
31446         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31447             
31448             pos.push({
31449                 x : x,
31450                 y : y
31451             });
31452
31453             pos.push({
31454                 x : x + (this.unitWidth + this.gutter) * 1,
31455                 y : y
31456             });
31457             
31458             pos.push({
31459                 x : x + (this.unitWidth + this.gutter) * 2,
31460                 y : y
31461             });
31462             
31463             return pos;
31464             
31465         }
31466         
31467         if(box[0].size == 'xs' && box[1].size == 'xs'){
31468             
31469             pos.push({
31470                 x : x,
31471                 y : y
31472             });
31473
31474             pos.push({
31475                 x : x,
31476                 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31477             });
31478             
31479             pos.push({
31480                 x : x + (this.unitWidth + this.gutter) * 1,
31481                 y : y
31482             });
31483             
31484             return pos;
31485             
31486         }
31487         
31488         pos.push({
31489             x : x,
31490             y : y
31491         });
31492
31493         pos.push({
31494             x : x + (this.unitWidth + this.gutter) * 2,
31495             y : y
31496         });
31497
31498         pos.push({
31499             x : x + (this.unitWidth + this.gutter) * 2,
31500             y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31501         });
31502             
31503         return pos;
31504         
31505     },
31506     
31507     getVerticalFourBoxColPositions : function(x, y, box)
31508     {
31509         var pos = [];
31510         
31511         if(box[0].size == 'xs'){
31512             
31513             pos.push({
31514                 x : x,
31515                 y : y
31516             });
31517
31518             pos.push({
31519                 x : x,
31520                 y : y + (this.unitHeight + this.gutter) * 1
31521             });
31522             
31523             pos.push({
31524                 x : x,
31525                 y : y + (this.unitHeight + this.gutter) * 2
31526             });
31527             
31528             pos.push({
31529                 x : x + (this.unitWidth + this.gutter) * 1,
31530                 y : y
31531             });
31532             
31533             return pos;
31534             
31535         }
31536         
31537         pos.push({
31538             x : x,
31539             y : y
31540         });
31541
31542         pos.push({
31543             x : x + (this.unitWidth + this.gutter) * 2,
31544             y : y
31545         });
31546
31547         pos.push({
31548             x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31549             y : y + (this.unitHeight + this.gutter) * 1
31550         });
31551
31552         pos.push({
31553             x : x + (this.unitWidth + this.gutter) * 2,
31554             y : y + (this.unitWidth + this.gutter) * 2
31555         });
31556
31557         return pos;
31558         
31559     },
31560     
31561     getHorizontalOneBoxColPositions : function(maxX, minY, box)
31562     {
31563         var pos = [];
31564         
31565         if(box[0].size == 'md-left'){
31566             pos.push({
31567                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31568                 y : minY
31569             });
31570             
31571             return pos;
31572         }
31573         
31574         if(box[0].size == 'md-right'){
31575             pos.push({
31576                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31577                 y : minY + (this.unitWidth + this.gutter) * 1
31578             });
31579             
31580             return pos;
31581         }
31582         
31583         var rand = Math.floor(Math.random() * (4 - box[0].y));
31584         
31585         pos.push({
31586             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31587             y : minY + (this.unitWidth + this.gutter) * rand
31588         });
31589         
31590         return pos;
31591         
31592     },
31593     
31594     getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31595     {
31596         var pos = [];
31597         
31598         if(box[0].size == 'xs'){
31599             
31600             pos.push({
31601                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31602                 y : minY
31603             });
31604
31605             pos.push({
31606                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31607                 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31608             });
31609             
31610             return pos;
31611             
31612         }
31613         
31614         pos.push({
31615             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31616             y : minY
31617         });
31618
31619         pos.push({
31620             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31621             y : minY + (this.unitWidth + this.gutter) * 2
31622         });
31623         
31624         return pos;
31625         
31626     },
31627     
31628     getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31629     {
31630         var pos = [];
31631         
31632         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31633             
31634             pos.push({
31635                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31636                 y : minY
31637             });
31638
31639             pos.push({
31640                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31641                 y : minY + (this.unitWidth + this.gutter) * 1
31642             });
31643             
31644             pos.push({
31645                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31646                 y : minY + (this.unitWidth + this.gutter) * 2
31647             });
31648             
31649             return pos;
31650             
31651         }
31652         
31653         if(box[0].size == 'xs' && box[1].size == 'xs'){
31654             
31655             pos.push({
31656                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31657                 y : minY
31658             });
31659
31660             pos.push({
31661                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31662                 y : minY
31663             });
31664             
31665             pos.push({
31666                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31667                 y : minY + (this.unitWidth + this.gutter) * 1
31668             });
31669             
31670             return pos;
31671             
31672         }
31673         
31674         pos.push({
31675             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31676             y : minY
31677         });
31678
31679         pos.push({
31680             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31681             y : minY + (this.unitWidth + this.gutter) * 2
31682         });
31683
31684         pos.push({
31685             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31686             y : minY + (this.unitWidth + this.gutter) * 2
31687         });
31688             
31689         return pos;
31690         
31691     },
31692     
31693     getHorizontalFourBoxColPositions : function(maxX, minY, box)
31694     {
31695         var pos = [];
31696         
31697         if(box[0].size == 'xs'){
31698             
31699             pos.push({
31700                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31701                 y : minY
31702             });
31703
31704             pos.push({
31705                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31706                 y : minY
31707             });
31708             
31709             pos.push({
31710                 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),
31711                 y : minY
31712             });
31713             
31714             pos.push({
31715                 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31716                 y : minY + (this.unitWidth + this.gutter) * 1
31717             });
31718             
31719             return pos;
31720             
31721         }
31722         
31723         pos.push({
31724             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31725             y : minY
31726         });
31727         
31728         pos.push({
31729             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31730             y : minY + (this.unitWidth + this.gutter) * 2
31731         });
31732         
31733         pos.push({
31734             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31735             y : minY + (this.unitWidth + this.gutter) * 2
31736         });
31737         
31738         pos.push({
31739             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),
31740             y : minY + (this.unitWidth + this.gutter) * 2
31741         });
31742
31743         return pos;
31744         
31745     },
31746     
31747     /**
31748     * remove a Masonry Brick
31749     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31750     */
31751     removeBrick : function(brick_id)
31752     {
31753         if (!brick_id) {
31754             return;
31755         }
31756         
31757         for (var i = 0; i<this.bricks.length; i++) {
31758             if (this.bricks[i].id == brick_id) {
31759                 this.bricks.splice(i,1);
31760                 this.el.dom.removeChild(Roo.get(brick_id).dom);
31761                 this.initial();
31762             }
31763         }
31764     },
31765     
31766     /**
31767     * adds a Masonry Brick
31768     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31769     */
31770     addBrick : function(cfg)
31771     {
31772         var cn = new Roo.bootstrap.MasonryBrick(cfg);
31773         //this.register(cn);
31774         cn.parentId = this.id;
31775         cn.onRender(this.el, null);
31776         return cn;
31777     },
31778     
31779     /**
31780     * register a Masonry Brick
31781     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31782     */
31783     
31784     register : function(brick)
31785     {
31786         this.bricks.push(brick);
31787         brick.masonryId = this.id;
31788     },
31789     
31790     /**
31791     * clear all the Masonry Brick
31792     */
31793     clearAll : function()
31794     {
31795         this.bricks = [];
31796         //this.getChildContainer().dom.innerHTML = "";
31797         this.el.dom.innerHTML = '';
31798     },
31799     
31800     getSelected : function()
31801     {
31802         if (!this.selectedBrick) {
31803             return false;
31804         }
31805         
31806         return this.selectedBrick;
31807     }
31808 });
31809
31810 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31811     
31812     groups: {},
31813      /**
31814     * register a Masonry Layout
31815     * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31816     */
31817     
31818     register : function(layout)
31819     {
31820         this.groups[layout.id] = layout;
31821     },
31822     /**
31823     * fetch a  Masonry Layout based on the masonry layout ID
31824     * @param {string} the masonry layout to add
31825     * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31826     */
31827     
31828     get: function(layout_id) {
31829         if (typeof(this.groups[layout_id]) == 'undefined') {
31830             return false;
31831         }
31832         return this.groups[layout_id] ;
31833     }
31834     
31835     
31836     
31837 });
31838
31839  
31840
31841  /**
31842  *
31843  * This is based on 
31844  * http://masonry.desandro.com
31845  *
31846  * The idea is to render all the bricks based on vertical width...
31847  *
31848  * The original code extends 'outlayer' - we might need to use that....
31849  * 
31850  */
31851
31852
31853 /**
31854  * @class Roo.bootstrap.LayoutMasonryAuto
31855  * @extends Roo.bootstrap.Component
31856  * Bootstrap Layout Masonry class
31857  * 
31858  * @constructor
31859  * Create a new Element
31860  * @param {Object} config The config object
31861  */
31862
31863 Roo.bootstrap.LayoutMasonryAuto = function(config){
31864     Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31865 };
31866
31867 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component,  {
31868     
31869       /**
31870      * @cfg {Boolean} isFitWidth  - resize the width..
31871      */   
31872     isFitWidth : false,  // options..
31873     /**
31874      * @cfg {Boolean} isOriginLeft = left align?
31875      */   
31876     isOriginLeft : true,
31877     /**
31878      * @cfg {Boolean} isOriginTop = top align?
31879      */   
31880     isOriginTop : false,
31881     /**
31882      * @cfg {Boolean} isLayoutInstant = no animation?
31883      */   
31884     isLayoutInstant : false, // needed?
31885     /**
31886      * @cfg {Boolean} isResizingContainer = not sure if this is used..
31887      */   
31888     isResizingContainer : true,
31889     /**
31890      * @cfg {Number} columnWidth  width of the columns 
31891      */   
31892     
31893     columnWidth : 0,
31894     
31895     /**
31896      * @cfg {Number} maxCols maximum number of columns
31897      */   
31898     
31899     maxCols: 0,
31900     /**
31901      * @cfg {Number} padHeight padding below box..
31902      */   
31903     
31904     padHeight : 10, 
31905     
31906     /**
31907      * @cfg {Boolean} isAutoInitial defalut true
31908      */   
31909     
31910     isAutoInitial : true, 
31911     
31912     // private?
31913     gutter : 0,
31914     
31915     containerWidth: 0,
31916     initialColumnWidth : 0,
31917     currentSize : null,
31918     
31919     colYs : null, // array.
31920     maxY : 0,
31921     padWidth: 10,
31922     
31923     
31924     tag: 'div',
31925     cls: '',
31926     bricks: null, //CompositeElement
31927     cols : 0, // array?
31928     // element : null, // wrapped now this.el
31929     _isLayoutInited : null, 
31930     
31931     
31932     getAutoCreate : function(){
31933         
31934         var cfg = {
31935             tag: this.tag,
31936             cls: 'blog-masonary-wrapper ' + this.cls,
31937             cn : {
31938                 cls : 'mas-boxes masonary'
31939             }
31940         };
31941         
31942         return cfg;
31943     },
31944     
31945     getChildContainer: function( )
31946     {
31947         if (this.boxesEl) {
31948             return this.boxesEl;
31949         }
31950         
31951         this.boxesEl = this.el.select('.mas-boxes').first();
31952         
31953         return this.boxesEl;
31954     },
31955     
31956     
31957     initEvents : function()
31958     {
31959         var _this = this;
31960         
31961         if(this.isAutoInitial){
31962             Roo.log('hook children rendered');
31963             this.on('childrenrendered', function() {
31964                 Roo.log('children rendered');
31965                 _this.initial();
31966             } ,this);
31967         }
31968         
31969     },
31970     
31971     initial : function()
31972     {
31973         this.reloadItems();
31974
31975         this.currentSize = this.el.getBox(true);
31976
31977         /// was window resize... - let's see if this works..
31978         Roo.EventManager.onWindowResize(this.resize, this); 
31979
31980         if(!this.isAutoInitial){
31981             this.layout();
31982             return;
31983         }
31984         
31985         this.layout.defer(500,this);
31986     },
31987     
31988     reloadItems: function()
31989     {
31990         this.bricks = this.el.select('.masonry-brick', true);
31991         
31992         this.bricks.each(function(b) {
31993             //Roo.log(b.getSize());
31994             if (!b.attr('originalwidth')) {
31995                 b.attr('originalwidth',  b.getSize().width);
31996             }
31997             
31998         });
31999         
32000         Roo.log(this.bricks.elements.length);
32001     },
32002     
32003     resize : function()
32004     {
32005         Roo.log('resize');
32006         var cs = this.el.getBox(true);
32007         
32008         if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32009             Roo.log("no change in with or X");
32010             return;
32011         }
32012         this.currentSize = cs;
32013         this.layout();
32014     },
32015     
32016     layout : function()
32017     {
32018          Roo.log('layout');
32019         this._resetLayout();
32020         //this._manageStamps();
32021       
32022         // don't animate first layout
32023         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32024         this.layoutItems( isInstant );
32025       
32026         // flag for initalized
32027         this._isLayoutInited = true;
32028     },
32029     
32030     layoutItems : function( isInstant )
32031     {
32032         //var items = this._getItemsForLayout( this.items );
32033         // original code supports filtering layout items.. we just ignore it..
32034         
32035         this._layoutItems( this.bricks , isInstant );
32036       
32037         this._postLayout();
32038     },
32039     _layoutItems : function ( items , isInstant)
32040     {
32041        //this.fireEvent( 'layout', this, items );
32042     
32043
32044         if ( !items || !items.elements.length ) {
32045           // no items, emit event with empty array
32046             return;
32047         }
32048
32049         var queue = [];
32050         items.each(function(item) {
32051             Roo.log("layout item");
32052             Roo.log(item);
32053             // get x/y object from method
32054             var position = this._getItemLayoutPosition( item );
32055             // enqueue
32056             position.item = item;
32057             position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32058             queue.push( position );
32059         }, this);
32060       
32061         this._processLayoutQueue( queue );
32062     },
32063     /** Sets position of item in DOM
32064     * @param {Element} item
32065     * @param {Number} x - horizontal position
32066     * @param {Number} y - vertical position
32067     * @param {Boolean} isInstant - disables transitions
32068     */
32069     _processLayoutQueue : function( queue )
32070     {
32071         for ( var i=0, len = queue.length; i < len; i++ ) {
32072             var obj = queue[i];
32073             obj.item.position('absolute');
32074             obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32075         }
32076     },
32077       
32078     
32079     /**
32080     * Any logic you want to do after each layout,
32081     * i.e. size the container
32082     */
32083     _postLayout : function()
32084     {
32085         this.resizeContainer();
32086     },
32087     
32088     resizeContainer : function()
32089     {
32090         if ( !this.isResizingContainer ) {
32091             return;
32092         }
32093         var size = this._getContainerSize();
32094         if ( size ) {
32095             this.el.setSize(size.width,size.height);
32096             this.boxesEl.setSize(size.width,size.height);
32097         }
32098     },
32099     
32100     
32101     
32102     _resetLayout : function()
32103     {
32104         //this.getSize();  // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32105         this.colWidth = this.el.getWidth();
32106         //this.gutter = this.el.getWidth(); 
32107         
32108         this.measureColumns();
32109
32110         // reset column Y
32111         var i = this.cols;
32112         this.colYs = [];
32113         while (i--) {
32114             this.colYs.push( 0 );
32115         }
32116     
32117         this.maxY = 0;
32118     },
32119
32120     measureColumns : function()
32121     {
32122         this.getContainerWidth();
32123       // if columnWidth is 0, default to outerWidth of first item
32124         if ( !this.columnWidth ) {
32125             var firstItem = this.bricks.first();
32126             Roo.log(firstItem);
32127             this.columnWidth  = this.containerWidth;
32128             if (firstItem && firstItem.attr('originalwidth') ) {
32129                 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32130             }
32131             // columnWidth fall back to item of first element
32132             Roo.log("set column width?");
32133                         this.initialColumnWidth = this.columnWidth  ;
32134
32135             // if first elem has no width, default to size of container
32136             
32137         }
32138         
32139         
32140         if (this.initialColumnWidth) {
32141             this.columnWidth = this.initialColumnWidth;
32142         }
32143         
32144         
32145             
32146         // column width is fixed at the top - however if container width get's smaller we should
32147         // reduce it...
32148         
32149         // this bit calcs how man columns..
32150             
32151         var columnWidth = this.columnWidth += this.gutter;
32152       
32153         // calculate columns
32154         var containerWidth = this.containerWidth + this.gutter;
32155         
32156         var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32157         // fix rounding errors, typically with gutters
32158         var excess = columnWidth - containerWidth % columnWidth;
32159         
32160         
32161         // if overshoot is less than a pixel, round up, otherwise floor it
32162         var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32163         cols = Math[ mathMethod ]( cols );
32164         this.cols = Math.max( cols, 1 );
32165         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32166         
32167          // padding positioning..
32168         var totalColWidth = this.cols * this.columnWidth;
32169         var padavail = this.containerWidth - totalColWidth;
32170         // so for 2 columns - we need 3 'pads'
32171         
32172         var padNeeded = (1+this.cols) * this.padWidth;
32173         
32174         var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32175         
32176         this.columnWidth += padExtra
32177         //this.padWidth = Math.floor(padavail /  ( this.cols));
32178         
32179         // adjust colum width so that padding is fixed??
32180         
32181         // we have 3 columns ... total = width * 3
32182         // we have X left over... that should be used by 
32183         
32184         //if (this.expandC) {
32185             
32186         //}
32187         
32188         
32189         
32190     },
32191     
32192     getContainerWidth : function()
32193     {
32194        /* // container is parent if fit width
32195         var container = this.isFitWidth ? this.element.parentNode : this.element;
32196         // check that this.size and size are there
32197         // IE8 triggers resize on body size change, so they might not be
32198         
32199         var size = getSize( container );  //FIXME
32200         this.containerWidth = size && size.innerWidth; //FIXME
32201         */
32202          
32203         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
32204         
32205     },
32206     
32207     _getItemLayoutPosition : function( item )  // what is item?
32208     {
32209         // we resize the item to our columnWidth..
32210       
32211         item.setWidth(this.columnWidth);
32212         item.autoBoxAdjust  = false;
32213         
32214         var sz = item.getSize();
32215  
32216         // how many columns does this brick span
32217         var remainder = this.containerWidth % this.columnWidth;
32218         
32219         var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32220         // round if off by 1 pixel, otherwise use ceil
32221         var colSpan = Math[ mathMethod ]( sz.width  / this.columnWidth );
32222         colSpan = Math.min( colSpan, this.cols );
32223         
32224         // normally this should be '1' as we dont' currently allow multi width columns..
32225         
32226         var colGroup = this._getColGroup( colSpan );
32227         // get the minimum Y value from the columns
32228         var minimumY = Math.min.apply( Math, colGroup );
32229         Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32230         
32231         var shortColIndex = colGroup.indexOf(  minimumY ); // broken on ie8..?? probably...
32232          
32233         // position the brick
32234         var position = {
32235             x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32236             y: this.currentSize.y + minimumY + this.padHeight
32237         };
32238         
32239         Roo.log(position);
32240         // apply setHeight to necessary columns
32241         var setHeight = minimumY + sz.height + this.padHeight;
32242         //Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32243         
32244         var setSpan = this.cols + 1 - colGroup.length;
32245         for ( var i = 0; i < setSpan; i++ ) {
32246           this.colYs[ shortColIndex + i ] = setHeight ;
32247         }
32248       
32249         return position;
32250     },
32251     
32252     /**
32253      * @param {Number} colSpan - number of columns the element spans
32254      * @returns {Array} colGroup
32255      */
32256     _getColGroup : function( colSpan )
32257     {
32258         if ( colSpan < 2 ) {
32259           // if brick spans only one column, use all the column Ys
32260           return this.colYs;
32261         }
32262       
32263         var colGroup = [];
32264         // how many different places could this brick fit horizontally
32265         var groupCount = this.cols + 1 - colSpan;
32266         // for each group potential horizontal position
32267         for ( var i = 0; i < groupCount; i++ ) {
32268           // make an array of colY values for that one group
32269           var groupColYs = this.colYs.slice( i, i + colSpan );
32270           // and get the max value of the array
32271           colGroup[i] = Math.max.apply( Math, groupColYs );
32272         }
32273         return colGroup;
32274     },
32275     /*
32276     _manageStamp : function( stamp )
32277     {
32278         var stampSize =  stamp.getSize();
32279         var offset = stamp.getBox();
32280         // get the columns that this stamp affects
32281         var firstX = this.isOriginLeft ? offset.x : offset.right;
32282         var lastX = firstX + stampSize.width;
32283         var firstCol = Math.floor( firstX / this.columnWidth );
32284         firstCol = Math.max( 0, firstCol );
32285         
32286         var lastCol = Math.floor( lastX / this.columnWidth );
32287         // lastCol should not go over if multiple of columnWidth #425
32288         lastCol -= lastX % this.columnWidth ? 0 : 1;
32289         lastCol = Math.min( this.cols - 1, lastCol );
32290         
32291         // set colYs to bottom of the stamp
32292         var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32293             stampSize.height;
32294             
32295         for ( var i = firstCol; i <= lastCol; i++ ) {
32296           this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32297         }
32298     },
32299     */
32300     
32301     _getContainerSize : function()
32302     {
32303         this.maxY = Math.max.apply( Math, this.colYs );
32304         var size = {
32305             height: this.maxY
32306         };
32307       
32308         if ( this.isFitWidth ) {
32309             size.width = this._getContainerFitWidth();
32310         }
32311       
32312         return size;
32313     },
32314     
32315     _getContainerFitWidth : function()
32316     {
32317         var unusedCols = 0;
32318         // count unused columns
32319         var i = this.cols;
32320         while ( --i ) {
32321           if ( this.colYs[i] !== 0 ) {
32322             break;
32323           }
32324           unusedCols++;
32325         }
32326         // fit container to columns that have been used
32327         return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32328     },
32329     
32330     needsResizeLayout : function()
32331     {
32332         var previousWidth = this.containerWidth;
32333         this.getContainerWidth();
32334         return previousWidth !== this.containerWidth;
32335     }
32336  
32337 });
32338
32339  
32340
32341  /*
32342  * - LGPL
32343  *
32344  * element
32345  * 
32346  */
32347
32348 /**
32349  * @class Roo.bootstrap.MasonryBrick
32350  * @extends Roo.bootstrap.Component
32351  * Bootstrap MasonryBrick class
32352  * 
32353  * @constructor
32354  * Create a new MasonryBrick
32355  * @param {Object} config The config object
32356  */
32357
32358 Roo.bootstrap.MasonryBrick = function(config){
32359     
32360     Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32361     
32362     Roo.bootstrap.MasonryBrick.register(this);
32363     
32364     this.addEvents({
32365         // raw events
32366         /**
32367          * @event click
32368          * When a MasonryBrick is clcik
32369          * @param {Roo.bootstrap.MasonryBrick} this
32370          * @param {Roo.EventObject} e
32371          */
32372         "click" : true
32373     });
32374 };
32375
32376 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component,  {
32377     
32378     /**
32379      * @cfg {String} title
32380      */   
32381     title : '',
32382     /**
32383      * @cfg {String} html
32384      */   
32385     html : '',
32386     /**
32387      * @cfg {String} bgimage
32388      */   
32389     bgimage : '',
32390     /**
32391      * @cfg {String} videourl
32392      */   
32393     videourl : '',
32394     /**
32395      * @cfg {String} cls
32396      */   
32397     cls : '',
32398     /**
32399      * @cfg {String} href
32400      */   
32401     href : '',
32402     /**
32403      * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32404      */   
32405     size : 'xs',
32406     
32407     /**
32408      * @cfg {String} placetitle (center|bottom)
32409      */   
32410     placetitle : '',
32411     
32412     /**
32413      * @cfg {Boolean} isFitContainer defalut true
32414      */   
32415     isFitContainer : true, 
32416     
32417     /**
32418      * @cfg {Boolean} preventDefault defalut false
32419      */   
32420     preventDefault : false, 
32421     
32422     /**
32423      * @cfg {Boolean} inverse defalut false
32424      */   
32425     maskInverse : false, 
32426     
32427     getAutoCreate : function()
32428     {
32429         if(!this.isFitContainer){
32430             return this.getSplitAutoCreate();
32431         }
32432         
32433         var cls = 'masonry-brick masonry-brick-full';
32434         
32435         if(this.href.length){
32436             cls += ' masonry-brick-link';
32437         }
32438         
32439         if(this.bgimage.length){
32440             cls += ' masonry-brick-image';
32441         }
32442         
32443         if(this.maskInverse){
32444             cls += ' mask-inverse';
32445         }
32446         
32447         if(!this.html.length && !this.maskInverse && !this.videourl.length){
32448             cls += ' enable-mask';
32449         }
32450         
32451         if(this.size){
32452             cls += ' masonry-' + this.size + '-brick';
32453         }
32454         
32455         if(this.placetitle.length){
32456             
32457             switch (this.placetitle) {
32458                 case 'center' :
32459                     cls += ' masonry-center-title';
32460                     break;
32461                 case 'bottom' :
32462                     cls += ' masonry-bottom-title';
32463                     break;
32464                 default:
32465                     break;
32466             }
32467             
32468         } else {
32469             if(!this.html.length && !this.bgimage.length){
32470                 cls += ' masonry-center-title';
32471             }
32472
32473             if(!this.html.length && this.bgimage.length){
32474                 cls += ' masonry-bottom-title';
32475             }
32476         }
32477         
32478         if(this.cls){
32479             cls += ' ' + this.cls;
32480         }
32481         
32482         var cfg = {
32483             tag: (this.href.length) ? 'a' : 'div',
32484             cls: cls,
32485             cn: [
32486                 {
32487                     tag: 'div',
32488                     cls: 'masonry-brick-mask'
32489                 },
32490                 {
32491                     tag: 'div',
32492                     cls: 'masonry-brick-paragraph',
32493                     cn: []
32494                 }
32495             ]
32496         };
32497         
32498         if(this.href.length){
32499             cfg.href = this.href;
32500         }
32501         
32502         var cn = cfg.cn[1].cn;
32503         
32504         if(this.title.length){
32505             cn.push({
32506                 tag: 'h4',
32507                 cls: 'masonry-brick-title',
32508                 html: this.title
32509             });
32510         }
32511         
32512         if(this.html.length){
32513             cn.push({
32514                 tag: 'p',
32515                 cls: 'masonry-brick-text',
32516                 html: this.html
32517             });
32518         }
32519         
32520         if (!this.title.length && !this.html.length) {
32521             cfg.cn[1].cls += ' hide';
32522         }
32523         
32524         if(this.bgimage.length){
32525             cfg.cn.push({
32526                 tag: 'img',
32527                 cls: 'masonry-brick-image-view',
32528                 src: this.bgimage
32529             });
32530         }
32531         
32532         if(this.videourl.length){
32533             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32534             // youtube support only?
32535             cfg.cn.push({
32536                 tag: 'iframe',
32537                 cls: 'masonry-brick-image-view',
32538                 src: vurl,
32539                 frameborder : 0,
32540                 allowfullscreen : true
32541             });
32542         }
32543         
32544         return cfg;
32545         
32546     },
32547     
32548     getSplitAutoCreate : function()
32549     {
32550         var cls = 'masonry-brick masonry-brick-split';
32551         
32552         if(this.href.length){
32553             cls += ' masonry-brick-link';
32554         }
32555         
32556         if(this.bgimage.length){
32557             cls += ' masonry-brick-image';
32558         }
32559         
32560         if(this.size){
32561             cls += ' masonry-' + this.size + '-brick';
32562         }
32563         
32564         switch (this.placetitle) {
32565             case 'center' :
32566                 cls += ' masonry-center-title';
32567                 break;
32568             case 'bottom' :
32569                 cls += ' masonry-bottom-title';
32570                 break;
32571             default:
32572                 if(!this.bgimage.length){
32573                     cls += ' masonry-center-title';
32574                 }
32575
32576                 if(this.bgimage.length){
32577                     cls += ' masonry-bottom-title';
32578                 }
32579                 break;
32580         }
32581         
32582         if(this.cls){
32583             cls += ' ' + this.cls;
32584         }
32585         
32586         var cfg = {
32587             tag: (this.href.length) ? 'a' : 'div',
32588             cls: cls,
32589             cn: [
32590                 {
32591                     tag: 'div',
32592                     cls: 'masonry-brick-split-head',
32593                     cn: [
32594                         {
32595                             tag: 'div',
32596                             cls: 'masonry-brick-paragraph',
32597                             cn: []
32598                         }
32599                     ]
32600                 },
32601                 {
32602                     tag: 'div',
32603                     cls: 'masonry-brick-split-body',
32604                     cn: []
32605                 }
32606             ]
32607         };
32608         
32609         if(this.href.length){
32610             cfg.href = this.href;
32611         }
32612         
32613         if(this.title.length){
32614             cfg.cn[0].cn[0].cn.push({
32615                 tag: 'h4',
32616                 cls: 'masonry-brick-title',
32617                 html: this.title
32618             });
32619         }
32620         
32621         if(this.html.length){
32622             cfg.cn[1].cn.push({
32623                 tag: 'p',
32624                 cls: 'masonry-brick-text',
32625                 html: this.html
32626             });
32627         }
32628
32629         if(this.bgimage.length){
32630             cfg.cn[0].cn.push({
32631                 tag: 'img',
32632                 cls: 'masonry-brick-image-view',
32633                 src: this.bgimage
32634             });
32635         }
32636         
32637         if(this.videourl.length){
32638             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32639             // youtube support only?
32640             cfg.cn[0].cn.cn.push({
32641                 tag: 'iframe',
32642                 cls: 'masonry-brick-image-view',
32643                 src: vurl,
32644                 frameborder : 0,
32645                 allowfullscreen : true
32646             });
32647         }
32648         
32649         return cfg;
32650     },
32651     
32652     initEvents: function() 
32653     {
32654         switch (this.size) {
32655             case 'xs' :
32656                 this.x = 1;
32657                 this.y = 1;
32658                 break;
32659             case 'sm' :
32660                 this.x = 2;
32661                 this.y = 2;
32662                 break;
32663             case 'md' :
32664             case 'md-left' :
32665             case 'md-right' :
32666                 this.x = 3;
32667                 this.y = 3;
32668                 break;
32669             case 'tall' :
32670                 this.x = 2;
32671                 this.y = 3;
32672                 break;
32673             case 'wide' :
32674                 this.x = 3;
32675                 this.y = 2;
32676                 break;
32677             case 'wide-thin' :
32678                 this.x = 3;
32679                 this.y = 1;
32680                 break;
32681                         
32682             default :
32683                 break;
32684         }
32685         
32686         if(Roo.isTouch){
32687             this.el.on('touchstart', this.onTouchStart, this);
32688             this.el.on('touchmove', this.onTouchMove, this);
32689             this.el.on('touchend', this.onTouchEnd, this);
32690             this.el.on('contextmenu', this.onContextMenu, this);
32691         } else {
32692             this.el.on('mouseenter'  ,this.enter, this);
32693             this.el.on('mouseleave', this.leave, this);
32694             this.el.on('click', this.onClick, this);
32695         }
32696         
32697         if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32698             this.parent().bricks.push(this);   
32699         }
32700         
32701     },
32702     
32703     onClick: function(e, el)
32704     {
32705         var time = this.endTimer - this.startTimer;
32706         // Roo.log(e.preventDefault());
32707         if(Roo.isTouch){
32708             if(time > 1000){
32709                 e.preventDefault();
32710                 return;
32711             }
32712         }
32713         
32714         if(!this.preventDefault){
32715             return;
32716         }
32717         
32718         e.preventDefault();
32719         
32720         if (this.activcClass != '') {
32721             this.selectBrick();
32722         }
32723         
32724         this.fireEvent('click', this);
32725     },
32726     
32727     enter: function(e, el)
32728     {
32729         e.preventDefault();
32730         
32731         if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32732             return;
32733         }
32734         
32735         if(this.bgimage.length && this.html.length){
32736             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32737         }
32738     },
32739     
32740     leave: function(e, el)
32741     {
32742         e.preventDefault();
32743         
32744         if(!this.isFitContainer || this.maskInverse  || this.videourl.length){
32745             return;
32746         }
32747         
32748         if(this.bgimage.length && this.html.length){
32749             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32750         }
32751     },
32752     
32753     onTouchStart: function(e, el)
32754     {
32755 //        e.preventDefault();
32756         
32757         this.touchmoved = false;
32758         
32759         if(!this.isFitContainer){
32760             return;
32761         }
32762         
32763         if(!this.bgimage.length || !this.html.length){
32764             return;
32765         }
32766         
32767         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32768         
32769         this.timer = new Date().getTime();
32770         
32771     },
32772     
32773     onTouchMove: function(e, el)
32774     {
32775         this.touchmoved = true;
32776     },
32777     
32778     onContextMenu : function(e,el)
32779     {
32780         e.preventDefault();
32781         e.stopPropagation();
32782         return false;
32783     },
32784     
32785     onTouchEnd: function(e, el)
32786     {
32787 //        e.preventDefault();
32788         
32789         if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32790         
32791             this.leave(e,el);
32792             
32793             return;
32794         }
32795         
32796         if(!this.bgimage.length || !this.html.length){
32797             
32798             if(this.href.length){
32799                 window.location.href = this.href;
32800             }
32801             
32802             return;
32803         }
32804         
32805         if(!this.isFitContainer){
32806             return;
32807         }
32808         
32809         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32810         
32811         window.location.href = this.href;
32812     },
32813     
32814     //selection on single brick only
32815     selectBrick : function() {
32816         
32817         if (!this.parentId) {
32818             return;
32819         }
32820         
32821         var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32822         var index = m.selectedBrick.indexOf(this.id);
32823         
32824         if ( index > -1) {
32825             m.selectedBrick.splice(index,1);
32826             this.el.removeClass(this.activeClass);
32827             return;
32828         }
32829         
32830         for(var i = 0; i < m.selectedBrick.length; i++) {
32831             var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32832             b.el.removeClass(b.activeClass);
32833         }
32834         
32835         m.selectedBrick = [];
32836         
32837         m.selectedBrick.push(this.id);
32838         this.el.addClass(this.activeClass);
32839         return;
32840     }
32841     
32842 });
32843
32844 Roo.apply(Roo.bootstrap.MasonryBrick, {
32845     
32846     //groups: {},
32847     groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32848      /**
32849     * register a Masonry Brick
32850     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32851     */
32852     
32853     register : function(brick)
32854     {
32855         //this.groups[brick.id] = brick;
32856         this.groups.add(brick.id, brick);
32857     },
32858     /**
32859     * fetch a  masonry brick based on the masonry brick ID
32860     * @param {string} the masonry brick to add
32861     * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32862     */
32863     
32864     get: function(brick_id) 
32865     {
32866         // if (typeof(this.groups[brick_id]) == 'undefined') {
32867         //     return false;
32868         // }
32869         // return this.groups[brick_id] ;
32870         
32871         if(this.groups.key(brick_id)) {
32872             return this.groups.key(brick_id);
32873         }
32874         
32875         return false;
32876     }
32877     
32878     
32879     
32880 });
32881
32882  /*
32883  * - LGPL
32884  *
32885  * element
32886  * 
32887  */
32888
32889 /**
32890  * @class Roo.bootstrap.Brick
32891  * @extends Roo.bootstrap.Component
32892  * Bootstrap Brick class
32893  * 
32894  * @constructor
32895  * Create a new Brick
32896  * @param {Object} config The config object
32897  */
32898
32899 Roo.bootstrap.Brick = function(config){
32900     Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32901     
32902     this.addEvents({
32903         // raw events
32904         /**
32905          * @event click
32906          * When a Brick is click
32907          * @param {Roo.bootstrap.Brick} this
32908          * @param {Roo.EventObject} e
32909          */
32910         "click" : true
32911     });
32912 };
32913
32914 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
32915     
32916     /**
32917      * @cfg {String} title
32918      */   
32919     title : '',
32920     /**
32921      * @cfg {String} html
32922      */   
32923     html : '',
32924     /**
32925      * @cfg {String} bgimage
32926      */   
32927     bgimage : '',
32928     /**
32929      * @cfg {String} cls
32930      */   
32931     cls : '',
32932     /**
32933      * @cfg {String} href
32934      */   
32935     href : '',
32936     /**
32937      * @cfg {String} video
32938      */   
32939     video : '',
32940     /**
32941      * @cfg {Boolean} square
32942      */   
32943     square : true,
32944     
32945     getAutoCreate : function()
32946     {
32947         var cls = 'roo-brick';
32948         
32949         if(this.href.length){
32950             cls += ' roo-brick-link';
32951         }
32952         
32953         if(this.bgimage.length){
32954             cls += ' roo-brick-image';
32955         }
32956         
32957         if(!this.html.length && !this.bgimage.length){
32958             cls += ' roo-brick-center-title';
32959         }
32960         
32961         if(!this.html.length && this.bgimage.length){
32962             cls += ' roo-brick-bottom-title';
32963         }
32964         
32965         if(this.cls){
32966             cls += ' ' + this.cls;
32967         }
32968         
32969         var cfg = {
32970             tag: (this.href.length) ? 'a' : 'div',
32971             cls: cls,
32972             cn: [
32973                 {
32974                     tag: 'div',
32975                     cls: 'roo-brick-paragraph',
32976                     cn: []
32977                 }
32978             ]
32979         };
32980         
32981         if(this.href.length){
32982             cfg.href = this.href;
32983         }
32984         
32985         var cn = cfg.cn[0].cn;
32986         
32987         if(this.title.length){
32988             cn.push({
32989                 tag: 'h4',
32990                 cls: 'roo-brick-title',
32991                 html: this.title
32992             });
32993         }
32994         
32995         if(this.html.length){
32996             cn.push({
32997                 tag: 'p',
32998                 cls: 'roo-brick-text',
32999                 html: this.html
33000             });
33001         } else {
33002             cn.cls += ' hide';
33003         }
33004         
33005         if(this.bgimage.length){
33006             cfg.cn.push({
33007                 tag: 'img',
33008                 cls: 'roo-brick-image-view',
33009                 src: this.bgimage
33010             });
33011         }
33012         
33013         return cfg;
33014     },
33015     
33016     initEvents: function() 
33017     {
33018         if(this.title.length || this.html.length){
33019             this.el.on('mouseenter'  ,this.enter, this);
33020             this.el.on('mouseleave', this.leave, this);
33021         }
33022         
33023         Roo.EventManager.onWindowResize(this.resize, this); 
33024         
33025         if(this.bgimage.length){
33026             this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33027             this.imageEl.on('load', this.onImageLoad, this);
33028             return;
33029         }
33030         
33031         this.resize();
33032     },
33033     
33034     onImageLoad : function()
33035     {
33036         this.resize();
33037     },
33038     
33039     resize : function()
33040     {
33041         var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33042         
33043         paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33044         
33045         if(this.bgimage.length){
33046             var image = this.el.select('.roo-brick-image-view', true).first();
33047             
33048             image.setWidth(paragraph.getWidth());
33049             
33050             if(this.square){
33051                 image.setHeight(paragraph.getWidth());
33052             }
33053             
33054             this.el.setHeight(image.getHeight());
33055             paragraph.setHeight(image.getHeight());
33056             
33057         }
33058         
33059     },
33060     
33061     enter: function(e, el)
33062     {
33063         e.preventDefault();
33064         
33065         if(this.bgimage.length){
33066             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33067             this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33068         }
33069     },
33070     
33071     leave: function(e, el)
33072     {
33073         e.preventDefault();
33074         
33075         if(this.bgimage.length){
33076             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33077             this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33078         }
33079     }
33080     
33081 });
33082
33083  
33084
33085  /*
33086  * - LGPL
33087  *
33088  * Number field 
33089  */
33090
33091 /**
33092  * @class Roo.bootstrap.NumberField
33093  * @extends Roo.bootstrap.Input
33094  * Bootstrap NumberField class
33095  * 
33096  * 
33097  * 
33098  * 
33099  * @constructor
33100  * Create a new NumberField
33101  * @param {Object} config The config object
33102  */
33103
33104 Roo.bootstrap.NumberField = function(config){
33105     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33106 };
33107
33108 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33109     
33110     /**
33111      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33112      */
33113     allowDecimals : true,
33114     /**
33115      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33116      */
33117     decimalSeparator : ".",
33118     /**
33119      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33120      */
33121     decimalPrecision : 2,
33122     /**
33123      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33124      */
33125     allowNegative : true,
33126     
33127     /**
33128      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33129      */
33130     allowZero: true,
33131     /**
33132      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33133      */
33134     minValue : Number.NEGATIVE_INFINITY,
33135     /**
33136      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33137      */
33138     maxValue : Number.MAX_VALUE,
33139     /**
33140      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33141      */
33142     minText : "The minimum value for this field is {0}",
33143     /**
33144      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33145      */
33146     maxText : "The maximum value for this field is {0}",
33147     /**
33148      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
33149      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33150      */
33151     nanText : "{0} is not a valid number",
33152     /**
33153      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33154      */
33155     castInt : true,
33156     /**
33157      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33158      */
33159     thousandsDelimiter : false,
33160     /**
33161      * @cfg {String} valueAlign alignment of value
33162      */
33163     valueAlign : "left",
33164
33165     getAutoCreate : function()
33166     {
33167         var hiddenInput = {
33168             tag: 'input',
33169             type: 'hidden',
33170             id: Roo.id(),
33171             cls: 'hidden-number-input'
33172         };
33173         
33174         if (this.name) {
33175             hiddenInput.name = this.name;
33176         }
33177         
33178         this.name = '';
33179         
33180         var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33181         
33182         this.name = hiddenInput.name;
33183         
33184         if(cfg.cn.length > 0) {
33185             cfg.cn.push(hiddenInput);
33186         }
33187         
33188         return cfg;
33189     },
33190
33191     // private
33192     initEvents : function()
33193     {   
33194         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33195         
33196         var allowed = "0123456789";
33197         
33198         if(this.allowDecimals){
33199             allowed += this.decimalSeparator;
33200         }
33201         
33202         if(this.allowNegative){
33203             allowed += "-";
33204         }
33205         
33206         if(this.thousandsDelimiter) {
33207             allowed += ",";
33208         }
33209         
33210         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33211         
33212         var keyPress = function(e){
33213             
33214             var k = e.getKey();
33215             
33216             var c = e.getCharCode();
33217             
33218             if(
33219                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33220                     allowed.indexOf(String.fromCharCode(c)) === -1
33221             ){
33222                 e.stopEvent();
33223                 return;
33224             }
33225             
33226             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33227                 return;
33228             }
33229             
33230             if(allowed.indexOf(String.fromCharCode(c)) === -1){
33231                 e.stopEvent();
33232             }
33233         };
33234         
33235         this.el.on("keypress", keyPress, this);
33236     },
33237     
33238     validateValue : function(value)
33239     {
33240         
33241         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33242             return false;
33243         }
33244         
33245         var num = this.parseValue(value);
33246         
33247         if(isNaN(num)){
33248             this.markInvalid(String.format(this.nanText, value));
33249             return false;
33250         }
33251         
33252         if(num < this.minValue){
33253             this.markInvalid(String.format(this.minText, this.minValue));
33254             return false;
33255         }
33256         
33257         if(num > this.maxValue){
33258             this.markInvalid(String.format(this.maxText, this.maxValue));
33259             return false;
33260         }
33261         
33262         return true;
33263     },
33264
33265     getValue : function()
33266     {
33267         var v = this.hiddenEl().getValue();
33268         
33269         return this.fixPrecision(this.parseValue(v));
33270     },
33271
33272     parseValue : function(value)
33273     {
33274         if(this.thousandsDelimiter) {
33275             value += "";
33276             r = new RegExp(",", "g");
33277             value = value.replace(r, "");
33278         }
33279         
33280         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33281         return isNaN(value) ? '' : value;
33282     },
33283
33284     fixPrecision : function(value)
33285     {
33286         if(this.thousandsDelimiter) {
33287             value += "";
33288             r = new RegExp(",", "g");
33289             value = value.replace(r, "");
33290         }
33291         
33292         var nan = isNaN(value);
33293         
33294         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33295             return nan ? '' : value;
33296         }
33297         return parseFloat(value).toFixed(this.decimalPrecision);
33298     },
33299
33300     setValue : function(v)
33301     {
33302         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33303         
33304         this.value = v;
33305         
33306         if(this.rendered){
33307             
33308             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33309             
33310             this.inputEl().dom.value = (v == '') ? '' :
33311                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33312             
33313             if(!this.allowZero && v === '0') {
33314                 this.hiddenEl().dom.value = '';
33315                 this.inputEl().dom.value = '';
33316             }
33317             
33318             this.validate();
33319         }
33320     },
33321
33322     decimalPrecisionFcn : function(v)
33323     {
33324         return Math.floor(v);
33325     },
33326
33327     beforeBlur : function()
33328     {
33329         if(!this.castInt){
33330             return;
33331         }
33332         
33333         var v = this.parseValue(this.getRawValue());
33334         
33335         if(v || v === 0){
33336             this.setValue(v);
33337         }
33338     },
33339     
33340     hiddenEl : function()
33341     {
33342         return this.el.select('input.hidden-number-input',true).first();
33343     }
33344     
33345 });
33346
33347  
33348
33349 /*
33350 * Licence: LGPL
33351 */
33352
33353 /**
33354  * @class Roo.bootstrap.DocumentSlider
33355  * @extends Roo.bootstrap.Component
33356  * Bootstrap DocumentSlider class
33357  * 
33358  * @constructor
33359  * Create a new DocumentViewer
33360  * @param {Object} config The config object
33361  */
33362
33363 Roo.bootstrap.DocumentSlider = function(config){
33364     Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33365     
33366     this.files = [];
33367     
33368     this.addEvents({
33369         /**
33370          * @event initial
33371          * Fire after initEvent
33372          * @param {Roo.bootstrap.DocumentSlider} this
33373          */
33374         "initial" : true,
33375         /**
33376          * @event update
33377          * Fire after update
33378          * @param {Roo.bootstrap.DocumentSlider} this
33379          */
33380         "update" : true,
33381         /**
33382          * @event click
33383          * Fire after click
33384          * @param {Roo.bootstrap.DocumentSlider} this
33385          */
33386         "click" : true
33387     });
33388 };
33389
33390 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
33391     
33392     files : false,
33393     
33394     indicator : 0,
33395     
33396     getAutoCreate : function()
33397     {
33398         var cfg = {
33399             tag : 'div',
33400             cls : 'roo-document-slider',
33401             cn : [
33402                 {
33403                     tag : 'div',
33404                     cls : 'roo-document-slider-header',
33405                     cn : [
33406                         {
33407                             tag : 'div',
33408                             cls : 'roo-document-slider-header-title'
33409                         }
33410                     ]
33411                 },
33412                 {
33413                     tag : 'div',
33414                     cls : 'roo-document-slider-body',
33415                     cn : [
33416                         {
33417                             tag : 'div',
33418                             cls : 'roo-document-slider-prev',
33419                             cn : [
33420                                 {
33421                                     tag : 'i',
33422                                     cls : 'fa fa-chevron-left'
33423                                 }
33424                             ]
33425                         },
33426                         {
33427                             tag : 'div',
33428                             cls : 'roo-document-slider-thumb',
33429                             cn : [
33430                                 {
33431                                     tag : 'img',
33432                                     cls : 'roo-document-slider-image'
33433                                 }
33434                             ]
33435                         },
33436                         {
33437                             tag : 'div',
33438                             cls : 'roo-document-slider-next',
33439                             cn : [
33440                                 {
33441                                     tag : 'i',
33442                                     cls : 'fa fa-chevron-right'
33443                                 }
33444                             ]
33445                         }
33446                     ]
33447                 }
33448             ]
33449         };
33450         
33451         return cfg;
33452     },
33453     
33454     initEvents : function()
33455     {
33456         this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33457         this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33458         
33459         this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33460         this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33461         
33462         this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33463         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33464         
33465         this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33466         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33467         
33468         this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33469         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33470         
33471         this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33472         this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33473         
33474         this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33475         this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33476         
33477         this.thumbEl.on('click', this.onClick, this);
33478         
33479         this.prevIndicator.on('click', this.prev, this);
33480         
33481         this.nextIndicator.on('click', this.next, this);
33482         
33483     },
33484     
33485     initial : function()
33486     {
33487         if(this.files.length){
33488             this.indicator = 1;
33489             this.update()
33490         }
33491         
33492         this.fireEvent('initial', this);
33493     },
33494     
33495     update : function()
33496     {
33497         this.imageEl.attr('src', this.files[this.indicator - 1]);
33498         
33499         this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33500         
33501         this.prevIndicator.show();
33502         
33503         if(this.indicator == 1){
33504             this.prevIndicator.hide();
33505         }
33506         
33507         this.nextIndicator.show();
33508         
33509         if(this.indicator == this.files.length){
33510             this.nextIndicator.hide();
33511         }
33512         
33513         this.thumbEl.scrollTo('top');
33514         
33515         this.fireEvent('update', this);
33516     },
33517     
33518     onClick : function(e)
33519     {
33520         e.preventDefault();
33521         
33522         this.fireEvent('click', this);
33523     },
33524     
33525     prev : function(e)
33526     {
33527         e.preventDefault();
33528         
33529         this.indicator = Math.max(1, this.indicator - 1);
33530         
33531         this.update();
33532     },
33533     
33534     next : function(e)
33535     {
33536         e.preventDefault();
33537         
33538         this.indicator = Math.min(this.files.length, this.indicator + 1);
33539         
33540         this.update();
33541     }
33542 });
33543 /*
33544  * - LGPL
33545  *
33546  * RadioSet
33547  *
33548  *
33549  */
33550
33551 /**
33552  * @class Roo.bootstrap.RadioSet
33553  * @extends Roo.bootstrap.Input
33554  * Bootstrap RadioSet class
33555  * @cfg {String} indicatorpos (left|right) default left
33556  * @cfg {Boolean} inline (true|false) inline the element (default true)
33557  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33558  * @constructor
33559  * Create a new RadioSet
33560  * @param {Object} config The config object
33561  */
33562
33563 Roo.bootstrap.RadioSet = function(config){
33564     
33565     Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33566     
33567     this.radioes = [];
33568     
33569     Roo.bootstrap.RadioSet.register(this);
33570     
33571     this.addEvents({
33572         /**
33573         * @event check
33574         * Fires when the element is checked or unchecked.
33575         * @param {Roo.bootstrap.RadioSet} this This radio
33576         * @param {Roo.bootstrap.Radio} item The checked item
33577         */
33578        check : true,
33579        /**
33580         * @event click
33581         * Fires when the element is click.
33582         * @param {Roo.bootstrap.RadioSet} this This radio set
33583         * @param {Roo.bootstrap.Radio} item The checked item
33584         * @param {Roo.EventObject} e The event object
33585         */
33586        click : true
33587     });
33588     
33589 };
33590
33591 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
33592
33593     radioes : false,
33594     
33595     inline : true,
33596     
33597     weight : '',
33598     
33599     indicatorpos : 'left',
33600     
33601     getAutoCreate : function()
33602     {
33603         var label = {
33604             tag : 'label',
33605             cls : 'roo-radio-set-label',
33606             cn : [
33607                 {
33608                     tag : 'span',
33609                     html : this.fieldLabel
33610                 }
33611             ]
33612         };
33613         
33614         if(this.indicatorpos == 'left'){
33615             label.cn.unshift({
33616                 tag : 'i',
33617                 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33618                 tooltip : 'This field is required'
33619             });
33620         } else {
33621             label.cn.push({
33622                 tag : 'i',
33623                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33624                 tooltip : 'This field is required'
33625             });
33626         }
33627         
33628         var items = {
33629             tag : 'div',
33630             cls : 'roo-radio-set-items'
33631         };
33632         
33633         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33634         
33635         if (align === 'left' && this.fieldLabel.length) {
33636             
33637             items = {
33638                 cls : "roo-radio-set-right", 
33639                 cn: [
33640                     items
33641                 ]
33642             };
33643             
33644             if(this.labelWidth > 12){
33645                 label.style = "width: " + this.labelWidth + 'px';
33646             }
33647             
33648             if(this.labelWidth < 13 && this.labelmd == 0){
33649                 this.labelmd = this.labelWidth;
33650             }
33651             
33652             if(this.labellg > 0){
33653                 label.cls += ' col-lg-' + this.labellg;
33654                 items.cls += ' col-lg-' + (12 - this.labellg);
33655             }
33656             
33657             if(this.labelmd > 0){
33658                 label.cls += ' col-md-' + this.labelmd;
33659                 items.cls += ' col-md-' + (12 - this.labelmd);
33660             }
33661             
33662             if(this.labelsm > 0){
33663                 label.cls += ' col-sm-' + this.labelsm;
33664                 items.cls += ' col-sm-' + (12 - this.labelsm);
33665             }
33666             
33667             if(this.labelxs > 0){
33668                 label.cls += ' col-xs-' + this.labelxs;
33669                 items.cls += ' col-xs-' + (12 - this.labelxs);
33670             }
33671         }
33672         
33673         var cfg = {
33674             tag : 'div',
33675             cls : 'roo-radio-set',
33676             cn : [
33677                 {
33678                     tag : 'input',
33679                     cls : 'roo-radio-set-input',
33680                     type : 'hidden',
33681                     name : this.name,
33682                     value : this.value ? this.value :  ''
33683                 },
33684                 label,
33685                 items
33686             ]
33687         };
33688         
33689         if(this.weight.length){
33690             cfg.cls += ' roo-radio-' + this.weight;
33691         }
33692         
33693         if(this.inline) {
33694             cfg.cls += ' roo-radio-set-inline';
33695         }
33696         
33697         var settings=this;
33698         ['xs','sm','md','lg'].map(function(size){
33699             if (settings[size]) {
33700                 cfg.cls += ' col-' + size + '-' + settings[size];
33701             }
33702         });
33703         
33704         return cfg;
33705         
33706     },
33707
33708     initEvents : function()
33709     {
33710         this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33711         this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33712         
33713         if(!this.fieldLabel.length){
33714             this.labelEl.hide();
33715         }
33716         
33717         this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33718         this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33719         
33720         this.indicatorEl().addClass('invisible');
33721         
33722         this.originalValue = this.getValue();
33723         
33724     },
33725     
33726     inputEl: function ()
33727     {
33728         return this.el.select('.roo-radio-set-input', true).first();
33729     },
33730     
33731     getChildContainer : function()
33732     {
33733         return this.itemsEl;
33734     },
33735     
33736     register : function(item)
33737     {
33738         this.radioes.push(item);
33739         
33740     },
33741     
33742     validate : function()
33743     {   
33744         if(this.getEl().hasClass('hidden')){
33745             return true;
33746         }
33747         
33748         var valid = false;
33749         
33750         Roo.each(this.radioes, function(i){
33751             if(!i.checked){
33752                 return;
33753             }
33754             
33755             valid = true;
33756             return false;
33757         });
33758         
33759         if(this.allowBlank) {
33760             return true;
33761         }
33762         
33763         if(this.disabled || valid){
33764             this.markValid();
33765             return true;
33766         }
33767         
33768         this.markInvalid();
33769         return false;
33770         
33771     },
33772     
33773     markValid : function()
33774     {
33775         if(this.labelEl.isVisible(true)){
33776             this.indicatorEl().removeClass('visible');
33777             this.indicatorEl().addClass('invisible');
33778         }
33779         
33780         this.el.removeClass([this.invalidClass, this.validClass]);
33781         this.el.addClass(this.validClass);
33782         
33783         this.fireEvent('valid', this);
33784     },
33785     
33786     markInvalid : function(msg)
33787     {
33788         if(this.allowBlank || this.disabled){
33789             return;
33790         }
33791         
33792         if(this.labelEl.isVisible(true)){
33793             this.indicatorEl().removeClass('invisible');
33794             this.indicatorEl().addClass('visible');
33795         }
33796         
33797         this.el.removeClass([this.invalidClass, this.validClass]);
33798         this.el.addClass(this.invalidClass);
33799         
33800         this.fireEvent('invalid', this, msg);
33801         
33802     },
33803     
33804     setValue : function(v, suppressEvent)
33805     {   
33806         if(this.value === v){
33807             return;
33808         }
33809         
33810         this.value = v;
33811         
33812         if(this.rendered){
33813             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33814         }
33815         
33816         Roo.each(this.radioes, function(i){
33817             i.checked = false;
33818             i.el.removeClass('checked');
33819         });
33820         
33821         Roo.each(this.radioes, function(i){
33822             
33823             if(i.value === v || i.value.toString() === v.toString()){
33824                 i.checked = true;
33825                 i.el.addClass('checked');
33826                 
33827                 if(suppressEvent !== true){
33828                     this.fireEvent('check', this, i);
33829                 }
33830                 
33831                 return false;
33832             }
33833             
33834         }, this);
33835         
33836         this.validate();
33837     },
33838     
33839     clearInvalid : function(){
33840         
33841         if(!this.el || this.preventMark){
33842             return;
33843         }
33844         
33845         this.el.removeClass([this.invalidClass]);
33846         
33847         this.fireEvent('valid', this);
33848     }
33849     
33850 });
33851
33852 Roo.apply(Roo.bootstrap.RadioSet, {
33853     
33854     groups: {},
33855     
33856     register : function(set)
33857     {
33858         this.groups[set.name] = set;
33859     },
33860     
33861     get: function(name) 
33862     {
33863         if (typeof(this.groups[name]) == 'undefined') {
33864             return false;
33865         }
33866         
33867         return this.groups[name] ;
33868     }
33869     
33870 });
33871 /*
33872  * Based on:
33873  * Ext JS Library 1.1.1
33874  * Copyright(c) 2006-2007, Ext JS, LLC.
33875  *
33876  * Originally Released Under LGPL - original licence link has changed is not relivant.
33877  *
33878  * Fork - LGPL
33879  * <script type="text/javascript">
33880  */
33881
33882
33883 /**
33884  * @class Roo.bootstrap.SplitBar
33885  * @extends Roo.util.Observable
33886  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33887  * <br><br>
33888  * Usage:
33889  * <pre><code>
33890 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33891                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33892 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33893 split.minSize = 100;
33894 split.maxSize = 600;
33895 split.animate = true;
33896 split.on('moved', splitterMoved);
33897 </code></pre>
33898  * @constructor
33899  * Create a new SplitBar
33900  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
33901  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
33902  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33903  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
33904                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33905                         position of the SplitBar).
33906  */
33907 Roo.bootstrap.SplitBar = function(cfg){
33908     
33909     /** @private */
33910     
33911     //{
33912     //  dragElement : elm
33913     //  resizingElement: el,
33914         // optional..
33915     //    orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33916     //    placement : Roo.bootstrap.SplitBar.LEFT  ,
33917         // existingProxy ???
33918     //}
33919     
33920     this.el = Roo.get(cfg.dragElement, true);
33921     this.el.dom.unselectable = "on";
33922     /** @private */
33923     this.resizingEl = Roo.get(cfg.resizingElement, true);
33924
33925     /**
33926      * @private
33927      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33928      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33929      * @type Number
33930      */
33931     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33932     
33933     /**
33934      * The minimum size of the resizing element. (Defaults to 0)
33935      * @type Number
33936      */
33937     this.minSize = 0;
33938     
33939     /**
33940      * The maximum size of the resizing element. (Defaults to 2000)
33941      * @type Number
33942      */
33943     this.maxSize = 2000;
33944     
33945     /**
33946      * Whether to animate the transition to the new size
33947      * @type Boolean
33948      */
33949     this.animate = false;
33950     
33951     /**
33952      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33953      * @type Boolean
33954      */
33955     this.useShim = false;
33956     
33957     /** @private */
33958     this.shim = null;
33959     
33960     if(!cfg.existingProxy){
33961         /** @private */
33962         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33963     }else{
33964         this.proxy = Roo.get(cfg.existingProxy).dom;
33965     }
33966     /** @private */
33967     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33968     
33969     /** @private */
33970     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33971     
33972     /** @private */
33973     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33974     
33975     /** @private */
33976     this.dragSpecs = {};
33977     
33978     /**
33979      * @private The adapter to use to positon and resize elements
33980      */
33981     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33982     this.adapter.init(this);
33983     
33984     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33985         /** @private */
33986         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33987         this.el.addClass("roo-splitbar-h");
33988     }else{
33989         /** @private */
33990         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33991         this.el.addClass("roo-splitbar-v");
33992     }
33993     
33994     this.addEvents({
33995         /**
33996          * @event resize
33997          * Fires when the splitter is moved (alias for {@link #event-moved})
33998          * @param {Roo.bootstrap.SplitBar} this
33999          * @param {Number} newSize the new width or height
34000          */
34001         "resize" : true,
34002         /**
34003          * @event moved
34004          * Fires when the splitter is moved
34005          * @param {Roo.bootstrap.SplitBar} this
34006          * @param {Number} newSize the new width or height
34007          */
34008         "moved" : true,
34009         /**
34010          * @event beforeresize
34011          * Fires before the splitter is dragged
34012          * @param {Roo.bootstrap.SplitBar} this
34013          */
34014         "beforeresize" : true,
34015
34016         "beforeapply" : true
34017     });
34018
34019     Roo.util.Observable.call(this);
34020 };
34021
34022 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34023     onStartProxyDrag : function(x, y){
34024         this.fireEvent("beforeresize", this);
34025         if(!this.overlay){
34026             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "roo-drag-overlay", html: "&#160;"}, true);
34027             o.unselectable();
34028             o.enableDisplayMode("block");
34029             // all splitbars share the same overlay
34030             Roo.bootstrap.SplitBar.prototype.overlay = o;
34031         }
34032         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34033         this.overlay.show();
34034         Roo.get(this.proxy).setDisplayed("block");
34035         var size = this.adapter.getElementSize(this);
34036         this.activeMinSize = this.getMinimumSize();;
34037         this.activeMaxSize = this.getMaximumSize();;
34038         var c1 = size - this.activeMinSize;
34039         var c2 = Math.max(this.activeMaxSize - size, 0);
34040         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34041             this.dd.resetConstraints();
34042             this.dd.setXConstraint(
34043                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
34044                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34045             );
34046             this.dd.setYConstraint(0, 0);
34047         }else{
34048             this.dd.resetConstraints();
34049             this.dd.setXConstraint(0, 0);
34050             this.dd.setYConstraint(
34051                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
34052                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34053             );
34054          }
34055         this.dragSpecs.startSize = size;
34056         this.dragSpecs.startPoint = [x, y];
34057         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34058     },
34059     
34060     /** 
34061      * @private Called after the drag operation by the DDProxy
34062      */
34063     onEndProxyDrag : function(e){
34064         Roo.get(this.proxy).setDisplayed(false);
34065         var endPoint = Roo.lib.Event.getXY(e);
34066         if(this.overlay){
34067             this.overlay.hide();
34068         }
34069         var newSize;
34070         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34071             newSize = this.dragSpecs.startSize + 
34072                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34073                     endPoint[0] - this.dragSpecs.startPoint[0] :
34074                     this.dragSpecs.startPoint[0] - endPoint[0]
34075                 );
34076         }else{
34077             newSize = this.dragSpecs.startSize + 
34078                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34079                     endPoint[1] - this.dragSpecs.startPoint[1] :
34080                     this.dragSpecs.startPoint[1] - endPoint[1]
34081                 );
34082         }
34083         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34084         if(newSize != this.dragSpecs.startSize){
34085             if(this.fireEvent('beforeapply', this, newSize) !== false){
34086                 this.adapter.setElementSize(this, newSize);
34087                 this.fireEvent("moved", this, newSize);
34088                 this.fireEvent("resize", this, newSize);
34089             }
34090         }
34091     },
34092     
34093     /**
34094      * Get the adapter this SplitBar uses
34095      * @return The adapter object
34096      */
34097     getAdapter : function(){
34098         return this.adapter;
34099     },
34100     
34101     /**
34102      * Set the adapter this SplitBar uses
34103      * @param {Object} adapter A SplitBar adapter object
34104      */
34105     setAdapter : function(adapter){
34106         this.adapter = adapter;
34107         this.adapter.init(this);
34108     },
34109     
34110     /**
34111      * Gets the minimum size for the resizing element
34112      * @return {Number} The minimum size
34113      */
34114     getMinimumSize : function(){
34115         return this.minSize;
34116     },
34117     
34118     /**
34119      * Sets the minimum size for the resizing element
34120      * @param {Number} minSize The minimum size
34121      */
34122     setMinimumSize : function(minSize){
34123         this.minSize = minSize;
34124     },
34125     
34126     /**
34127      * Gets the maximum size for the resizing element
34128      * @return {Number} The maximum size
34129      */
34130     getMaximumSize : function(){
34131         return this.maxSize;
34132     },
34133     
34134     /**
34135      * Sets the maximum size for the resizing element
34136      * @param {Number} maxSize The maximum size
34137      */
34138     setMaximumSize : function(maxSize){
34139         this.maxSize = maxSize;
34140     },
34141     
34142     /**
34143      * Sets the initialize size for the resizing element
34144      * @param {Number} size The initial size
34145      */
34146     setCurrentSize : function(size){
34147         var oldAnimate = this.animate;
34148         this.animate = false;
34149         this.adapter.setElementSize(this, size);
34150         this.animate = oldAnimate;
34151     },
34152     
34153     /**
34154      * Destroy this splitbar. 
34155      * @param {Boolean} removeEl True to remove the element
34156      */
34157     destroy : function(removeEl){
34158         if(this.shim){
34159             this.shim.remove();
34160         }
34161         this.dd.unreg();
34162         this.proxy.parentNode.removeChild(this.proxy);
34163         if(removeEl){
34164             this.el.remove();
34165         }
34166     }
34167 });
34168
34169 /**
34170  * @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.
34171  */
34172 Roo.bootstrap.SplitBar.createProxy = function(dir){
34173     var proxy = new Roo.Element(document.createElement("div"));
34174     proxy.unselectable();
34175     var cls = 'roo-splitbar-proxy';
34176     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34177     document.body.appendChild(proxy.dom);
34178     return proxy.dom;
34179 };
34180
34181 /** 
34182  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34183  * Default Adapter. It assumes the splitter and resizing element are not positioned
34184  * elements and only gets/sets the width of the element. Generally used for table based layouts.
34185  */
34186 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34187 };
34188
34189 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34190     // do nothing for now
34191     init : function(s){
34192     
34193     },
34194     /**
34195      * Called before drag operations to get the current size of the resizing element. 
34196      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34197      */
34198      getElementSize : function(s){
34199         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34200             return s.resizingEl.getWidth();
34201         }else{
34202             return s.resizingEl.getHeight();
34203         }
34204     },
34205     
34206     /**
34207      * Called after drag operations to set the size of the resizing element.
34208      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34209      * @param {Number} newSize The new size to set
34210      * @param {Function} onComplete A function to be invoked when resizing is complete
34211      */
34212     setElementSize : function(s, newSize, onComplete){
34213         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34214             if(!s.animate){
34215                 s.resizingEl.setWidth(newSize);
34216                 if(onComplete){
34217                     onComplete(s, newSize);
34218                 }
34219             }else{
34220                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34221             }
34222         }else{
34223             
34224             if(!s.animate){
34225                 s.resizingEl.setHeight(newSize);
34226                 if(onComplete){
34227                     onComplete(s, newSize);
34228                 }
34229             }else{
34230                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34231             }
34232         }
34233     }
34234 };
34235
34236 /** 
34237  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34238  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34239  * Adapter that  moves the splitter element to align with the resized sizing element. 
34240  * Used with an absolute positioned SplitBar.
34241  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34242  * document.body, make sure you assign an id to the body element.
34243  */
34244 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34245     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34246     this.container = Roo.get(container);
34247 };
34248
34249 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34250     init : function(s){
34251         this.basic.init(s);
34252     },
34253     
34254     getElementSize : function(s){
34255         return this.basic.getElementSize(s);
34256     },
34257     
34258     setElementSize : function(s, newSize, onComplete){
34259         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34260     },
34261     
34262     moveSplitter : function(s){
34263         var yes = Roo.bootstrap.SplitBar;
34264         switch(s.placement){
34265             case yes.LEFT:
34266                 s.el.setX(s.resizingEl.getRight());
34267                 break;
34268             case yes.RIGHT:
34269                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34270                 break;
34271             case yes.TOP:
34272                 s.el.setY(s.resizingEl.getBottom());
34273                 break;
34274             case yes.BOTTOM:
34275                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34276                 break;
34277         }
34278     }
34279 };
34280
34281 /**
34282  * Orientation constant - Create a vertical SplitBar
34283  * @static
34284  * @type Number
34285  */
34286 Roo.bootstrap.SplitBar.VERTICAL = 1;
34287
34288 /**
34289  * Orientation constant - Create a horizontal SplitBar
34290  * @static
34291  * @type Number
34292  */
34293 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34294
34295 /**
34296  * Placement constant - The resizing element is to the left of the splitter element
34297  * @static
34298  * @type Number
34299  */
34300 Roo.bootstrap.SplitBar.LEFT = 1;
34301
34302 /**
34303  * Placement constant - The resizing element is to the right of the splitter element
34304  * @static
34305  * @type Number
34306  */
34307 Roo.bootstrap.SplitBar.RIGHT = 2;
34308
34309 /**
34310  * Placement constant - The resizing element is positioned above the splitter element
34311  * @static
34312  * @type Number
34313  */
34314 Roo.bootstrap.SplitBar.TOP = 3;
34315
34316 /**
34317  * Placement constant - The resizing element is positioned under splitter element
34318  * @static
34319  * @type Number
34320  */
34321 Roo.bootstrap.SplitBar.BOTTOM = 4;
34322 Roo.namespace("Roo.bootstrap.layout");/*
34323  * Based on:
34324  * Ext JS Library 1.1.1
34325  * Copyright(c) 2006-2007, Ext JS, LLC.
34326  *
34327  * Originally Released Under LGPL - original licence link has changed is not relivant.
34328  *
34329  * Fork - LGPL
34330  * <script type="text/javascript">
34331  */
34332
34333 /**
34334  * @class Roo.bootstrap.layout.Manager
34335  * @extends Roo.bootstrap.Component
34336  * Base class for layout managers.
34337  */
34338 Roo.bootstrap.layout.Manager = function(config)
34339 {
34340     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34341
34342
34343
34344
34345
34346     /** false to disable window resize monitoring @type Boolean */
34347     this.monitorWindowResize = true;
34348     this.regions = {};
34349     this.addEvents({
34350         /**
34351          * @event layout
34352          * Fires when a layout is performed.
34353          * @param {Roo.LayoutManager} this
34354          */
34355         "layout" : true,
34356         /**
34357          * @event regionresized
34358          * Fires when the user resizes a region.
34359          * @param {Roo.LayoutRegion} region The resized region
34360          * @param {Number} newSize The new size (width for east/west, height for north/south)
34361          */
34362         "regionresized" : true,
34363         /**
34364          * @event regioncollapsed
34365          * Fires when a region is collapsed.
34366          * @param {Roo.LayoutRegion} region The collapsed region
34367          */
34368         "regioncollapsed" : true,
34369         /**
34370          * @event regionexpanded
34371          * Fires when a region is expanded.
34372          * @param {Roo.LayoutRegion} region The expanded region
34373          */
34374         "regionexpanded" : true
34375     });
34376     this.updating = false;
34377
34378     if (config.el) {
34379         this.el = Roo.get(config.el);
34380         this.initEvents();
34381     }
34382
34383 };
34384
34385 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34386
34387
34388     regions : null,
34389
34390     monitorWindowResize : true,
34391
34392
34393     updating : false,
34394
34395
34396     onRender : function(ct, position)
34397     {
34398         if(!this.el){
34399             this.el = Roo.get(ct);
34400             this.initEvents();
34401         }
34402         //this.fireEvent('render',this);
34403     },
34404
34405
34406     initEvents: function()
34407     {
34408
34409
34410         // ie scrollbar fix
34411         if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34412             document.body.scroll = "no";
34413         }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34414             this.el.position('relative');
34415         }
34416         this.id = this.el.id;
34417         this.el.addClass("roo-layout-container");
34418         Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34419         if(this.el.dom != document.body ) {
34420             this.el.on('resize', this.layout,this);
34421             this.el.on('show', this.layout,this);
34422         }
34423
34424     },
34425
34426     /**
34427      * Returns true if this layout is currently being updated
34428      * @return {Boolean}
34429      */
34430     isUpdating : function(){
34431         return this.updating;
34432     },
34433
34434     /**
34435      * Suspend the LayoutManager from doing auto-layouts while
34436      * making multiple add or remove calls
34437      */
34438     beginUpdate : function(){
34439         this.updating = true;
34440     },
34441
34442     /**
34443      * Restore auto-layouts and optionally disable the manager from performing a layout
34444      * @param {Boolean} noLayout true to disable a layout update
34445      */
34446     endUpdate : function(noLayout){
34447         this.updating = false;
34448         if(!noLayout){
34449             this.layout();
34450         }
34451     },
34452
34453     layout: function(){
34454         // abstract...
34455     },
34456
34457     onRegionResized : function(region, newSize){
34458         this.fireEvent("regionresized", region, newSize);
34459         this.layout();
34460     },
34461
34462     onRegionCollapsed : function(region){
34463         this.fireEvent("regioncollapsed", region);
34464     },
34465
34466     onRegionExpanded : function(region){
34467         this.fireEvent("regionexpanded", region);
34468     },
34469
34470     /**
34471      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34472      * performs box-model adjustments.
34473      * @return {Object} The size as an object {width: (the width), height: (the height)}
34474      */
34475     getViewSize : function()
34476     {
34477         var size;
34478         if(this.el.dom != document.body){
34479             size = this.el.getSize();
34480         }else{
34481             size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34482         }
34483         size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34484         size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34485         return size;
34486     },
34487
34488     /**
34489      * Returns the Element this layout is bound to.
34490      * @return {Roo.Element}
34491      */
34492     getEl : function(){
34493         return this.el;
34494     },
34495
34496     /**
34497      * Returns the specified region.
34498      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34499      * @return {Roo.LayoutRegion}
34500      */
34501     getRegion : function(target){
34502         return this.regions[target.toLowerCase()];
34503     },
34504
34505     onWindowResize : function(){
34506         if(this.monitorWindowResize){
34507             this.layout();
34508         }
34509     }
34510 });
34511 /*
34512  * Based on:
34513  * Ext JS Library 1.1.1
34514  * Copyright(c) 2006-2007, Ext JS, LLC.
34515  *
34516  * Originally Released Under LGPL - original licence link has changed is not relivant.
34517  *
34518  * Fork - LGPL
34519  * <script type="text/javascript">
34520  */
34521 /**
34522  * @class Roo.bootstrap.layout.Border
34523  * @extends Roo.bootstrap.layout.Manager
34524  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34525  * please see: examples/bootstrap/nested.html<br><br>
34526  
34527 <b>The container the layout is rendered into can be either the body element or any other element.
34528 If it is not the body element, the container needs to either be an absolute positioned element,
34529 or you will need to add "position:relative" to the css of the container.  You will also need to specify
34530 the container size if it is not the body element.</b>
34531
34532 * @constructor
34533 * Create a new Border
34534 * @param {Object} config Configuration options
34535  */
34536 Roo.bootstrap.layout.Border = function(config){
34537     config = config || {};
34538     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34539     
34540     
34541     
34542     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34543         if(config[region]){
34544             config[region].region = region;
34545             this.addRegion(config[region]);
34546         }
34547     },this);
34548     
34549 };
34550
34551 Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
34552
34553 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34554     /**
34555      * Creates and adds a new region if it doesn't already exist.
34556      * @param {String} target The target region key (north, south, east, west or center).
34557      * @param {Object} config The regions config object
34558      * @return {BorderLayoutRegion} The new region
34559      */
34560     addRegion : function(config)
34561     {
34562         if(!this.regions[config.region]){
34563             var r = this.factory(config);
34564             this.bindRegion(r);
34565         }
34566         return this.regions[config.region];
34567     },
34568
34569     // private (kinda)
34570     bindRegion : function(r){
34571         this.regions[r.config.region] = r;
34572         
34573         r.on("visibilitychange",    this.layout, this);
34574         r.on("paneladded",          this.layout, this);
34575         r.on("panelremoved",        this.layout, this);
34576         r.on("invalidated",         this.layout, this);
34577         r.on("resized",             this.onRegionResized, this);
34578         r.on("collapsed",           this.onRegionCollapsed, this);
34579         r.on("expanded",            this.onRegionExpanded, this);
34580     },
34581
34582     /**
34583      * Performs a layout update.
34584      */
34585     layout : function()
34586     {
34587         if(this.updating) {
34588             return;
34589         }
34590         
34591         // render all the rebions if they have not been done alreayd?
34592         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34593             if(this.regions[region] && !this.regions[region].bodyEl){
34594                 this.regions[region].onRender(this.el)
34595             }
34596         },this);
34597         
34598         var size = this.getViewSize();
34599         var w = size.width;
34600         var h = size.height;
34601         var centerW = w;
34602         var centerH = h;
34603         var centerY = 0;
34604         var centerX = 0;
34605         //var x = 0, y = 0;
34606
34607         var rs = this.regions;
34608         var north = rs["north"];
34609         var south = rs["south"]; 
34610         var west = rs["west"];
34611         var east = rs["east"];
34612         var center = rs["center"];
34613         //if(this.hideOnLayout){ // not supported anymore
34614             //c.el.setStyle("display", "none");
34615         //}
34616         if(north && north.isVisible()){
34617             var b = north.getBox();
34618             var m = north.getMargins();
34619             b.width = w - (m.left+m.right);
34620             b.x = m.left;
34621             b.y = m.top;
34622             centerY = b.height + b.y + m.bottom;
34623             centerH -= centerY;
34624             north.updateBox(this.safeBox(b));
34625         }
34626         if(south && south.isVisible()){
34627             var b = south.getBox();
34628             var m = south.getMargins();
34629             b.width = w - (m.left+m.right);
34630             b.x = m.left;
34631             var totalHeight = (b.height + m.top + m.bottom);
34632             b.y = h - totalHeight + m.top;
34633             centerH -= totalHeight;
34634             south.updateBox(this.safeBox(b));
34635         }
34636         if(west && west.isVisible()){
34637             var b = west.getBox();
34638             var m = west.getMargins();
34639             b.height = centerH - (m.top+m.bottom);
34640             b.x = m.left;
34641             b.y = centerY + m.top;
34642             var totalWidth = (b.width + m.left + m.right);
34643             centerX += totalWidth;
34644             centerW -= totalWidth;
34645             west.updateBox(this.safeBox(b));
34646         }
34647         if(east && east.isVisible()){
34648             var b = east.getBox();
34649             var m = east.getMargins();
34650             b.height = centerH - (m.top+m.bottom);
34651             var totalWidth = (b.width + m.left + m.right);
34652             b.x = w - totalWidth + m.left;
34653             b.y = centerY + m.top;
34654             centerW -= totalWidth;
34655             east.updateBox(this.safeBox(b));
34656         }
34657         if(center){
34658             var m = center.getMargins();
34659             var centerBox = {
34660                 x: centerX + m.left,
34661                 y: centerY + m.top,
34662                 width: centerW - (m.left+m.right),
34663                 height: centerH - (m.top+m.bottom)
34664             };
34665             //if(this.hideOnLayout){
34666                 //center.el.setStyle("display", "block");
34667             //}
34668             center.updateBox(this.safeBox(centerBox));
34669         }
34670         this.el.repaint();
34671         this.fireEvent("layout", this);
34672     },
34673
34674     // private
34675     safeBox : function(box){
34676         box.width = Math.max(0, box.width);
34677         box.height = Math.max(0, box.height);
34678         return box;
34679     },
34680
34681     /**
34682      * Adds a ContentPanel (or subclass) to this layout.
34683      * @param {String} target The target region key (north, south, east, west or center).
34684      * @param {Roo.ContentPanel} panel The panel to add
34685      * @return {Roo.ContentPanel} The added panel
34686      */
34687     add : function(target, panel){
34688          
34689         target = target.toLowerCase();
34690         return this.regions[target].add(panel);
34691     },
34692
34693     /**
34694      * Remove a ContentPanel (or subclass) to this layout.
34695      * @param {String} target The target region key (north, south, east, west or center).
34696      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34697      * @return {Roo.ContentPanel} The removed panel
34698      */
34699     remove : function(target, panel){
34700         target = target.toLowerCase();
34701         return this.regions[target].remove(panel);
34702     },
34703
34704     /**
34705      * Searches all regions for a panel with the specified id
34706      * @param {String} panelId
34707      * @return {Roo.ContentPanel} The panel or null if it wasn't found
34708      */
34709     findPanel : function(panelId){
34710         var rs = this.regions;
34711         for(var target in rs){
34712             if(typeof rs[target] != "function"){
34713                 var p = rs[target].getPanel(panelId);
34714                 if(p){
34715                     return p;
34716                 }
34717             }
34718         }
34719         return null;
34720     },
34721
34722     /**
34723      * Searches all regions for a panel with the specified id and activates (shows) it.
34724      * @param {String/ContentPanel} panelId The panels id or the panel itself
34725      * @return {Roo.ContentPanel} The shown panel or null
34726      */
34727     showPanel : function(panelId) {
34728       var rs = this.regions;
34729       for(var target in rs){
34730          var r = rs[target];
34731          if(typeof r != "function"){
34732             if(r.hasPanel(panelId)){
34733                return r.showPanel(panelId);
34734             }
34735          }
34736       }
34737       return null;
34738    },
34739
34740    /**
34741      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34742      * @param {Roo.state.Provider} provider (optional) An alternate state provider
34743      */
34744    /*
34745     restoreState : function(provider){
34746         if(!provider){
34747             provider = Roo.state.Manager;
34748         }
34749         var sm = new Roo.LayoutStateManager();
34750         sm.init(this, provider);
34751     },
34752 */
34753  
34754  
34755     /**
34756      * Adds a xtype elements to the layout.
34757      * <pre><code>
34758
34759 layout.addxtype({
34760        xtype : 'ContentPanel',
34761        region: 'west',
34762        items: [ .... ]
34763    }
34764 );
34765
34766 layout.addxtype({
34767         xtype : 'NestedLayoutPanel',
34768         region: 'west',
34769         layout: {
34770            center: { },
34771            west: { }   
34772         },
34773         items : [ ... list of content panels or nested layout panels.. ]
34774    }
34775 );
34776 </code></pre>
34777      * @param {Object} cfg Xtype definition of item to add.
34778      */
34779     addxtype : function(cfg)
34780     {
34781         // basically accepts a pannel...
34782         // can accept a layout region..!?!?
34783         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34784         
34785         
34786         // theory?  children can only be panels??
34787         
34788         //if (!cfg.xtype.match(/Panel$/)) {
34789         //    return false;
34790         //}
34791         var ret = false;
34792         
34793         if (typeof(cfg.region) == 'undefined') {
34794             Roo.log("Failed to add Panel, region was not set");
34795             Roo.log(cfg);
34796             return false;
34797         }
34798         var region = cfg.region;
34799         delete cfg.region;
34800         
34801           
34802         var xitems = [];
34803         if (cfg.items) {
34804             xitems = cfg.items;
34805             delete cfg.items;
34806         }
34807         var nb = false;
34808         
34809         switch(cfg.xtype) 
34810         {
34811             case 'Content':  // ContentPanel (el, cfg)
34812             case 'Scroll':  // ContentPanel (el, cfg)
34813             case 'View': 
34814                 cfg.autoCreate = true;
34815                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34816                 //} else {
34817                 //    var el = this.el.createChild();
34818                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34819                 //}
34820                 
34821                 this.add(region, ret);
34822                 break;
34823             
34824             /*
34825             case 'TreePanel': // our new panel!
34826                 cfg.el = this.el.createChild();
34827                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34828                 this.add(region, ret);
34829                 break;
34830             */
34831             
34832             case 'Nest': 
34833                 // create a new Layout (which is  a Border Layout...
34834                 
34835                 var clayout = cfg.layout;
34836                 clayout.el  = this.el.createChild();
34837                 clayout.items   = clayout.items  || [];
34838                 
34839                 delete cfg.layout;
34840                 
34841                 // replace this exitems with the clayout ones..
34842                 xitems = clayout.items;
34843                  
34844                 // force background off if it's in center...
34845                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34846                     cfg.background = false;
34847                 }
34848                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
34849                 
34850                 
34851                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34852                 //console.log('adding nested layout panel '  + cfg.toSource());
34853                 this.add(region, ret);
34854                 nb = {}; /// find first...
34855                 break;
34856             
34857             case 'Grid':
34858                 
34859                 // needs grid and region
34860                 
34861                 //var el = this.getRegion(region).el.createChild();
34862                 /*
34863                  *var el = this.el.createChild();
34864                 // create the grid first...
34865                 cfg.grid.container = el;
34866                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34867                 */
34868                 
34869                 if (region == 'center' && this.active ) {
34870                     cfg.background = false;
34871                 }
34872                 
34873                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34874                 
34875                 this.add(region, ret);
34876                 /*
34877                 if (cfg.background) {
34878                     // render grid on panel activation (if panel background)
34879                     ret.on('activate', function(gp) {
34880                         if (!gp.grid.rendered) {
34881                     //        gp.grid.render(el);
34882                         }
34883                     });
34884                 } else {
34885                   //  cfg.grid.render(el);
34886                 }
34887                 */
34888                 break;
34889            
34890            
34891             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34892                 // it was the old xcomponent building that caused this before.
34893                 // espeically if border is the top element in the tree.
34894                 ret = this;
34895                 break; 
34896                 
34897                     
34898                 
34899                 
34900                 
34901             default:
34902                 /*
34903                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34904                     
34905                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34906                     this.add(region, ret);
34907                 } else {
34908                 */
34909                     Roo.log(cfg);
34910                     throw "Can not add '" + cfg.xtype + "' to Border";
34911                     return null;
34912              
34913                                 
34914              
34915         }
34916         this.beginUpdate();
34917         // add children..
34918         var region = '';
34919         var abn = {};
34920         Roo.each(xitems, function(i)  {
34921             region = nb && i.region ? i.region : false;
34922             
34923             var add = ret.addxtype(i);
34924            
34925             if (region) {
34926                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34927                 if (!i.background) {
34928                     abn[region] = nb[region] ;
34929                 }
34930             }
34931             
34932         });
34933         this.endUpdate();
34934
34935         // make the last non-background panel active..
34936         //if (nb) { Roo.log(abn); }
34937         if (nb) {
34938             
34939             for(var r in abn) {
34940                 region = this.getRegion(r);
34941                 if (region) {
34942                     // tried using nb[r], but it does not work..
34943                      
34944                     region.showPanel(abn[r]);
34945                    
34946                 }
34947             }
34948         }
34949         return ret;
34950         
34951     },
34952     
34953     
34954 // private
34955     factory : function(cfg)
34956     {
34957         
34958         var validRegions = Roo.bootstrap.layout.Border.regions;
34959
34960         var target = cfg.region;
34961         cfg.mgr = this;
34962         
34963         var r = Roo.bootstrap.layout;
34964         Roo.log(target);
34965         switch(target){
34966             case "north":
34967                 return new r.North(cfg);
34968             case "south":
34969                 return new r.South(cfg);
34970             case "east":
34971                 return new r.East(cfg);
34972             case "west":
34973                 return new r.West(cfg);
34974             case "center":
34975                 return new r.Center(cfg);
34976         }
34977         throw 'Layout region "'+target+'" not supported.';
34978     }
34979     
34980     
34981 });
34982  /*
34983  * Based on:
34984  * Ext JS Library 1.1.1
34985  * Copyright(c) 2006-2007, Ext JS, LLC.
34986  *
34987  * Originally Released Under LGPL - original licence link has changed is not relivant.
34988  *
34989  * Fork - LGPL
34990  * <script type="text/javascript">
34991  */
34992  
34993 /**
34994  * @class Roo.bootstrap.layout.Basic
34995  * @extends Roo.util.Observable
34996  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34997  * and does not have a titlebar, tabs or any other features. All it does is size and position 
34998  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34999  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35000  * @cfg {string}   region  the region that it inhabits..
35001  * @cfg {bool}   skipConfig skip config?
35002  * 
35003
35004  */
35005 Roo.bootstrap.layout.Basic = function(config){
35006     
35007     this.mgr = config.mgr;
35008     
35009     this.position = config.region;
35010     
35011     var skipConfig = config.skipConfig;
35012     
35013     this.events = {
35014         /**
35015          * @scope Roo.BasicLayoutRegion
35016          */
35017         
35018         /**
35019          * @event beforeremove
35020          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35021          * @param {Roo.LayoutRegion} this
35022          * @param {Roo.ContentPanel} panel The panel
35023          * @param {Object} e The cancel event object
35024          */
35025         "beforeremove" : true,
35026         /**
35027          * @event invalidated
35028          * Fires when the layout for this region is changed.
35029          * @param {Roo.LayoutRegion} this
35030          */
35031         "invalidated" : true,
35032         /**
35033          * @event visibilitychange
35034          * Fires when this region is shown or hidden 
35035          * @param {Roo.LayoutRegion} this
35036          * @param {Boolean} visibility true or false
35037          */
35038         "visibilitychange" : true,
35039         /**
35040          * @event paneladded
35041          * Fires when a panel is added. 
35042          * @param {Roo.LayoutRegion} this
35043          * @param {Roo.ContentPanel} panel The panel
35044          */
35045         "paneladded" : true,
35046         /**
35047          * @event panelremoved
35048          * Fires when a panel is removed. 
35049          * @param {Roo.LayoutRegion} this
35050          * @param {Roo.ContentPanel} panel The panel
35051          */
35052         "panelremoved" : true,
35053         /**
35054          * @event beforecollapse
35055          * Fires when this region before collapse.
35056          * @param {Roo.LayoutRegion} this
35057          */
35058         "beforecollapse" : true,
35059         /**
35060          * @event collapsed
35061          * Fires when this region is collapsed.
35062          * @param {Roo.LayoutRegion} this
35063          */
35064         "collapsed" : true,
35065         /**
35066          * @event expanded
35067          * Fires when this region is expanded.
35068          * @param {Roo.LayoutRegion} this
35069          */
35070         "expanded" : true,
35071         /**
35072          * @event slideshow
35073          * Fires when this region is slid into view.
35074          * @param {Roo.LayoutRegion} this
35075          */
35076         "slideshow" : true,
35077         /**
35078          * @event slidehide
35079          * Fires when this region slides out of view. 
35080          * @param {Roo.LayoutRegion} this
35081          */
35082         "slidehide" : true,
35083         /**
35084          * @event panelactivated
35085          * Fires when a panel is activated. 
35086          * @param {Roo.LayoutRegion} this
35087          * @param {Roo.ContentPanel} panel The activated panel
35088          */
35089         "panelactivated" : true,
35090         /**
35091          * @event resized
35092          * Fires when the user resizes this region. 
35093          * @param {Roo.LayoutRegion} this
35094          * @param {Number} newSize The new size (width for east/west, height for north/south)
35095          */
35096         "resized" : true
35097     };
35098     /** A collection of panels in this region. @type Roo.util.MixedCollection */
35099     this.panels = new Roo.util.MixedCollection();
35100     this.panels.getKey = this.getPanelId.createDelegate(this);
35101     this.box = null;
35102     this.activePanel = null;
35103     // ensure listeners are added...
35104     
35105     if (config.listeners || config.events) {
35106         Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35107             listeners : config.listeners || {},
35108             events : config.events || {}
35109         });
35110     }
35111     
35112     if(skipConfig !== true){
35113         this.applyConfig(config);
35114     }
35115 };
35116
35117 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35118 {
35119     getPanelId : function(p){
35120         return p.getId();
35121     },
35122     
35123     applyConfig : function(config){
35124         this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35125         this.config = config;
35126         
35127     },
35128     
35129     /**
35130      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
35131      * the width, for horizontal (north, south) the height.
35132      * @param {Number} newSize The new width or height
35133      */
35134     resizeTo : function(newSize){
35135         var el = this.el ? this.el :
35136                  (this.activePanel ? this.activePanel.getEl() : null);
35137         if(el){
35138             switch(this.position){
35139                 case "east":
35140                 case "west":
35141                     el.setWidth(newSize);
35142                     this.fireEvent("resized", this, newSize);
35143                 break;
35144                 case "north":
35145                 case "south":
35146                     el.setHeight(newSize);
35147                     this.fireEvent("resized", this, newSize);
35148                 break;                
35149             }
35150         }
35151     },
35152     
35153     getBox : function(){
35154         return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35155     },
35156     
35157     getMargins : function(){
35158         return this.margins;
35159     },
35160     
35161     updateBox : function(box){
35162         this.box = box;
35163         var el = this.activePanel.getEl();
35164         el.dom.style.left = box.x + "px";
35165         el.dom.style.top = box.y + "px";
35166         this.activePanel.setSize(box.width, box.height);
35167     },
35168     
35169     /**
35170      * Returns the container element for this region.
35171      * @return {Roo.Element}
35172      */
35173     getEl : function(){
35174         return this.activePanel;
35175     },
35176     
35177     /**
35178      * Returns true if this region is currently visible.
35179      * @return {Boolean}
35180      */
35181     isVisible : function(){
35182         return this.activePanel ? true : false;
35183     },
35184     
35185     setActivePanel : function(panel){
35186         panel = this.getPanel(panel);
35187         if(this.activePanel && this.activePanel != panel){
35188             this.activePanel.setActiveState(false);
35189             this.activePanel.getEl().setLeftTop(-10000,-10000);
35190         }
35191         this.activePanel = panel;
35192         panel.setActiveState(true);
35193         if(this.box){
35194             panel.setSize(this.box.width, this.box.height);
35195         }
35196         this.fireEvent("panelactivated", this, panel);
35197         this.fireEvent("invalidated");
35198     },
35199     
35200     /**
35201      * Show the specified panel.
35202      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35203      * @return {Roo.ContentPanel} The shown panel or null
35204      */
35205     showPanel : function(panel){
35206         panel = this.getPanel(panel);
35207         if(panel){
35208             this.setActivePanel(panel);
35209         }
35210         return panel;
35211     },
35212     
35213     /**
35214      * Get the active panel for this region.
35215      * @return {Roo.ContentPanel} The active panel or null
35216      */
35217     getActivePanel : function(){
35218         return this.activePanel;
35219     },
35220     
35221     /**
35222      * Add the passed ContentPanel(s)
35223      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35224      * @return {Roo.ContentPanel} The panel added (if only one was added)
35225      */
35226     add : function(panel){
35227         if(arguments.length > 1){
35228             for(var i = 0, len = arguments.length; i < len; i++) {
35229                 this.add(arguments[i]);
35230             }
35231             return null;
35232         }
35233         if(this.hasPanel(panel)){
35234             this.showPanel(panel);
35235             return panel;
35236         }
35237         var el = panel.getEl();
35238         if(el.dom.parentNode != this.mgr.el.dom){
35239             this.mgr.el.dom.appendChild(el.dom);
35240         }
35241         if(panel.setRegion){
35242             panel.setRegion(this);
35243         }
35244         this.panels.add(panel);
35245         el.setStyle("position", "absolute");
35246         if(!panel.background){
35247             this.setActivePanel(panel);
35248             if(this.config.initialSize && this.panels.getCount()==1){
35249                 this.resizeTo(this.config.initialSize);
35250             }
35251         }
35252         this.fireEvent("paneladded", this, panel);
35253         return panel;
35254     },
35255     
35256     /**
35257      * Returns true if the panel is in this region.
35258      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35259      * @return {Boolean}
35260      */
35261     hasPanel : function(panel){
35262         if(typeof panel == "object"){ // must be panel obj
35263             panel = panel.getId();
35264         }
35265         return this.getPanel(panel) ? true : false;
35266     },
35267     
35268     /**
35269      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35270      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35271      * @param {Boolean} preservePanel Overrides the config preservePanel option
35272      * @return {Roo.ContentPanel} The panel that was removed
35273      */
35274     remove : function(panel, preservePanel){
35275         panel = this.getPanel(panel);
35276         if(!panel){
35277             return null;
35278         }
35279         var e = {};
35280         this.fireEvent("beforeremove", this, panel, e);
35281         if(e.cancel === true){
35282             return null;
35283         }
35284         var panelId = panel.getId();
35285         this.panels.removeKey(panelId);
35286         return panel;
35287     },
35288     
35289     /**
35290      * Returns the panel specified or null if it's not in this region.
35291      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35292      * @return {Roo.ContentPanel}
35293      */
35294     getPanel : function(id){
35295         if(typeof id == "object"){ // must be panel obj
35296             return id;
35297         }
35298         return this.panels.get(id);
35299     },
35300     
35301     /**
35302      * Returns this regions position (north/south/east/west/center).
35303      * @return {String} 
35304      */
35305     getPosition: function(){
35306         return this.position;    
35307     }
35308 });/*
35309  * Based on:
35310  * Ext JS Library 1.1.1
35311  * Copyright(c) 2006-2007, Ext JS, LLC.
35312  *
35313  * Originally Released Under LGPL - original licence link has changed is not relivant.
35314  *
35315  * Fork - LGPL
35316  * <script type="text/javascript">
35317  */
35318  
35319 /**
35320  * @class Roo.bootstrap.layout.Region
35321  * @extends Roo.bootstrap.layout.Basic
35322  * This class represents a region in a layout manager.
35323  
35324  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35325  * @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})
35326  * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
35327  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
35328  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
35329  * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
35330  * @cfg {String}    title           The title for the region (overrides panel titles)
35331  * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
35332  * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35333  * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
35334  * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35335  * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
35336  * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35337  *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
35338  * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
35339  * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
35340  * @cfg {String}    overflow       (hidden|visible) if you have menus in the region, then you need to set this to visible.
35341
35342  * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
35343  * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
35344  * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
35345  * @cfg {Number}    width           For East/West panels
35346  * @cfg {Number}    height          For North/South panels
35347  * @cfg {Boolean}   split           To show the splitter
35348  * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
35349  * 
35350  * @cfg {string}   cls             Extra CSS classes to add to region
35351  * 
35352  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35353  * @cfg {string}   region  the region that it inhabits..
35354  *
35355
35356  * @xxxcfg {Boolean}   collapsible     DISABLED False to disable collapsing (defaults to true)
35357  * @xxxcfg {Boolean}   collapsed       DISABLED True to set the initial display to collapsed (defaults to false)
35358
35359  * @xxxcfg {String}    collapsedTitle  DISABLED Optional string message to display in the collapsed block of a north or south region
35360  * @xxxxcfg {Boolean}   floatable       DISABLED False to disable floating (defaults to true)
35361  * @xxxxcfg {Boolean}   showPin         True to show a pin button NOT SUPPORTED YET
35362  */
35363 Roo.bootstrap.layout.Region = function(config)
35364 {
35365     this.applyConfig(config);
35366
35367     var mgr = config.mgr;
35368     var pos = config.region;
35369     config.skipConfig = true;
35370     Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35371     
35372     if (mgr.el) {
35373         this.onRender(mgr.el);   
35374     }
35375      
35376     this.visible = true;
35377     this.collapsed = false;
35378     this.unrendered_panels = [];
35379 };
35380
35381 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35382
35383     position: '', // set by wrapper (eg. north/south etc..)
35384     unrendered_panels : null,  // unrendered panels.
35385     createBody : function(){
35386         /** This region's body element 
35387         * @type Roo.Element */
35388         this.bodyEl = this.el.createChild({
35389                 tag: "div",
35390                 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35391         });
35392     },
35393
35394     onRender: function(ctr, pos)
35395     {
35396         var dh = Roo.DomHelper;
35397         /** This region's container element 
35398         * @type Roo.Element */
35399         this.el = dh.append(ctr.dom, {
35400                 tag: "div",
35401                 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35402             }, true);
35403         /** This region's title element 
35404         * @type Roo.Element */
35405     
35406         this.titleEl = dh.append(this.el.dom,
35407             {
35408                     tag: "div",
35409                     unselectable: "on",
35410                     cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35411                     children:[
35412                         {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
35413                         {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35414                     ]}, true);
35415         
35416         this.titleEl.enableDisplayMode();
35417         /** This region's title text element 
35418         * @type HTMLElement */
35419         this.titleTextEl = this.titleEl.dom.firstChild;
35420         this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35421         /*
35422         this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35423         this.closeBtn.enableDisplayMode();
35424         this.closeBtn.on("click", this.closeClicked, this);
35425         this.closeBtn.hide();
35426     */
35427         this.createBody(this.config);
35428         if(this.config.hideWhenEmpty){
35429             this.hide();
35430             this.on("paneladded", this.validateVisibility, this);
35431             this.on("panelremoved", this.validateVisibility, this);
35432         }
35433         if(this.autoScroll){
35434             this.bodyEl.setStyle("overflow", "auto");
35435         }else{
35436             this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35437         }
35438         //if(c.titlebar !== false){
35439             if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35440                 this.titleEl.hide();
35441             }else{
35442                 this.titleEl.show();
35443                 if(this.config.title){
35444                     this.titleTextEl.innerHTML = this.config.title;
35445                 }
35446             }
35447         //}
35448         if(this.config.collapsed){
35449             this.collapse(true);
35450         }
35451         if(this.config.hidden){
35452             this.hide();
35453         }
35454         
35455         if (this.unrendered_panels && this.unrendered_panels.length) {
35456             for (var i =0;i< this.unrendered_panels.length; i++) {
35457                 this.add(this.unrendered_panels[i]);
35458             }
35459             this.unrendered_panels = null;
35460             
35461         }
35462         
35463     },
35464     
35465     applyConfig : function(c)
35466     {
35467         /*
35468          *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35469             var dh = Roo.DomHelper;
35470             if(c.titlebar !== false){
35471                 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35472                 this.collapseBtn.on("click", this.collapse, this);
35473                 this.collapseBtn.enableDisplayMode();
35474                 /*
35475                 if(c.showPin === true || this.showPin){
35476                     this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35477                     this.stickBtn.enableDisplayMode();
35478                     this.stickBtn.on("click", this.expand, this);
35479                     this.stickBtn.hide();
35480                 }
35481                 
35482             }
35483             */
35484             /** This region's collapsed element
35485             * @type Roo.Element */
35486             /*
35487              *
35488             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35489                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35490             ]}, true);
35491             
35492             if(c.floatable !== false){
35493                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35494                this.collapsedEl.on("click", this.collapseClick, this);
35495             }
35496
35497             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35498                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35499                    id: "message", unselectable: "on", style:{"float":"left"}});
35500                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35501              }
35502             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35503             this.expandBtn.on("click", this.expand, this);
35504             
35505         }
35506         
35507         if(this.collapseBtn){
35508             this.collapseBtn.setVisible(c.collapsible == true);
35509         }
35510         
35511         this.cmargins = c.cmargins || this.cmargins ||
35512                          (this.position == "west" || this.position == "east" ?
35513                              {top: 0, left: 2, right:2, bottom: 0} :
35514                              {top: 2, left: 0, right:0, bottom: 2});
35515         */
35516         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35517         
35518         
35519         this.bottomTabs = c.tabPosition != "top";
35520         
35521         this.autoScroll = c.autoScroll || false;
35522         
35523         
35524        
35525         
35526         this.duration = c.duration || .30;
35527         this.slideDuration = c.slideDuration || .45;
35528         this.config = c;
35529        
35530     },
35531     /**
35532      * Returns true if this region is currently visible.
35533      * @return {Boolean}
35534      */
35535     isVisible : function(){
35536         return this.visible;
35537     },
35538
35539     /**
35540      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35541      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
35542      */
35543     //setCollapsedTitle : function(title){
35544     //    title = title || "&#160;";
35545      //   if(this.collapsedTitleTextEl){
35546       //      this.collapsedTitleTextEl.innerHTML = title;
35547        // }
35548     //},
35549
35550     getBox : function(){
35551         var b;
35552       //  if(!this.collapsed){
35553             b = this.el.getBox(false, true);
35554        // }else{
35555           //  b = this.collapsedEl.getBox(false, true);
35556         //}
35557         return b;
35558     },
35559
35560     getMargins : function(){
35561         return this.margins;
35562         //return this.collapsed ? this.cmargins : this.margins;
35563     },
35564 /*
35565     highlight : function(){
35566         this.el.addClass("x-layout-panel-dragover");
35567     },
35568
35569     unhighlight : function(){
35570         this.el.removeClass("x-layout-panel-dragover");
35571     },
35572 */
35573     updateBox : function(box)
35574     {
35575         if (!this.bodyEl) {
35576             return; // not rendered yet..
35577         }
35578         
35579         this.box = box;
35580         if(!this.collapsed){
35581             this.el.dom.style.left = box.x + "px";
35582             this.el.dom.style.top = box.y + "px";
35583             this.updateBody(box.width, box.height);
35584         }else{
35585             this.collapsedEl.dom.style.left = box.x + "px";
35586             this.collapsedEl.dom.style.top = box.y + "px";
35587             this.collapsedEl.setSize(box.width, box.height);
35588         }
35589         if(this.tabs){
35590             this.tabs.autoSizeTabs();
35591         }
35592     },
35593
35594     updateBody : function(w, h)
35595     {
35596         if(w !== null){
35597             this.el.setWidth(w);
35598             w -= this.el.getBorderWidth("rl");
35599             if(this.config.adjustments){
35600                 w += this.config.adjustments[0];
35601             }
35602         }
35603         if(h !== null && h > 0){
35604             this.el.setHeight(h);
35605             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35606             h -= this.el.getBorderWidth("tb");
35607             if(this.config.adjustments){
35608                 h += this.config.adjustments[1];
35609             }
35610             this.bodyEl.setHeight(h);
35611             if(this.tabs){
35612                 h = this.tabs.syncHeight(h);
35613             }
35614         }
35615         if(this.panelSize){
35616             w = w !== null ? w : this.panelSize.width;
35617             h = h !== null ? h : this.panelSize.height;
35618         }
35619         if(this.activePanel){
35620             var el = this.activePanel.getEl();
35621             w = w !== null ? w : el.getWidth();
35622             h = h !== null ? h : el.getHeight();
35623             this.panelSize = {width: w, height: h};
35624             this.activePanel.setSize(w, h);
35625         }
35626         if(Roo.isIE && this.tabs){
35627             this.tabs.el.repaint();
35628         }
35629     },
35630
35631     /**
35632      * Returns the container element for this region.
35633      * @return {Roo.Element}
35634      */
35635     getEl : function(){
35636         return this.el;
35637     },
35638
35639     /**
35640      * Hides this region.
35641      */
35642     hide : function(){
35643         //if(!this.collapsed){
35644             this.el.dom.style.left = "-2000px";
35645             this.el.hide();
35646         //}else{
35647          //   this.collapsedEl.dom.style.left = "-2000px";
35648          //   this.collapsedEl.hide();
35649        // }
35650         this.visible = false;
35651         this.fireEvent("visibilitychange", this, false);
35652     },
35653
35654     /**
35655      * Shows this region if it was previously hidden.
35656      */
35657     show : function(){
35658         //if(!this.collapsed){
35659             this.el.show();
35660         //}else{
35661         //    this.collapsedEl.show();
35662        // }
35663         this.visible = true;
35664         this.fireEvent("visibilitychange", this, true);
35665     },
35666 /*
35667     closeClicked : function(){
35668         if(this.activePanel){
35669             this.remove(this.activePanel);
35670         }
35671     },
35672
35673     collapseClick : function(e){
35674         if(this.isSlid){
35675            e.stopPropagation();
35676            this.slideIn();
35677         }else{
35678            e.stopPropagation();
35679            this.slideOut();
35680         }
35681     },
35682 */
35683     /**
35684      * Collapses this region.
35685      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35686      */
35687     /*
35688     collapse : function(skipAnim, skipCheck = false){
35689         if(this.collapsed) {
35690             return;
35691         }
35692         
35693         if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35694             
35695             this.collapsed = true;
35696             if(this.split){
35697                 this.split.el.hide();
35698             }
35699             if(this.config.animate && skipAnim !== true){
35700                 this.fireEvent("invalidated", this);
35701                 this.animateCollapse();
35702             }else{
35703                 this.el.setLocation(-20000,-20000);
35704                 this.el.hide();
35705                 this.collapsedEl.show();
35706                 this.fireEvent("collapsed", this);
35707                 this.fireEvent("invalidated", this);
35708             }
35709         }
35710         
35711     },
35712 */
35713     animateCollapse : function(){
35714         // overridden
35715     },
35716
35717     /**
35718      * Expands this region if it was previously collapsed.
35719      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35720      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35721      */
35722     /*
35723     expand : function(e, skipAnim){
35724         if(e) {
35725             e.stopPropagation();
35726         }
35727         if(!this.collapsed || this.el.hasActiveFx()) {
35728             return;
35729         }
35730         if(this.isSlid){
35731             this.afterSlideIn();
35732             skipAnim = true;
35733         }
35734         this.collapsed = false;
35735         if(this.config.animate && skipAnim !== true){
35736             this.animateExpand();
35737         }else{
35738             this.el.show();
35739             if(this.split){
35740                 this.split.el.show();
35741             }
35742             this.collapsedEl.setLocation(-2000,-2000);
35743             this.collapsedEl.hide();
35744             this.fireEvent("invalidated", this);
35745             this.fireEvent("expanded", this);
35746         }
35747     },
35748 */
35749     animateExpand : function(){
35750         // overridden
35751     },
35752
35753     initTabs : function()
35754     {
35755         //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35756         
35757         var ts = new Roo.bootstrap.panel.Tabs({
35758                 el: this.bodyEl.dom,
35759                 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35760                 disableTooltips: this.config.disableTabTips,
35761                 toolbar : this.config.toolbar
35762             });
35763         
35764         if(this.config.hideTabs){
35765             ts.stripWrap.setDisplayed(false);
35766         }
35767         this.tabs = ts;
35768         ts.resizeTabs = this.config.resizeTabs === true;
35769         ts.minTabWidth = this.config.minTabWidth || 40;
35770         ts.maxTabWidth = this.config.maxTabWidth || 250;
35771         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35772         ts.monitorResize = false;
35773         //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35774         ts.bodyEl.addClass('roo-layout-tabs-body');
35775         this.panels.each(this.initPanelAsTab, this);
35776     },
35777
35778     initPanelAsTab : function(panel){
35779         var ti = this.tabs.addTab(
35780             panel.getEl().id,
35781             panel.getTitle(),
35782             null,
35783             this.config.closeOnTab && panel.isClosable(),
35784             panel.tpl
35785         );
35786         if(panel.tabTip !== undefined){
35787             ti.setTooltip(panel.tabTip);
35788         }
35789         ti.on("activate", function(){
35790               this.setActivePanel(panel);
35791         }, this);
35792         
35793         if(this.config.closeOnTab){
35794             ti.on("beforeclose", function(t, e){
35795                 e.cancel = true;
35796                 this.remove(panel);
35797             }, this);
35798         }
35799         
35800         panel.tabItem = ti;
35801         
35802         return ti;
35803     },
35804
35805     updatePanelTitle : function(panel, title)
35806     {
35807         if(this.activePanel == panel){
35808             this.updateTitle(title);
35809         }
35810         if(this.tabs){
35811             var ti = this.tabs.getTab(panel.getEl().id);
35812             ti.setText(title);
35813             if(panel.tabTip !== undefined){
35814                 ti.setTooltip(panel.tabTip);
35815             }
35816         }
35817     },
35818
35819     updateTitle : function(title){
35820         if(this.titleTextEl && !this.config.title){
35821             this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
35822         }
35823     },
35824
35825     setActivePanel : function(panel)
35826     {
35827         panel = this.getPanel(panel);
35828         if(this.activePanel && this.activePanel != panel){
35829             if(this.activePanel.setActiveState(false) === false){
35830                 return;
35831             }
35832         }
35833         this.activePanel = panel;
35834         panel.setActiveState(true);
35835         if(this.panelSize){
35836             panel.setSize(this.panelSize.width, this.panelSize.height);
35837         }
35838         if(this.closeBtn){
35839             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35840         }
35841         this.updateTitle(panel.getTitle());
35842         if(this.tabs){
35843             this.fireEvent("invalidated", this);
35844         }
35845         this.fireEvent("panelactivated", this, panel);
35846     },
35847
35848     /**
35849      * Shows the specified panel.
35850      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35851      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35852      */
35853     showPanel : function(panel)
35854     {
35855         panel = this.getPanel(panel);
35856         if(panel){
35857             if(this.tabs){
35858                 var tab = this.tabs.getTab(panel.getEl().id);
35859                 if(tab.isHidden()){
35860                     this.tabs.unhideTab(tab.id);
35861                 }
35862                 tab.activate();
35863             }else{
35864                 this.setActivePanel(panel);
35865             }
35866         }
35867         return panel;
35868     },
35869
35870     /**
35871      * Get the active panel for this region.
35872      * @return {Roo.ContentPanel} The active panel or null
35873      */
35874     getActivePanel : function(){
35875         return this.activePanel;
35876     },
35877
35878     validateVisibility : function(){
35879         if(this.panels.getCount() < 1){
35880             this.updateTitle("&#160;");
35881             this.closeBtn.hide();
35882             this.hide();
35883         }else{
35884             if(!this.isVisible()){
35885                 this.show();
35886             }
35887         }
35888     },
35889
35890     /**
35891      * Adds the passed ContentPanel(s) to this region.
35892      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35893      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35894      */
35895     add : function(panel)
35896     {
35897         if(arguments.length > 1){
35898             for(var i = 0, len = arguments.length; i < len; i++) {
35899                 this.add(arguments[i]);
35900             }
35901             return null;
35902         }
35903         
35904         // if we have not been rendered yet, then we can not really do much of this..
35905         if (!this.bodyEl) {
35906             this.unrendered_panels.push(panel);
35907             return panel;
35908         }
35909         
35910         
35911         
35912         
35913         if(this.hasPanel(panel)){
35914             this.showPanel(panel);
35915             return panel;
35916         }
35917         panel.setRegion(this);
35918         this.panels.add(panel);
35919        /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35920             // sinle panel - no tab...?? would it not be better to render it with the tabs,
35921             // and hide them... ???
35922             this.bodyEl.dom.appendChild(panel.getEl().dom);
35923             if(panel.background !== true){
35924                 this.setActivePanel(panel);
35925             }
35926             this.fireEvent("paneladded", this, panel);
35927             return panel;
35928         }
35929         */
35930         if(!this.tabs){
35931             this.initTabs();
35932         }else{
35933             this.initPanelAsTab(panel);
35934         }
35935         
35936         
35937         if(panel.background !== true){
35938             this.tabs.activate(panel.getEl().id);
35939         }
35940         this.fireEvent("paneladded", this, panel);
35941         return panel;
35942     },
35943
35944     /**
35945      * Hides the tab for the specified panel.
35946      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35947      */
35948     hidePanel : function(panel){
35949         if(this.tabs && (panel = this.getPanel(panel))){
35950             this.tabs.hideTab(panel.getEl().id);
35951         }
35952     },
35953
35954     /**
35955      * Unhides the tab for a previously hidden panel.
35956      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35957      */
35958     unhidePanel : function(panel){
35959         if(this.tabs && (panel = this.getPanel(panel))){
35960             this.tabs.unhideTab(panel.getEl().id);
35961         }
35962     },
35963
35964     clearPanels : function(){
35965         while(this.panels.getCount() > 0){
35966              this.remove(this.panels.first());
35967         }
35968     },
35969
35970     /**
35971      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35972      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35973      * @param {Boolean} preservePanel Overrides the config preservePanel option
35974      * @return {Roo.ContentPanel} The panel that was removed
35975      */
35976     remove : function(panel, preservePanel)
35977     {
35978         panel = this.getPanel(panel);
35979         if(!panel){
35980             return null;
35981         }
35982         var e = {};
35983         this.fireEvent("beforeremove", this, panel, e);
35984         if(e.cancel === true){
35985             return null;
35986         }
35987         preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35988         var panelId = panel.getId();
35989         this.panels.removeKey(panelId);
35990         if(preservePanel){
35991             document.body.appendChild(panel.getEl().dom);
35992         }
35993         if(this.tabs){
35994             this.tabs.removeTab(panel.getEl().id);
35995         }else if (!preservePanel){
35996             this.bodyEl.dom.removeChild(panel.getEl().dom);
35997         }
35998         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35999             var p = this.panels.first();
36000             var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36001             tempEl.appendChild(p.getEl().dom);
36002             this.bodyEl.update("");
36003             this.bodyEl.dom.appendChild(p.getEl().dom);
36004             tempEl = null;
36005             this.updateTitle(p.getTitle());
36006             this.tabs = null;
36007             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36008             this.setActivePanel(p);
36009         }
36010         panel.setRegion(null);
36011         if(this.activePanel == panel){
36012             this.activePanel = null;
36013         }
36014         if(this.config.autoDestroy !== false && preservePanel !== true){
36015             try{panel.destroy();}catch(e){}
36016         }
36017         this.fireEvent("panelremoved", this, panel);
36018         return panel;
36019     },
36020
36021     /**
36022      * Returns the TabPanel component used by this region
36023      * @return {Roo.TabPanel}
36024      */
36025     getTabs : function(){
36026         return this.tabs;
36027     },
36028
36029     createTool : function(parentEl, className){
36030         var btn = Roo.DomHelper.append(parentEl, {
36031             tag: "div",
36032             cls: "x-layout-tools-button",
36033             children: [ {
36034                 tag: "div",
36035                 cls: "roo-layout-tools-button-inner " + className,
36036                 html: "&#160;"
36037             }]
36038         }, true);
36039         btn.addClassOnOver("roo-layout-tools-button-over");
36040         return btn;
36041     }
36042 });/*
36043  * Based on:
36044  * Ext JS Library 1.1.1
36045  * Copyright(c) 2006-2007, Ext JS, LLC.
36046  *
36047  * Originally Released Under LGPL - original licence link has changed is not relivant.
36048  *
36049  * Fork - LGPL
36050  * <script type="text/javascript">
36051  */
36052  
36053
36054
36055 /**
36056  * @class Roo.SplitLayoutRegion
36057  * @extends Roo.LayoutRegion
36058  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36059  */
36060 Roo.bootstrap.layout.Split = function(config){
36061     this.cursor = config.cursor;
36062     Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36063 };
36064
36065 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36066 {
36067     splitTip : "Drag to resize.",
36068     collapsibleSplitTip : "Drag to resize. Double click to hide.",
36069     useSplitTips : false,
36070
36071     applyConfig : function(config){
36072         Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36073     },
36074     
36075     onRender : function(ctr,pos) {
36076         
36077         Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36078         if(!this.config.split){
36079             return;
36080         }
36081         if(!this.split){
36082             
36083             var splitEl = Roo.DomHelper.append(ctr.dom,  {
36084                             tag: "div",
36085                             id: this.el.id + "-split",
36086                             cls: "roo-layout-split roo-layout-split-"+this.position,
36087                             html: "&#160;"
36088             });
36089             /** The SplitBar for this region 
36090             * @type Roo.SplitBar */
36091             // does not exist yet...
36092             Roo.log([this.position, this.orientation]);
36093             
36094             this.split = new Roo.bootstrap.SplitBar({
36095                 dragElement : splitEl,
36096                 resizingElement: this.el,
36097                 orientation : this.orientation
36098             });
36099             
36100             this.split.on("moved", this.onSplitMove, this);
36101             this.split.useShim = this.config.useShim === true;
36102             this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36103             if(this.useSplitTips){
36104                 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36105             }
36106             //if(config.collapsible){
36107             //    this.split.el.on("dblclick", this.collapse,  this);
36108             //}
36109         }
36110         if(typeof this.config.minSize != "undefined"){
36111             this.split.minSize = this.config.minSize;
36112         }
36113         if(typeof this.config.maxSize != "undefined"){
36114             this.split.maxSize = this.config.maxSize;
36115         }
36116         if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36117             this.hideSplitter();
36118         }
36119         
36120     },
36121
36122     getHMaxSize : function(){
36123          var cmax = this.config.maxSize || 10000;
36124          var center = this.mgr.getRegion("center");
36125          return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36126     },
36127
36128     getVMaxSize : function(){
36129          var cmax = this.config.maxSize || 10000;
36130          var center = this.mgr.getRegion("center");
36131          return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36132     },
36133
36134     onSplitMove : function(split, newSize){
36135         this.fireEvent("resized", this, newSize);
36136     },
36137     
36138     /** 
36139      * Returns the {@link Roo.SplitBar} for this region.
36140      * @return {Roo.SplitBar}
36141      */
36142     getSplitBar : function(){
36143         return this.split;
36144     },
36145     
36146     hide : function(){
36147         this.hideSplitter();
36148         Roo.bootstrap.layout.Split.superclass.hide.call(this);
36149     },
36150
36151     hideSplitter : function(){
36152         if(this.split){
36153             this.split.el.setLocation(-2000,-2000);
36154             this.split.el.hide();
36155         }
36156     },
36157
36158     show : function(){
36159         if(this.split){
36160             this.split.el.show();
36161         }
36162         Roo.bootstrap.layout.Split.superclass.show.call(this);
36163     },
36164     
36165     beforeSlide: function(){
36166         if(Roo.isGecko){// firefox overflow auto bug workaround
36167             this.bodyEl.clip();
36168             if(this.tabs) {
36169                 this.tabs.bodyEl.clip();
36170             }
36171             if(this.activePanel){
36172                 this.activePanel.getEl().clip();
36173                 
36174                 if(this.activePanel.beforeSlide){
36175                     this.activePanel.beforeSlide();
36176                 }
36177             }
36178         }
36179     },
36180     
36181     afterSlide : function(){
36182         if(Roo.isGecko){// firefox overflow auto bug workaround
36183             this.bodyEl.unclip();
36184             if(this.tabs) {
36185                 this.tabs.bodyEl.unclip();
36186             }
36187             if(this.activePanel){
36188                 this.activePanel.getEl().unclip();
36189                 if(this.activePanel.afterSlide){
36190                     this.activePanel.afterSlide();
36191                 }
36192             }
36193         }
36194     },
36195
36196     initAutoHide : function(){
36197         if(this.autoHide !== false){
36198             if(!this.autoHideHd){
36199                 var st = new Roo.util.DelayedTask(this.slideIn, this);
36200                 this.autoHideHd = {
36201                     "mouseout": function(e){
36202                         if(!e.within(this.el, true)){
36203                             st.delay(500);
36204                         }
36205                     },
36206                     "mouseover" : function(e){
36207                         st.cancel();
36208                     },
36209                     scope : this
36210                 };
36211             }
36212             this.el.on(this.autoHideHd);
36213         }
36214     },
36215
36216     clearAutoHide : function(){
36217         if(this.autoHide !== false){
36218             this.el.un("mouseout", this.autoHideHd.mouseout);
36219             this.el.un("mouseover", this.autoHideHd.mouseover);
36220         }
36221     },
36222
36223     clearMonitor : function(){
36224         Roo.get(document).un("click", this.slideInIf, this);
36225     },
36226
36227     // these names are backwards but not changed for compat
36228     slideOut : function(){
36229         if(this.isSlid || this.el.hasActiveFx()){
36230             return;
36231         }
36232         this.isSlid = true;
36233         if(this.collapseBtn){
36234             this.collapseBtn.hide();
36235         }
36236         this.closeBtnState = this.closeBtn.getStyle('display');
36237         this.closeBtn.hide();
36238         if(this.stickBtn){
36239             this.stickBtn.show();
36240         }
36241         this.el.show();
36242         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36243         this.beforeSlide();
36244         this.el.setStyle("z-index", 10001);
36245         this.el.slideIn(this.getSlideAnchor(), {
36246             callback: function(){
36247                 this.afterSlide();
36248                 this.initAutoHide();
36249                 Roo.get(document).on("click", this.slideInIf, this);
36250                 this.fireEvent("slideshow", this);
36251             },
36252             scope: this,
36253             block: true
36254         });
36255     },
36256
36257     afterSlideIn : function(){
36258         this.clearAutoHide();
36259         this.isSlid = false;
36260         this.clearMonitor();
36261         this.el.setStyle("z-index", "");
36262         if(this.collapseBtn){
36263             this.collapseBtn.show();
36264         }
36265         this.closeBtn.setStyle('display', this.closeBtnState);
36266         if(this.stickBtn){
36267             this.stickBtn.hide();
36268         }
36269         this.fireEvent("slidehide", this);
36270     },
36271
36272     slideIn : function(cb){
36273         if(!this.isSlid || this.el.hasActiveFx()){
36274             Roo.callback(cb);
36275             return;
36276         }
36277         this.isSlid = false;
36278         this.beforeSlide();
36279         this.el.slideOut(this.getSlideAnchor(), {
36280             callback: function(){
36281                 this.el.setLeftTop(-10000, -10000);
36282                 this.afterSlide();
36283                 this.afterSlideIn();
36284                 Roo.callback(cb);
36285             },
36286             scope: this,
36287             block: true
36288         });
36289     },
36290     
36291     slideInIf : function(e){
36292         if(!e.within(this.el)){
36293             this.slideIn();
36294         }
36295     },
36296
36297     animateCollapse : function(){
36298         this.beforeSlide();
36299         this.el.setStyle("z-index", 20000);
36300         var anchor = this.getSlideAnchor();
36301         this.el.slideOut(anchor, {
36302             callback : function(){
36303                 this.el.setStyle("z-index", "");
36304                 this.collapsedEl.slideIn(anchor, {duration:.3});
36305                 this.afterSlide();
36306                 this.el.setLocation(-10000,-10000);
36307                 this.el.hide();
36308                 this.fireEvent("collapsed", this);
36309             },
36310             scope: this,
36311             block: true
36312         });
36313     },
36314
36315     animateExpand : function(){
36316         this.beforeSlide();
36317         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36318         this.el.setStyle("z-index", 20000);
36319         this.collapsedEl.hide({
36320             duration:.1
36321         });
36322         this.el.slideIn(this.getSlideAnchor(), {
36323             callback : function(){
36324                 this.el.setStyle("z-index", "");
36325                 this.afterSlide();
36326                 if(this.split){
36327                     this.split.el.show();
36328                 }
36329                 this.fireEvent("invalidated", this);
36330                 this.fireEvent("expanded", this);
36331             },
36332             scope: this,
36333             block: true
36334         });
36335     },
36336
36337     anchors : {
36338         "west" : "left",
36339         "east" : "right",
36340         "north" : "top",
36341         "south" : "bottom"
36342     },
36343
36344     sanchors : {
36345         "west" : "l",
36346         "east" : "r",
36347         "north" : "t",
36348         "south" : "b"
36349     },
36350
36351     canchors : {
36352         "west" : "tl-tr",
36353         "east" : "tr-tl",
36354         "north" : "tl-bl",
36355         "south" : "bl-tl"
36356     },
36357
36358     getAnchor : function(){
36359         return this.anchors[this.position];
36360     },
36361
36362     getCollapseAnchor : function(){
36363         return this.canchors[this.position];
36364     },
36365
36366     getSlideAnchor : function(){
36367         return this.sanchors[this.position];
36368     },
36369
36370     getAlignAdj : function(){
36371         var cm = this.cmargins;
36372         switch(this.position){
36373             case "west":
36374                 return [0, 0];
36375             break;
36376             case "east":
36377                 return [0, 0];
36378             break;
36379             case "north":
36380                 return [0, 0];
36381             break;
36382             case "south":
36383                 return [0, 0];
36384             break;
36385         }
36386     },
36387
36388     getExpandAdj : function(){
36389         var c = this.collapsedEl, cm = this.cmargins;
36390         switch(this.position){
36391             case "west":
36392                 return [-(cm.right+c.getWidth()+cm.left), 0];
36393             break;
36394             case "east":
36395                 return [cm.right+c.getWidth()+cm.left, 0];
36396             break;
36397             case "north":
36398                 return [0, -(cm.top+cm.bottom+c.getHeight())];
36399             break;
36400             case "south":
36401                 return [0, cm.top+cm.bottom+c.getHeight()];
36402             break;
36403         }
36404     }
36405 });/*
36406  * Based on:
36407  * Ext JS Library 1.1.1
36408  * Copyright(c) 2006-2007, Ext JS, LLC.
36409  *
36410  * Originally Released Under LGPL - original licence link has changed is not relivant.
36411  *
36412  * Fork - LGPL
36413  * <script type="text/javascript">
36414  */
36415 /*
36416  * These classes are private internal classes
36417  */
36418 Roo.bootstrap.layout.Center = function(config){
36419     config.region = "center";
36420     Roo.bootstrap.layout.Region.call(this, config);
36421     this.visible = true;
36422     this.minWidth = config.minWidth || 20;
36423     this.minHeight = config.minHeight || 20;
36424 };
36425
36426 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36427     hide : function(){
36428         // center panel can't be hidden
36429     },
36430     
36431     show : function(){
36432         // center panel can't be hidden
36433     },
36434     
36435     getMinWidth: function(){
36436         return this.minWidth;
36437     },
36438     
36439     getMinHeight: function(){
36440         return this.minHeight;
36441     }
36442 });
36443
36444
36445
36446
36447  
36448
36449
36450
36451
36452
36453 Roo.bootstrap.layout.North = function(config)
36454 {
36455     config.region = 'north';
36456     config.cursor = 'n-resize';
36457     
36458     Roo.bootstrap.layout.Split.call(this, config);
36459     
36460     
36461     if(this.split){
36462         this.split.placement = Roo.bootstrap.SplitBar.TOP;
36463         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36464         this.split.el.addClass("roo-layout-split-v");
36465     }
36466     var size = config.initialSize || config.height;
36467     if(typeof size != "undefined"){
36468         this.el.setHeight(size);
36469     }
36470 };
36471 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36472 {
36473     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36474     
36475     
36476     
36477     getBox : function(){
36478         if(this.collapsed){
36479             return this.collapsedEl.getBox();
36480         }
36481         var box = this.el.getBox();
36482         if(this.split){
36483             box.height += this.split.el.getHeight();
36484         }
36485         return box;
36486     },
36487     
36488     updateBox : function(box){
36489         if(this.split && !this.collapsed){
36490             box.height -= this.split.el.getHeight();
36491             this.split.el.setLeft(box.x);
36492             this.split.el.setTop(box.y+box.height);
36493             this.split.el.setWidth(box.width);
36494         }
36495         if(this.collapsed){
36496             this.updateBody(box.width, null);
36497         }
36498         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36499     }
36500 });
36501
36502
36503
36504
36505
36506 Roo.bootstrap.layout.South = function(config){
36507     config.region = 'south';
36508     config.cursor = 's-resize';
36509     Roo.bootstrap.layout.Split.call(this, config);
36510     if(this.split){
36511         this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36512         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36513         this.split.el.addClass("roo-layout-split-v");
36514     }
36515     var size = config.initialSize || config.height;
36516     if(typeof size != "undefined"){
36517         this.el.setHeight(size);
36518     }
36519 };
36520
36521 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36522     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36523     getBox : function(){
36524         if(this.collapsed){
36525             return this.collapsedEl.getBox();
36526         }
36527         var box = this.el.getBox();
36528         if(this.split){
36529             var sh = this.split.el.getHeight();
36530             box.height += sh;
36531             box.y -= sh;
36532         }
36533         return box;
36534     },
36535     
36536     updateBox : function(box){
36537         if(this.split && !this.collapsed){
36538             var sh = this.split.el.getHeight();
36539             box.height -= sh;
36540             box.y += sh;
36541             this.split.el.setLeft(box.x);
36542             this.split.el.setTop(box.y-sh);
36543             this.split.el.setWidth(box.width);
36544         }
36545         if(this.collapsed){
36546             this.updateBody(box.width, null);
36547         }
36548         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36549     }
36550 });
36551
36552 Roo.bootstrap.layout.East = function(config){
36553     config.region = "east";
36554     config.cursor = "e-resize";
36555     Roo.bootstrap.layout.Split.call(this, config);
36556     if(this.split){
36557         this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36558         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36559         this.split.el.addClass("roo-layout-split-h");
36560     }
36561     var size = config.initialSize || config.width;
36562     if(typeof size != "undefined"){
36563         this.el.setWidth(size);
36564     }
36565 };
36566 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36567     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36568     getBox : function(){
36569         if(this.collapsed){
36570             return this.collapsedEl.getBox();
36571         }
36572         var box = this.el.getBox();
36573         if(this.split){
36574             var sw = this.split.el.getWidth();
36575             box.width += sw;
36576             box.x -= sw;
36577         }
36578         return box;
36579     },
36580
36581     updateBox : function(box){
36582         if(this.split && !this.collapsed){
36583             var sw = this.split.el.getWidth();
36584             box.width -= sw;
36585             this.split.el.setLeft(box.x);
36586             this.split.el.setTop(box.y);
36587             this.split.el.setHeight(box.height);
36588             box.x += sw;
36589         }
36590         if(this.collapsed){
36591             this.updateBody(null, box.height);
36592         }
36593         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36594     }
36595 });
36596
36597 Roo.bootstrap.layout.West = function(config){
36598     config.region = "west";
36599     config.cursor = "w-resize";
36600     
36601     Roo.bootstrap.layout.Split.call(this, config);
36602     if(this.split){
36603         this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36604         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36605         this.split.el.addClass("roo-layout-split-h");
36606     }
36607     
36608 };
36609 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36610     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36611     
36612     onRender: function(ctr, pos)
36613     {
36614         Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36615         var size = this.config.initialSize || this.config.width;
36616         if(typeof size != "undefined"){
36617             this.el.setWidth(size);
36618         }
36619     },
36620     
36621     getBox : function(){
36622         if(this.collapsed){
36623             return this.collapsedEl.getBox();
36624         }
36625         var box = this.el.getBox();
36626         if(this.split){
36627             box.width += this.split.el.getWidth();
36628         }
36629         return box;
36630     },
36631     
36632     updateBox : function(box){
36633         if(this.split && !this.collapsed){
36634             var sw = this.split.el.getWidth();
36635             box.width -= sw;
36636             this.split.el.setLeft(box.x+box.width);
36637             this.split.el.setTop(box.y);
36638             this.split.el.setHeight(box.height);
36639         }
36640         if(this.collapsed){
36641             this.updateBody(null, box.height);
36642         }
36643         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36644     }
36645 });
36646 Roo.namespace("Roo.bootstrap.panel");/*
36647  * Based on:
36648  * Ext JS Library 1.1.1
36649  * Copyright(c) 2006-2007, Ext JS, LLC.
36650  *
36651  * Originally Released Under LGPL - original licence link has changed is not relivant.
36652  *
36653  * Fork - LGPL
36654  * <script type="text/javascript">
36655  */
36656 /**
36657  * @class Roo.ContentPanel
36658  * @extends Roo.util.Observable
36659  * A basic ContentPanel element.
36660  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
36661  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
36662  * @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
36663  * @cfg {Boolean}   closable      True if the panel can be closed/removed
36664  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
36665  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36666  * @cfg {Toolbar}   toolbar       A toolbar for this panel
36667  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
36668  * @cfg {String} title          The title for this panel
36669  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36670  * @cfg {String} url            Calls {@link #setUrl} with this value
36671  * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36672  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
36673  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
36674  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
36675  * @cfg {Boolean} badges render the badges
36676
36677  * @constructor
36678  * Create a new ContentPanel.
36679  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36680  * @param {String/Object} config A string to set only the title or a config object
36681  * @param {String} content (optional) Set the HTML content for this panel
36682  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36683  */
36684 Roo.bootstrap.panel.Content = function( config){
36685     
36686     this.tpl = config.tpl || false;
36687     
36688     var el = config.el;
36689     var content = config.content;
36690
36691     if(config.autoCreate){ // xtype is available if this is called from factory
36692         el = Roo.id();
36693     }
36694     this.el = Roo.get(el);
36695     if(!this.el && config && config.autoCreate){
36696         if(typeof config.autoCreate == "object"){
36697             if(!config.autoCreate.id){
36698                 config.autoCreate.id = config.id||el;
36699             }
36700             this.el = Roo.DomHelper.append(document.body,
36701                         config.autoCreate, true);
36702         }else{
36703             var elcfg =  {   tag: "div",
36704                             cls: "roo-layout-inactive-content",
36705                             id: config.id||el
36706                             };
36707             if (config.html) {
36708                 elcfg.html = config.html;
36709                 
36710             }
36711                         
36712             this.el = Roo.DomHelper.append(document.body, elcfg , true);
36713         }
36714     } 
36715     this.closable = false;
36716     this.loaded = false;
36717     this.active = false;
36718    
36719       
36720     if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36721         
36722         this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36723         
36724         this.wrapEl = this.el; //this.el.wrap();
36725         var ti = [];
36726         if (config.toolbar.items) {
36727             ti = config.toolbar.items ;
36728             delete config.toolbar.items ;
36729         }
36730         
36731         var nitems = [];
36732         this.toolbar.render(this.wrapEl, 'before');
36733         for(var i =0;i < ti.length;i++) {
36734           //  Roo.log(['add child', items[i]]);
36735             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36736         }
36737         this.toolbar.items = nitems;
36738         this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36739         delete config.toolbar;
36740         
36741     }
36742     /*
36743     // xtype created footer. - not sure if will work as we normally have to render first..
36744     if (this.footer && !this.footer.el && this.footer.xtype) {
36745         if (!this.wrapEl) {
36746             this.wrapEl = this.el.wrap();
36747         }
36748     
36749         this.footer.container = this.wrapEl.createChild();
36750          
36751         this.footer = Roo.factory(this.footer, Roo);
36752         
36753     }
36754     */
36755     
36756      if(typeof config == "string"){
36757         this.title = config;
36758     }else{
36759         Roo.apply(this, config);
36760     }
36761     
36762     if(this.resizeEl){
36763         this.resizeEl = Roo.get(this.resizeEl, true);
36764     }else{
36765         this.resizeEl = this.el;
36766     }
36767     // handle view.xtype
36768     
36769  
36770     
36771     
36772     this.addEvents({
36773         /**
36774          * @event activate
36775          * Fires when this panel is activated. 
36776          * @param {Roo.ContentPanel} this
36777          */
36778         "activate" : true,
36779         /**
36780          * @event deactivate
36781          * Fires when this panel is activated. 
36782          * @param {Roo.ContentPanel} this
36783          */
36784         "deactivate" : true,
36785
36786         /**
36787          * @event resize
36788          * Fires when this panel is resized if fitToFrame is true.
36789          * @param {Roo.ContentPanel} this
36790          * @param {Number} width The width after any component adjustments
36791          * @param {Number} height The height after any component adjustments
36792          */
36793         "resize" : true,
36794         
36795          /**
36796          * @event render
36797          * Fires when this tab is created
36798          * @param {Roo.ContentPanel} this
36799          */
36800         "render" : true
36801         
36802         
36803         
36804     });
36805     
36806
36807     
36808     
36809     if(this.autoScroll){
36810         this.resizeEl.setStyle("overflow", "auto");
36811     } else {
36812         // fix randome scrolling
36813         //this.el.on('scroll', function() {
36814         //    Roo.log('fix random scolling');
36815         //    this.scrollTo('top',0); 
36816         //});
36817     }
36818     content = content || this.content;
36819     if(content){
36820         this.setContent(content);
36821     }
36822     if(config && config.url){
36823         this.setUrl(this.url, this.params, this.loadOnce);
36824     }
36825     
36826     
36827     
36828     Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36829     
36830     if (this.view && typeof(this.view.xtype) != 'undefined') {
36831         this.view.el = this.el.appendChild(document.createElement("div"));
36832         this.view = Roo.factory(this.view); 
36833         this.view.render  &&  this.view.render(false, '');  
36834     }
36835     
36836     
36837     this.fireEvent('render', this);
36838 };
36839
36840 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36841     
36842     tabTip : '',
36843     
36844     setRegion : function(region){
36845         this.region = region;
36846         this.setActiveClass(region && !this.background);
36847     },
36848     
36849     
36850     setActiveClass: function(state)
36851     {
36852         if(state){
36853            this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36854            this.el.setStyle('position','relative');
36855         }else{
36856            this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36857            this.el.setStyle('position', 'absolute');
36858         } 
36859     },
36860     
36861     /**
36862      * Returns the toolbar for this Panel if one was configured. 
36863      * @return {Roo.Toolbar} 
36864      */
36865     getToolbar : function(){
36866         return this.toolbar;
36867     },
36868     
36869     setActiveState : function(active)
36870     {
36871         this.active = active;
36872         this.setActiveClass(active);
36873         if(!active){
36874             if(this.fireEvent("deactivate", this) === false){
36875                 return false;
36876             }
36877             return true;
36878         }
36879         this.fireEvent("activate", this);
36880         return true;
36881     },
36882     /**
36883      * Updates this panel's element
36884      * @param {String} content The new content
36885      * @param {Boolean} loadScripts (optional) true to look for and process scripts
36886     */
36887     setContent : function(content, loadScripts){
36888         this.el.update(content, loadScripts);
36889     },
36890
36891     ignoreResize : function(w, h){
36892         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36893             return true;
36894         }else{
36895             this.lastSize = {width: w, height: h};
36896             return false;
36897         }
36898     },
36899     /**
36900      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36901      * @return {Roo.UpdateManager} The UpdateManager
36902      */
36903     getUpdateManager : function(){
36904         return this.el.getUpdateManager();
36905     },
36906      /**
36907      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36908      * @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:
36909 <pre><code>
36910 panel.load({
36911     url: "your-url.php",
36912     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36913     callback: yourFunction,
36914     scope: yourObject, //(optional scope)
36915     discardUrl: false,
36916     nocache: false,
36917     text: "Loading...",
36918     timeout: 30,
36919     scripts: false
36920 });
36921 </code></pre>
36922      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36923      * 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.
36924      * @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}
36925      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36926      * @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.
36927      * @return {Roo.ContentPanel} this
36928      */
36929     load : function(){
36930         var um = this.el.getUpdateManager();
36931         um.update.apply(um, arguments);
36932         return this;
36933     },
36934
36935
36936     /**
36937      * 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.
36938      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36939      * @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)
36940      * @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)
36941      * @return {Roo.UpdateManager} The UpdateManager
36942      */
36943     setUrl : function(url, params, loadOnce){
36944         if(this.refreshDelegate){
36945             this.removeListener("activate", this.refreshDelegate);
36946         }
36947         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36948         this.on("activate", this.refreshDelegate);
36949         return this.el.getUpdateManager();
36950     },
36951     
36952     _handleRefresh : function(url, params, loadOnce){
36953         if(!loadOnce || !this.loaded){
36954             var updater = this.el.getUpdateManager();
36955             updater.update(url, params, this._setLoaded.createDelegate(this));
36956         }
36957     },
36958     
36959     _setLoaded : function(){
36960         this.loaded = true;
36961     }, 
36962     
36963     /**
36964      * Returns this panel's id
36965      * @return {String} 
36966      */
36967     getId : function(){
36968         return this.el.id;
36969     },
36970     
36971     /** 
36972      * Returns this panel's element - used by regiosn to add.
36973      * @return {Roo.Element} 
36974      */
36975     getEl : function(){
36976         return this.wrapEl || this.el;
36977     },
36978     
36979    
36980     
36981     adjustForComponents : function(width, height)
36982     {
36983         //Roo.log('adjustForComponents ');
36984         if(this.resizeEl != this.el){
36985             width -= this.el.getFrameWidth('lr');
36986             height -= this.el.getFrameWidth('tb');
36987         }
36988         if(this.toolbar){
36989             var te = this.toolbar.getEl();
36990             te.setWidth(width);
36991             height -= te.getHeight();
36992         }
36993         if(this.footer){
36994             var te = this.footer.getEl();
36995             te.setWidth(width);
36996             height -= te.getHeight();
36997         }
36998         
36999         
37000         if(this.adjustments){
37001             width += this.adjustments[0];
37002             height += this.adjustments[1];
37003         }
37004         return {"width": width, "height": height};
37005     },
37006     
37007     setSize : function(width, height){
37008         if(this.fitToFrame && !this.ignoreResize(width, height)){
37009             if(this.fitContainer && this.resizeEl != this.el){
37010                 this.el.setSize(width, height);
37011             }
37012             var size = this.adjustForComponents(width, height);
37013             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37014             this.fireEvent('resize', this, size.width, size.height);
37015         }
37016     },
37017     
37018     /**
37019      * Returns this panel's title
37020      * @return {String} 
37021      */
37022     getTitle : function(){
37023         
37024         if (typeof(this.title) != 'object') {
37025             return this.title;
37026         }
37027         
37028         var t = '';
37029         for (var k in this.title) {
37030             if (!this.title.hasOwnProperty(k)) {
37031                 continue;
37032             }
37033             
37034             if (k.indexOf('-') >= 0) {
37035                 var s = k.split('-');
37036                 for (var i = 0; i<s.length; i++) {
37037                     t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37038                 }
37039             } else {
37040                 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37041             }
37042         }
37043         return t;
37044     },
37045     
37046     /**
37047      * Set this panel's title
37048      * @param {String} title
37049      */
37050     setTitle : function(title){
37051         this.title = title;
37052         if(this.region){
37053             this.region.updatePanelTitle(this, title);
37054         }
37055     },
37056     
37057     /**
37058      * Returns true is this panel was configured to be closable
37059      * @return {Boolean} 
37060      */
37061     isClosable : function(){
37062         return this.closable;
37063     },
37064     
37065     beforeSlide : function(){
37066         this.el.clip();
37067         this.resizeEl.clip();
37068     },
37069     
37070     afterSlide : function(){
37071         this.el.unclip();
37072         this.resizeEl.unclip();
37073     },
37074     
37075     /**
37076      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
37077      *   Will fail silently if the {@link #setUrl} method has not been called.
37078      *   This does not activate the panel, just updates its content.
37079      */
37080     refresh : function(){
37081         if(this.refreshDelegate){
37082            this.loaded = false;
37083            this.refreshDelegate();
37084         }
37085     },
37086     
37087     /**
37088      * Destroys this panel
37089      */
37090     destroy : function(){
37091         this.el.removeAllListeners();
37092         var tempEl = document.createElement("span");
37093         tempEl.appendChild(this.el.dom);
37094         tempEl.innerHTML = "";
37095         this.el.remove();
37096         this.el = null;
37097     },
37098     
37099     /**
37100      * form - if the content panel contains a form - this is a reference to it.
37101      * @type {Roo.form.Form}
37102      */
37103     form : false,
37104     /**
37105      * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37106      *    This contains a reference to it.
37107      * @type {Roo.View}
37108      */
37109     view : false,
37110     
37111       /**
37112      * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37113      * <pre><code>
37114
37115 layout.addxtype({
37116        xtype : 'Form',
37117        items: [ .... ]
37118    }
37119 );
37120
37121 </code></pre>
37122      * @param {Object} cfg Xtype definition of item to add.
37123      */
37124     
37125     
37126     getChildContainer: function () {
37127         return this.getEl();
37128     }
37129     
37130     
37131     /*
37132         var  ret = new Roo.factory(cfg);
37133         return ret;
37134         
37135         
37136         // add form..
37137         if (cfg.xtype.match(/^Form$/)) {
37138             
37139             var el;
37140             //if (this.footer) {
37141             //    el = this.footer.container.insertSibling(false, 'before');
37142             //} else {
37143                 el = this.el.createChild();
37144             //}
37145
37146             this.form = new  Roo.form.Form(cfg);
37147             
37148             
37149             if ( this.form.allItems.length) {
37150                 this.form.render(el.dom);
37151             }
37152             return this.form;
37153         }
37154         // should only have one of theses..
37155         if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37156             // views.. should not be just added - used named prop 'view''
37157             
37158             cfg.el = this.el.appendChild(document.createElement("div"));
37159             // factory?
37160             
37161             var ret = new Roo.factory(cfg);
37162              
37163              ret.render && ret.render(false, ''); // render blank..
37164             this.view = ret;
37165             return ret;
37166         }
37167         return false;
37168     }
37169     \*/
37170 });
37171  
37172 /**
37173  * @class Roo.bootstrap.panel.Grid
37174  * @extends Roo.bootstrap.panel.Content
37175  * @constructor
37176  * Create a new GridPanel.
37177  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37178  * @param {Object} config A the config object
37179   
37180  */
37181
37182
37183
37184 Roo.bootstrap.panel.Grid = function(config)
37185 {
37186     
37187       
37188     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37189         {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37190
37191     config.el = this.wrapper;
37192     //this.el = this.wrapper;
37193     
37194       if (config.container) {
37195         // ctor'ed from a Border/panel.grid
37196         
37197         
37198         this.wrapper.setStyle("overflow", "hidden");
37199         this.wrapper.addClass('roo-grid-container');
37200
37201     }
37202     
37203     
37204     if(config.toolbar){
37205         var tool_el = this.wrapper.createChild();    
37206         this.toolbar = Roo.factory(config.toolbar);
37207         var ti = [];
37208         if (config.toolbar.items) {
37209             ti = config.toolbar.items ;
37210             delete config.toolbar.items ;
37211         }
37212         
37213         var nitems = [];
37214         this.toolbar.render(tool_el);
37215         for(var i =0;i < ti.length;i++) {
37216           //  Roo.log(['add child', items[i]]);
37217             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37218         }
37219         this.toolbar.items = nitems;
37220         
37221         delete config.toolbar;
37222     }
37223     
37224     Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37225     config.grid.scrollBody = true;;
37226     config.grid.monitorWindowResize = false; // turn off autosizing
37227     config.grid.autoHeight = false;
37228     config.grid.autoWidth = false;
37229     
37230     this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37231     
37232     if (config.background) {
37233         // render grid on panel activation (if panel background)
37234         this.on('activate', function(gp) {
37235             if (!gp.grid.rendered) {
37236                 gp.grid.render(this.wrapper);
37237                 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");   
37238             }
37239         });
37240             
37241     } else {
37242         this.grid.render(this.wrapper);
37243         this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");               
37244
37245     }
37246     //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37247     // ??? needed ??? config.el = this.wrapper;
37248     
37249     
37250     
37251   
37252     // xtype created footer. - not sure if will work as we normally have to render first..
37253     if (this.footer && !this.footer.el && this.footer.xtype) {
37254         
37255         var ctr = this.grid.getView().getFooterPanel(true);
37256         this.footer.dataSource = this.grid.dataSource;
37257         this.footer = Roo.factory(this.footer, Roo);
37258         this.footer.render(ctr);
37259         
37260     }
37261     
37262     
37263     
37264     
37265      
37266 };
37267
37268 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37269     getId : function(){
37270         return this.grid.id;
37271     },
37272     
37273     /**
37274      * Returns the grid for this panel
37275      * @return {Roo.bootstrap.Table} 
37276      */
37277     getGrid : function(){
37278         return this.grid;    
37279     },
37280     
37281     setSize : function(width, height){
37282         if(!this.ignoreResize(width, height)){
37283             var grid = this.grid;
37284             var size = this.adjustForComponents(width, height);
37285             var gridel = grid.getGridEl();
37286             gridel.setSize(size.width, size.height);
37287             /*
37288             var thd = grid.getGridEl().select('thead',true).first();
37289             var tbd = grid.getGridEl().select('tbody', true).first();
37290             if (tbd) {
37291                 tbd.setSize(width, height - thd.getHeight());
37292             }
37293             */
37294             grid.autoSize();
37295         }
37296     },
37297      
37298     
37299     
37300     beforeSlide : function(){
37301         this.grid.getView().scroller.clip();
37302     },
37303     
37304     afterSlide : function(){
37305         this.grid.getView().scroller.unclip();
37306     },
37307     
37308     destroy : function(){
37309         this.grid.destroy();
37310         delete this.grid;
37311         Roo.bootstrap.panel.Grid.superclass.destroy.call(this); 
37312     }
37313 });
37314
37315 /**
37316  * @class Roo.bootstrap.panel.Nest
37317  * @extends Roo.bootstrap.panel.Content
37318  * @constructor
37319  * Create a new Panel, that can contain a layout.Border.
37320  * 
37321  * 
37322  * @param {Roo.BorderLayout} layout The layout for this panel
37323  * @param {String/Object} config A string to set only the title or a config object
37324  */
37325 Roo.bootstrap.panel.Nest = function(config)
37326 {
37327     // construct with only one argument..
37328     /* FIXME - implement nicer consturctors
37329     if (layout.layout) {
37330         config = layout;
37331         layout = config.layout;
37332         delete config.layout;
37333     }
37334     if (layout.xtype && !layout.getEl) {
37335         // then layout needs constructing..
37336         layout = Roo.factory(layout, Roo);
37337     }
37338     */
37339     
37340     config.el =  config.layout.getEl();
37341     
37342     Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37343     
37344     config.layout.monitorWindowResize = false; // turn off autosizing
37345     this.layout = config.layout;
37346     this.layout.getEl().addClass("roo-layout-nested-layout");
37347     
37348     
37349     
37350     
37351 };
37352
37353 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37354
37355     setSize : function(width, height){
37356         if(!this.ignoreResize(width, height)){
37357             var size = this.adjustForComponents(width, height);
37358             var el = this.layout.getEl();
37359             if (size.height < 1) {
37360                 el.setWidth(size.width);   
37361             } else {
37362                 el.setSize(size.width, size.height);
37363             }
37364             var touch = el.dom.offsetWidth;
37365             this.layout.layout();
37366             // ie requires a double layout on the first pass
37367             if(Roo.isIE && !this.initialized){
37368                 this.initialized = true;
37369                 this.layout.layout();
37370             }
37371         }
37372     },
37373     
37374     // activate all subpanels if not currently active..
37375     
37376     setActiveState : function(active){
37377         this.active = active;
37378         this.setActiveClass(active);
37379         
37380         if(!active){
37381             this.fireEvent("deactivate", this);
37382             return;
37383         }
37384         
37385         this.fireEvent("activate", this);
37386         // not sure if this should happen before or after..
37387         if (!this.layout) {
37388             return; // should not happen..
37389         }
37390         var reg = false;
37391         for (var r in this.layout.regions) {
37392             reg = this.layout.getRegion(r);
37393             if (reg.getActivePanel()) {
37394                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
37395                 reg.setActivePanel(reg.getActivePanel());
37396                 continue;
37397             }
37398             if (!reg.panels.length) {
37399                 continue;
37400             }
37401             reg.showPanel(reg.getPanel(0));
37402         }
37403         
37404         
37405         
37406         
37407     },
37408     
37409     /**
37410      * Returns the nested BorderLayout for this panel
37411      * @return {Roo.BorderLayout} 
37412      */
37413     getLayout : function(){
37414         return this.layout;
37415     },
37416     
37417      /**
37418      * Adds a xtype elements to the layout of the nested panel
37419      * <pre><code>
37420
37421 panel.addxtype({
37422        xtype : 'ContentPanel',
37423        region: 'west',
37424        items: [ .... ]
37425    }
37426 );
37427
37428 panel.addxtype({
37429         xtype : 'NestedLayoutPanel',
37430         region: 'west',
37431         layout: {
37432            center: { },
37433            west: { }   
37434         },
37435         items : [ ... list of content panels or nested layout panels.. ]
37436    }
37437 );
37438 </code></pre>
37439      * @param {Object} cfg Xtype definition of item to add.
37440      */
37441     addxtype : function(cfg) {
37442         return this.layout.addxtype(cfg);
37443     
37444     }
37445 });        /*
37446  * Based on:
37447  * Ext JS Library 1.1.1
37448  * Copyright(c) 2006-2007, Ext JS, LLC.
37449  *
37450  * Originally Released Under LGPL - original licence link has changed is not relivant.
37451  *
37452  * Fork - LGPL
37453  * <script type="text/javascript">
37454  */
37455 /**
37456  * @class Roo.TabPanel
37457  * @extends Roo.util.Observable
37458  * A lightweight tab container.
37459  * <br><br>
37460  * Usage:
37461  * <pre><code>
37462 // basic tabs 1, built from existing content
37463 var tabs = new Roo.TabPanel("tabs1");
37464 tabs.addTab("script", "View Script");
37465 tabs.addTab("markup", "View Markup");
37466 tabs.activate("script");
37467
37468 // more advanced tabs, built from javascript
37469 var jtabs = new Roo.TabPanel("jtabs");
37470 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37471
37472 // set up the UpdateManager
37473 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37474 var updater = tab2.getUpdateManager();
37475 updater.setDefaultUrl("ajax1.htm");
37476 tab2.on('activate', updater.refresh, updater, true);
37477
37478 // Use setUrl for Ajax loading
37479 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37480 tab3.setUrl("ajax2.htm", null, true);
37481
37482 // Disabled tab
37483 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37484 tab4.disable();
37485
37486 jtabs.activate("jtabs-1");
37487  * </code></pre>
37488  * @constructor
37489  * Create a new TabPanel.
37490  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37491  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37492  */
37493 Roo.bootstrap.panel.Tabs = function(config){
37494     /**
37495     * The container element for this TabPanel.
37496     * @type Roo.Element
37497     */
37498     this.el = Roo.get(config.el);
37499     delete config.el;
37500     if(config){
37501         if(typeof config == "boolean"){
37502             this.tabPosition = config ? "bottom" : "top";
37503         }else{
37504             Roo.apply(this, config);
37505         }
37506     }
37507     
37508     if(this.tabPosition == "bottom"){
37509         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37510         this.el.addClass("roo-tabs-bottom");
37511     }
37512     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37513     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37514     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37515     if(Roo.isIE){
37516         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37517     }
37518     if(this.tabPosition != "bottom"){
37519         /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37520          * @type Roo.Element
37521          */
37522         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37523         this.el.addClass("roo-tabs-top");
37524     }
37525     this.items = [];
37526
37527     this.bodyEl.setStyle("position", "relative");
37528
37529     this.active = null;
37530     this.activateDelegate = this.activate.createDelegate(this);
37531
37532     this.addEvents({
37533         /**
37534          * @event tabchange
37535          * Fires when the active tab changes
37536          * @param {Roo.TabPanel} this
37537          * @param {Roo.TabPanelItem} activePanel The new active tab
37538          */
37539         "tabchange": true,
37540         /**
37541          * @event beforetabchange
37542          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37543          * @param {Roo.TabPanel} this
37544          * @param {Object} e Set cancel to true on this object to cancel the tab change
37545          * @param {Roo.TabPanelItem} tab The tab being changed to
37546          */
37547         "beforetabchange" : true
37548     });
37549
37550     Roo.EventManager.onWindowResize(this.onResize, this);
37551     this.cpad = this.el.getPadding("lr");
37552     this.hiddenCount = 0;
37553
37554
37555     // toolbar on the tabbar support...
37556     if (this.toolbar) {
37557         alert("no toolbar support yet");
37558         this.toolbar  = false;
37559         /*
37560         var tcfg = this.toolbar;
37561         tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
37562         this.toolbar = new Roo.Toolbar(tcfg);
37563         if (Roo.isSafari) {
37564             var tbl = tcfg.container.child('table', true);
37565             tbl.setAttribute('width', '100%');
37566         }
37567         */
37568         
37569     }
37570    
37571
37572
37573     Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37574 };
37575
37576 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37577     /*
37578      *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37579      */
37580     tabPosition : "top",
37581     /*
37582      *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37583      */
37584     currentTabWidth : 0,
37585     /*
37586      *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37587      */
37588     minTabWidth : 40,
37589     /*
37590      *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37591      */
37592     maxTabWidth : 250,
37593     /*
37594      *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37595      */
37596     preferredTabWidth : 175,
37597     /*
37598      *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37599      */
37600     resizeTabs : false,
37601     /*
37602      *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37603      */
37604     monitorResize : true,
37605     /*
37606      *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
37607      */
37608     toolbar : false,
37609
37610     /**
37611      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37612      * @param {String} id The id of the div to use <b>or create</b>
37613      * @param {String} text The text for the tab
37614      * @param {String} content (optional) Content to put in the TabPanelItem body
37615      * @param {Boolean} closable (optional) True to create a close icon on the tab
37616      * @return {Roo.TabPanelItem} The created TabPanelItem
37617      */
37618     addTab : function(id, text, content, closable, tpl)
37619     {
37620         var item = new Roo.bootstrap.panel.TabItem({
37621             panel: this,
37622             id : id,
37623             text : text,
37624             closable : closable,
37625             tpl : tpl
37626         });
37627         this.addTabItem(item);
37628         if(content){
37629             item.setContent(content);
37630         }
37631         return item;
37632     },
37633
37634     /**
37635      * Returns the {@link Roo.TabPanelItem} with the specified id/index
37636      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37637      * @return {Roo.TabPanelItem}
37638      */
37639     getTab : function(id){
37640         return this.items[id];
37641     },
37642
37643     /**
37644      * Hides the {@link Roo.TabPanelItem} with the specified id/index
37645      * @param {String/Number} id The id or index of the TabPanelItem to hide.
37646      */
37647     hideTab : function(id){
37648         var t = this.items[id];
37649         if(!t.isHidden()){
37650            t.setHidden(true);
37651            this.hiddenCount++;
37652            this.autoSizeTabs();
37653         }
37654     },
37655
37656     /**
37657      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37658      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37659      */
37660     unhideTab : function(id){
37661         var t = this.items[id];
37662         if(t.isHidden()){
37663            t.setHidden(false);
37664            this.hiddenCount--;
37665            this.autoSizeTabs();
37666         }
37667     },
37668
37669     /**
37670      * Adds an existing {@link Roo.TabPanelItem}.
37671      * @param {Roo.TabPanelItem} item The TabPanelItem to add
37672      */
37673     addTabItem : function(item){
37674         this.items[item.id] = item;
37675         this.items.push(item);
37676       //  if(this.resizeTabs){
37677     //       item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37678   //         this.autoSizeTabs();
37679 //        }else{
37680 //            item.autoSize();
37681        // }
37682     },
37683
37684     /**
37685      * Removes a {@link Roo.TabPanelItem}.
37686      * @param {String/Number} id The id or index of the TabPanelItem to remove.
37687      */
37688     removeTab : function(id){
37689         var items = this.items;
37690         var tab = items[id];
37691         if(!tab) { return; }
37692         var index = items.indexOf(tab);
37693         if(this.active == tab && items.length > 1){
37694             var newTab = this.getNextAvailable(index);
37695             if(newTab) {
37696                 newTab.activate();
37697             }
37698         }
37699         this.stripEl.dom.removeChild(tab.pnode.dom);
37700         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37701             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37702         }
37703         items.splice(index, 1);
37704         delete this.items[tab.id];
37705         tab.fireEvent("close", tab);
37706         tab.purgeListeners();
37707         this.autoSizeTabs();
37708     },
37709
37710     getNextAvailable : function(start){
37711         var items = this.items;
37712         var index = start;
37713         // look for a next tab that will slide over to
37714         // replace the one being removed
37715         while(index < items.length){
37716             var item = items[++index];
37717             if(item && !item.isHidden()){
37718                 return item;
37719             }
37720         }
37721         // if one isn't found select the previous tab (on the left)
37722         index = start;
37723         while(index >= 0){
37724             var item = items[--index];
37725             if(item && !item.isHidden()){
37726                 return item;
37727             }
37728         }
37729         return null;
37730     },
37731
37732     /**
37733      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37734      * @param {String/Number} id The id or index of the TabPanelItem to disable.
37735      */
37736     disableTab : function(id){
37737         var tab = this.items[id];
37738         if(tab && this.active != tab){
37739             tab.disable();
37740         }
37741     },
37742
37743     /**
37744      * Enables a {@link Roo.TabPanelItem} that is disabled.
37745      * @param {String/Number} id The id or index of the TabPanelItem to enable.
37746      */
37747     enableTab : function(id){
37748         var tab = this.items[id];
37749         tab.enable();
37750     },
37751
37752     /**
37753      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37754      * @param {String/Number} id The id or index of the TabPanelItem to activate.
37755      * @return {Roo.TabPanelItem} The TabPanelItem.
37756      */
37757     activate : function(id){
37758         var tab = this.items[id];
37759         if(!tab){
37760             return null;
37761         }
37762         if(tab == this.active || tab.disabled){
37763             return tab;
37764         }
37765         var e = {};
37766         this.fireEvent("beforetabchange", this, e, tab);
37767         if(e.cancel !== true && !tab.disabled){
37768             if(this.active){
37769                 this.active.hide();
37770             }
37771             this.active = this.items[id];
37772             this.active.show();
37773             this.fireEvent("tabchange", this, this.active);
37774         }
37775         return tab;
37776     },
37777
37778     /**
37779      * Gets the active {@link Roo.TabPanelItem}.
37780      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37781      */
37782     getActiveTab : function(){
37783         return this.active;
37784     },
37785
37786     /**
37787      * Updates the tab body element to fit the height of the container element
37788      * for overflow scrolling
37789      * @param {Number} targetHeight (optional) Override the starting height from the elements height
37790      */
37791     syncHeight : function(targetHeight){
37792         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37793         var bm = this.bodyEl.getMargins();
37794         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37795         this.bodyEl.setHeight(newHeight);
37796         return newHeight;
37797     },
37798
37799     onResize : function(){
37800         if(this.monitorResize){
37801             this.autoSizeTabs();
37802         }
37803     },
37804
37805     /**
37806      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37807      */
37808     beginUpdate : function(){
37809         this.updating = true;
37810     },
37811
37812     /**
37813      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37814      */
37815     endUpdate : function(){
37816         this.updating = false;
37817         this.autoSizeTabs();
37818     },
37819
37820     /**
37821      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37822      */
37823     autoSizeTabs : function(){
37824         var count = this.items.length;
37825         var vcount = count - this.hiddenCount;
37826         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37827             return;
37828         }
37829         var w = Math.max(this.el.getWidth() - this.cpad, 10);
37830         var availWidth = Math.floor(w / vcount);
37831         var b = this.stripBody;
37832         if(b.getWidth() > w){
37833             var tabs = this.items;
37834             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37835             if(availWidth < this.minTabWidth){
37836                 /*if(!this.sleft){    // incomplete scrolling code
37837                     this.createScrollButtons();
37838                 }
37839                 this.showScroll();
37840                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37841             }
37842         }else{
37843             if(this.currentTabWidth < this.preferredTabWidth){
37844                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37845             }
37846         }
37847     },
37848
37849     /**
37850      * Returns the number of tabs in this TabPanel.
37851      * @return {Number}
37852      */
37853      getCount : function(){
37854          return this.items.length;
37855      },
37856
37857     /**
37858      * Resizes all the tabs to the passed width
37859      * @param {Number} The new width
37860      */
37861     setTabWidth : function(width){
37862         this.currentTabWidth = width;
37863         for(var i = 0, len = this.items.length; i < len; i++) {
37864                 if(!this.items[i].isHidden()) {
37865                 this.items[i].setWidth(width);
37866             }
37867         }
37868     },
37869
37870     /**
37871      * Destroys this TabPanel
37872      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37873      */
37874     destroy : function(removeEl){
37875         Roo.EventManager.removeResizeListener(this.onResize, this);
37876         for(var i = 0, len = this.items.length; i < len; i++){
37877             this.items[i].purgeListeners();
37878         }
37879         if(removeEl === true){
37880             this.el.update("");
37881             this.el.remove();
37882         }
37883     },
37884     
37885     createStrip : function(container)
37886     {
37887         var strip = document.createElement("nav");
37888         strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37889         container.appendChild(strip);
37890         return strip;
37891     },
37892     
37893     createStripList : function(strip)
37894     {
37895         // div wrapper for retard IE
37896         // returns the "tr" element.
37897         strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37898         //'<div class="x-tabs-strip-wrap">'+
37899           //  '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37900           //  '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37901         return strip.firstChild; //.firstChild.firstChild.firstChild;
37902     },
37903     createBody : function(container)
37904     {
37905         var body = document.createElement("div");
37906         Roo.id(body, "tab-body");
37907         //Roo.fly(body).addClass("x-tabs-body");
37908         Roo.fly(body).addClass("tab-content");
37909         container.appendChild(body);
37910         return body;
37911     },
37912     createItemBody :function(bodyEl, id){
37913         var body = Roo.getDom(id);
37914         if(!body){
37915             body = document.createElement("div");
37916             body.id = id;
37917         }
37918         //Roo.fly(body).addClass("x-tabs-item-body");
37919         Roo.fly(body).addClass("tab-pane");
37920          bodyEl.insertBefore(body, bodyEl.firstChild);
37921         return body;
37922     },
37923     /** @private */
37924     createStripElements :  function(stripEl, text, closable, tpl)
37925     {
37926         var td = document.createElement("li"); // was td..
37927         
37928         
37929         //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37930         
37931         
37932         stripEl.appendChild(td);
37933         /*if(closable){
37934             td.className = "x-tabs-closable";
37935             if(!this.closeTpl){
37936                 this.closeTpl = new Roo.Template(
37937                    '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37938                    '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37939                    '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
37940                 );
37941             }
37942             var el = this.closeTpl.overwrite(td, {"text": text});
37943             var close = el.getElementsByTagName("div")[0];
37944             var inner = el.getElementsByTagName("em")[0];
37945             return {"el": el, "close": close, "inner": inner};
37946         } else {
37947         */
37948         // not sure what this is..
37949 //            if(!this.tabTpl){
37950                 //this.tabTpl = new Roo.Template(
37951                 //   '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37952                 //   '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37953                 //);
37954 //                this.tabTpl = new Roo.Template(
37955 //                   '<a href="#">' +
37956 //                   '<span unselectable="on"' +
37957 //                            (this.disableTooltips ? '' : ' title="{text}"') +
37958 //                            ' >{text}</span></a>'
37959 //                );
37960 //                
37961 //            }
37962
37963
37964             var template = tpl || this.tabTpl || false;
37965             
37966             if(!template){
37967                 
37968                 template = new Roo.Template(
37969                    '<a href="#">' +
37970                    '<span unselectable="on"' +
37971                             (this.disableTooltips ? '' : ' title="{text}"') +
37972                             ' >{text}</span></a>'
37973                 );
37974             }
37975             
37976             switch (typeof(template)) {
37977                 case 'object' :
37978                     break;
37979                 case 'string' :
37980                     template = new Roo.Template(template);
37981                     break;
37982                 default :
37983                     break;
37984             }
37985             
37986             var el = template.overwrite(td, {"text": text});
37987             
37988             var inner = el.getElementsByTagName("span")[0];
37989             
37990             return {"el": el, "inner": inner};
37991             
37992     }
37993         
37994     
37995 });
37996
37997 /**
37998  * @class Roo.TabPanelItem
37999  * @extends Roo.util.Observable
38000  * Represents an individual item (tab plus body) in a TabPanel.
38001  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38002  * @param {String} id The id of this TabPanelItem
38003  * @param {String} text The text for the tab of this TabPanelItem
38004  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38005  */
38006 Roo.bootstrap.panel.TabItem = function(config){
38007     /**
38008      * The {@link Roo.TabPanel} this TabPanelItem belongs to
38009      * @type Roo.TabPanel
38010      */
38011     this.tabPanel = config.panel;
38012     /**
38013      * The id for this TabPanelItem
38014      * @type String
38015      */
38016     this.id = config.id;
38017     /** @private */
38018     this.disabled = false;
38019     /** @private */
38020     this.text = config.text;
38021     /** @private */
38022     this.loaded = false;
38023     this.closable = config.closable;
38024
38025     /**
38026      * The body element for this TabPanelItem.
38027      * @type Roo.Element
38028      */
38029     this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38030     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38031     this.bodyEl.setStyle("display", "block");
38032     this.bodyEl.setStyle("zoom", "1");
38033     //this.hideAction();
38034
38035     var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38036     /** @private */
38037     this.el = Roo.get(els.el);
38038     this.inner = Roo.get(els.inner, true);
38039     this.textEl = Roo.get(this.el.dom.firstChild, true);
38040     this.pnode = Roo.get(els.el.parentNode, true);
38041 //    this.el.on("mousedown", this.onTabMouseDown, this);
38042     this.el.on("click", this.onTabClick, this);
38043     /** @private */
38044     if(config.closable){
38045         var c = Roo.get(els.close, true);
38046         c.dom.title = this.closeText;
38047         c.addClassOnOver("close-over");
38048         c.on("click", this.closeClick, this);
38049      }
38050
38051     this.addEvents({
38052          /**
38053          * @event activate
38054          * Fires when this tab becomes the active tab.
38055          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38056          * @param {Roo.TabPanelItem} this
38057          */
38058         "activate": true,
38059         /**
38060          * @event beforeclose
38061          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38062          * @param {Roo.TabPanelItem} this
38063          * @param {Object} e Set cancel to true on this object to cancel the close.
38064          */
38065         "beforeclose": true,
38066         /**
38067          * @event close
38068          * Fires when this tab is closed.
38069          * @param {Roo.TabPanelItem} this
38070          */
38071          "close": true,
38072         /**
38073          * @event deactivate
38074          * Fires when this tab is no longer the active tab.
38075          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38076          * @param {Roo.TabPanelItem} this
38077          */
38078          "deactivate" : true
38079     });
38080     this.hidden = false;
38081
38082     Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38083 };
38084
38085 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38086            {
38087     purgeListeners : function(){
38088        Roo.util.Observable.prototype.purgeListeners.call(this);
38089        this.el.removeAllListeners();
38090     },
38091     /**
38092      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38093      */
38094     show : function(){
38095         this.pnode.addClass("active");
38096         this.showAction();
38097         if(Roo.isOpera){
38098             this.tabPanel.stripWrap.repaint();
38099         }
38100         this.fireEvent("activate", this.tabPanel, this);
38101     },
38102
38103     /**
38104      * Returns true if this tab is the active tab.
38105      * @return {Boolean}
38106      */
38107     isActive : function(){
38108         return this.tabPanel.getActiveTab() == this;
38109     },
38110
38111     /**
38112      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38113      */
38114     hide : function(){
38115         this.pnode.removeClass("active");
38116         this.hideAction();
38117         this.fireEvent("deactivate", this.tabPanel, this);
38118     },
38119
38120     hideAction : function(){
38121         this.bodyEl.hide();
38122         this.bodyEl.setStyle("position", "absolute");
38123         this.bodyEl.setLeft("-20000px");
38124         this.bodyEl.setTop("-20000px");
38125     },
38126
38127     showAction : function(){
38128         this.bodyEl.setStyle("position", "relative");
38129         this.bodyEl.setTop("");
38130         this.bodyEl.setLeft("");
38131         this.bodyEl.show();
38132     },
38133
38134     /**
38135      * Set the tooltip for the tab.
38136      * @param {String} tooltip The tab's tooltip
38137      */
38138     setTooltip : function(text){
38139         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38140             this.textEl.dom.qtip = text;
38141             this.textEl.dom.removeAttribute('title');
38142         }else{
38143             this.textEl.dom.title = text;
38144         }
38145     },
38146
38147     onTabClick : function(e){
38148         e.preventDefault();
38149         this.tabPanel.activate(this.id);
38150     },
38151
38152     onTabMouseDown : function(e){
38153         e.preventDefault();
38154         this.tabPanel.activate(this.id);
38155     },
38156 /*
38157     getWidth : function(){
38158         return this.inner.getWidth();
38159     },
38160
38161     setWidth : function(width){
38162         var iwidth = width - this.pnode.getPadding("lr");
38163         this.inner.setWidth(iwidth);
38164         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38165         this.pnode.setWidth(width);
38166     },
38167 */
38168     /**
38169      * Show or hide the tab
38170      * @param {Boolean} hidden True to hide or false to show.
38171      */
38172     setHidden : function(hidden){
38173         this.hidden = hidden;
38174         this.pnode.setStyle("display", hidden ? "none" : "");
38175     },
38176
38177     /**
38178      * Returns true if this tab is "hidden"
38179      * @return {Boolean}
38180      */
38181     isHidden : function(){
38182         return this.hidden;
38183     },
38184
38185     /**
38186      * Returns the text for this tab
38187      * @return {String}
38188      */
38189     getText : function(){
38190         return this.text;
38191     },
38192     /*
38193     autoSize : function(){
38194         //this.el.beginMeasure();
38195         this.textEl.setWidth(1);
38196         /*
38197          *  #2804 [new] Tabs in Roojs
38198          *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38199          */
38200         //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38201         //this.el.endMeasure();
38202     //},
38203
38204     /**
38205      * Sets the text for the tab (Note: this also sets the tooltip text)
38206      * @param {String} text The tab's text and tooltip
38207      */
38208     setText : function(text){
38209         this.text = text;
38210         this.textEl.update(text);
38211         this.setTooltip(text);
38212         //if(!this.tabPanel.resizeTabs){
38213         //    this.autoSize();
38214         //}
38215     },
38216     /**
38217      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38218      */
38219     activate : function(){
38220         this.tabPanel.activate(this.id);
38221     },
38222
38223     /**
38224      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38225      */
38226     disable : function(){
38227         if(this.tabPanel.active != this){
38228             this.disabled = true;
38229             this.pnode.addClass("disabled");
38230         }
38231     },
38232
38233     /**
38234      * Enables this TabPanelItem if it was previously disabled.
38235      */
38236     enable : function(){
38237         this.disabled = false;
38238         this.pnode.removeClass("disabled");
38239     },
38240
38241     /**
38242      * Sets the content for this TabPanelItem.
38243      * @param {String} content The content
38244      * @param {Boolean} loadScripts true to look for and load scripts
38245      */
38246     setContent : function(content, loadScripts){
38247         this.bodyEl.update(content, loadScripts);
38248     },
38249
38250     /**
38251      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38252      * @return {Roo.UpdateManager} The UpdateManager
38253      */
38254     getUpdateManager : function(){
38255         return this.bodyEl.getUpdateManager();
38256     },
38257
38258     /**
38259      * Set a URL to be used to load the content for this TabPanelItem.
38260      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38261      * @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)
38262      * @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)
38263      * @return {Roo.UpdateManager} The UpdateManager
38264      */
38265     setUrl : function(url, params, loadOnce){
38266         if(this.refreshDelegate){
38267             this.un('activate', this.refreshDelegate);
38268         }
38269         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38270         this.on("activate", this.refreshDelegate);
38271         return this.bodyEl.getUpdateManager();
38272     },
38273
38274     /** @private */
38275     _handleRefresh : function(url, params, loadOnce){
38276         if(!loadOnce || !this.loaded){
38277             var updater = this.bodyEl.getUpdateManager();
38278             updater.update(url, params, this._setLoaded.createDelegate(this));
38279         }
38280     },
38281
38282     /**
38283      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
38284      *   Will fail silently if the setUrl method has not been called.
38285      *   This does not activate the panel, just updates its content.
38286      */
38287     refresh : function(){
38288         if(this.refreshDelegate){
38289            this.loaded = false;
38290            this.refreshDelegate();
38291         }
38292     },
38293
38294     /** @private */
38295     _setLoaded : function(){
38296         this.loaded = true;
38297     },
38298
38299     /** @private */
38300     closeClick : function(e){
38301         var o = {};
38302         e.stopEvent();
38303         this.fireEvent("beforeclose", this, o);
38304         if(o.cancel !== true){
38305             this.tabPanel.removeTab(this.id);
38306         }
38307     },
38308     /**
38309      * The text displayed in the tooltip for the close icon.
38310      * @type String
38311      */
38312     closeText : "Close this tab"
38313 });
38314 /**
38315 *    This script refer to:
38316 *    Title: International Telephone Input
38317 *    Author: Jack O'Connor
38318 *    Code version:  v12.1.12
38319 *    Availability: https://github.com/jackocnr/intl-tel-input.git
38320 **/
38321
38322 Roo.bootstrap.PhoneInputData = function() {
38323     var d = [
38324       [
38325         "Afghanistan (‫افغانستان‬‎)",
38326         "af",
38327         "93"
38328       ],
38329       [
38330         "Albania (Shqipëri)",
38331         "al",
38332         "355"
38333       ],
38334       [
38335         "Algeria (‫الجزائر‬‎)",
38336         "dz",
38337         "213"
38338       ],
38339       [
38340         "American Samoa",
38341         "as",
38342         "1684"
38343       ],
38344       [
38345         "Andorra",
38346         "ad",
38347         "376"
38348       ],
38349       [
38350         "Angola",
38351         "ao",
38352         "244"
38353       ],
38354       [
38355         "Anguilla",
38356         "ai",
38357         "1264"
38358       ],
38359       [
38360         "Antigua and Barbuda",
38361         "ag",
38362         "1268"
38363       ],
38364       [
38365         "Argentina",
38366         "ar",
38367         "54"
38368       ],
38369       [
38370         "Armenia (Հայաստան)",
38371         "am",
38372         "374"
38373       ],
38374       [
38375         "Aruba",
38376         "aw",
38377         "297"
38378       ],
38379       [
38380         "Australia",
38381         "au",
38382         "61",
38383         0
38384       ],
38385       [
38386         "Austria (Österreich)",
38387         "at",
38388         "43"
38389       ],
38390       [
38391         "Azerbaijan (Azərbaycan)",
38392         "az",
38393         "994"
38394       ],
38395       [
38396         "Bahamas",
38397         "bs",
38398         "1242"
38399       ],
38400       [
38401         "Bahrain (‫البحرين‬‎)",
38402         "bh",
38403         "973"
38404       ],
38405       [
38406         "Bangladesh (বাংলাদেশ)",
38407         "bd",
38408         "880"
38409       ],
38410       [
38411         "Barbados",
38412         "bb",
38413         "1246"
38414       ],
38415       [
38416         "Belarus (Беларусь)",
38417         "by",
38418         "375"
38419       ],
38420       [
38421         "Belgium (België)",
38422         "be",
38423         "32"
38424       ],
38425       [
38426         "Belize",
38427         "bz",
38428         "501"
38429       ],
38430       [
38431         "Benin (Bénin)",
38432         "bj",
38433         "229"
38434       ],
38435       [
38436         "Bermuda",
38437         "bm",
38438         "1441"
38439       ],
38440       [
38441         "Bhutan (འབྲུག)",
38442         "bt",
38443         "975"
38444       ],
38445       [
38446         "Bolivia",
38447         "bo",
38448         "591"
38449       ],
38450       [
38451         "Bosnia and Herzegovina (Босна и Херцеговина)",
38452         "ba",
38453         "387"
38454       ],
38455       [
38456         "Botswana",
38457         "bw",
38458         "267"
38459       ],
38460       [
38461         "Brazil (Brasil)",
38462         "br",
38463         "55"
38464       ],
38465       [
38466         "British Indian Ocean Territory",
38467         "io",
38468         "246"
38469       ],
38470       [
38471         "British Virgin Islands",
38472         "vg",
38473         "1284"
38474       ],
38475       [
38476         "Brunei",
38477         "bn",
38478         "673"
38479       ],
38480       [
38481         "Bulgaria (България)",
38482         "bg",
38483         "359"
38484       ],
38485       [
38486         "Burkina Faso",
38487         "bf",
38488         "226"
38489       ],
38490       [
38491         "Burundi (Uburundi)",
38492         "bi",
38493         "257"
38494       ],
38495       [
38496         "Cambodia (កម្ពុជា)",
38497         "kh",
38498         "855"
38499       ],
38500       [
38501         "Cameroon (Cameroun)",
38502         "cm",
38503         "237"
38504       ],
38505       [
38506         "Canada",
38507         "ca",
38508         "1",
38509         1,
38510         ["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"]
38511       ],
38512       [
38513         "Cape Verde (Kabu Verdi)",
38514         "cv",
38515         "238"
38516       ],
38517       [
38518         "Caribbean Netherlands",
38519         "bq",
38520         "599",
38521         1
38522       ],
38523       [
38524         "Cayman Islands",
38525         "ky",
38526         "1345"
38527       ],
38528       [
38529         "Central African Republic (République centrafricaine)",
38530         "cf",
38531         "236"
38532       ],
38533       [
38534         "Chad (Tchad)",
38535         "td",
38536         "235"
38537       ],
38538       [
38539         "Chile",
38540         "cl",
38541         "56"
38542       ],
38543       [
38544         "China (中国)",
38545         "cn",
38546         "86"
38547       ],
38548       [
38549         "Christmas Island",
38550         "cx",
38551         "61",
38552         2
38553       ],
38554       [
38555         "Cocos (Keeling) Islands",
38556         "cc",
38557         "61",
38558         1
38559       ],
38560       [
38561         "Colombia",
38562         "co",
38563         "57"
38564       ],
38565       [
38566         "Comoros (‫جزر القمر‬‎)",
38567         "km",
38568         "269"
38569       ],
38570       [
38571         "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38572         "cd",
38573         "243"
38574       ],
38575       [
38576         "Congo (Republic) (Congo-Brazzaville)",
38577         "cg",
38578         "242"
38579       ],
38580       [
38581         "Cook Islands",
38582         "ck",
38583         "682"
38584       ],
38585       [
38586         "Costa Rica",
38587         "cr",
38588         "506"
38589       ],
38590       [
38591         "Côte d’Ivoire",
38592         "ci",
38593         "225"
38594       ],
38595       [
38596         "Croatia (Hrvatska)",
38597         "hr",
38598         "385"
38599       ],
38600       [
38601         "Cuba",
38602         "cu",
38603         "53"
38604       ],
38605       [
38606         "Curaçao",
38607         "cw",
38608         "599",
38609         0
38610       ],
38611       [
38612         "Cyprus (Κύπρος)",
38613         "cy",
38614         "357"
38615       ],
38616       [
38617         "Czech Republic (Česká republika)",
38618         "cz",
38619         "420"
38620       ],
38621       [
38622         "Denmark (Danmark)",
38623         "dk",
38624         "45"
38625       ],
38626       [
38627         "Djibouti",
38628         "dj",
38629         "253"
38630       ],
38631       [
38632         "Dominica",
38633         "dm",
38634         "1767"
38635       ],
38636       [
38637         "Dominican Republic (República Dominicana)",
38638         "do",
38639         "1",
38640         2,
38641         ["809", "829", "849"]
38642       ],
38643       [
38644         "Ecuador",
38645         "ec",
38646         "593"
38647       ],
38648       [
38649         "Egypt (‫مصر‬‎)",
38650         "eg",
38651         "20"
38652       ],
38653       [
38654         "El Salvador",
38655         "sv",
38656         "503"
38657       ],
38658       [
38659         "Equatorial Guinea (Guinea Ecuatorial)",
38660         "gq",
38661         "240"
38662       ],
38663       [
38664         "Eritrea",
38665         "er",
38666         "291"
38667       ],
38668       [
38669         "Estonia (Eesti)",
38670         "ee",
38671         "372"
38672       ],
38673       [
38674         "Ethiopia",
38675         "et",
38676         "251"
38677       ],
38678       [
38679         "Falkland Islands (Islas Malvinas)",
38680         "fk",
38681         "500"
38682       ],
38683       [
38684         "Faroe Islands (Føroyar)",
38685         "fo",
38686         "298"
38687       ],
38688       [
38689         "Fiji",
38690         "fj",
38691         "679"
38692       ],
38693       [
38694         "Finland (Suomi)",
38695         "fi",
38696         "358",
38697         0
38698       ],
38699       [
38700         "France",
38701         "fr",
38702         "33"
38703       ],
38704       [
38705         "French Guiana (Guyane française)",
38706         "gf",
38707         "594"
38708       ],
38709       [
38710         "French Polynesia (Polynésie française)",
38711         "pf",
38712         "689"
38713       ],
38714       [
38715         "Gabon",
38716         "ga",
38717         "241"
38718       ],
38719       [
38720         "Gambia",
38721         "gm",
38722         "220"
38723       ],
38724       [
38725         "Georgia (საქართველო)",
38726         "ge",
38727         "995"
38728       ],
38729       [
38730         "Germany (Deutschland)",
38731         "de",
38732         "49"
38733       ],
38734       [
38735         "Ghana (Gaana)",
38736         "gh",
38737         "233"
38738       ],
38739       [
38740         "Gibraltar",
38741         "gi",
38742         "350"
38743       ],
38744       [
38745         "Greece (Ελλάδα)",
38746         "gr",
38747         "30"
38748       ],
38749       [
38750         "Greenland (Kalaallit Nunaat)",
38751         "gl",
38752         "299"
38753       ],
38754       [
38755         "Grenada",
38756         "gd",
38757         "1473"
38758       ],
38759       [
38760         "Guadeloupe",
38761         "gp",
38762         "590",
38763         0
38764       ],
38765       [
38766         "Guam",
38767         "gu",
38768         "1671"
38769       ],
38770       [
38771         "Guatemala",
38772         "gt",
38773         "502"
38774       ],
38775       [
38776         "Guernsey",
38777         "gg",
38778         "44",
38779         1
38780       ],
38781       [
38782         "Guinea (Guinée)",
38783         "gn",
38784         "224"
38785       ],
38786       [
38787         "Guinea-Bissau (Guiné Bissau)",
38788         "gw",
38789         "245"
38790       ],
38791       [
38792         "Guyana",
38793         "gy",
38794         "592"
38795       ],
38796       [
38797         "Haiti",
38798         "ht",
38799         "509"
38800       ],
38801       [
38802         "Honduras",
38803         "hn",
38804         "504"
38805       ],
38806       [
38807         "Hong Kong (香港)",
38808         "hk",
38809         "852"
38810       ],
38811       [
38812         "Hungary (Magyarország)",
38813         "hu",
38814         "36"
38815       ],
38816       [
38817         "Iceland (Ísland)",
38818         "is",
38819         "354"
38820       ],
38821       [
38822         "India (भारत)",
38823         "in",
38824         "91"
38825       ],
38826       [
38827         "Indonesia",
38828         "id",
38829         "62"
38830       ],
38831       [
38832         "Iran (‫ایران‬‎)",
38833         "ir",
38834         "98"
38835       ],
38836       [
38837         "Iraq (‫العراق‬‎)",
38838         "iq",
38839         "964"
38840       ],
38841       [
38842         "Ireland",
38843         "ie",
38844         "353"
38845       ],
38846       [
38847         "Isle of Man",
38848         "im",
38849         "44",
38850         2
38851       ],
38852       [
38853         "Israel (‫ישראל‬‎)",
38854         "il",
38855         "972"
38856       ],
38857       [
38858         "Italy (Italia)",
38859         "it",
38860         "39",
38861         0
38862       ],
38863       [
38864         "Jamaica",
38865         "jm",
38866         "1876"
38867       ],
38868       [
38869         "Japan (日本)",
38870         "jp",
38871         "81"
38872       ],
38873       [
38874         "Jersey",
38875         "je",
38876         "44",
38877         3
38878       ],
38879       [
38880         "Jordan (‫الأردن‬‎)",
38881         "jo",
38882         "962"
38883       ],
38884       [
38885         "Kazakhstan (Казахстан)",
38886         "kz",
38887         "7",
38888         1
38889       ],
38890       [
38891         "Kenya",
38892         "ke",
38893         "254"
38894       ],
38895       [
38896         "Kiribati",
38897         "ki",
38898         "686"
38899       ],
38900       [
38901         "Kosovo",
38902         "xk",
38903         "383"
38904       ],
38905       [
38906         "Kuwait (‫الكويت‬‎)",
38907         "kw",
38908         "965"
38909       ],
38910       [
38911         "Kyrgyzstan (Кыргызстан)",
38912         "kg",
38913         "996"
38914       ],
38915       [
38916         "Laos (ລາວ)",
38917         "la",
38918         "856"
38919       ],
38920       [
38921         "Latvia (Latvija)",
38922         "lv",
38923         "371"
38924       ],
38925       [
38926         "Lebanon (‫لبنان‬‎)",
38927         "lb",
38928         "961"
38929       ],
38930       [
38931         "Lesotho",
38932         "ls",
38933         "266"
38934       ],
38935       [
38936         "Liberia",
38937         "lr",
38938         "231"
38939       ],
38940       [
38941         "Libya (‫ليبيا‬‎)",
38942         "ly",
38943         "218"
38944       ],
38945       [
38946         "Liechtenstein",
38947         "li",
38948         "423"
38949       ],
38950       [
38951         "Lithuania (Lietuva)",
38952         "lt",
38953         "370"
38954       ],
38955       [
38956         "Luxembourg",
38957         "lu",
38958         "352"
38959       ],
38960       [
38961         "Macau (澳門)",
38962         "mo",
38963         "853"
38964       ],
38965       [
38966         "Macedonia (FYROM) (Македонија)",
38967         "mk",
38968         "389"
38969       ],
38970       [
38971         "Madagascar (Madagasikara)",
38972         "mg",
38973         "261"
38974       ],
38975       [
38976         "Malawi",
38977         "mw",
38978         "265"
38979       ],
38980       [
38981         "Malaysia",
38982         "my",
38983         "60"
38984       ],
38985       [
38986         "Maldives",
38987         "mv",
38988         "960"
38989       ],
38990       [
38991         "Mali",
38992         "ml",
38993         "223"
38994       ],
38995       [
38996         "Malta",
38997         "mt",
38998         "356"
38999       ],
39000       [
39001         "Marshall Islands",
39002         "mh",
39003         "692"
39004       ],
39005       [
39006         "Martinique",
39007         "mq",
39008         "596"
39009       ],
39010       [
39011         "Mauritania (‫موريتانيا‬‎)",
39012         "mr",
39013         "222"
39014       ],
39015       [
39016         "Mauritius (Moris)",
39017         "mu",
39018         "230"
39019       ],
39020       [
39021         "Mayotte",
39022         "yt",
39023         "262",
39024         1
39025       ],
39026       [
39027         "Mexico (México)",
39028         "mx",
39029         "52"
39030       ],
39031       [
39032         "Micronesia",
39033         "fm",
39034         "691"
39035       ],
39036       [
39037         "Moldova (Republica Moldova)",
39038         "md",
39039         "373"
39040       ],
39041       [
39042         "Monaco",
39043         "mc",
39044         "377"
39045       ],
39046       [
39047         "Mongolia (Монгол)",
39048         "mn",
39049         "976"
39050       ],
39051       [
39052         "Montenegro (Crna Gora)",
39053         "me",
39054         "382"
39055       ],
39056       [
39057         "Montserrat",
39058         "ms",
39059         "1664"
39060       ],
39061       [
39062         "Morocco (‫المغرب‬‎)",
39063         "ma",
39064         "212",
39065         0
39066       ],
39067       [
39068         "Mozambique (Moçambique)",
39069         "mz",
39070         "258"
39071       ],
39072       [
39073         "Myanmar (Burma) (မြန်မာ)",
39074         "mm",
39075         "95"
39076       ],
39077       [
39078         "Namibia (Namibië)",
39079         "na",
39080         "264"
39081       ],
39082       [
39083         "Nauru",
39084         "nr",
39085         "674"
39086       ],
39087       [
39088         "Nepal (नेपाल)",
39089         "np",
39090         "977"
39091       ],
39092       [
39093         "Netherlands (Nederland)",
39094         "nl",
39095         "31"
39096       ],
39097       [
39098         "New Caledonia (Nouvelle-Calédonie)",
39099         "nc",
39100         "687"
39101       ],
39102       [
39103         "New Zealand",
39104         "nz",
39105         "64"
39106       ],
39107       [
39108         "Nicaragua",
39109         "ni",
39110         "505"
39111       ],
39112       [
39113         "Niger (Nijar)",
39114         "ne",
39115         "227"
39116       ],
39117       [
39118         "Nigeria",
39119         "ng",
39120         "234"
39121       ],
39122       [
39123         "Niue",
39124         "nu",
39125         "683"
39126       ],
39127       [
39128         "Norfolk Island",
39129         "nf",
39130         "672"
39131       ],
39132       [
39133         "North Korea (조선 민주주의 인민 공화국)",
39134         "kp",
39135         "850"
39136       ],
39137       [
39138         "Northern Mariana Islands",
39139         "mp",
39140         "1670"
39141       ],
39142       [
39143         "Norway (Norge)",
39144         "no",
39145         "47",
39146         0
39147       ],
39148       [
39149         "Oman (‫عُمان‬‎)",
39150         "om",
39151         "968"
39152       ],
39153       [
39154         "Pakistan (‫پاکستان‬‎)",
39155         "pk",
39156         "92"
39157       ],
39158       [
39159         "Palau",
39160         "pw",
39161         "680"
39162       ],
39163       [
39164         "Palestine (‫فلسطين‬‎)",
39165         "ps",
39166         "970"
39167       ],
39168       [
39169         "Panama (Panamá)",
39170         "pa",
39171         "507"
39172       ],
39173       [
39174         "Papua New Guinea",
39175         "pg",
39176         "675"
39177       ],
39178       [
39179         "Paraguay",
39180         "py",
39181         "595"
39182       ],
39183       [
39184         "Peru (Perú)",
39185         "pe",
39186         "51"
39187       ],
39188       [
39189         "Philippines",
39190         "ph",
39191         "63"
39192       ],
39193       [
39194         "Poland (Polska)",
39195         "pl",
39196         "48"
39197       ],
39198       [
39199         "Portugal",
39200         "pt",
39201         "351"
39202       ],
39203       [
39204         "Puerto Rico",
39205         "pr",
39206         "1",
39207         3,
39208         ["787", "939"]
39209       ],
39210       [
39211         "Qatar (‫قطر‬‎)",
39212         "qa",
39213         "974"
39214       ],
39215       [
39216         "Réunion (La Réunion)",
39217         "re",
39218         "262",
39219         0
39220       ],
39221       [
39222         "Romania (România)",
39223         "ro",
39224         "40"
39225       ],
39226       [
39227         "Russia (Россия)",
39228         "ru",
39229         "7",
39230         0
39231       ],
39232       [
39233         "Rwanda",
39234         "rw",
39235         "250"
39236       ],
39237       [
39238         "Saint Barthélemy",
39239         "bl",
39240         "590",
39241         1
39242       ],
39243       [
39244         "Saint Helena",
39245         "sh",
39246         "290"
39247       ],
39248       [
39249         "Saint Kitts and Nevis",
39250         "kn",
39251         "1869"
39252       ],
39253       [
39254         "Saint Lucia",
39255         "lc",
39256         "1758"
39257       ],
39258       [
39259         "Saint Martin (Saint-Martin (partie française))",
39260         "mf",
39261         "590",
39262         2
39263       ],
39264       [
39265         "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39266         "pm",
39267         "508"
39268       ],
39269       [
39270         "Saint Vincent and the Grenadines",
39271         "vc",
39272         "1784"
39273       ],
39274       [
39275         "Samoa",
39276         "ws",
39277         "685"
39278       ],
39279       [
39280         "San Marino",
39281         "sm",
39282         "378"
39283       ],
39284       [
39285         "São Tomé and Príncipe (São Tomé e Príncipe)",
39286         "st",
39287         "239"
39288       ],
39289       [
39290         "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
39291         "sa",
39292         "966"
39293       ],
39294       [
39295         "Senegal (Sénégal)",
39296         "sn",
39297         "221"
39298       ],
39299       [
39300         "Serbia (Србија)",
39301         "rs",
39302         "381"
39303       ],
39304       [
39305         "Seychelles",
39306         "sc",
39307         "248"
39308       ],
39309       [
39310         "Sierra Leone",
39311         "sl",
39312         "232"
39313       ],
39314       [
39315         "Singapore",
39316         "sg",
39317         "65"
39318       ],
39319       [
39320         "Sint Maarten",
39321         "sx",
39322         "1721"
39323       ],
39324       [
39325         "Slovakia (Slovensko)",
39326         "sk",
39327         "421"
39328       ],
39329       [
39330         "Slovenia (Slovenija)",
39331         "si",
39332         "386"
39333       ],
39334       [
39335         "Solomon Islands",
39336         "sb",
39337         "677"
39338       ],
39339       [
39340         "Somalia (Soomaaliya)",
39341         "so",
39342         "252"
39343       ],
39344       [
39345         "South Africa",
39346         "za",
39347         "27"
39348       ],
39349       [
39350         "South Korea (대한민국)",
39351         "kr",
39352         "82"
39353       ],
39354       [
39355         "South Sudan (‫جنوب السودان‬‎)",
39356         "ss",
39357         "211"
39358       ],
39359       [
39360         "Spain (España)",
39361         "es",
39362         "34"
39363       ],
39364       [
39365         "Sri Lanka (ශ්‍රී ලංකාව)",
39366         "lk",
39367         "94"
39368       ],
39369       [
39370         "Sudan (‫السودان‬‎)",
39371         "sd",
39372         "249"
39373       ],
39374       [
39375         "Suriname",
39376         "sr",
39377         "597"
39378       ],
39379       [
39380         "Svalbard and Jan Mayen",
39381         "sj",
39382         "47",
39383         1
39384       ],
39385       [
39386         "Swaziland",
39387         "sz",
39388         "268"
39389       ],
39390       [
39391         "Sweden (Sverige)",
39392         "se",
39393         "46"
39394       ],
39395       [
39396         "Switzerland (Schweiz)",
39397         "ch",
39398         "41"
39399       ],
39400       [
39401         "Syria (‫سوريا‬‎)",
39402         "sy",
39403         "963"
39404       ],
39405       [
39406         "Taiwan (台灣)",
39407         "tw",
39408         "886"
39409       ],
39410       [
39411         "Tajikistan",
39412         "tj",
39413         "992"
39414       ],
39415       [
39416         "Tanzania",
39417         "tz",
39418         "255"
39419       ],
39420       [
39421         "Thailand (ไทย)",
39422         "th",
39423         "66"
39424       ],
39425       [
39426         "Timor-Leste",
39427         "tl",
39428         "670"
39429       ],
39430       [
39431         "Togo",
39432         "tg",
39433         "228"
39434       ],
39435       [
39436         "Tokelau",
39437         "tk",
39438         "690"
39439       ],
39440       [
39441         "Tonga",
39442         "to",
39443         "676"
39444       ],
39445       [
39446         "Trinidad and Tobago",
39447         "tt",
39448         "1868"
39449       ],
39450       [
39451         "Tunisia (‫تونس‬‎)",
39452         "tn",
39453         "216"
39454       ],
39455       [
39456         "Turkey (Türkiye)",
39457         "tr",
39458         "90"
39459       ],
39460       [
39461         "Turkmenistan",
39462         "tm",
39463         "993"
39464       ],
39465       [
39466         "Turks and Caicos Islands",
39467         "tc",
39468         "1649"
39469       ],
39470       [
39471         "Tuvalu",
39472         "tv",
39473         "688"
39474       ],
39475       [
39476         "U.S. Virgin Islands",
39477         "vi",
39478         "1340"
39479       ],
39480       [
39481         "Uganda",
39482         "ug",
39483         "256"
39484       ],
39485       [
39486         "Ukraine (Україна)",
39487         "ua",
39488         "380"
39489       ],
39490       [
39491         "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
39492         "ae",
39493         "971"
39494       ],
39495       [
39496         "United Kingdom",
39497         "gb",
39498         "44",
39499         0
39500       ],
39501       [
39502         "United States",
39503         "us",
39504         "1",
39505         0
39506       ],
39507       [
39508         "Uruguay",
39509         "uy",
39510         "598"
39511       ],
39512       [
39513         "Uzbekistan (Oʻzbekiston)",
39514         "uz",
39515         "998"
39516       ],
39517       [
39518         "Vanuatu",
39519         "vu",
39520         "678"
39521       ],
39522       [
39523         "Vatican City (Città del Vaticano)",
39524         "va",
39525         "39",
39526         1
39527       ],
39528       [
39529         "Venezuela",
39530         "ve",
39531         "58"
39532       ],
39533       [
39534         "Vietnam (Việt Nam)",
39535         "vn",
39536         "84"
39537       ],
39538       [
39539         "Wallis and Futuna (Wallis-et-Futuna)",
39540         "wf",
39541         "681"
39542       ],
39543       [
39544         "Western Sahara (‫الصحراء الغربية‬‎)",
39545         "eh",
39546         "212",
39547         1
39548       ],
39549       [
39550         "Yemen (‫اليمن‬‎)",
39551         "ye",
39552         "967"
39553       ],
39554       [
39555         "Zambia",
39556         "zm",
39557         "260"
39558       ],
39559       [
39560         "Zimbabwe",
39561         "zw",
39562         "263"
39563       ],
39564       [
39565         "Åland Islands",
39566         "ax",
39567         "358",
39568         1
39569       ]
39570   ];
39571   
39572   return d;
39573 }/**
39574 *    This script refer to:
39575 *    Title: International Telephone Input
39576 *    Author: Jack O'Connor
39577 *    Code version:  v12.1.12
39578 *    Availability: https://github.com/jackocnr/intl-tel-input.git
39579 **/
39580
39581 /**
39582  * @class Roo.bootstrap.PhoneInput
39583  * @extends Roo.bootstrap.TriggerField
39584  * An input with International dial-code selection
39585  
39586  * @cfg {String} defaultDialCode default '+852'
39587  * @cfg {Array} preferedCountries default []
39588   
39589  * @constructor
39590  * Create a new PhoneInput.
39591  * @param {Object} config Configuration options
39592  */
39593
39594 Roo.bootstrap.PhoneInput = function(config) {
39595     Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39596 };
39597
39598 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39599         
39600         listWidth: undefined,
39601         
39602         selectedClass: 'active',
39603         
39604         invalidClass : "has-warning",
39605         
39606         validClass: 'has-success',
39607         
39608         allowed: '0123456789',
39609         
39610         /**
39611          * @cfg {String} defaultDialCode The default dial code when initializing the input
39612          */
39613         defaultDialCode: '+852',
39614         
39615         /**
39616          * @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
39617          */
39618         preferedCountries: false,
39619         
39620         getAutoCreate : function()
39621         {
39622             var data = Roo.bootstrap.PhoneInputData();
39623             var align = this.labelAlign || this.parentLabelAlign();
39624             var id = Roo.id();
39625             
39626             this.allCountries = [];
39627             this.dialCodeMapping = [];
39628             
39629             for (var i = 0; i < data.length; i++) {
39630               var c = data[i];
39631               this.allCountries[i] = {
39632                 name: c[0],
39633                 iso2: c[1],
39634                 dialCode: c[2],
39635                 priority: c[3] || 0,
39636                 areaCodes: c[4] || null
39637               };
39638               this.dialCodeMapping[c[2]] = {
39639                   name: c[0],
39640                   iso2: c[1],
39641                   priority: c[3] || 0,
39642                   areaCodes: c[4] || null
39643               };
39644             }
39645             
39646             var cfg = {
39647                 cls: 'form-group',
39648                 cn: []
39649             };
39650             
39651             var input =  {
39652                 tag: 'input',
39653                 id : id,
39654                 cls : 'form-control tel-input',
39655                 autocomplete: 'new-password'
39656             };
39657             
39658             var hiddenInput = {
39659                 tag: 'input',
39660                 type: 'hidden',
39661                 cls: 'hidden-tel-input'
39662             };
39663             
39664             if (this.name) {
39665                 hiddenInput.name = this.name;
39666             }
39667             
39668             if (this.disabled) {
39669                 input.disabled = true;
39670             }
39671             
39672             var flag_container = {
39673                 tag: 'div',
39674                 cls: 'flag-box',
39675                 cn: [
39676                     {
39677                         tag: 'div',
39678                         cls: 'flag'
39679                     },
39680                     {
39681                         tag: 'div',
39682                         cls: 'caret'
39683                     }
39684                 ]
39685             };
39686             
39687             var box = {
39688                 tag: 'div',
39689                 cls: this.hasFeedback ? 'has-feedback' : '',
39690                 cn: [
39691                     hiddenInput,
39692                     input,
39693                     {
39694                         tag: 'input',
39695                         cls: 'dial-code-holder',
39696                         disabled: true
39697                     }
39698                 ]
39699             };
39700             
39701             var container = {
39702                 cls: 'roo-select2-container input-group',
39703                 cn: [
39704                     flag_container,
39705                     box
39706                 ]
39707             };
39708             
39709             if (this.fieldLabel.length) {
39710                 var indicator = {
39711                     tag: 'i',
39712                     tooltip: 'This field is required'
39713                 };
39714                 
39715                 var label = {
39716                     tag: 'label',
39717                     'for':  id,
39718                     cls: 'control-label',
39719                     cn: []
39720                 };
39721                 
39722                 var label_text = {
39723                     tag: 'span',
39724                     html: this.fieldLabel
39725                 };
39726                 
39727                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39728                 label.cn = [
39729                     indicator,
39730                     label_text
39731                 ];
39732                 
39733                 if(this.indicatorpos == 'right') {
39734                     indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39735                     label.cn = [
39736                         label_text,
39737                         indicator
39738                     ];
39739                 }
39740                 
39741                 if(align == 'left') {
39742                     container = {
39743                         tag: 'div',
39744                         cn: [
39745                             container
39746                         ]
39747                     };
39748                     
39749                     if(this.labelWidth > 12){
39750                         label.style = "width: " + this.labelWidth + 'px';
39751                     }
39752                     if(this.labelWidth < 13 && this.labelmd == 0){
39753                         this.labelmd = this.labelWidth;
39754                     }
39755                     if(this.labellg > 0){
39756                         label.cls += ' col-lg-' + this.labellg;
39757                         input.cls += ' col-lg-' + (12 - this.labellg);
39758                     }
39759                     if(this.labelmd > 0){
39760                         label.cls += ' col-md-' + this.labelmd;
39761                         container.cls += ' col-md-' + (12 - this.labelmd);
39762                     }
39763                     if(this.labelsm > 0){
39764                         label.cls += ' col-sm-' + this.labelsm;
39765                         container.cls += ' col-sm-' + (12 - this.labelsm);
39766                     }
39767                     if(this.labelxs > 0){
39768                         label.cls += ' col-xs-' + this.labelxs;
39769                         container.cls += ' col-xs-' + (12 - this.labelxs);
39770                     }
39771                 }
39772             }
39773             
39774             cfg.cn = [
39775                 label,
39776                 container
39777             ];
39778             
39779             var settings = this;
39780             
39781             ['xs','sm','md','lg'].map(function(size){
39782                 if (settings[size]) {
39783                     cfg.cls += ' col-' + size + '-' + settings[size];
39784                 }
39785             });
39786             
39787             this.store = new Roo.data.Store({
39788                 proxy : new Roo.data.MemoryProxy({}),
39789                 reader : new Roo.data.JsonReader({
39790                     fields : [
39791                         {
39792                             'name' : 'name',
39793                             'type' : 'string'
39794                         },
39795                         {
39796                             'name' : 'iso2',
39797                             'type' : 'string'
39798                         },
39799                         {
39800                             'name' : 'dialCode',
39801                             'type' : 'string'
39802                         },
39803                         {
39804                             'name' : 'priority',
39805                             'type' : 'string'
39806                         },
39807                         {
39808                             'name' : 'areaCodes',
39809                             'type' : 'string'
39810                         }
39811                     ]
39812                 })
39813             });
39814             
39815             if(!this.preferedCountries) {
39816                 this.preferedCountries = [
39817                     'hk',
39818                     'gb',
39819                     'us'
39820                 ];
39821             }
39822             
39823             var p = this.preferedCountries.reverse();
39824             
39825             if(p) {
39826                 for (var i = 0; i < p.length; i++) {
39827                     for (var j = 0; j < this.allCountries.length; j++) {
39828                         if(this.allCountries[j].iso2 == p[i]) {
39829                             var t = this.allCountries[j];
39830                             this.allCountries.splice(j,1);
39831                             this.allCountries.unshift(t);
39832                         }
39833                     } 
39834                 }
39835             }
39836             
39837             this.store.proxy.data = {
39838                 success: true,
39839                 data: this.allCountries
39840             };
39841             
39842             return cfg;
39843         },
39844         
39845         initEvents : function()
39846         {
39847             this.createList();
39848             Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39849             
39850             this.indicator = this.indicatorEl();
39851             this.flag = this.flagEl();
39852             this.dialCodeHolder = this.dialCodeHolderEl();
39853             
39854             this.trigger = this.el.select('div.flag-box',true).first();
39855             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39856             
39857             var _this = this;
39858             
39859             (function(){
39860                 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39861                 _this.list.setWidth(lw);
39862             }).defer(100);
39863             
39864             this.list.on('mouseover', this.onViewOver, this);
39865             this.list.on('mousemove', this.onViewMove, this);
39866             this.inputEl().on("keyup", this.onKeyUp, this);
39867             
39868             this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39869
39870             this.view = new Roo.View(this.list, this.tpl, {
39871                 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39872             });
39873             
39874             this.view.on('click', this.onViewClick, this);
39875             this.setValue(this.defaultDialCode);
39876         },
39877         
39878         onTriggerClick : function(e)
39879         {
39880             Roo.log('trigger click');
39881             if(this.disabled){
39882                 return;
39883             }
39884             
39885             if(this.isExpanded()){
39886                 this.collapse();
39887                 this.hasFocus = false;
39888             }else {
39889                 this.store.load({});
39890                 this.hasFocus = true;
39891                 this.expand();
39892             }
39893         },
39894         
39895         isExpanded : function()
39896         {
39897             return this.list.isVisible();
39898         },
39899         
39900         collapse : function()
39901         {
39902             if(!this.isExpanded()){
39903                 return;
39904             }
39905             this.list.hide();
39906             Roo.get(document).un('mousedown', this.collapseIf, this);
39907             Roo.get(document).un('mousewheel', this.collapseIf, this);
39908             this.fireEvent('collapse', this);
39909             this.validate();
39910         },
39911         
39912         expand : function()
39913         {
39914             Roo.log('expand');
39915
39916             if(this.isExpanded() || !this.hasFocus){
39917                 return;
39918             }
39919             
39920             var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39921             this.list.setWidth(lw);
39922             
39923             this.list.show();
39924             this.restrictHeight();
39925             
39926             Roo.get(document).on('mousedown', this.collapseIf, this);
39927             Roo.get(document).on('mousewheel', this.collapseIf, this);
39928             
39929             this.fireEvent('expand', this);
39930         },
39931         
39932         restrictHeight : function()
39933         {
39934             this.list.alignTo(this.inputEl(), this.listAlign);
39935             this.list.alignTo(this.inputEl(), this.listAlign);
39936         },
39937         
39938         onViewOver : function(e, t)
39939         {
39940             if(this.inKeyMode){
39941                 return;
39942             }
39943             var item = this.view.findItemFromChild(t);
39944             
39945             if(item){
39946                 var index = this.view.indexOf(item);
39947                 this.select(index, false);
39948             }
39949         },
39950
39951         // private
39952         onViewClick : function(view, doFocus, el, e)
39953         {
39954             var index = this.view.getSelectedIndexes()[0];
39955             
39956             var r = this.store.getAt(index);
39957             
39958             if(r){
39959                 this.onSelect(r, index);
39960             }
39961             if(doFocus !== false && !this.blockFocus){
39962                 this.inputEl().focus();
39963             }
39964         },
39965         
39966         onViewMove : function(e, t)
39967         {
39968             this.inKeyMode = false;
39969         },
39970         
39971         select : function(index, scrollIntoView)
39972         {
39973             this.selectedIndex = index;
39974             this.view.select(index);
39975             if(scrollIntoView !== false){
39976                 var el = this.view.getNode(index);
39977                 if(el){
39978                     this.list.scrollChildIntoView(el, false);
39979                 }
39980             }
39981         },
39982         
39983         createList : function()
39984         {
39985             this.list = Roo.get(document.body).createChild({
39986                 tag: 'ul',
39987                 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39988                 style: 'display:none'
39989             });
39990             this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39991         },
39992         
39993         collapseIf : function(e)
39994         {
39995             var in_combo  = e.within(this.el);
39996             var in_list =  e.within(this.list);
39997             var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39998             
39999             if (in_combo || in_list || is_list) {
40000                 return;
40001             }
40002             this.collapse();
40003         },
40004         
40005         onSelect : function(record, index)
40006         {
40007             if(this.fireEvent('beforeselect', this, record, index) !== false){
40008                 
40009                 this.setFlagClass(record.data.iso2);
40010                 this.setDialCode(record.data.dialCode);
40011                 this.hasFocus = false;
40012                 this.collapse();
40013                 this.fireEvent('select', this, record, index);
40014             }
40015         },
40016         
40017         flagEl : function()
40018         {
40019             var flag = this.el.select('div.flag',true).first();
40020             if(!flag){
40021                 return false;
40022             }
40023             return flag;
40024         },
40025         
40026         dialCodeHolderEl : function()
40027         {
40028             var d = this.el.select('input.dial-code-holder',true).first();
40029             if(!d){
40030                 return false;
40031             }
40032             return d;
40033         },
40034         
40035         setDialCode : function(v)
40036         {
40037             this.dialCodeHolder.dom.value = '+'+v;
40038         },
40039         
40040         setFlagClass : function(n)
40041         {
40042             this.flag.dom.className = 'flag '+n;
40043         },
40044         
40045         getValue : function()
40046         {
40047             var v = this.inputEl().getValue();
40048             if(this.dialCodeHolder) {
40049                 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40050             }
40051             return v;
40052         },
40053         
40054         setValue : function(v)
40055         {
40056             var d = this.getDialCode(v);
40057             
40058             //invalid dial code
40059             if(v.length == 0 || !d || d.length == 0) {
40060                 if(this.rendered){
40061                     this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40062                     this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40063                 }
40064                 return;
40065             }
40066             
40067             //valid dial code
40068             this.setFlagClass(this.dialCodeMapping[d].iso2);
40069             this.setDialCode(d);
40070             this.inputEl().dom.value = v.replace('+'+d,'');
40071             this.hiddenEl().dom.value = this.getValue();
40072             
40073             this.validate();
40074         },
40075         
40076         getDialCode : function(v = '')
40077         {
40078             if (v.length == 0) {
40079                 return this.dialCodeHolder.dom.value;
40080             }
40081             
40082             var dialCode = "";
40083             if (v.charAt(0) != "+") {
40084                 return false;
40085             }
40086             var numericChars = "";
40087             for (var i = 1; i < v.length; i++) {
40088               var c = v.charAt(i);
40089               if (!isNaN(c)) {
40090                 numericChars += c;
40091                 if (this.dialCodeMapping[numericChars]) {
40092                   dialCode = v.substr(1, i);
40093                 }
40094                 if (numericChars.length == 4) {
40095                   break;
40096                 }
40097               }
40098             }
40099             return dialCode;
40100         },
40101         
40102         reset : function()
40103         {
40104             this.setValue(this.defaultDialCode);
40105             this.validate();
40106         },
40107         
40108         hiddenEl : function()
40109         {
40110             return this.el.select('input.hidden-tel-input',true).first();
40111         },
40112         
40113         onKeyUp : function(e){
40114             
40115             var k = e.getKey();
40116             var c = e.getCharCode();
40117             
40118             if(
40119                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40120                     this.allowed.indexOf(String.fromCharCode(c)) === -1
40121             ){
40122                 e.stopEvent();
40123             }
40124             
40125             // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40126             //     return;
40127             // }
40128             if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40129                 e.stopEvent();
40130             }
40131             
40132             this.setValue(this.getValue());
40133         }
40134         
40135 });
40136 /**
40137  * @class Roo.bootstrap.MoneyField
40138  * @extends Roo.bootstrap.ComboBox
40139  * Bootstrap MoneyField class
40140  * 
40141  * @constructor
40142  * Create a new MoneyField.
40143  * @param {Object} config Configuration options
40144  */
40145
40146 Roo.bootstrap.MoneyField = function(config) {
40147     
40148     Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40149     
40150 };
40151
40152 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40153     
40154     /**
40155      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40156      */
40157     allowDecimals : true,
40158     /**
40159      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40160      */
40161     decimalSeparator : ".",
40162     /**
40163      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40164      */
40165     decimalPrecision : 0,
40166     /**
40167      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40168      */
40169     allowNegative : true,
40170     /**
40171      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40172      */
40173     minValue : Number.NEGATIVE_INFINITY,
40174     /**
40175      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40176      */
40177     maxValue : Number.MAX_VALUE,
40178     /**
40179      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40180      */
40181     minText : "The minimum value for this field is {0}",
40182     /**
40183      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40184      */
40185     maxText : "The maximum value for this field is {0}",
40186     /**
40187      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
40188      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40189      */
40190     nanText : "{0} is not a valid number",
40191     /**
40192      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40193      */
40194     castInt : true,
40195     /**
40196      * @cfg {String} defaults currency of the MoneyField
40197      * value should be in lkey
40198      */
40199     defaultCurrency : false,
40200     /**
40201      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40202      */
40203     thousandsDelimiter : false,
40204     
40205     
40206     inputlg : 9,
40207     inputmd : 9,
40208     inputsm : 9,
40209     inputxs : 6,
40210     
40211     store : false,
40212     
40213     getAutoCreate : function()
40214     {
40215         var align = this.labelAlign || this.parentLabelAlign();
40216         
40217         var id = Roo.id();
40218
40219         var cfg = {
40220             cls: 'form-group',
40221             cn: []
40222         };
40223
40224         var input =  {
40225             tag: 'input',
40226             id : id,
40227             cls : 'form-control roo-money-amount-input',
40228             autocomplete: 'new-password'
40229         };
40230         
40231         var hiddenInput = {
40232             tag: 'input',
40233             type: 'hidden',
40234             id: Roo.id(),
40235             cls: 'hidden-number-input'
40236         };
40237         
40238         if (this.name) {
40239             hiddenInput.name = this.name;
40240         }
40241
40242         if (this.disabled) {
40243             input.disabled = true;
40244         }
40245
40246         var clg = 12 - this.inputlg;
40247         var cmd = 12 - this.inputmd;
40248         var csm = 12 - this.inputsm;
40249         var cxs = 12 - this.inputxs;
40250         
40251         var container = {
40252             tag : 'div',
40253             cls : 'row roo-money-field',
40254             cn : [
40255                 {
40256                     tag : 'div',
40257                     cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40258                     cn : [
40259                         {
40260                             tag : 'div',
40261                             cls: 'roo-select2-container input-group',
40262                             cn: [
40263                                 {
40264                                     tag : 'input',
40265                                     cls : 'form-control roo-money-currency-input',
40266                                     autocomplete: 'new-password',
40267                                     readOnly : 1,
40268                                     name : this.currencyName
40269                                 },
40270                                 {
40271                                     tag :'span',
40272                                     cls : 'input-group-addon',
40273                                     cn : [
40274                                         {
40275                                             tag: 'span',
40276                                             cls: 'caret'
40277                                         }
40278                                     ]
40279                                 }
40280                             ]
40281                         }
40282                     ]
40283                 },
40284                 {
40285                     tag : 'div',
40286                     cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40287                     cn : [
40288                         {
40289                             tag: 'div',
40290                             cls: this.hasFeedback ? 'has-feedback' : '',
40291                             cn: [
40292                                 input
40293                             ]
40294                         }
40295                     ]
40296                 }
40297             ]
40298             
40299         };
40300         
40301         if (this.fieldLabel.length) {
40302             var indicator = {
40303                 tag: 'i',
40304                 tooltip: 'This field is required'
40305             };
40306
40307             var label = {
40308                 tag: 'label',
40309                 'for':  id,
40310                 cls: 'control-label',
40311                 cn: []
40312             };
40313
40314             var label_text = {
40315                 tag: 'span',
40316                 html: this.fieldLabel
40317             };
40318
40319             indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40320             label.cn = [
40321                 indicator,
40322                 label_text
40323             ];
40324
40325             if(this.indicatorpos == 'right') {
40326                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40327                 label.cn = [
40328                     label_text,
40329                     indicator
40330                 ];
40331             }
40332
40333             if(align == 'left') {
40334                 container = {
40335                     tag: 'div',
40336                     cn: [
40337                         container
40338                     ]
40339                 };
40340
40341                 if(this.labelWidth > 12){
40342                     label.style = "width: " + this.labelWidth + 'px';
40343                 }
40344                 if(this.labelWidth < 13 && this.labelmd == 0){
40345                     this.labelmd = this.labelWidth;
40346                 }
40347                 if(this.labellg > 0){
40348                     label.cls += ' col-lg-' + this.labellg;
40349                     input.cls += ' col-lg-' + (12 - this.labellg);
40350                 }
40351                 if(this.labelmd > 0){
40352                     label.cls += ' col-md-' + this.labelmd;
40353                     container.cls += ' col-md-' + (12 - this.labelmd);
40354                 }
40355                 if(this.labelsm > 0){
40356                     label.cls += ' col-sm-' + this.labelsm;
40357                     container.cls += ' col-sm-' + (12 - this.labelsm);
40358                 }
40359                 if(this.labelxs > 0){
40360                     label.cls += ' col-xs-' + this.labelxs;
40361                     container.cls += ' col-xs-' + (12 - this.labelxs);
40362                 }
40363             }
40364         }
40365
40366         cfg.cn = [
40367             label,
40368             container,
40369             hiddenInput
40370         ];
40371         
40372         var settings = this;
40373
40374         ['xs','sm','md','lg'].map(function(size){
40375             if (settings[size]) {
40376                 cfg.cls += ' col-' + size + '-' + settings[size];
40377             }
40378         });
40379         
40380         return cfg;
40381     },
40382     
40383     initEvents : function()
40384     {
40385         this.indicator = this.indicatorEl();
40386         
40387         this.initCurrencyEvent();
40388         
40389         this.initNumberEvent();
40390     },
40391     
40392     initCurrencyEvent : function()
40393     {
40394         if (!this.store) {
40395             throw "can not find store for combo";
40396         }
40397         
40398         this.store = Roo.factory(this.store, Roo.data);
40399         this.store.parent = this;
40400         
40401         this.createList();
40402         
40403         this.triggerEl = this.el.select('.input-group-addon', true).first();
40404         
40405         this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40406         
40407         var _this = this;
40408         
40409         (function(){
40410             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40411             _this.list.setWidth(lw);
40412         }).defer(100);
40413         
40414         this.list.on('mouseover', this.onViewOver, this);
40415         this.list.on('mousemove', this.onViewMove, this);
40416         this.list.on('scroll', this.onViewScroll, this);
40417         
40418         if(!this.tpl){
40419             this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40420         }
40421         
40422         this.view = new Roo.View(this.list, this.tpl, {
40423             singleSelect:true, store: this.store, selectedClass: this.selectedClass
40424         });
40425         
40426         this.view.on('click', this.onViewClick, this);
40427         
40428         this.store.on('beforeload', this.onBeforeLoad, this);
40429         this.store.on('load', this.onLoad, this);
40430         this.store.on('loadexception', this.onLoadException, this);
40431         
40432         this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40433             "up" : function(e){
40434                 this.inKeyMode = true;
40435                 this.selectPrev();
40436             },
40437
40438             "down" : function(e){
40439                 if(!this.isExpanded()){
40440                     this.onTriggerClick();
40441                 }else{
40442                     this.inKeyMode = true;
40443                     this.selectNext();
40444                 }
40445             },
40446
40447             "enter" : function(e){
40448                 this.collapse();
40449                 
40450                 if(this.fireEvent("specialkey", this, e)){
40451                     this.onViewClick(false);
40452                 }
40453                 
40454                 return true;
40455             },
40456
40457             "esc" : function(e){
40458                 this.collapse();
40459             },
40460
40461             "tab" : function(e){
40462                 this.collapse();
40463                 
40464                 if(this.fireEvent("specialkey", this, e)){
40465                     this.onViewClick(false);
40466                 }
40467                 
40468                 return true;
40469             },
40470
40471             scope : this,
40472
40473             doRelay : function(foo, bar, hname){
40474                 if(hname == 'down' || this.scope.isExpanded()){
40475                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40476                 }
40477                 return true;
40478             },
40479
40480             forceKeyDown: true
40481         });
40482         
40483         this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40484         
40485     },
40486     
40487     initNumberEvent : function(e)
40488     {
40489         this.inputEl().on("keydown" , this.fireKey,  this);
40490         this.inputEl().on("focus", this.onFocus,  this);
40491         this.inputEl().on("blur", this.onBlur,  this);
40492         
40493         this.inputEl().relayEvent('keyup', this);
40494         
40495         if(this.indicator){
40496             this.indicator.addClass('invisible');
40497         }
40498  
40499         this.originalValue = this.getValue();
40500         
40501         if(this.validationEvent == 'keyup'){
40502             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40503             this.inputEl().on('keyup', this.filterValidation, this);
40504         }
40505         else if(this.validationEvent !== false){
40506             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40507         }
40508         
40509         if(this.selectOnFocus){
40510             this.on("focus", this.preFocus, this);
40511             
40512         }
40513         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40514             this.inputEl().on("keypress", this.filterKeys, this);
40515         } else {
40516             this.inputEl().relayEvent('keypress', this);
40517         }
40518         
40519         var allowed = "0123456789";
40520         
40521         if(this.allowDecimals){
40522             allowed += this.decimalSeparator;
40523         }
40524         
40525         if(this.allowNegative){
40526             allowed += "-";
40527         }
40528         
40529         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40530         
40531         var keyPress = function(e){
40532             
40533             var k = e.getKey();
40534             
40535             var c = e.getCharCode();
40536             
40537             if(
40538                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40539                     allowed.indexOf(String.fromCharCode(c)) === -1
40540             ){
40541                 e.stopEvent();
40542                 return;
40543             }
40544             
40545             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40546                 return;
40547             }
40548             
40549             if(allowed.indexOf(String.fromCharCode(c)) === -1){
40550                 e.stopEvent();
40551             }
40552         };
40553         
40554         this.inputEl().on("keypress", keyPress, this);
40555         
40556     },
40557     
40558     onTriggerClick : function(e)
40559     {   
40560         if(this.disabled){
40561             return;
40562         }
40563         
40564         this.page = 0;
40565         this.loadNext = false;
40566         
40567         if(this.isExpanded()){
40568             this.collapse();
40569             return;
40570         }
40571         
40572         this.hasFocus = true;
40573         
40574         if(this.triggerAction == 'all') {
40575             this.doQuery(this.allQuery, true);
40576             return;
40577         }
40578         
40579         this.doQuery(this.getRawValue());
40580     },
40581     
40582     getCurrency : function()
40583     {   
40584         var v = this.currencyEl().getValue();
40585         
40586         return v;
40587     },
40588     
40589     restrictHeight : function()
40590     {
40591         this.list.alignTo(this.currencyEl(), this.listAlign);
40592         this.list.alignTo(this.currencyEl(), this.listAlign);
40593     },
40594     
40595     onViewClick : function(view, doFocus, el, e)
40596     {
40597         var index = this.view.getSelectedIndexes()[0];
40598         
40599         var r = this.store.getAt(index);
40600         
40601         if(r){
40602             this.onSelect(r, index);
40603         }
40604     },
40605     
40606     onSelect : function(record, index){
40607         
40608         if(this.fireEvent('beforeselect', this, record, index) !== false){
40609         
40610             this.setFromCurrencyData(index > -1 ? record.data : false);
40611             
40612             this.collapse();
40613             
40614             this.fireEvent('select', this, record, index);
40615         }
40616     },
40617     
40618     setFromCurrencyData : function(o)
40619     {
40620         var currency = '';
40621         
40622         this.lastCurrency = o;
40623         
40624         if (this.currencyField) {
40625             currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40626         } else {
40627             Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
40628         }
40629         
40630         this.lastSelectionText = currency;
40631         
40632         //setting default currency
40633         if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40634             this.setCurrency(this.defaultCurrency);
40635             return;
40636         }
40637         
40638         this.setCurrency(currency);
40639     },
40640     
40641     setFromData : function(o)
40642     {
40643         var c = {};
40644         
40645         c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40646         
40647         this.setFromCurrencyData(c);
40648         
40649         var value = '';
40650         
40651         if (this.name) {
40652             value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40653         } else {
40654             Roo.log('no value set for '+ (this.name ? this.name : this.id));
40655         }
40656         
40657         this.setValue(value);
40658         
40659     },
40660     
40661     setCurrency : function(v)
40662     {   
40663         this.currencyValue = v;
40664         
40665         if(this.rendered){
40666             this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40667             this.validate();
40668         }
40669     },
40670     
40671     setValue : function(v)
40672     {
40673         v = this.fixPrecision(v);
40674         
40675         v = String(v).replace(".", this.decimalSeparator);
40676         
40677         this.value = v;
40678         
40679         if(this.rendered){
40680             
40681             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40682             
40683             this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision, 
40684                 this.thousandsDelimiter || ','
40685             );
40686             
40687             if(this.allowBlank && !v) {
40688                 this.inputEl().dom.value = '';
40689             }
40690             
40691             this.validate();
40692         }
40693     },
40694     
40695     getRawValue : function()
40696     {
40697         var v = this.inputEl().getValue();
40698         
40699         return v;
40700     },
40701     
40702     getValue : function()
40703     {
40704         return this.fixPrecision(this.parseValue(this.getRawValue()));
40705     },
40706     
40707     parseValue : function(value)
40708     {
40709         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40710         return isNaN(value) ? '' : value;
40711     },
40712     
40713     fixPrecision : function(value)
40714     {
40715         var nan = isNaN(value);
40716         
40717         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40718             return nan ? '' : value;
40719         }
40720         
40721         return parseFloat(value).toFixed(this.decimalPrecision);
40722     },
40723     
40724     decimalPrecisionFcn : function(v)
40725     {
40726         return Math.floor(v);
40727     },
40728     
40729     validateValue : function(value)
40730     {
40731         if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40732             return false;
40733         }
40734         
40735         var num = this.parseValue(value);
40736         
40737         if(isNaN(num)){
40738             this.markInvalid(String.format(this.nanText, value));
40739             return false;
40740         }
40741         
40742         if(num < this.minValue){
40743             this.markInvalid(String.format(this.minText, this.minValue));
40744             return false;
40745         }
40746         
40747         if(num > this.maxValue){
40748             this.markInvalid(String.format(this.maxText, this.maxValue));
40749             return false;
40750         }
40751         
40752         return true;
40753     },
40754     
40755     validate : function()
40756     {
40757         if(this.disabled || this.allowBlank){
40758             this.markValid();
40759             return true;
40760         }
40761         
40762         var currency = this.getCurrency();
40763         
40764         if(this.validateValue(this.getRawValue()) && currency.length){
40765             this.markValid();
40766             return true;
40767         }
40768         
40769         this.markInvalid();
40770         return false;
40771     },
40772     
40773     getName: function()
40774     {
40775         return this.name;
40776     },
40777     
40778     beforeBlur : function()
40779     {
40780         if(!this.castInt){
40781             return;
40782         }
40783         
40784         var v = this.parseValue(this.getRawValue());
40785         
40786         if(v || v == 0){
40787             this.setValue(v);
40788         }
40789     },
40790     
40791     onBlur : function()
40792     {
40793         this.beforeBlur();
40794         
40795         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40796             //this.el.removeClass(this.focusClass);
40797         }
40798         
40799         this.hasFocus = false;
40800         
40801         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40802             this.validate();
40803         }
40804         
40805         var v = this.getValue();
40806         
40807         if(String(v) !== String(this.startValue)){
40808             this.fireEvent('change', this, v, this.startValue);
40809         }
40810         
40811         this.fireEvent("blur", this);
40812     },
40813     
40814     inputEl : function()
40815     {
40816         return this.el.select('.roo-money-amount-input', true).first();
40817     },
40818     
40819     currencyEl : function()
40820     {
40821         return this.el.select('.roo-money-currency-input', true).first();
40822     },
40823     
40824     hiddenEl : function()
40825     {
40826         return this.el.select('input.hidden-number-input',true).first();
40827     }
40828     
40829 });