25b0826927b558f428e30e73296c0ad35ed91ec6
[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         var v = this.getRawValue();
14694         
14695         if(this.multiple){
14696             v = this.getValue();
14697         }
14698         
14699         if(this.disabled || this.allowBlank || v.length){
14700             this.markValid();
14701             return true;
14702         }
14703         
14704         this.markInvalid();
14705         return false;
14706     },
14707     
14708     tickableInputEl : function()
14709     {
14710         if(!this.tickable || !this.editable){
14711             return this.inputEl();
14712         }
14713         
14714         return this.inputEl().select('.roo-select2-search-field-input', true).first();
14715     },
14716     
14717     
14718     getAutoCreateTouchView : function()
14719     {
14720         var id = Roo.id();
14721         
14722         var cfg = {
14723             cls: 'form-group' //input-group
14724         };
14725         
14726         var input =  {
14727             tag: 'input',
14728             id : id,
14729             type : this.inputType,
14730             cls : 'form-control x-combo-noedit',
14731             autocomplete: 'new-password',
14732             placeholder : this.placeholder || '',
14733             readonly : true
14734         };
14735         
14736         if (this.name) {
14737             input.name = this.name;
14738         }
14739         
14740         if (this.size) {
14741             input.cls += ' input-' + this.size;
14742         }
14743         
14744         if (this.disabled) {
14745             input.disabled = true;
14746         }
14747         
14748         var inputblock = {
14749             cls : '',
14750             cn : [
14751                 input
14752             ]
14753         };
14754         
14755         if(this.before){
14756             inputblock.cls += ' input-group';
14757             
14758             inputblock.cn.unshift({
14759                 tag :'span',
14760                 cls : 'input-group-addon',
14761                 html : this.before
14762             });
14763         }
14764         
14765         if(this.removable && !this.multiple){
14766             inputblock.cls += ' roo-removable';
14767             
14768             inputblock.cn.push({
14769                 tag: 'button',
14770                 html : 'x',
14771                 cls : 'roo-combo-removable-btn close'
14772             });
14773         }
14774
14775         if(this.hasFeedback && !this.allowBlank){
14776             
14777             inputblock.cls += ' has-feedback';
14778             
14779             inputblock.cn.push({
14780                 tag: 'span',
14781                 cls: 'glyphicon form-control-feedback'
14782             });
14783             
14784         }
14785         
14786         if (this.after) {
14787             
14788             inputblock.cls += (this.before) ? '' : ' input-group';
14789             
14790             inputblock.cn.push({
14791                 tag :'span',
14792                 cls : 'input-group-addon',
14793                 html : this.after
14794             });
14795         }
14796
14797         var box = {
14798             tag: 'div',
14799             cn: [
14800                 {
14801                     tag: 'input',
14802                     type : 'hidden',
14803                     cls: 'form-hidden-field'
14804                 },
14805                 inputblock
14806             ]
14807             
14808         };
14809         
14810         if(this.multiple){
14811             box = {
14812                 tag: 'div',
14813                 cn: [
14814                     {
14815                         tag: 'input',
14816                         type : 'hidden',
14817                         cls: 'form-hidden-field'
14818                     },
14819                     {
14820                         tag: 'ul',
14821                         cls: 'roo-select2-choices',
14822                         cn:[
14823                             {
14824                                 tag: 'li',
14825                                 cls: 'roo-select2-search-field',
14826                                 cn: [
14827
14828                                     inputblock
14829                                 ]
14830                             }
14831                         ]
14832                     }
14833                 ]
14834             }
14835         };
14836         
14837         var combobox = {
14838             cls: 'roo-select2-container input-group roo-touchview-combobox ',
14839             cn: [
14840                 box
14841             ]
14842         };
14843         
14844         if(!this.multiple && this.showToggleBtn){
14845             
14846             var caret = {
14847                         tag: 'span',
14848                         cls: 'caret'
14849             };
14850             
14851             if (this.caret != false) {
14852                 caret = {
14853                      tag: 'i',
14854                      cls: 'fa fa-' + this.caret
14855                 };
14856                 
14857             }
14858             
14859             combobox.cn.push({
14860                 tag :'span',
14861                 cls : 'input-group-addon btn dropdown-toggle',
14862                 cn : [
14863                     caret,
14864                     {
14865                         tag: 'span',
14866                         cls: 'combobox-clear',
14867                         cn  : [
14868                             {
14869                                 tag : 'i',
14870                                 cls: 'icon-remove'
14871                             }
14872                         ]
14873                     }
14874                 ]
14875
14876             })
14877         }
14878         
14879         if(this.multiple){
14880             combobox.cls += ' roo-select2-container-multi';
14881         }
14882         
14883         var align = this.labelAlign || this.parentLabelAlign();
14884         
14885         if (align ==='left' && this.fieldLabel.length) {
14886
14887             cfg.cn = [
14888                 {
14889                    tag : 'i',
14890                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14891                    tooltip : 'This field is required'
14892                 },
14893                 {
14894                     tag: 'label',
14895                     cls : 'control-label',
14896                     html : this.fieldLabel
14897
14898                 },
14899                 {
14900                     cls : '', 
14901                     cn: [
14902                         combobox
14903                     ]
14904                 }
14905             ];
14906             
14907             var labelCfg = cfg.cn[1];
14908             var contentCfg = cfg.cn[2];
14909             
14910
14911             if(this.indicatorpos == 'right'){
14912                 cfg.cn = [
14913                     {
14914                         tag: 'label',
14915                         'for' :  id,
14916                         cls : 'control-label',
14917                         cn : [
14918                             {
14919                                 tag : 'span',
14920                                 html : this.fieldLabel
14921                             },
14922                             {
14923                                 tag : 'i',
14924                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14925                                 tooltip : 'This field is required'
14926                             }
14927                         ]
14928                     },
14929                     {
14930                         cls : "",
14931                         cn: [
14932                             combobox
14933                         ]
14934                     }
14935
14936                 ];
14937                 
14938                 labelCfg = cfg.cn[0];
14939                 contentCfg = cfg.cn[1];
14940             }
14941             
14942            
14943             
14944             if(this.labelWidth > 12){
14945                 labelCfg.style = "width: " + this.labelWidth + 'px';
14946             }
14947             
14948             if(this.labelWidth < 13 && this.labelmd == 0){
14949                 this.labelmd = this.labelWidth;
14950             }
14951             
14952             if(this.labellg > 0){
14953                 labelCfg.cls += ' col-lg-' + this.labellg;
14954                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14955             }
14956             
14957             if(this.labelmd > 0){
14958                 labelCfg.cls += ' col-md-' + this.labelmd;
14959                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14960             }
14961             
14962             if(this.labelsm > 0){
14963                 labelCfg.cls += ' col-sm-' + this.labelsm;
14964                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14965             }
14966             
14967             if(this.labelxs > 0){
14968                 labelCfg.cls += ' col-xs-' + this.labelxs;
14969                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14970             }
14971                 
14972                 
14973         } else if ( this.fieldLabel.length) {
14974             cfg.cn = [
14975                 {
14976                    tag : 'i',
14977                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14978                    tooltip : 'This field is required'
14979                 },
14980                 {
14981                     tag: 'label',
14982                     cls : 'control-label',
14983                     html : this.fieldLabel
14984
14985                 },
14986                 {
14987                     cls : '', 
14988                     cn: [
14989                         combobox
14990                     ]
14991                 }
14992             ];
14993             
14994             if(this.indicatorpos == 'right'){
14995                 cfg.cn = [
14996                     {
14997                         tag: 'label',
14998                         cls : 'control-label',
14999                         html : this.fieldLabel,
15000                         cn : [
15001                             {
15002                                tag : 'i',
15003                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15004                                tooltip : 'This field is required'
15005                             }
15006                         ]
15007                     },
15008                     {
15009                         cls : '', 
15010                         cn: [
15011                             combobox
15012                         ]
15013                     }
15014                 ];
15015             }
15016         } else {
15017             cfg.cn = combobox;    
15018         }
15019         
15020         
15021         var settings = this;
15022         
15023         ['xs','sm','md','lg'].map(function(size){
15024             if (settings[size]) {
15025                 cfg.cls += ' col-' + size + '-' + settings[size];
15026             }
15027         });
15028         
15029         return cfg;
15030     },
15031     
15032     initTouchView : function()
15033     {
15034         this.renderTouchView();
15035         
15036         this.touchViewEl.on('scroll', function(){
15037             this.el.dom.scrollTop = 0;
15038         }, this);
15039         
15040         this.originalValue = this.getValue();
15041         
15042         this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15043         
15044         this.inputEl().on("click", this.showTouchView, this);
15045         if (this.triggerEl) {
15046             this.triggerEl.on("click", this.showTouchView, this);
15047         }
15048         
15049         
15050         this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15051         this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15052         
15053         this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15054         
15055         this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15056         this.store.on('load', this.onTouchViewLoad, this);
15057         this.store.on('loadexception', this.onTouchViewLoadException, this);
15058         
15059         if(this.hiddenName){
15060             
15061             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15062             
15063             this.hiddenField.dom.value =
15064                 this.hiddenValue !== undefined ? this.hiddenValue :
15065                 this.value !== undefined ? this.value : '';
15066         
15067             this.el.dom.removeAttribute('name');
15068             this.hiddenField.dom.setAttribute('name', this.hiddenName);
15069         }
15070         
15071         if(this.multiple){
15072             this.choices = this.el.select('ul.roo-select2-choices', true).first();
15073             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15074         }
15075         
15076         if(this.removable && !this.multiple){
15077             var close = this.closeTriggerEl();
15078             if(close){
15079                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15080                 close.on('click', this.removeBtnClick, this, close);
15081             }
15082         }
15083         /*
15084          * fix the bug in Safari iOS8
15085          */
15086         this.inputEl().on("focus", function(e){
15087             document.activeElement.blur();
15088         }, this);
15089         
15090         return;
15091         
15092         
15093     },
15094     
15095     renderTouchView : function()
15096     {
15097         this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15098         this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15099         
15100         this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15101         this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15102         
15103         this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15104         this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15105         this.touchViewBodyEl.setStyle('overflow', 'auto');
15106         
15107         this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15108         this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15109         
15110         this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15111         this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15112         
15113     },
15114     
15115     showTouchView : function()
15116     {
15117         if(this.disabled){
15118             return;
15119         }
15120         
15121         this.touchViewHeaderEl.hide();
15122
15123         if(this.modalTitle.length){
15124             this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15125             this.touchViewHeaderEl.show();
15126         }
15127
15128         this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15129         this.touchViewEl.show();
15130
15131         this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15132         
15133         //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15134         //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15135
15136         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15137
15138         if(this.modalTitle.length){
15139             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15140         }
15141         
15142         this.touchViewBodyEl.setHeight(bodyHeight);
15143
15144         if(this.animate){
15145             var _this = this;
15146             (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15147         }else{
15148             this.touchViewEl.addClass('in');
15149         }
15150
15151         this.doTouchViewQuery();
15152         
15153     },
15154     
15155     hideTouchView : function()
15156     {
15157         this.touchViewEl.removeClass('in');
15158
15159         if(this.animate){
15160             var _this = this;
15161             (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15162         }else{
15163             this.touchViewEl.setStyle('display', 'none');
15164         }
15165         
15166     },
15167     
15168     setTouchViewValue : function()
15169     {
15170         if(this.multiple){
15171             this.clearItem();
15172         
15173             var _this = this;
15174
15175             Roo.each(this.tickItems, function(o){
15176                 this.addItem(o);
15177             }, this);
15178         }
15179         
15180         this.hideTouchView();
15181     },
15182     
15183     doTouchViewQuery : function()
15184     {
15185         var qe = {
15186             query: '',
15187             forceAll: true,
15188             combo: this,
15189             cancel:false
15190         };
15191         
15192         if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15193             return false;
15194         }
15195         
15196         if(!this.alwaysQuery || this.mode == 'local'){
15197             this.onTouchViewLoad();
15198             return;
15199         }
15200         
15201         this.store.load();
15202     },
15203     
15204     onTouchViewBeforeLoad : function(combo,opts)
15205     {
15206         return;
15207     },
15208
15209     // private
15210     onTouchViewLoad : function()
15211     {
15212         if(this.store.getCount() < 1){
15213             this.onTouchViewEmptyResults();
15214             return;
15215         }
15216         
15217         this.clearTouchView();
15218         
15219         var rawValue = this.getRawValue();
15220         
15221         var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15222         
15223         this.tickItems = [];
15224         
15225         this.store.data.each(function(d, rowIndex){
15226             var row = this.touchViewListGroup.createChild(template);
15227             
15228             if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15229                 row.addClass(d.data.cls);
15230             }
15231             
15232             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15233                 var cfg = {
15234                     data : d.data,
15235                     html : d.data[this.displayField]
15236                 };
15237                 
15238                 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15239                     row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15240                 }
15241             }
15242             row.removeClass('selected');
15243             if(!this.multiple && this.valueField &&
15244                     typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15245             {
15246                 // radio buttons..
15247                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15248                 row.addClass('selected');
15249             }
15250             
15251             if(this.multiple && this.valueField &&
15252                     typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15253             {
15254                 
15255                 // checkboxes...
15256                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15257                 this.tickItems.push(d.data);
15258             }
15259             
15260             row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15261             
15262         }, this);
15263         
15264         var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15265         
15266         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15267
15268         if(this.modalTitle.length){
15269             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15270         }
15271
15272         var listHeight = this.touchViewListGroup.getHeight();
15273         
15274         var _this = this;
15275         
15276         if(firstChecked && listHeight > bodyHeight){
15277             (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15278         }
15279         
15280     },
15281     
15282     onTouchViewLoadException : function()
15283     {
15284         this.hideTouchView();
15285     },
15286     
15287     onTouchViewEmptyResults : function()
15288     {
15289         this.clearTouchView();
15290         
15291         this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15292         
15293         this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15294         
15295     },
15296     
15297     clearTouchView : function()
15298     {
15299         this.touchViewListGroup.dom.innerHTML = '';
15300     },
15301     
15302     onTouchViewClick : function(e, el, o)
15303     {
15304         e.preventDefault();
15305         
15306         var row = o.row;
15307         var rowIndex = o.rowIndex;
15308         
15309         var r = this.store.getAt(rowIndex);
15310         
15311         if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15312             
15313             if(!this.multiple){
15314                 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15315                     c.dom.removeAttribute('checked');
15316                 }, this);
15317
15318                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15319
15320                 this.setFromData(r.data);
15321
15322                 var close = this.closeTriggerEl();
15323
15324                 if(close){
15325                     close.show();
15326                 }
15327
15328                 this.hideTouchView();
15329
15330                 this.fireEvent('select', this, r, rowIndex);
15331
15332                 return;
15333             }
15334
15335             if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15336                 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15337                 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15338                 return;
15339             }
15340
15341             row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15342             this.addItem(r.data);
15343             this.tickItems.push(r.data);
15344         }
15345     },
15346     
15347     getAutoCreateNativeIOS : function()
15348     {
15349         var cfg = {
15350             cls: 'form-group' //input-group,
15351         };
15352         
15353         var combobox =  {
15354             tag: 'select',
15355             cls : 'roo-ios-select'
15356         };
15357         
15358         if (this.name) {
15359             combobox.name = this.name;
15360         }
15361         
15362         if (this.disabled) {
15363             combobox.disabled = true;
15364         }
15365         
15366         var settings = this;
15367         
15368         ['xs','sm','md','lg'].map(function(size){
15369             if (settings[size]) {
15370                 cfg.cls += ' col-' + size + '-' + settings[size];
15371             }
15372         });
15373         
15374         cfg.cn = combobox;
15375         
15376         return cfg;
15377         
15378     },
15379     
15380     initIOSView : function()
15381     {
15382         this.store.on('load', this.onIOSViewLoad, this);
15383         
15384         return;
15385     },
15386     
15387     onIOSViewLoad : function()
15388     {
15389         if(this.store.getCount() < 1){
15390             return;
15391         }
15392         
15393         this.clearIOSView();
15394         
15395         if(this.allowBlank) {
15396             
15397             var default_text = '-- SELECT --';
15398             
15399             if(this.placeholder.length){
15400                 default_text = this.placeholder;
15401             }
15402             
15403             if(this.emptyTitle.length){
15404                 default_text += ' - ' + this.emptyTitle + ' -';
15405             }
15406             
15407             var opt = this.inputEl().createChild({
15408                 tag: 'option',
15409                 value : 0,
15410                 html : default_text
15411             });
15412             
15413             var o = {};
15414             o[this.valueField] = 0;
15415             o[this.displayField] = default_text;
15416             
15417             this.ios_options.push({
15418                 data : o,
15419                 el : opt
15420             });
15421             
15422         }
15423         
15424         this.store.data.each(function(d, rowIndex){
15425             
15426             var html = '';
15427             
15428             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15429                 html = d.data[this.displayField];
15430             }
15431             
15432             var value = '';
15433             
15434             if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15435                 value = d.data[this.valueField];
15436             }
15437             
15438             var option = {
15439                 tag: 'option',
15440                 value : value,
15441                 html : html
15442             };
15443             
15444             if(this.value == d.data[this.valueField]){
15445                 option['selected'] = true;
15446             }
15447             
15448             var opt = this.inputEl().createChild(option);
15449             
15450             this.ios_options.push({
15451                 data : d.data,
15452                 el : opt
15453             });
15454             
15455         }, this);
15456         
15457         this.inputEl().on('change', function(){
15458            this.fireEvent('select', this);
15459         }, this);
15460         
15461     },
15462     
15463     clearIOSView: function()
15464     {
15465         this.inputEl().dom.innerHTML = '';
15466         
15467         this.ios_options = [];
15468     },
15469     
15470     setIOSValue: function(v)
15471     {
15472         this.value = v;
15473         
15474         if(!this.ios_options){
15475             return;
15476         }
15477         
15478         Roo.each(this.ios_options, function(opts){
15479            
15480            opts.el.dom.removeAttribute('selected');
15481            
15482            if(opts.data[this.valueField] != v){
15483                return;
15484            }
15485            
15486            opts.el.dom.setAttribute('selected', true);
15487            
15488         }, this);
15489     }
15490
15491     /** 
15492     * @cfg {Boolean} grow 
15493     * @hide 
15494     */
15495     /** 
15496     * @cfg {Number} growMin 
15497     * @hide 
15498     */
15499     /** 
15500     * @cfg {Number} growMax 
15501     * @hide 
15502     */
15503     /**
15504      * @hide
15505      * @method autoSize
15506      */
15507 });
15508
15509 Roo.apply(Roo.bootstrap.ComboBox,  {
15510     
15511     header : {
15512         tag: 'div',
15513         cls: 'modal-header',
15514         cn: [
15515             {
15516                 tag: 'h4',
15517                 cls: 'modal-title'
15518             }
15519         ]
15520     },
15521     
15522     body : {
15523         tag: 'div',
15524         cls: 'modal-body',
15525         cn: [
15526             {
15527                 tag: 'ul',
15528                 cls: 'list-group'
15529             }
15530         ]
15531     },
15532     
15533     listItemRadio : {
15534         tag: 'li',
15535         cls: 'list-group-item',
15536         cn: [
15537             {
15538                 tag: 'span',
15539                 cls: 'roo-combobox-list-group-item-value'
15540             },
15541             {
15542                 tag: 'div',
15543                 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15544                 cn: [
15545                     {
15546                         tag: 'input',
15547                         type: 'radio'
15548                     },
15549                     {
15550                         tag: 'label'
15551                     }
15552                 ]
15553             }
15554         ]
15555     },
15556     
15557     listItemCheckbox : {
15558         tag: 'li',
15559         cls: 'list-group-item',
15560         cn: [
15561             {
15562                 tag: 'span',
15563                 cls: 'roo-combobox-list-group-item-value'
15564             },
15565             {
15566                 tag: 'div',
15567                 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15568                 cn: [
15569                     {
15570                         tag: 'input',
15571                         type: 'checkbox'
15572                     },
15573                     {
15574                         tag: 'label'
15575                     }
15576                 ]
15577             }
15578         ]
15579     },
15580     
15581     emptyResult : {
15582         tag: 'div',
15583         cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15584     },
15585     
15586     footer : {
15587         tag: 'div',
15588         cls: 'modal-footer',
15589         cn: [
15590             {
15591                 tag: 'div',
15592                 cls: 'row',
15593                 cn: [
15594                     {
15595                         tag: 'div',
15596                         cls: 'col-xs-6 text-left',
15597                         cn: {
15598                             tag: 'button',
15599                             cls: 'btn btn-danger roo-touch-view-cancel',
15600                             html: 'Cancel'
15601                         }
15602                     },
15603                     {
15604                         tag: 'div',
15605                         cls: 'col-xs-6 text-right',
15606                         cn: {
15607                             tag: 'button',
15608                             cls: 'btn btn-success roo-touch-view-ok',
15609                             html: 'OK'
15610                         }
15611                     }
15612                 ]
15613             }
15614         ]
15615         
15616     }
15617 });
15618
15619 Roo.apply(Roo.bootstrap.ComboBox,  {
15620     
15621     touchViewTemplate : {
15622         tag: 'div',
15623         cls: 'modal fade roo-combobox-touch-view',
15624         cn: [
15625             {
15626                 tag: 'div',
15627                 cls: 'modal-dialog',
15628                 style : 'position:fixed', // we have to fix position....
15629                 cn: [
15630                     {
15631                         tag: 'div',
15632                         cls: 'modal-content',
15633                         cn: [
15634                             Roo.bootstrap.ComboBox.header,
15635                             Roo.bootstrap.ComboBox.body,
15636                             Roo.bootstrap.ComboBox.footer
15637                         ]
15638                     }
15639                 ]
15640             }
15641         ]
15642     }
15643 });/*
15644  * Based on:
15645  * Ext JS Library 1.1.1
15646  * Copyright(c) 2006-2007, Ext JS, LLC.
15647  *
15648  * Originally Released Under LGPL - original licence link has changed is not relivant.
15649  *
15650  * Fork - LGPL
15651  * <script type="text/javascript">
15652  */
15653
15654 /**
15655  * @class Roo.View
15656  * @extends Roo.util.Observable
15657  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
15658  * This class also supports single and multi selection modes. <br>
15659  * Create a data model bound view:
15660  <pre><code>
15661  var store = new Roo.data.Store(...);
15662
15663  var view = new Roo.View({
15664     el : "my-element",
15665     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
15666  
15667     singleSelect: true,
15668     selectedClass: "ydataview-selected",
15669     store: store
15670  });
15671
15672  // listen for node click?
15673  view.on("click", function(vw, index, node, e){
15674  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15675  });
15676
15677  // load XML data
15678  dataModel.load("foobar.xml");
15679  </code></pre>
15680  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15681  * <br><br>
15682  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15683  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15684  * 
15685  * Note: old style constructor is still suported (container, template, config)
15686  * 
15687  * @constructor
15688  * Create a new View
15689  * @param {Object} config The config object
15690  * 
15691  */
15692 Roo.View = function(config, depreciated_tpl, depreciated_config){
15693     
15694     this.parent = false;
15695     
15696     if (typeof(depreciated_tpl) == 'undefined') {
15697         // new way.. - universal constructor.
15698         Roo.apply(this, config);
15699         this.el  = Roo.get(this.el);
15700     } else {
15701         // old format..
15702         this.el  = Roo.get(config);
15703         this.tpl = depreciated_tpl;
15704         Roo.apply(this, depreciated_config);
15705     }
15706     this.wrapEl  = this.el.wrap().wrap();
15707     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15708     
15709     
15710     if(typeof(this.tpl) == "string"){
15711         this.tpl = new Roo.Template(this.tpl);
15712     } else {
15713         // support xtype ctors..
15714         this.tpl = new Roo.factory(this.tpl, Roo);
15715     }
15716     
15717     
15718     this.tpl.compile();
15719     
15720     /** @private */
15721     this.addEvents({
15722         /**
15723          * @event beforeclick
15724          * Fires before a click is processed. Returns false to cancel the default action.
15725          * @param {Roo.View} this
15726          * @param {Number} index The index of the target node
15727          * @param {HTMLElement} node The target node
15728          * @param {Roo.EventObject} e The raw event object
15729          */
15730             "beforeclick" : true,
15731         /**
15732          * @event click
15733          * Fires when a template node is clicked.
15734          * @param {Roo.View} this
15735          * @param {Number} index The index of the target node
15736          * @param {HTMLElement} node The target node
15737          * @param {Roo.EventObject} e The raw event object
15738          */
15739             "click" : true,
15740         /**
15741          * @event dblclick
15742          * Fires when a template node is double clicked.
15743          * @param {Roo.View} this
15744          * @param {Number} index The index of the target node
15745          * @param {HTMLElement} node The target node
15746          * @param {Roo.EventObject} e The raw event object
15747          */
15748             "dblclick" : true,
15749         /**
15750          * @event contextmenu
15751          * Fires when a template node is right clicked.
15752          * @param {Roo.View} this
15753          * @param {Number} index The index of the target node
15754          * @param {HTMLElement} node The target node
15755          * @param {Roo.EventObject} e The raw event object
15756          */
15757             "contextmenu" : true,
15758         /**
15759          * @event selectionchange
15760          * Fires when the selected nodes change.
15761          * @param {Roo.View} this
15762          * @param {Array} selections Array of the selected nodes
15763          */
15764             "selectionchange" : true,
15765     
15766         /**
15767          * @event beforeselect
15768          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15769          * @param {Roo.View} this
15770          * @param {HTMLElement} node The node to be selected
15771          * @param {Array} selections Array of currently selected nodes
15772          */
15773             "beforeselect" : true,
15774         /**
15775          * @event preparedata
15776          * Fires on every row to render, to allow you to change the data.
15777          * @param {Roo.View} this
15778          * @param {Object} data to be rendered (change this)
15779          */
15780           "preparedata" : true
15781           
15782           
15783         });
15784
15785
15786
15787     this.el.on({
15788         "click": this.onClick,
15789         "dblclick": this.onDblClick,
15790         "contextmenu": this.onContextMenu,
15791         scope:this
15792     });
15793
15794     this.selections = [];
15795     this.nodes = [];
15796     this.cmp = new Roo.CompositeElementLite([]);
15797     if(this.store){
15798         this.store = Roo.factory(this.store, Roo.data);
15799         this.setStore(this.store, true);
15800     }
15801     
15802     if ( this.footer && this.footer.xtype) {
15803            
15804          var fctr = this.wrapEl.appendChild(document.createElement("div"));
15805         
15806         this.footer.dataSource = this.store;
15807         this.footer.container = fctr;
15808         this.footer = Roo.factory(this.footer, Roo);
15809         fctr.insertFirst(this.el);
15810         
15811         // this is a bit insane - as the paging toolbar seems to detach the el..
15812 //        dom.parentNode.parentNode.parentNode
15813          // they get detached?
15814     }
15815     
15816     
15817     Roo.View.superclass.constructor.call(this);
15818     
15819     
15820 };
15821
15822 Roo.extend(Roo.View, Roo.util.Observable, {
15823     
15824      /**
15825      * @cfg {Roo.data.Store} store Data store to load data from.
15826      */
15827     store : false,
15828     
15829     /**
15830      * @cfg {String|Roo.Element} el The container element.
15831      */
15832     el : '',
15833     
15834     /**
15835      * @cfg {String|Roo.Template} tpl The template used by this View 
15836      */
15837     tpl : false,
15838     /**
15839      * @cfg {String} dataName the named area of the template to use as the data area
15840      *                          Works with domtemplates roo-name="name"
15841      */
15842     dataName: false,
15843     /**
15844      * @cfg {String} selectedClass The css class to add to selected nodes
15845      */
15846     selectedClass : "x-view-selected",
15847      /**
15848      * @cfg {String} emptyText The empty text to show when nothing is loaded.
15849      */
15850     emptyText : "",
15851     
15852     /**
15853      * @cfg {String} text to display on mask (default Loading)
15854      */
15855     mask : false,
15856     /**
15857      * @cfg {Boolean} multiSelect Allow multiple selection
15858      */
15859     multiSelect : false,
15860     /**
15861      * @cfg {Boolean} singleSelect Allow single selection
15862      */
15863     singleSelect:  false,
15864     
15865     /**
15866      * @cfg {Boolean} toggleSelect - selecting 
15867      */
15868     toggleSelect : false,
15869     
15870     /**
15871      * @cfg {Boolean} tickable - selecting 
15872      */
15873     tickable : false,
15874     
15875     /**
15876      * Returns the element this view is bound to.
15877      * @return {Roo.Element}
15878      */
15879     getEl : function(){
15880         return this.wrapEl;
15881     },
15882     
15883     
15884
15885     /**
15886      * Refreshes the view. - called by datachanged on the store. - do not call directly.
15887      */
15888     refresh : function(){
15889         //Roo.log('refresh');
15890         var t = this.tpl;
15891         
15892         // if we are using something like 'domtemplate', then
15893         // the what gets used is:
15894         // t.applySubtemplate(NAME, data, wrapping data..)
15895         // the outer template then get' applied with
15896         //     the store 'extra data'
15897         // and the body get's added to the
15898         //      roo-name="data" node?
15899         //      <span class='roo-tpl-{name}'></span> ?????
15900         
15901         
15902         
15903         this.clearSelections();
15904         this.el.update("");
15905         var html = [];
15906         var records = this.store.getRange();
15907         if(records.length < 1) {
15908             
15909             // is this valid??  = should it render a template??
15910             
15911             this.el.update(this.emptyText);
15912             return;
15913         }
15914         var el = this.el;
15915         if (this.dataName) {
15916             this.el.update(t.apply(this.store.meta)); //????
15917             el = this.el.child('.roo-tpl-' + this.dataName);
15918         }
15919         
15920         for(var i = 0, len = records.length; i < len; i++){
15921             var data = this.prepareData(records[i].data, i, records[i]);
15922             this.fireEvent("preparedata", this, data, i, records[i]);
15923             
15924             var d = Roo.apply({}, data);
15925             
15926             if(this.tickable){
15927                 Roo.apply(d, {'roo-id' : Roo.id()});
15928                 
15929                 var _this = this;
15930             
15931                 Roo.each(this.parent.item, function(item){
15932                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15933                         return;
15934                     }
15935                     Roo.apply(d, {'roo-data-checked' : 'checked'});
15936                 });
15937             }
15938             
15939             html[html.length] = Roo.util.Format.trim(
15940                 this.dataName ?
15941                     t.applySubtemplate(this.dataName, d, this.store.meta) :
15942                     t.apply(d)
15943             );
15944         }
15945         
15946         
15947         
15948         el.update(html.join(""));
15949         this.nodes = el.dom.childNodes;
15950         this.updateIndexes(0);
15951     },
15952     
15953
15954     /**
15955      * Function to override to reformat the data that is sent to
15956      * the template for each node.
15957      * DEPRICATED - use the preparedata event handler.
15958      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15959      * a JSON object for an UpdateManager bound view).
15960      */
15961     prepareData : function(data, index, record)
15962     {
15963         this.fireEvent("preparedata", this, data, index, record);
15964         return data;
15965     },
15966
15967     onUpdate : function(ds, record){
15968         // Roo.log('on update');   
15969         this.clearSelections();
15970         var index = this.store.indexOf(record);
15971         var n = this.nodes[index];
15972         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15973         n.parentNode.removeChild(n);
15974         this.updateIndexes(index, index);
15975     },
15976
15977     
15978     
15979 // --------- FIXME     
15980     onAdd : function(ds, records, index)
15981     {
15982         //Roo.log(['on Add', ds, records, index] );        
15983         this.clearSelections();
15984         if(this.nodes.length == 0){
15985             this.refresh();
15986             return;
15987         }
15988         var n = this.nodes[index];
15989         for(var i = 0, len = records.length; i < len; i++){
15990             var d = this.prepareData(records[i].data, i, records[i]);
15991             if(n){
15992                 this.tpl.insertBefore(n, d);
15993             }else{
15994                 
15995                 this.tpl.append(this.el, d);
15996             }
15997         }
15998         this.updateIndexes(index);
15999     },
16000
16001     onRemove : function(ds, record, index){
16002        // Roo.log('onRemove');
16003         this.clearSelections();
16004         var el = this.dataName  ?
16005             this.el.child('.roo-tpl-' + this.dataName) :
16006             this.el; 
16007         
16008         el.dom.removeChild(this.nodes[index]);
16009         this.updateIndexes(index);
16010     },
16011
16012     /**
16013      * Refresh an individual node.
16014      * @param {Number} index
16015      */
16016     refreshNode : function(index){
16017         this.onUpdate(this.store, this.store.getAt(index));
16018     },
16019
16020     updateIndexes : function(startIndex, endIndex){
16021         var ns = this.nodes;
16022         startIndex = startIndex || 0;
16023         endIndex = endIndex || ns.length - 1;
16024         for(var i = startIndex; i <= endIndex; i++){
16025             ns[i].nodeIndex = i;
16026         }
16027     },
16028
16029     /**
16030      * Changes the data store this view uses and refresh the view.
16031      * @param {Store} store
16032      */
16033     setStore : function(store, initial){
16034         if(!initial && this.store){
16035             this.store.un("datachanged", this.refresh);
16036             this.store.un("add", this.onAdd);
16037             this.store.un("remove", this.onRemove);
16038             this.store.un("update", this.onUpdate);
16039             this.store.un("clear", this.refresh);
16040             this.store.un("beforeload", this.onBeforeLoad);
16041             this.store.un("load", this.onLoad);
16042             this.store.un("loadexception", this.onLoad);
16043         }
16044         if(store){
16045           
16046             store.on("datachanged", this.refresh, this);
16047             store.on("add", this.onAdd, this);
16048             store.on("remove", this.onRemove, this);
16049             store.on("update", this.onUpdate, this);
16050             store.on("clear", this.refresh, this);
16051             store.on("beforeload", this.onBeforeLoad, this);
16052             store.on("load", this.onLoad, this);
16053             store.on("loadexception", this.onLoad, this);
16054         }
16055         
16056         if(store){
16057             this.refresh();
16058         }
16059     },
16060     /**
16061      * onbeforeLoad - masks the loading area.
16062      *
16063      */
16064     onBeforeLoad : function(store,opts)
16065     {
16066          //Roo.log('onBeforeLoad');   
16067         if (!opts.add) {
16068             this.el.update("");
16069         }
16070         this.el.mask(this.mask ? this.mask : "Loading" ); 
16071     },
16072     onLoad : function ()
16073     {
16074         this.el.unmask();
16075     },
16076     
16077
16078     /**
16079      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16080      * @param {HTMLElement} node
16081      * @return {HTMLElement} The template node
16082      */
16083     findItemFromChild : function(node){
16084         var el = this.dataName  ?
16085             this.el.child('.roo-tpl-' + this.dataName,true) :
16086             this.el.dom; 
16087         
16088         if(!node || node.parentNode == el){
16089                     return node;
16090             }
16091             var p = node.parentNode;
16092             while(p && p != el){
16093             if(p.parentNode == el){
16094                 return p;
16095             }
16096             p = p.parentNode;
16097         }
16098             return null;
16099     },
16100
16101     /** @ignore */
16102     onClick : function(e){
16103         var item = this.findItemFromChild(e.getTarget());
16104         if(item){
16105             var index = this.indexOf(item);
16106             if(this.onItemClick(item, index, e) !== false){
16107                 this.fireEvent("click", this, index, item, e);
16108             }
16109         }else{
16110             this.clearSelections();
16111         }
16112     },
16113
16114     /** @ignore */
16115     onContextMenu : function(e){
16116         var item = this.findItemFromChild(e.getTarget());
16117         if(item){
16118             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16119         }
16120     },
16121
16122     /** @ignore */
16123     onDblClick : function(e){
16124         var item = this.findItemFromChild(e.getTarget());
16125         if(item){
16126             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16127         }
16128     },
16129
16130     onItemClick : function(item, index, e)
16131     {
16132         if(this.fireEvent("beforeclick", this, index, item, e) === false){
16133             return false;
16134         }
16135         if (this.toggleSelect) {
16136             var m = this.isSelected(item) ? 'unselect' : 'select';
16137             //Roo.log(m);
16138             var _t = this;
16139             _t[m](item, true, false);
16140             return true;
16141         }
16142         if(this.multiSelect || this.singleSelect){
16143             if(this.multiSelect && e.shiftKey && this.lastSelection){
16144                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16145             }else{
16146                 this.select(item, this.multiSelect && e.ctrlKey);
16147                 this.lastSelection = item;
16148             }
16149             
16150             if(!this.tickable){
16151                 e.preventDefault();
16152             }
16153             
16154         }
16155         return true;
16156     },
16157
16158     /**
16159      * Get the number of selected nodes.
16160      * @return {Number}
16161      */
16162     getSelectionCount : function(){
16163         return this.selections.length;
16164     },
16165
16166     /**
16167      * Get the currently selected nodes.
16168      * @return {Array} An array of HTMLElements
16169      */
16170     getSelectedNodes : function(){
16171         return this.selections;
16172     },
16173
16174     /**
16175      * Get the indexes of the selected nodes.
16176      * @return {Array}
16177      */
16178     getSelectedIndexes : function(){
16179         var indexes = [], s = this.selections;
16180         for(var i = 0, len = s.length; i < len; i++){
16181             indexes.push(s[i].nodeIndex);
16182         }
16183         return indexes;
16184     },
16185
16186     /**
16187      * Clear all selections
16188      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16189      */
16190     clearSelections : function(suppressEvent){
16191         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16192             this.cmp.elements = this.selections;
16193             this.cmp.removeClass(this.selectedClass);
16194             this.selections = [];
16195             if(!suppressEvent){
16196                 this.fireEvent("selectionchange", this, this.selections);
16197             }
16198         }
16199     },
16200
16201     /**
16202      * Returns true if the passed node is selected
16203      * @param {HTMLElement/Number} node The node or node index
16204      * @return {Boolean}
16205      */
16206     isSelected : function(node){
16207         var s = this.selections;
16208         if(s.length < 1){
16209             return false;
16210         }
16211         node = this.getNode(node);
16212         return s.indexOf(node) !== -1;
16213     },
16214
16215     /**
16216      * Selects nodes.
16217      * @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
16218      * @param {Boolean} keepExisting (optional) true to keep existing selections
16219      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16220      */
16221     select : function(nodeInfo, keepExisting, suppressEvent){
16222         if(nodeInfo instanceof Array){
16223             if(!keepExisting){
16224                 this.clearSelections(true);
16225             }
16226             for(var i = 0, len = nodeInfo.length; i < len; i++){
16227                 this.select(nodeInfo[i], true, true);
16228             }
16229             return;
16230         } 
16231         var node = this.getNode(nodeInfo);
16232         if(!node || this.isSelected(node)){
16233             return; // already selected.
16234         }
16235         if(!keepExisting){
16236             this.clearSelections(true);
16237         }
16238         
16239         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16240             Roo.fly(node).addClass(this.selectedClass);
16241             this.selections.push(node);
16242             if(!suppressEvent){
16243                 this.fireEvent("selectionchange", this, this.selections);
16244             }
16245         }
16246         
16247         
16248     },
16249       /**
16250      * Unselects nodes.
16251      * @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
16252      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16253      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16254      */
16255     unselect : function(nodeInfo, keepExisting, suppressEvent)
16256     {
16257         if(nodeInfo instanceof Array){
16258             Roo.each(this.selections, function(s) {
16259                 this.unselect(s, nodeInfo);
16260             }, this);
16261             return;
16262         }
16263         var node = this.getNode(nodeInfo);
16264         if(!node || !this.isSelected(node)){
16265             //Roo.log("not selected");
16266             return; // not selected.
16267         }
16268         // fireevent???
16269         var ns = [];
16270         Roo.each(this.selections, function(s) {
16271             if (s == node ) {
16272                 Roo.fly(node).removeClass(this.selectedClass);
16273
16274                 return;
16275             }
16276             ns.push(s);
16277         },this);
16278         
16279         this.selections= ns;
16280         this.fireEvent("selectionchange", this, this.selections);
16281     },
16282
16283     /**
16284      * Gets a template node.
16285      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16286      * @return {HTMLElement} The node or null if it wasn't found
16287      */
16288     getNode : function(nodeInfo){
16289         if(typeof nodeInfo == "string"){
16290             return document.getElementById(nodeInfo);
16291         }else if(typeof nodeInfo == "number"){
16292             return this.nodes[nodeInfo];
16293         }
16294         return nodeInfo;
16295     },
16296
16297     /**
16298      * Gets a range template nodes.
16299      * @param {Number} startIndex
16300      * @param {Number} endIndex
16301      * @return {Array} An array of nodes
16302      */
16303     getNodes : function(start, end){
16304         var ns = this.nodes;
16305         start = start || 0;
16306         end = typeof end == "undefined" ? ns.length - 1 : end;
16307         var nodes = [];
16308         if(start <= end){
16309             for(var i = start; i <= end; i++){
16310                 nodes.push(ns[i]);
16311             }
16312         } else{
16313             for(var i = start; i >= end; i--){
16314                 nodes.push(ns[i]);
16315             }
16316         }
16317         return nodes;
16318     },
16319
16320     /**
16321      * Finds the index of the passed node
16322      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16323      * @return {Number} The index of the node or -1
16324      */
16325     indexOf : function(node){
16326         node = this.getNode(node);
16327         if(typeof node.nodeIndex == "number"){
16328             return node.nodeIndex;
16329         }
16330         var ns = this.nodes;
16331         for(var i = 0, len = ns.length; i < len; i++){
16332             if(ns[i] == node){
16333                 return i;
16334             }
16335         }
16336         return -1;
16337     }
16338 });
16339 /*
16340  * - LGPL
16341  *
16342  * based on jquery fullcalendar
16343  * 
16344  */
16345
16346 Roo.bootstrap = Roo.bootstrap || {};
16347 /**
16348  * @class Roo.bootstrap.Calendar
16349  * @extends Roo.bootstrap.Component
16350  * Bootstrap Calendar class
16351  * @cfg {Boolean} loadMask (true|false) default false
16352  * @cfg {Object} header generate the user specific header of the calendar, default false
16353
16354  * @constructor
16355  * Create a new Container
16356  * @param {Object} config The config object
16357  */
16358
16359
16360
16361 Roo.bootstrap.Calendar = function(config){
16362     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16363      this.addEvents({
16364         /**
16365              * @event select
16366              * Fires when a date is selected
16367              * @param {DatePicker} this
16368              * @param {Date} date The selected date
16369              */
16370         'select': true,
16371         /**
16372              * @event monthchange
16373              * Fires when the displayed month changes 
16374              * @param {DatePicker} this
16375              * @param {Date} date The selected month
16376              */
16377         'monthchange': true,
16378         /**
16379              * @event evententer
16380              * Fires when mouse over an event
16381              * @param {Calendar} this
16382              * @param {event} Event
16383              */
16384         'evententer': true,
16385         /**
16386              * @event eventleave
16387              * Fires when the mouse leaves an
16388              * @param {Calendar} this
16389              * @param {event}
16390              */
16391         'eventleave': true,
16392         /**
16393              * @event eventclick
16394              * Fires when the mouse click an
16395              * @param {Calendar} this
16396              * @param {event}
16397              */
16398         'eventclick': true
16399         
16400     });
16401
16402 };
16403
16404 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
16405     
16406      /**
16407      * @cfg {Number} startDay
16408      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16409      */
16410     startDay : 0,
16411     
16412     loadMask : false,
16413     
16414     header : false,
16415       
16416     getAutoCreate : function(){
16417         
16418         
16419         var fc_button = function(name, corner, style, content ) {
16420             return Roo.apply({},{
16421                 tag : 'span',
16422                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
16423                          (corner.length ?
16424                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16425                             ''
16426                         ),
16427                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16428                 unselectable: 'on'
16429             });
16430         };
16431         
16432         var header = {};
16433         
16434         if(!this.header){
16435             header = {
16436                 tag : 'table',
16437                 cls : 'fc-header',
16438                 style : 'width:100%',
16439                 cn : [
16440                     {
16441                         tag: 'tr',
16442                         cn : [
16443                             {
16444                                 tag : 'td',
16445                                 cls : 'fc-header-left',
16446                                 cn : [
16447                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
16448                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
16449                                     { tag: 'span', cls: 'fc-header-space' },
16450                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
16451
16452
16453                                 ]
16454                             },
16455
16456                             {
16457                                 tag : 'td',
16458                                 cls : 'fc-header-center',
16459                                 cn : [
16460                                     {
16461                                         tag: 'span',
16462                                         cls: 'fc-header-title',
16463                                         cn : {
16464                                             tag: 'H2',
16465                                             html : 'month / year'
16466                                         }
16467                                     }
16468
16469                                 ]
16470                             },
16471                             {
16472                                 tag : 'td',
16473                                 cls : 'fc-header-right',
16474                                 cn : [
16475                               /*      fc_button('month', 'left', '', 'month' ),
16476                                     fc_button('week', '', '', 'week' ),
16477                                     fc_button('day', 'right', '', 'day' )
16478                                 */    
16479
16480                                 ]
16481                             }
16482
16483                         ]
16484                     }
16485                 ]
16486             };
16487         }
16488         
16489         header = this.header;
16490         
16491        
16492         var cal_heads = function() {
16493             var ret = [];
16494             // fixme - handle this.
16495             
16496             for (var i =0; i < Date.dayNames.length; i++) {
16497                 var d = Date.dayNames[i];
16498                 ret.push({
16499                     tag: 'th',
16500                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16501                     html : d.substring(0,3)
16502                 });
16503                 
16504             }
16505             ret[0].cls += ' fc-first';
16506             ret[6].cls += ' fc-last';
16507             return ret;
16508         };
16509         var cal_cell = function(n) {
16510             return  {
16511                 tag: 'td',
16512                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16513                 cn : [
16514                     {
16515                         cn : [
16516                             {
16517                                 cls: 'fc-day-number',
16518                                 html: 'D'
16519                             },
16520                             {
16521                                 cls: 'fc-day-content',
16522                              
16523                                 cn : [
16524                                      {
16525                                         style: 'position: relative;' // height: 17px;
16526                                     }
16527                                 ]
16528                             }
16529                             
16530                             
16531                         ]
16532                     }
16533                 ]
16534                 
16535             }
16536         };
16537         var cal_rows = function() {
16538             
16539             var ret = [];
16540             for (var r = 0; r < 6; r++) {
16541                 var row= {
16542                     tag : 'tr',
16543                     cls : 'fc-week',
16544                     cn : []
16545                 };
16546                 
16547                 for (var i =0; i < Date.dayNames.length; i++) {
16548                     var d = Date.dayNames[i];
16549                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16550
16551                 }
16552                 row.cn[0].cls+=' fc-first';
16553                 row.cn[0].cn[0].style = 'min-height:90px';
16554                 row.cn[6].cls+=' fc-last';
16555                 ret.push(row);
16556                 
16557             }
16558             ret[0].cls += ' fc-first';
16559             ret[4].cls += ' fc-prev-last';
16560             ret[5].cls += ' fc-last';
16561             return ret;
16562             
16563         };
16564         
16565         var cal_table = {
16566             tag: 'table',
16567             cls: 'fc-border-separate',
16568             style : 'width:100%',
16569             cellspacing  : 0,
16570             cn : [
16571                 { 
16572                     tag: 'thead',
16573                     cn : [
16574                         { 
16575                             tag: 'tr',
16576                             cls : 'fc-first fc-last',
16577                             cn : cal_heads()
16578                         }
16579                     ]
16580                 },
16581                 { 
16582                     tag: 'tbody',
16583                     cn : cal_rows()
16584                 }
16585                   
16586             ]
16587         };
16588          
16589          var cfg = {
16590             cls : 'fc fc-ltr',
16591             cn : [
16592                 header,
16593                 {
16594                     cls : 'fc-content',
16595                     style : "position: relative;",
16596                     cn : [
16597                         {
16598                             cls : 'fc-view fc-view-month fc-grid',
16599                             style : 'position: relative',
16600                             unselectable : 'on',
16601                             cn : [
16602                                 {
16603                                     cls : 'fc-event-container',
16604                                     style : 'position:absolute;z-index:8;top:0;left:0;'
16605                                 },
16606                                 cal_table
16607                             ]
16608                         }
16609                     ]
16610     
16611                 }
16612            ] 
16613             
16614         };
16615         
16616          
16617         
16618         return cfg;
16619     },
16620     
16621     
16622     initEvents : function()
16623     {
16624         if(!this.store){
16625             throw "can not find store for calendar";
16626         }
16627         
16628         var mark = {
16629             tag: "div",
16630             cls:"x-dlg-mask",
16631             style: "text-align:center",
16632             cn: [
16633                 {
16634                     tag: "div",
16635                     style: "background-color:white;width:50%;margin:250 auto",
16636                     cn: [
16637                         {
16638                             tag: "img",
16639                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
16640                         },
16641                         {
16642                             tag: "span",
16643                             html: "Loading"
16644                         }
16645                         
16646                     ]
16647                 }
16648             ]
16649         };
16650         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16651         
16652         var size = this.el.select('.fc-content', true).first().getSize();
16653         this.maskEl.setSize(size.width, size.height);
16654         this.maskEl.enableDisplayMode("block");
16655         if(!this.loadMask){
16656             this.maskEl.hide();
16657         }
16658         
16659         this.store = Roo.factory(this.store, Roo.data);
16660         this.store.on('load', this.onLoad, this);
16661         this.store.on('beforeload', this.onBeforeLoad, this);
16662         
16663         this.resize();
16664         
16665         this.cells = this.el.select('.fc-day',true);
16666         //Roo.log(this.cells);
16667         this.textNodes = this.el.query('.fc-day-number');
16668         this.cells.addClassOnOver('fc-state-hover');
16669         
16670         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16671         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16672         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16673         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16674         
16675         this.on('monthchange', this.onMonthChange, this);
16676         
16677         this.update(new Date().clearTime());
16678     },
16679     
16680     resize : function() {
16681         var sz  = this.el.getSize();
16682         
16683         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16684         this.el.select('.fc-day-content div',true).setHeight(34);
16685     },
16686     
16687     
16688     // private
16689     showPrevMonth : function(e){
16690         this.update(this.activeDate.add("mo", -1));
16691     },
16692     showToday : function(e){
16693         this.update(new Date().clearTime());
16694     },
16695     // private
16696     showNextMonth : function(e){
16697         this.update(this.activeDate.add("mo", 1));
16698     },
16699
16700     // private
16701     showPrevYear : function(){
16702         this.update(this.activeDate.add("y", -1));
16703     },
16704
16705     // private
16706     showNextYear : function(){
16707         this.update(this.activeDate.add("y", 1));
16708     },
16709
16710     
16711    // private
16712     update : function(date)
16713     {
16714         var vd = this.activeDate;
16715         this.activeDate = date;
16716 //        if(vd && this.el){
16717 //            var t = date.getTime();
16718 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16719 //                Roo.log('using add remove');
16720 //                
16721 //                this.fireEvent('monthchange', this, date);
16722 //                
16723 //                this.cells.removeClass("fc-state-highlight");
16724 //                this.cells.each(function(c){
16725 //                   if(c.dateValue == t){
16726 //                       c.addClass("fc-state-highlight");
16727 //                       setTimeout(function(){
16728 //                            try{c.dom.firstChild.focus();}catch(e){}
16729 //                       }, 50);
16730 //                       return false;
16731 //                   }
16732 //                   return true;
16733 //                });
16734 //                return;
16735 //            }
16736 //        }
16737         
16738         var days = date.getDaysInMonth();
16739         
16740         var firstOfMonth = date.getFirstDateOfMonth();
16741         var startingPos = firstOfMonth.getDay()-this.startDay;
16742         
16743         if(startingPos < this.startDay){
16744             startingPos += 7;
16745         }
16746         
16747         var pm = date.add(Date.MONTH, -1);
16748         var prevStart = pm.getDaysInMonth()-startingPos;
16749 //        
16750         this.cells = this.el.select('.fc-day',true);
16751         this.textNodes = this.el.query('.fc-day-number');
16752         this.cells.addClassOnOver('fc-state-hover');
16753         
16754         var cells = this.cells.elements;
16755         var textEls = this.textNodes;
16756         
16757         Roo.each(cells, function(cell){
16758             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16759         });
16760         
16761         days += startingPos;
16762
16763         // convert everything to numbers so it's fast
16764         var day = 86400000;
16765         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16766         //Roo.log(d);
16767         //Roo.log(pm);
16768         //Roo.log(prevStart);
16769         
16770         var today = new Date().clearTime().getTime();
16771         var sel = date.clearTime().getTime();
16772         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16773         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16774         var ddMatch = this.disabledDatesRE;
16775         var ddText = this.disabledDatesText;
16776         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16777         var ddaysText = this.disabledDaysText;
16778         var format = this.format;
16779         
16780         var setCellClass = function(cal, cell){
16781             cell.row = 0;
16782             cell.events = [];
16783             cell.more = [];
16784             //Roo.log('set Cell Class');
16785             cell.title = "";
16786             var t = d.getTime();
16787             
16788             //Roo.log(d);
16789             
16790             cell.dateValue = t;
16791             if(t == today){
16792                 cell.className += " fc-today";
16793                 cell.className += " fc-state-highlight";
16794                 cell.title = cal.todayText;
16795             }
16796             if(t == sel){
16797                 // disable highlight in other month..
16798                 //cell.className += " fc-state-highlight";
16799                 
16800             }
16801             // disabling
16802             if(t < min) {
16803                 cell.className = " fc-state-disabled";
16804                 cell.title = cal.minText;
16805                 return;
16806             }
16807             if(t > max) {
16808                 cell.className = " fc-state-disabled";
16809                 cell.title = cal.maxText;
16810                 return;
16811             }
16812             if(ddays){
16813                 if(ddays.indexOf(d.getDay()) != -1){
16814                     cell.title = ddaysText;
16815                     cell.className = " fc-state-disabled";
16816                 }
16817             }
16818             if(ddMatch && format){
16819                 var fvalue = d.dateFormat(format);
16820                 if(ddMatch.test(fvalue)){
16821                     cell.title = ddText.replace("%0", fvalue);
16822                     cell.className = " fc-state-disabled";
16823                 }
16824             }
16825             
16826             if (!cell.initialClassName) {
16827                 cell.initialClassName = cell.dom.className;
16828             }
16829             
16830             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
16831         };
16832
16833         var i = 0;
16834         
16835         for(; i < startingPos; i++) {
16836             textEls[i].innerHTML = (++prevStart);
16837             d.setDate(d.getDate()+1);
16838             
16839             cells[i].className = "fc-past fc-other-month";
16840             setCellClass(this, cells[i]);
16841         }
16842         
16843         var intDay = 0;
16844         
16845         for(; i < days; i++){
16846             intDay = i - startingPos + 1;
16847             textEls[i].innerHTML = (intDay);
16848             d.setDate(d.getDate()+1);
16849             
16850             cells[i].className = ''; // "x-date-active";
16851             setCellClass(this, cells[i]);
16852         }
16853         var extraDays = 0;
16854         
16855         for(; i < 42; i++) {
16856             textEls[i].innerHTML = (++extraDays);
16857             d.setDate(d.getDate()+1);
16858             
16859             cells[i].className = "fc-future fc-other-month";
16860             setCellClass(this, cells[i]);
16861         }
16862         
16863         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16864         
16865         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16866         
16867         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16868         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16869         
16870         if(totalRows != 6){
16871             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16872             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16873         }
16874         
16875         this.fireEvent('monthchange', this, date);
16876         
16877         
16878         /*
16879         if(!this.internalRender){
16880             var main = this.el.dom.firstChild;
16881             var w = main.offsetWidth;
16882             this.el.setWidth(w + this.el.getBorderWidth("lr"));
16883             Roo.fly(main).setWidth(w);
16884             this.internalRender = true;
16885             // opera does not respect the auto grow header center column
16886             // then, after it gets a width opera refuses to recalculate
16887             // without a second pass
16888             if(Roo.isOpera && !this.secondPass){
16889                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16890                 this.secondPass = true;
16891                 this.update.defer(10, this, [date]);
16892             }
16893         }
16894         */
16895         
16896     },
16897     
16898     findCell : function(dt) {
16899         dt = dt.clearTime().getTime();
16900         var ret = false;
16901         this.cells.each(function(c){
16902             //Roo.log("check " +c.dateValue + '?=' + dt);
16903             if(c.dateValue == dt){
16904                 ret = c;
16905                 return false;
16906             }
16907             return true;
16908         });
16909         
16910         return ret;
16911     },
16912     
16913     findCells : function(ev) {
16914         var s = ev.start.clone().clearTime().getTime();
16915        // Roo.log(s);
16916         var e= ev.end.clone().clearTime().getTime();
16917        // Roo.log(e);
16918         var ret = [];
16919         this.cells.each(function(c){
16920              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16921             
16922             if(c.dateValue > e){
16923                 return ;
16924             }
16925             if(c.dateValue < s){
16926                 return ;
16927             }
16928             ret.push(c);
16929         });
16930         
16931         return ret;    
16932     },
16933     
16934 //    findBestRow: function(cells)
16935 //    {
16936 //        var ret = 0;
16937 //        
16938 //        for (var i =0 ; i < cells.length;i++) {
16939 //            ret  = Math.max(cells[i].rows || 0,ret);
16940 //        }
16941 //        return ret;
16942 //        
16943 //    },
16944     
16945     
16946     addItem : function(ev)
16947     {
16948         // look for vertical location slot in
16949         var cells = this.findCells(ev);
16950         
16951 //        ev.row = this.findBestRow(cells);
16952         
16953         // work out the location.
16954         
16955         var crow = false;
16956         var rows = [];
16957         for(var i =0; i < cells.length; i++) {
16958             
16959             cells[i].row = cells[0].row;
16960             
16961             if(i == 0){
16962                 cells[i].row = cells[i].row + 1;
16963             }
16964             
16965             if (!crow) {
16966                 crow = {
16967                     start : cells[i],
16968                     end :  cells[i]
16969                 };
16970                 continue;
16971             }
16972             if (crow.start.getY() == cells[i].getY()) {
16973                 // on same row.
16974                 crow.end = cells[i];
16975                 continue;
16976             }
16977             // different row.
16978             rows.push(crow);
16979             crow = {
16980                 start: cells[i],
16981                 end : cells[i]
16982             };
16983             
16984         }
16985         
16986         rows.push(crow);
16987         ev.els = [];
16988         ev.rows = rows;
16989         ev.cells = cells;
16990         
16991         cells[0].events.push(ev);
16992         
16993         this.calevents.push(ev);
16994     },
16995     
16996     clearEvents: function() {
16997         
16998         if(!this.calevents){
16999             return;
17000         }
17001         
17002         Roo.each(this.cells.elements, function(c){
17003             c.row = 0;
17004             c.events = [];
17005             c.more = [];
17006         });
17007         
17008         Roo.each(this.calevents, function(e) {
17009             Roo.each(e.els, function(el) {
17010                 el.un('mouseenter' ,this.onEventEnter, this);
17011                 el.un('mouseleave' ,this.onEventLeave, this);
17012                 el.remove();
17013             },this);
17014         },this);
17015         
17016         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17017             e.remove();
17018         });
17019         
17020     },
17021     
17022     renderEvents: function()
17023     {   
17024         var _this = this;
17025         
17026         this.cells.each(function(c) {
17027             
17028             if(c.row < 5){
17029                 return;
17030             }
17031             
17032             var ev = c.events;
17033             
17034             var r = 4;
17035             if(c.row != c.events.length){
17036                 r = 4 - (4 - (c.row - c.events.length));
17037             }
17038             
17039             c.events = ev.slice(0, r);
17040             c.more = ev.slice(r);
17041             
17042             if(c.more.length && c.more.length == 1){
17043                 c.events.push(c.more.pop());
17044             }
17045             
17046             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17047             
17048         });
17049             
17050         this.cells.each(function(c) {
17051             
17052             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17053             
17054             
17055             for (var e = 0; e < c.events.length; e++){
17056                 var ev = c.events[e];
17057                 var rows = ev.rows;
17058                 
17059                 for(var i = 0; i < rows.length; i++) {
17060                 
17061                     // how many rows should it span..
17062
17063                     var  cfg = {
17064                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17065                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17066
17067                         unselectable : "on",
17068                         cn : [
17069                             {
17070                                 cls: 'fc-event-inner',
17071                                 cn : [
17072     //                                {
17073     //                                  tag:'span',
17074     //                                  cls: 'fc-event-time',
17075     //                                  html : cells.length > 1 ? '' : ev.time
17076     //                                },
17077                                     {
17078                                       tag:'span',
17079                                       cls: 'fc-event-title',
17080                                       html : String.format('{0}', ev.title)
17081                                     }
17082
17083
17084                                 ]
17085                             },
17086                             {
17087                                 cls: 'ui-resizable-handle ui-resizable-e',
17088                                 html : '&nbsp;&nbsp;&nbsp'
17089                             }
17090
17091                         ]
17092                     };
17093
17094                     if (i == 0) {
17095                         cfg.cls += ' fc-event-start';
17096                     }
17097                     if ((i+1) == rows.length) {
17098                         cfg.cls += ' fc-event-end';
17099                     }
17100
17101                     var ctr = _this.el.select('.fc-event-container',true).first();
17102                     var cg = ctr.createChild(cfg);
17103
17104                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17105                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17106
17107                     var r = (c.more.length) ? 1 : 0;
17108                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
17109                     cg.setWidth(ebox.right - sbox.x -2);
17110
17111                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17112                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17113                     cg.on('click', _this.onEventClick, _this, ev);
17114
17115                     ev.els.push(cg);
17116                     
17117                 }
17118                 
17119             }
17120             
17121             
17122             if(c.more.length){
17123                 var  cfg = {
17124                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17125                     style : 'position: absolute',
17126                     unselectable : "on",
17127                     cn : [
17128                         {
17129                             cls: 'fc-event-inner',
17130                             cn : [
17131                                 {
17132                                   tag:'span',
17133                                   cls: 'fc-event-title',
17134                                   html : 'More'
17135                                 }
17136
17137
17138                             ]
17139                         },
17140                         {
17141                             cls: 'ui-resizable-handle ui-resizable-e',
17142                             html : '&nbsp;&nbsp;&nbsp'
17143                         }
17144
17145                     ]
17146                 };
17147
17148                 var ctr = _this.el.select('.fc-event-container',true).first();
17149                 var cg = ctr.createChild(cfg);
17150
17151                 var sbox = c.select('.fc-day-content',true).first().getBox();
17152                 var ebox = c.select('.fc-day-content',true).first().getBox();
17153                 //Roo.log(cg);
17154                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
17155                 cg.setWidth(ebox.right - sbox.x -2);
17156
17157                 cg.on('click', _this.onMoreEventClick, _this, c.more);
17158                 
17159             }
17160             
17161         });
17162         
17163         
17164         
17165     },
17166     
17167     onEventEnter: function (e, el,event,d) {
17168         this.fireEvent('evententer', this, el, event);
17169     },
17170     
17171     onEventLeave: function (e, el,event,d) {
17172         this.fireEvent('eventleave', this, el, event);
17173     },
17174     
17175     onEventClick: function (e, el,event,d) {
17176         this.fireEvent('eventclick', this, el, event);
17177     },
17178     
17179     onMonthChange: function () {
17180         this.store.load();
17181     },
17182     
17183     onMoreEventClick: function(e, el, more)
17184     {
17185         var _this = this;
17186         
17187         this.calpopover.placement = 'right';
17188         this.calpopover.setTitle('More');
17189         
17190         this.calpopover.setContent('');
17191         
17192         var ctr = this.calpopover.el.select('.popover-content', true).first();
17193         
17194         Roo.each(more, function(m){
17195             var cfg = {
17196                 cls : 'fc-event-hori fc-event-draggable',
17197                 html : m.title
17198             };
17199             var cg = ctr.createChild(cfg);
17200             
17201             cg.on('click', _this.onEventClick, _this, m);
17202         });
17203         
17204         this.calpopover.show(el);
17205         
17206         
17207     },
17208     
17209     onLoad: function () 
17210     {   
17211         this.calevents = [];
17212         var cal = this;
17213         
17214         if(this.store.getCount() > 0){
17215             this.store.data.each(function(d){
17216                cal.addItem({
17217                     id : d.data.id,
17218                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17219                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17220                     time : d.data.start_time,
17221                     title : d.data.title,
17222                     description : d.data.description,
17223                     venue : d.data.venue
17224                 });
17225             });
17226         }
17227         
17228         this.renderEvents();
17229         
17230         if(this.calevents.length && this.loadMask){
17231             this.maskEl.hide();
17232         }
17233     },
17234     
17235     onBeforeLoad: function()
17236     {
17237         this.clearEvents();
17238         if(this.loadMask){
17239             this.maskEl.show();
17240         }
17241     }
17242 });
17243
17244  
17245  /*
17246  * - LGPL
17247  *
17248  * element
17249  * 
17250  */
17251
17252 /**
17253  * @class Roo.bootstrap.Popover
17254  * @extends Roo.bootstrap.Component
17255  * Bootstrap Popover class
17256  * @cfg {String} html contents of the popover   (or false to use children..)
17257  * @cfg {String} title of popover (or false to hide)
17258  * @cfg {String} placement how it is placed
17259  * @cfg {String} trigger click || hover (or false to trigger manually)
17260  * @cfg {String} over what (parent or false to trigger manually.)
17261  * @cfg {Number} delay - delay before showing
17262  
17263  * @constructor
17264  * Create a new Popover
17265  * @param {Object} config The config object
17266  */
17267
17268 Roo.bootstrap.Popover = function(config){
17269     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17270     
17271     this.addEvents({
17272         // raw events
17273          /**
17274          * @event show
17275          * After the popover show
17276          * 
17277          * @param {Roo.bootstrap.Popover} this
17278          */
17279         "show" : true,
17280         /**
17281          * @event hide
17282          * After the popover hide
17283          * 
17284          * @param {Roo.bootstrap.Popover} this
17285          */
17286         "hide" : true
17287     });
17288 };
17289
17290 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
17291     
17292     title: 'Fill in a title',
17293     html: false,
17294     
17295     placement : 'right',
17296     trigger : 'hover', // hover
17297     
17298     delay : 0,
17299     
17300     over: 'parent',
17301     
17302     can_build_overlaid : false,
17303     
17304     getChildContainer : function()
17305     {
17306         return this.el.select('.popover-content',true).first();
17307     },
17308     
17309     getAutoCreate : function(){
17310          
17311         var cfg = {
17312            cls : 'popover roo-dynamic',
17313            style: 'display:block',
17314            cn : [
17315                 {
17316                     cls : 'arrow'
17317                 },
17318                 {
17319                     cls : 'popover-inner',
17320                     cn : [
17321                         {
17322                             tag: 'h3',
17323                             cls: 'popover-title',
17324                             html : this.title
17325                         },
17326                         {
17327                             cls : 'popover-content',
17328                             html : this.html
17329                         }
17330                     ]
17331                     
17332                 }
17333            ]
17334         };
17335         
17336         return cfg;
17337     },
17338     setTitle: function(str)
17339     {
17340         this.title = str;
17341         this.el.select('.popover-title',true).first().dom.innerHTML = str;
17342     },
17343     setContent: function(str)
17344     {
17345         this.html = str;
17346         this.el.select('.popover-content',true).first().dom.innerHTML = str;
17347     },
17348     // as it get's added to the bottom of the page.
17349     onRender : function(ct, position)
17350     {
17351         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17352         if(!this.el){
17353             var cfg = Roo.apply({},  this.getAutoCreate());
17354             cfg.id = Roo.id();
17355             
17356             if (this.cls) {
17357                 cfg.cls += ' ' + this.cls;
17358             }
17359             if (this.style) {
17360                 cfg.style = this.style;
17361             }
17362             //Roo.log("adding to ");
17363             this.el = Roo.get(document.body).createChild(cfg, position);
17364 //            Roo.log(this.el);
17365         }
17366         this.initEvents();
17367     },
17368     
17369     initEvents : function()
17370     {
17371         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17372         this.el.enableDisplayMode('block');
17373         this.el.hide();
17374         if (this.over === false) {
17375             return; 
17376         }
17377         if (this.triggers === false) {
17378             return;
17379         }
17380         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17381         var triggers = this.trigger ? this.trigger.split(' ') : [];
17382         Roo.each(triggers, function(trigger) {
17383         
17384             if (trigger == 'click') {
17385                 on_el.on('click', this.toggle, this);
17386             } else if (trigger != 'manual') {
17387                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
17388                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17389       
17390                 on_el.on(eventIn  ,this.enter, this);
17391                 on_el.on(eventOut, this.leave, this);
17392             }
17393         }, this);
17394         
17395     },
17396     
17397     
17398     // private
17399     timeout : null,
17400     hoverState : null,
17401     
17402     toggle : function () {
17403         this.hoverState == 'in' ? this.leave() : this.enter();
17404     },
17405     
17406     enter : function () {
17407         
17408         clearTimeout(this.timeout);
17409     
17410         this.hoverState = 'in';
17411     
17412         if (!this.delay || !this.delay.show) {
17413             this.show();
17414             return;
17415         }
17416         var _t = this;
17417         this.timeout = setTimeout(function () {
17418             if (_t.hoverState == 'in') {
17419                 _t.show();
17420             }
17421         }, this.delay.show)
17422     },
17423     
17424     leave : function() {
17425         clearTimeout(this.timeout);
17426     
17427         this.hoverState = 'out';
17428     
17429         if (!this.delay || !this.delay.hide) {
17430             this.hide();
17431             return;
17432         }
17433         var _t = this;
17434         this.timeout = setTimeout(function () {
17435             if (_t.hoverState == 'out') {
17436                 _t.hide();
17437             }
17438         }, this.delay.hide)
17439     },
17440     
17441     show : function (on_el)
17442     {
17443         if (!on_el) {
17444             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17445         }
17446         
17447         // set content.
17448         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17449         if (this.html !== false) {
17450             this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17451         }
17452         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17453         if (!this.title.length) {
17454             this.el.select('.popover-title',true).hide();
17455         }
17456         
17457         var placement = typeof this.placement == 'function' ?
17458             this.placement.call(this, this.el, on_el) :
17459             this.placement;
17460             
17461         var autoToken = /\s?auto?\s?/i;
17462         var autoPlace = autoToken.test(placement);
17463         if (autoPlace) {
17464             placement = placement.replace(autoToken, '') || 'top';
17465         }
17466         
17467         //this.el.detach()
17468         //this.el.setXY([0,0]);
17469         this.el.show();
17470         this.el.dom.style.display='block';
17471         this.el.addClass(placement);
17472         
17473         //this.el.appendTo(on_el);
17474         
17475         var p = this.getPosition();
17476         var box = this.el.getBox();
17477         
17478         if (autoPlace) {
17479             // fixme..
17480         }
17481         var align = Roo.bootstrap.Popover.alignment[placement];
17482         
17483 //        Roo.log(align);
17484         this.el.alignTo(on_el, align[0],align[1]);
17485         //var arrow = this.el.select('.arrow',true).first();
17486         //arrow.set(align[2], 
17487         
17488         this.el.addClass('in');
17489         
17490         
17491         if (this.el.hasClass('fade')) {
17492             // fade it?
17493         }
17494         
17495         this.hoverState = 'in';
17496         
17497         this.fireEvent('show', this);
17498         
17499     },
17500     hide : function()
17501     {
17502         this.el.setXY([0,0]);
17503         this.el.removeClass('in');
17504         this.el.hide();
17505         this.hoverState = null;
17506         
17507         this.fireEvent('hide', this);
17508     }
17509     
17510 });
17511
17512 Roo.bootstrap.Popover.alignment = {
17513     'left' : ['r-l', [-10,0], 'right'],
17514     'right' : ['l-r', [10,0], 'left'],
17515     'bottom' : ['t-b', [0,10], 'top'],
17516     'top' : [ 'b-t', [0,-10], 'bottom']
17517 };
17518
17519  /*
17520  * - LGPL
17521  *
17522  * Progress
17523  * 
17524  */
17525
17526 /**
17527  * @class Roo.bootstrap.Progress
17528  * @extends Roo.bootstrap.Component
17529  * Bootstrap Progress class
17530  * @cfg {Boolean} striped striped of the progress bar
17531  * @cfg {Boolean} active animated of the progress bar
17532  * 
17533  * 
17534  * @constructor
17535  * Create a new Progress
17536  * @param {Object} config The config object
17537  */
17538
17539 Roo.bootstrap.Progress = function(config){
17540     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17541 };
17542
17543 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
17544     
17545     striped : false,
17546     active: false,
17547     
17548     getAutoCreate : function(){
17549         var cfg = {
17550             tag: 'div',
17551             cls: 'progress'
17552         };
17553         
17554         
17555         if(this.striped){
17556             cfg.cls += ' progress-striped';
17557         }
17558       
17559         if(this.active){
17560             cfg.cls += ' active';
17561         }
17562         
17563         
17564         return cfg;
17565     }
17566    
17567 });
17568
17569  
17570
17571  /*
17572  * - LGPL
17573  *
17574  * ProgressBar
17575  * 
17576  */
17577
17578 /**
17579  * @class Roo.bootstrap.ProgressBar
17580  * @extends Roo.bootstrap.Component
17581  * Bootstrap ProgressBar class
17582  * @cfg {Number} aria_valuenow aria-value now
17583  * @cfg {Number} aria_valuemin aria-value min
17584  * @cfg {Number} aria_valuemax aria-value max
17585  * @cfg {String} label label for the progress bar
17586  * @cfg {String} panel (success | info | warning | danger )
17587  * @cfg {String} role role of the progress bar
17588  * @cfg {String} sr_only text
17589  * 
17590  * 
17591  * @constructor
17592  * Create a new ProgressBar
17593  * @param {Object} config The config object
17594  */
17595
17596 Roo.bootstrap.ProgressBar = function(config){
17597     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17598 };
17599
17600 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
17601     
17602     aria_valuenow : 0,
17603     aria_valuemin : 0,
17604     aria_valuemax : 100,
17605     label : false,
17606     panel : false,
17607     role : false,
17608     sr_only: false,
17609     
17610     getAutoCreate : function()
17611     {
17612         
17613         var cfg = {
17614             tag: 'div',
17615             cls: 'progress-bar',
17616             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17617         };
17618         
17619         if(this.sr_only){
17620             cfg.cn = {
17621                 tag: 'span',
17622                 cls: 'sr-only',
17623                 html: this.sr_only
17624             }
17625         }
17626         
17627         if(this.role){
17628             cfg.role = this.role;
17629         }
17630         
17631         if(this.aria_valuenow){
17632             cfg['aria-valuenow'] = this.aria_valuenow;
17633         }
17634         
17635         if(this.aria_valuemin){
17636             cfg['aria-valuemin'] = this.aria_valuemin;
17637         }
17638         
17639         if(this.aria_valuemax){
17640             cfg['aria-valuemax'] = this.aria_valuemax;
17641         }
17642         
17643         if(this.label && !this.sr_only){
17644             cfg.html = this.label;
17645         }
17646         
17647         if(this.panel){
17648             cfg.cls += ' progress-bar-' + this.panel;
17649         }
17650         
17651         return cfg;
17652     },
17653     
17654     update : function(aria_valuenow)
17655     {
17656         this.aria_valuenow = aria_valuenow;
17657         
17658         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17659     }
17660    
17661 });
17662
17663  
17664
17665  /*
17666  * - LGPL
17667  *
17668  * column
17669  * 
17670  */
17671
17672 /**
17673  * @class Roo.bootstrap.TabGroup
17674  * @extends Roo.bootstrap.Column
17675  * Bootstrap Column class
17676  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17677  * @cfg {Boolean} carousel true to make the group behave like a carousel
17678  * @cfg {Boolean} bullets show bullets for the panels
17679  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17680  * @cfg {Number} timer auto slide timer .. default 0 millisecond
17681  * @cfg {Boolean} showarrow (true|false) show arrow default true
17682  * 
17683  * @constructor
17684  * Create a new TabGroup
17685  * @param {Object} config The config object
17686  */
17687
17688 Roo.bootstrap.TabGroup = function(config){
17689     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17690     if (!this.navId) {
17691         this.navId = Roo.id();
17692     }
17693     this.tabs = [];
17694     Roo.bootstrap.TabGroup.register(this);
17695     
17696 };
17697
17698 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
17699     
17700     carousel : false,
17701     transition : false,
17702     bullets : 0,
17703     timer : 0,
17704     autoslide : false,
17705     slideFn : false,
17706     slideOnTouch : false,
17707     showarrow : true,
17708     
17709     getAutoCreate : function()
17710     {
17711         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17712         
17713         cfg.cls += ' tab-content';
17714         
17715         if (this.carousel) {
17716             cfg.cls += ' carousel slide';
17717             
17718             cfg.cn = [{
17719                cls : 'carousel-inner',
17720                cn : []
17721             }];
17722         
17723             if(this.bullets  && !Roo.isTouch){
17724                 
17725                 var bullets = {
17726                     cls : 'carousel-bullets',
17727                     cn : []
17728                 };
17729                
17730                 if(this.bullets_cls){
17731                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17732                 }
17733                 
17734                 bullets.cn.push({
17735                     cls : 'clear'
17736                 });
17737                 
17738                 cfg.cn[0].cn.push(bullets);
17739             }
17740             
17741             if(this.showarrow){
17742                 cfg.cn[0].cn.push({
17743                     tag : 'div',
17744                     class : 'carousel-arrow',
17745                     cn : [
17746                         {
17747                             tag : 'div',
17748                             class : 'carousel-prev',
17749                             cn : [
17750                                 {
17751                                     tag : 'i',
17752                                     class : 'fa fa-chevron-left'
17753                                 }
17754                             ]
17755                         },
17756                         {
17757                             tag : 'div',
17758                             class : 'carousel-next',
17759                             cn : [
17760                                 {
17761                                     tag : 'i',
17762                                     class : 'fa fa-chevron-right'
17763                                 }
17764                             ]
17765                         }
17766                     ]
17767                 });
17768             }
17769             
17770         }
17771         
17772         return cfg;
17773     },
17774     
17775     initEvents:  function()
17776     {
17777 //        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17778 //            this.el.on("touchstart", this.onTouchStart, this);
17779 //        }
17780         
17781         if(this.autoslide){
17782             var _this = this;
17783             
17784             this.slideFn = window.setInterval(function() {
17785                 _this.showPanelNext();
17786             }, this.timer);
17787         }
17788         
17789         if(this.showarrow){
17790             this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17791             this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17792         }
17793         
17794         
17795     },
17796     
17797 //    onTouchStart : function(e, el, o)
17798 //    {
17799 //        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17800 //            return;
17801 //        }
17802 //        
17803 //        this.showPanelNext();
17804 //    },
17805     
17806     
17807     getChildContainer : function()
17808     {
17809         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17810     },
17811     
17812     /**
17813     * register a Navigation item
17814     * @param {Roo.bootstrap.NavItem} the navitem to add
17815     */
17816     register : function(item)
17817     {
17818         this.tabs.push( item);
17819         item.navId = this.navId; // not really needed..
17820         this.addBullet();
17821     
17822     },
17823     
17824     getActivePanel : function()
17825     {
17826         var r = false;
17827         Roo.each(this.tabs, function(t) {
17828             if (t.active) {
17829                 r = t;
17830                 return false;
17831             }
17832             return null;
17833         });
17834         return r;
17835         
17836     },
17837     getPanelByName : function(n)
17838     {
17839         var r = false;
17840         Roo.each(this.tabs, function(t) {
17841             if (t.tabId == n) {
17842                 r = t;
17843                 return false;
17844             }
17845             return null;
17846         });
17847         return r;
17848     },
17849     indexOfPanel : function(p)
17850     {
17851         var r = false;
17852         Roo.each(this.tabs, function(t,i) {
17853             if (t.tabId == p.tabId) {
17854                 r = i;
17855                 return false;
17856             }
17857             return null;
17858         });
17859         return r;
17860     },
17861     /**
17862      * show a specific panel
17863      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17864      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17865      */
17866     showPanel : function (pan)
17867     {
17868         if(this.transition || typeof(pan) == 'undefined'){
17869             Roo.log("waiting for the transitionend");
17870             return;
17871         }
17872         
17873         if (typeof(pan) == 'number') {
17874             pan = this.tabs[pan];
17875         }
17876         
17877         if (typeof(pan) == 'string') {
17878             pan = this.getPanelByName(pan);
17879         }
17880         
17881         var cur = this.getActivePanel();
17882         
17883         if(!pan || !cur){
17884             Roo.log('pan or acitve pan is undefined');
17885             return false;
17886         }
17887         
17888         if (pan.tabId == this.getActivePanel().tabId) {
17889             return true;
17890         }
17891         
17892         if (false === cur.fireEvent('beforedeactivate')) {
17893             return false;
17894         }
17895         
17896         if(this.bullets > 0 && !Roo.isTouch){
17897             this.setActiveBullet(this.indexOfPanel(pan));
17898         }
17899         
17900         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17901             
17902             this.transition = true;
17903             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
17904             var lr = dir == 'next' ? 'left' : 'right';
17905             pan.el.addClass(dir); // or prev
17906             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17907             cur.el.addClass(lr); // or right
17908             pan.el.addClass(lr);
17909             
17910             var _this = this;
17911             cur.el.on('transitionend', function() {
17912                 Roo.log("trans end?");
17913                 
17914                 pan.el.removeClass([lr,dir]);
17915                 pan.setActive(true);
17916                 
17917                 cur.el.removeClass([lr]);
17918                 cur.setActive(false);
17919                 
17920                 _this.transition = false;
17921                 
17922             }, this, { single:  true } );
17923             
17924             return true;
17925         }
17926         
17927         cur.setActive(false);
17928         pan.setActive(true);
17929         
17930         return true;
17931         
17932     },
17933     showPanelNext : function()
17934     {
17935         var i = this.indexOfPanel(this.getActivePanel());
17936         
17937         if (i >= this.tabs.length - 1 && !this.autoslide) {
17938             return;
17939         }
17940         
17941         if (i >= this.tabs.length - 1 && this.autoslide) {
17942             i = -1;
17943         }
17944         
17945         this.showPanel(this.tabs[i+1]);
17946     },
17947     
17948     showPanelPrev : function()
17949     {
17950         var i = this.indexOfPanel(this.getActivePanel());
17951         
17952         if (i  < 1 && !this.autoslide) {
17953             return;
17954         }
17955         
17956         if (i < 1 && this.autoslide) {
17957             i = this.tabs.length;
17958         }
17959         
17960         this.showPanel(this.tabs[i-1]);
17961     },
17962     
17963     
17964     addBullet: function()
17965     {
17966         if(!this.bullets || Roo.isTouch){
17967             return;
17968         }
17969         var ctr = this.el.select('.carousel-bullets',true).first();
17970         var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17971         var bullet = ctr.createChild({
17972             cls : 'bullet bullet-' + i
17973         },ctr.dom.lastChild);
17974         
17975         
17976         var _this = this;
17977         
17978         bullet.on('click', (function(e, el, o, ii, t){
17979
17980             e.preventDefault();
17981
17982             this.showPanel(ii);
17983
17984             if(this.autoslide && this.slideFn){
17985                 clearInterval(this.slideFn);
17986                 this.slideFn = window.setInterval(function() {
17987                     _this.showPanelNext();
17988                 }, this.timer);
17989             }
17990
17991         }).createDelegate(this, [i, bullet], true));
17992                 
17993         
17994     },
17995      
17996     setActiveBullet : function(i)
17997     {
17998         if(Roo.isTouch){
17999             return;
18000         }
18001         
18002         Roo.each(this.el.select('.bullet', true).elements, function(el){
18003             el.removeClass('selected');
18004         });
18005
18006         var bullet = this.el.select('.bullet-' + i, true).first();
18007         
18008         if(!bullet){
18009             return;
18010         }
18011         
18012         bullet.addClass('selected');
18013     }
18014     
18015     
18016   
18017 });
18018
18019  
18020
18021  
18022  
18023 Roo.apply(Roo.bootstrap.TabGroup, {
18024     
18025     groups: {},
18026      /**
18027     * register a Navigation Group
18028     * @param {Roo.bootstrap.NavGroup} the navgroup to add
18029     */
18030     register : function(navgrp)
18031     {
18032         this.groups[navgrp.navId] = navgrp;
18033         
18034     },
18035     /**
18036     * fetch a Navigation Group based on the navigation ID
18037     * if one does not exist , it will get created.
18038     * @param {string} the navgroup to add
18039     * @returns {Roo.bootstrap.NavGroup} the navgroup 
18040     */
18041     get: function(navId) {
18042         if (typeof(this.groups[navId]) == 'undefined') {
18043             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18044         }
18045         return this.groups[navId] ;
18046     }
18047     
18048     
18049     
18050 });
18051
18052  /*
18053  * - LGPL
18054  *
18055  * TabPanel
18056  * 
18057  */
18058
18059 /**
18060  * @class Roo.bootstrap.TabPanel
18061  * @extends Roo.bootstrap.Component
18062  * Bootstrap TabPanel class
18063  * @cfg {Boolean} active panel active
18064  * @cfg {String} html panel content
18065  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18066  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18067  * @cfg {String} href click to link..
18068  * 
18069  * 
18070  * @constructor
18071  * Create a new TabPanel
18072  * @param {Object} config The config object
18073  */
18074
18075 Roo.bootstrap.TabPanel = function(config){
18076     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18077     this.addEvents({
18078         /**
18079              * @event changed
18080              * Fires when the active status changes
18081              * @param {Roo.bootstrap.TabPanel} this
18082              * @param {Boolean} state the new state
18083             
18084          */
18085         'changed': true,
18086         /**
18087              * @event beforedeactivate
18088              * Fires before a tab is de-activated - can be used to do validation on a form.
18089              * @param {Roo.bootstrap.TabPanel} this
18090              * @return {Boolean} false if there is an error
18091             
18092          */
18093         'beforedeactivate': true
18094      });
18095     
18096     this.tabId = this.tabId || Roo.id();
18097   
18098 };
18099
18100 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
18101     
18102     active: false,
18103     html: false,
18104     tabId: false,
18105     navId : false,
18106     href : '',
18107     
18108     getAutoCreate : function(){
18109         var cfg = {
18110             tag: 'div',
18111             // item is needed for carousel - not sure if it has any effect otherwise
18112             cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18113             html: this.html || ''
18114         };
18115         
18116         if(this.active){
18117             cfg.cls += ' active';
18118         }
18119         
18120         if(this.tabId){
18121             cfg.tabId = this.tabId;
18122         }
18123         
18124         
18125         return cfg;
18126     },
18127     
18128     initEvents:  function()
18129     {
18130         var p = this.parent();
18131         
18132         this.navId = this.navId || p.navId;
18133         
18134         if (typeof(this.navId) != 'undefined') {
18135             // not really needed.. but just in case.. parent should be a NavGroup.
18136             var tg = Roo.bootstrap.TabGroup.get(this.navId);
18137             
18138             tg.register(this);
18139             
18140             var i = tg.tabs.length - 1;
18141             
18142             if(this.active && tg.bullets > 0 && i < tg.bullets){
18143                 tg.setActiveBullet(i);
18144             }
18145         }
18146         
18147         this.el.on('click', this.onClick, this);
18148         
18149         if(Roo.isTouch){
18150             this.el.on("touchstart", this.onTouchStart, this);
18151             this.el.on("touchmove", this.onTouchMove, this);
18152             this.el.on("touchend", this.onTouchEnd, this);
18153         }
18154         
18155     },
18156     
18157     onRender : function(ct, position)
18158     {
18159         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18160     },
18161     
18162     setActive : function(state)
18163     {
18164         Roo.log("panel - set active " + this.tabId + "=" + state);
18165         
18166         this.active = state;
18167         if (!state) {
18168             this.el.removeClass('active');
18169             
18170         } else  if (!this.el.hasClass('active')) {
18171             this.el.addClass('active');
18172         }
18173         
18174         this.fireEvent('changed', this, state);
18175     },
18176     
18177     onClick : function(e)
18178     {
18179         e.preventDefault();
18180         
18181         if(!this.href.length){
18182             return;
18183         }
18184         
18185         window.location.href = this.href;
18186     },
18187     
18188     startX : 0,
18189     startY : 0,
18190     endX : 0,
18191     endY : 0,
18192     swiping : false,
18193     
18194     onTouchStart : function(e)
18195     {
18196         this.swiping = false;
18197         
18198         this.startX = e.browserEvent.touches[0].clientX;
18199         this.startY = e.browserEvent.touches[0].clientY;
18200     },
18201     
18202     onTouchMove : function(e)
18203     {
18204         this.swiping = true;
18205         
18206         this.endX = e.browserEvent.touches[0].clientX;
18207         this.endY = e.browserEvent.touches[0].clientY;
18208     },
18209     
18210     onTouchEnd : function(e)
18211     {
18212         if(!this.swiping){
18213             this.onClick(e);
18214             return;
18215         }
18216         
18217         var tabGroup = this.parent();
18218         
18219         if(this.endX > this.startX){ // swiping right
18220             tabGroup.showPanelPrev();
18221             return;
18222         }
18223         
18224         if(this.startX > this.endX){ // swiping left
18225             tabGroup.showPanelNext();
18226             return;
18227         }
18228     }
18229     
18230     
18231 });
18232  
18233
18234  
18235
18236  /*
18237  * - LGPL
18238  *
18239  * DateField
18240  * 
18241  */
18242
18243 /**
18244  * @class Roo.bootstrap.DateField
18245  * @extends Roo.bootstrap.Input
18246  * Bootstrap DateField class
18247  * @cfg {Number} weekStart default 0
18248  * @cfg {String} viewMode default empty, (months|years)
18249  * @cfg {String} minViewMode default empty, (months|years)
18250  * @cfg {Number} startDate default -Infinity
18251  * @cfg {Number} endDate default Infinity
18252  * @cfg {Boolean} todayHighlight default false
18253  * @cfg {Boolean} todayBtn default false
18254  * @cfg {Boolean} calendarWeeks default false
18255  * @cfg {Object} daysOfWeekDisabled default empty
18256  * @cfg {Boolean} singleMode default false (true | false)
18257  * 
18258  * @cfg {Boolean} keyboardNavigation default true
18259  * @cfg {String} language default en
18260  * 
18261  * @constructor
18262  * Create a new DateField
18263  * @param {Object} config The config object
18264  */
18265
18266 Roo.bootstrap.DateField = function(config){
18267     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18268      this.addEvents({
18269             /**
18270              * @event show
18271              * Fires when this field show.
18272              * @param {Roo.bootstrap.DateField} this
18273              * @param {Mixed} date The date value
18274              */
18275             show : true,
18276             /**
18277              * @event show
18278              * Fires when this field hide.
18279              * @param {Roo.bootstrap.DateField} this
18280              * @param {Mixed} date The date value
18281              */
18282             hide : true,
18283             /**
18284              * @event select
18285              * Fires when select a date.
18286              * @param {Roo.bootstrap.DateField} this
18287              * @param {Mixed} date The date value
18288              */
18289             select : true,
18290             /**
18291              * @event beforeselect
18292              * Fires when before select a date.
18293              * @param {Roo.bootstrap.DateField} this
18294              * @param {Mixed} date The date value
18295              */
18296             beforeselect : true
18297         });
18298 };
18299
18300 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
18301     
18302     /**
18303      * @cfg {String} format
18304      * The default date format string which can be overriden for localization support.  The format must be
18305      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18306      */
18307     format : "m/d/y",
18308     /**
18309      * @cfg {String} altFormats
18310      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18311      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18312      */
18313     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18314     
18315     weekStart : 0,
18316     
18317     viewMode : '',
18318     
18319     minViewMode : '',
18320     
18321     todayHighlight : false,
18322     
18323     todayBtn: false,
18324     
18325     language: 'en',
18326     
18327     keyboardNavigation: true,
18328     
18329     calendarWeeks: false,
18330     
18331     startDate: -Infinity,
18332     
18333     endDate: Infinity,
18334     
18335     daysOfWeekDisabled: [],
18336     
18337     _events: [],
18338     
18339     singleMode : false,
18340     
18341     UTCDate: function()
18342     {
18343         return new Date(Date.UTC.apply(Date, arguments));
18344     },
18345     
18346     UTCToday: function()
18347     {
18348         var today = new Date();
18349         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18350     },
18351     
18352     getDate: function() {
18353             var d = this.getUTCDate();
18354             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18355     },
18356     
18357     getUTCDate: function() {
18358             return this.date;
18359     },
18360     
18361     setDate: function(d) {
18362             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18363     },
18364     
18365     setUTCDate: function(d) {
18366             this.date = d;
18367             this.setValue(this.formatDate(this.date));
18368     },
18369         
18370     onRender: function(ct, position)
18371     {
18372         
18373         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18374         
18375         this.language = this.language || 'en';
18376         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18377         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18378         
18379         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18380         this.format = this.format || 'm/d/y';
18381         this.isInline = false;
18382         this.isInput = true;
18383         this.component = this.el.select('.add-on', true).first() || false;
18384         this.component = (this.component && this.component.length === 0) ? false : this.component;
18385         this.hasInput = this.component && this.inputEl().length;
18386         
18387         if (typeof(this.minViewMode === 'string')) {
18388             switch (this.minViewMode) {
18389                 case 'months':
18390                     this.minViewMode = 1;
18391                     break;
18392                 case 'years':
18393                     this.minViewMode = 2;
18394                     break;
18395                 default:
18396                     this.minViewMode = 0;
18397                     break;
18398             }
18399         }
18400         
18401         if (typeof(this.viewMode === 'string')) {
18402             switch (this.viewMode) {
18403                 case 'months':
18404                     this.viewMode = 1;
18405                     break;
18406                 case 'years':
18407                     this.viewMode = 2;
18408                     break;
18409                 default:
18410                     this.viewMode = 0;
18411                     break;
18412             }
18413         }
18414                 
18415         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18416         
18417 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18418         
18419         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18420         
18421         this.picker().on('mousedown', this.onMousedown, this);
18422         this.picker().on('click', this.onClick, this);
18423         
18424         this.picker().addClass('datepicker-dropdown');
18425         
18426         this.startViewMode = this.viewMode;
18427         
18428         if(this.singleMode){
18429             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18430                 v.setVisibilityMode(Roo.Element.DISPLAY);
18431                 v.hide();
18432             });
18433             
18434             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18435                 v.setStyle('width', '189px');
18436             });
18437         }
18438         
18439         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18440             if(!this.calendarWeeks){
18441                 v.remove();
18442                 return;
18443             }
18444             
18445             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18446             v.attr('colspan', function(i, val){
18447                 return parseInt(val) + 1;
18448             });
18449         });
18450                         
18451         
18452         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18453         
18454         this.setStartDate(this.startDate);
18455         this.setEndDate(this.endDate);
18456         
18457         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18458         
18459         this.fillDow();
18460         this.fillMonths();
18461         this.update();
18462         this.showMode();
18463         
18464         if(this.isInline) {
18465             this.show();
18466         }
18467     },
18468     
18469     picker : function()
18470     {
18471         return this.pickerEl;
18472 //        return this.el.select('.datepicker', true).first();
18473     },
18474     
18475     fillDow: function()
18476     {
18477         var dowCnt = this.weekStart;
18478         
18479         var dow = {
18480             tag: 'tr',
18481             cn: [
18482                 
18483             ]
18484         };
18485         
18486         if(this.calendarWeeks){
18487             dow.cn.push({
18488                 tag: 'th',
18489                 cls: 'cw',
18490                 html: '&nbsp;'
18491             })
18492         }
18493         
18494         while (dowCnt < this.weekStart + 7) {
18495             dow.cn.push({
18496                 tag: 'th',
18497                 cls: 'dow',
18498                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18499             });
18500         }
18501         
18502         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18503     },
18504     
18505     fillMonths: function()
18506     {    
18507         var i = 0;
18508         var months = this.picker().select('>.datepicker-months td', true).first();
18509         
18510         months.dom.innerHTML = '';
18511         
18512         while (i < 12) {
18513             var month = {
18514                 tag: 'span',
18515                 cls: 'month',
18516                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18517             };
18518             
18519             months.createChild(month);
18520         }
18521         
18522     },
18523     
18524     update: function()
18525     {
18526         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;
18527         
18528         if (this.date < this.startDate) {
18529             this.viewDate = new Date(this.startDate);
18530         } else if (this.date > this.endDate) {
18531             this.viewDate = new Date(this.endDate);
18532         } else {
18533             this.viewDate = new Date(this.date);
18534         }
18535         
18536         this.fill();
18537     },
18538     
18539     fill: function() 
18540     {
18541         var d = new Date(this.viewDate),
18542                 year = d.getUTCFullYear(),
18543                 month = d.getUTCMonth(),
18544                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18545                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18546                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18547                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18548                 currentDate = this.date && this.date.valueOf(),
18549                 today = this.UTCToday();
18550         
18551         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18552         
18553 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18554         
18555 //        this.picker.select('>tfoot th.today').
18556 //                                              .text(dates[this.language].today)
18557 //                                              .toggle(this.todayBtn !== false);
18558     
18559         this.updateNavArrows();
18560         this.fillMonths();
18561                                                 
18562         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18563         
18564         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18565          
18566         prevMonth.setUTCDate(day);
18567         
18568         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18569         
18570         var nextMonth = new Date(prevMonth);
18571         
18572         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18573         
18574         nextMonth = nextMonth.valueOf();
18575         
18576         var fillMonths = false;
18577         
18578         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18579         
18580         while(prevMonth.valueOf() < nextMonth) {
18581             var clsName = '';
18582             
18583             if (prevMonth.getUTCDay() === this.weekStart) {
18584                 if(fillMonths){
18585                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18586                 }
18587                     
18588                 fillMonths = {
18589                     tag: 'tr',
18590                     cn: []
18591                 };
18592                 
18593                 if(this.calendarWeeks){
18594                     // ISO 8601: First week contains first thursday.
18595                     // ISO also states week starts on Monday, but we can be more abstract here.
18596                     var
18597                     // Start of current week: based on weekstart/current date
18598                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18599                     // Thursday of this week
18600                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18601                     // First Thursday of year, year from thursday
18602                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18603                     // Calendar week: ms between thursdays, div ms per day, div 7 days
18604                     calWeek =  (th - yth) / 864e5 / 7 + 1;
18605                     
18606                     fillMonths.cn.push({
18607                         tag: 'td',
18608                         cls: 'cw',
18609                         html: calWeek
18610                     });
18611                 }
18612             }
18613             
18614             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18615                 clsName += ' old';
18616             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18617                 clsName += ' new';
18618             }
18619             if (this.todayHighlight &&
18620                 prevMonth.getUTCFullYear() == today.getFullYear() &&
18621                 prevMonth.getUTCMonth() == today.getMonth() &&
18622                 prevMonth.getUTCDate() == today.getDate()) {
18623                 clsName += ' today';
18624             }
18625             
18626             if (currentDate && prevMonth.valueOf() === currentDate) {
18627                 clsName += ' active';
18628             }
18629             
18630             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18631                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18632                     clsName += ' disabled';
18633             }
18634             
18635             fillMonths.cn.push({
18636                 tag: 'td',
18637                 cls: 'day ' + clsName,
18638                 html: prevMonth.getDate()
18639             });
18640             
18641             prevMonth.setDate(prevMonth.getDate()+1);
18642         }
18643           
18644         var currentYear = this.date && this.date.getUTCFullYear();
18645         var currentMonth = this.date && this.date.getUTCMonth();
18646         
18647         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18648         
18649         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18650             v.removeClass('active');
18651             
18652             if(currentYear === year && k === currentMonth){
18653                 v.addClass('active');
18654             }
18655             
18656             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18657                 v.addClass('disabled');
18658             }
18659             
18660         });
18661         
18662         
18663         year = parseInt(year/10, 10) * 10;
18664         
18665         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18666         
18667         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18668         
18669         year -= 1;
18670         for (var i = -1; i < 11; i++) {
18671             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18672                 tag: 'span',
18673                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18674                 html: year
18675             });
18676             
18677             year += 1;
18678         }
18679     },
18680     
18681     showMode: function(dir) 
18682     {
18683         if (dir) {
18684             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18685         }
18686         
18687         Roo.each(this.picker().select('>div',true).elements, function(v){
18688             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18689             v.hide();
18690         });
18691         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18692     },
18693     
18694     place: function()
18695     {
18696         if(this.isInline) {
18697             return;
18698         }
18699         
18700         this.picker().removeClass(['bottom', 'top']);
18701         
18702         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18703             /*
18704              * place to the top of element!
18705              *
18706              */
18707             
18708             this.picker().addClass('top');
18709             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18710             
18711             return;
18712         }
18713         
18714         this.picker().addClass('bottom');
18715         
18716         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18717     },
18718     
18719     parseDate : function(value)
18720     {
18721         if(!value || value instanceof Date){
18722             return value;
18723         }
18724         var v = Date.parseDate(value, this.format);
18725         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18726             v = Date.parseDate(value, 'Y-m-d');
18727         }
18728         if(!v && this.altFormats){
18729             if(!this.altFormatsArray){
18730                 this.altFormatsArray = this.altFormats.split("|");
18731             }
18732             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18733                 v = Date.parseDate(value, this.altFormatsArray[i]);
18734             }
18735         }
18736         return v;
18737     },
18738     
18739     formatDate : function(date, fmt)
18740     {   
18741         return (!date || !(date instanceof Date)) ?
18742         date : date.dateFormat(fmt || this.format);
18743     },
18744     
18745     onFocus : function()
18746     {
18747         Roo.bootstrap.DateField.superclass.onFocus.call(this);
18748         this.show();
18749     },
18750     
18751     onBlur : function()
18752     {
18753         Roo.bootstrap.DateField.superclass.onBlur.call(this);
18754         
18755         var d = this.inputEl().getValue();
18756         
18757         this.setValue(d);
18758                 
18759         this.hide();
18760     },
18761     
18762     show : function()
18763     {
18764         this.picker().show();
18765         this.update();
18766         this.place();
18767         
18768         this.fireEvent('show', this, this.date);
18769     },
18770     
18771     hide : function()
18772     {
18773         if(this.isInline) {
18774             return;
18775         }
18776         this.picker().hide();
18777         this.viewMode = this.startViewMode;
18778         this.showMode();
18779         
18780         this.fireEvent('hide', this, this.date);
18781         
18782     },
18783     
18784     onMousedown: function(e)
18785     {
18786         e.stopPropagation();
18787         e.preventDefault();
18788     },
18789     
18790     keyup: function(e)
18791     {
18792         Roo.bootstrap.DateField.superclass.keyup.call(this);
18793         this.update();
18794     },
18795
18796     setValue: function(v)
18797     {
18798         if(this.fireEvent('beforeselect', this, v) !== false){
18799             var d = new Date(this.parseDate(v) ).clearTime();
18800         
18801             if(isNaN(d.getTime())){
18802                 this.date = this.viewDate = '';
18803                 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18804                 return;
18805             }
18806
18807             v = this.formatDate(d);
18808
18809             Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18810
18811             this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18812
18813             this.update();
18814
18815             this.fireEvent('select', this, this.date);
18816         }
18817     },
18818     
18819     getValue: function()
18820     {
18821         return this.formatDate(this.date);
18822     },
18823     
18824     fireKey: function(e)
18825     {
18826         if (!this.picker().isVisible()){
18827             if (e.keyCode == 27) { // allow escape to hide and re-show picker
18828                 this.show();
18829             }
18830             return;
18831         }
18832         
18833         var dateChanged = false,
18834         dir, day, month,
18835         newDate, newViewDate;
18836         
18837         switch(e.keyCode){
18838             case 27: // escape
18839                 this.hide();
18840                 e.preventDefault();
18841                 break;
18842             case 37: // left
18843             case 39: // right
18844                 if (!this.keyboardNavigation) {
18845                     break;
18846                 }
18847                 dir = e.keyCode == 37 ? -1 : 1;
18848                 
18849                 if (e.ctrlKey){
18850                     newDate = this.moveYear(this.date, dir);
18851                     newViewDate = this.moveYear(this.viewDate, dir);
18852                 } else if (e.shiftKey){
18853                     newDate = this.moveMonth(this.date, dir);
18854                     newViewDate = this.moveMonth(this.viewDate, dir);
18855                 } else {
18856                     newDate = new Date(this.date);
18857                     newDate.setUTCDate(this.date.getUTCDate() + dir);
18858                     newViewDate = new Date(this.viewDate);
18859                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18860                 }
18861                 if (this.dateWithinRange(newDate)){
18862                     this.date = newDate;
18863                     this.viewDate = newViewDate;
18864                     this.setValue(this.formatDate(this.date));
18865 //                    this.update();
18866                     e.preventDefault();
18867                     dateChanged = true;
18868                 }
18869                 break;
18870             case 38: // up
18871             case 40: // down
18872                 if (!this.keyboardNavigation) {
18873                     break;
18874                 }
18875                 dir = e.keyCode == 38 ? -1 : 1;
18876                 if (e.ctrlKey){
18877                     newDate = this.moveYear(this.date, dir);
18878                     newViewDate = this.moveYear(this.viewDate, dir);
18879                 } else if (e.shiftKey){
18880                     newDate = this.moveMonth(this.date, dir);
18881                     newViewDate = this.moveMonth(this.viewDate, dir);
18882                 } else {
18883                     newDate = new Date(this.date);
18884                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18885                     newViewDate = new Date(this.viewDate);
18886                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18887                 }
18888                 if (this.dateWithinRange(newDate)){
18889                     this.date = newDate;
18890                     this.viewDate = newViewDate;
18891                     this.setValue(this.formatDate(this.date));
18892 //                    this.update();
18893                     e.preventDefault();
18894                     dateChanged = true;
18895                 }
18896                 break;
18897             case 13: // enter
18898                 this.setValue(this.formatDate(this.date));
18899                 this.hide();
18900                 e.preventDefault();
18901                 break;
18902             case 9: // tab
18903                 this.setValue(this.formatDate(this.date));
18904                 this.hide();
18905                 break;
18906             case 16: // shift
18907             case 17: // ctrl
18908             case 18: // alt
18909                 break;
18910             default :
18911                 this.hide();
18912                 
18913         }
18914     },
18915     
18916     
18917     onClick: function(e) 
18918     {
18919         e.stopPropagation();
18920         e.preventDefault();
18921         
18922         var target = e.getTarget();
18923         
18924         if(target.nodeName.toLowerCase() === 'i'){
18925             target = Roo.get(target).dom.parentNode;
18926         }
18927         
18928         var nodeName = target.nodeName;
18929         var className = target.className;
18930         var html = target.innerHTML;
18931         //Roo.log(nodeName);
18932         
18933         switch(nodeName.toLowerCase()) {
18934             case 'th':
18935                 switch(className) {
18936                     case 'switch':
18937                         this.showMode(1);
18938                         break;
18939                     case 'prev':
18940                     case 'next':
18941                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18942                         switch(this.viewMode){
18943                                 case 0:
18944                                         this.viewDate = this.moveMonth(this.viewDate, dir);
18945                                         break;
18946                                 case 1:
18947                                 case 2:
18948                                         this.viewDate = this.moveYear(this.viewDate, dir);
18949                                         break;
18950                         }
18951                         this.fill();
18952                         break;
18953                     case 'today':
18954                         var date = new Date();
18955                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18956 //                        this.fill()
18957                         this.setValue(this.formatDate(this.date));
18958                         
18959                         this.hide();
18960                         break;
18961                 }
18962                 break;
18963             case 'span':
18964                 if (className.indexOf('disabled') < 0) {
18965                     this.viewDate.setUTCDate(1);
18966                     if (className.indexOf('month') > -1) {
18967                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18968                     } else {
18969                         var year = parseInt(html, 10) || 0;
18970                         this.viewDate.setUTCFullYear(year);
18971                         
18972                     }
18973                     
18974                     if(this.singleMode){
18975                         this.setValue(this.formatDate(this.viewDate));
18976                         this.hide();
18977                         return;
18978                     }
18979                     
18980                     this.showMode(-1);
18981                     this.fill();
18982                 }
18983                 break;
18984                 
18985             case 'td':
18986                 //Roo.log(className);
18987                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18988                     var day = parseInt(html, 10) || 1;
18989                     var year = this.viewDate.getUTCFullYear(),
18990                         month = this.viewDate.getUTCMonth();
18991
18992                     if (className.indexOf('old') > -1) {
18993                         if(month === 0 ){
18994                             month = 11;
18995                             year -= 1;
18996                         }else{
18997                             month -= 1;
18998                         }
18999                     } else if (className.indexOf('new') > -1) {
19000                         if (month == 11) {
19001                             month = 0;
19002                             year += 1;
19003                         } else {
19004                             month += 1;
19005                         }
19006                     }
19007                     //Roo.log([year,month,day]);
19008                     this.date = this.UTCDate(year, month, day,0,0,0,0);
19009                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19010 //                    this.fill();
19011                     //Roo.log(this.formatDate(this.date));
19012                     this.setValue(this.formatDate(this.date));
19013                     this.hide();
19014                 }
19015                 break;
19016         }
19017     },
19018     
19019     setStartDate: function(startDate)
19020     {
19021         this.startDate = startDate || -Infinity;
19022         if (this.startDate !== -Infinity) {
19023             this.startDate = this.parseDate(this.startDate);
19024         }
19025         this.update();
19026         this.updateNavArrows();
19027     },
19028
19029     setEndDate: function(endDate)
19030     {
19031         this.endDate = endDate || Infinity;
19032         if (this.endDate !== Infinity) {
19033             this.endDate = this.parseDate(this.endDate);
19034         }
19035         this.update();
19036         this.updateNavArrows();
19037     },
19038     
19039     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19040     {
19041         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19042         if (typeof(this.daysOfWeekDisabled) !== 'object') {
19043             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19044         }
19045         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19046             return parseInt(d, 10);
19047         });
19048         this.update();
19049         this.updateNavArrows();
19050     },
19051     
19052     updateNavArrows: function() 
19053     {
19054         if(this.singleMode){
19055             return;
19056         }
19057         
19058         var d = new Date(this.viewDate),
19059         year = d.getUTCFullYear(),
19060         month = d.getUTCMonth();
19061         
19062         Roo.each(this.picker().select('.prev', true).elements, function(v){
19063             v.show();
19064             switch (this.viewMode) {
19065                 case 0:
19066
19067                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19068                         v.hide();
19069                     }
19070                     break;
19071                 case 1:
19072                 case 2:
19073                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19074                         v.hide();
19075                     }
19076                     break;
19077             }
19078         });
19079         
19080         Roo.each(this.picker().select('.next', true).elements, function(v){
19081             v.show();
19082             switch (this.viewMode) {
19083                 case 0:
19084
19085                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19086                         v.hide();
19087                     }
19088                     break;
19089                 case 1:
19090                 case 2:
19091                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19092                         v.hide();
19093                     }
19094                     break;
19095             }
19096         })
19097     },
19098     
19099     moveMonth: function(date, dir)
19100     {
19101         if (!dir) {
19102             return date;
19103         }
19104         var new_date = new Date(date.valueOf()),
19105         day = new_date.getUTCDate(),
19106         month = new_date.getUTCMonth(),
19107         mag = Math.abs(dir),
19108         new_month, test;
19109         dir = dir > 0 ? 1 : -1;
19110         if (mag == 1){
19111             test = dir == -1
19112             // If going back one month, make sure month is not current month
19113             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19114             ? function(){
19115                 return new_date.getUTCMonth() == month;
19116             }
19117             // If going forward one month, make sure month is as expected
19118             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19119             : function(){
19120                 return new_date.getUTCMonth() != new_month;
19121             };
19122             new_month = month + dir;
19123             new_date.setUTCMonth(new_month);
19124             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19125             if (new_month < 0 || new_month > 11) {
19126                 new_month = (new_month + 12) % 12;
19127             }
19128         } else {
19129             // For magnitudes >1, move one month at a time...
19130             for (var i=0; i<mag; i++) {
19131                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19132                 new_date = this.moveMonth(new_date, dir);
19133             }
19134             // ...then reset the day, keeping it in the new month
19135             new_month = new_date.getUTCMonth();
19136             new_date.setUTCDate(day);
19137             test = function(){
19138                 return new_month != new_date.getUTCMonth();
19139             };
19140         }
19141         // Common date-resetting loop -- if date is beyond end of month, make it
19142         // end of month
19143         while (test()){
19144             new_date.setUTCDate(--day);
19145             new_date.setUTCMonth(new_month);
19146         }
19147         return new_date;
19148     },
19149
19150     moveYear: function(date, dir)
19151     {
19152         return this.moveMonth(date, dir*12);
19153     },
19154
19155     dateWithinRange: function(date)
19156     {
19157         return date >= this.startDate && date <= this.endDate;
19158     },
19159
19160     
19161     remove: function() 
19162     {
19163         this.picker().remove();
19164     },
19165     
19166     validateValue : function(value)
19167     {
19168         if(value.length < 1)  {
19169             if(this.allowBlank){
19170                 return true;
19171             }
19172             return false;
19173         }
19174         
19175         if(value.length < this.minLength){
19176             return false;
19177         }
19178         if(value.length > this.maxLength){
19179             return false;
19180         }
19181         if(this.vtype){
19182             var vt = Roo.form.VTypes;
19183             if(!vt[this.vtype](value, this)){
19184                 return false;
19185             }
19186         }
19187         if(typeof this.validator == "function"){
19188             var msg = this.validator(value);
19189             if(msg !== true){
19190                 return false;
19191             }
19192         }
19193         
19194         if(this.regex && !this.regex.test(value)){
19195             return false;
19196         }
19197         
19198         if(typeof(this.parseDate(value)) == 'undefined'){
19199             return false;
19200         }
19201         
19202         if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19203             return false;
19204         }      
19205         
19206         if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19207             return false;
19208         } 
19209         
19210         
19211         return true;
19212     },
19213     
19214     setVisible : function(visible)
19215     {
19216         if(!this.getEl()){
19217             return;
19218         }
19219         
19220         this.getEl().removeClass('hidden');
19221         
19222         if(visible){
19223             return;
19224         }
19225         
19226         this.getEl().addClass('hidden');
19227     }
19228    
19229 });
19230
19231 Roo.apply(Roo.bootstrap.DateField,  {
19232     
19233     head : {
19234         tag: 'thead',
19235         cn: [
19236         {
19237             tag: 'tr',
19238             cn: [
19239             {
19240                 tag: 'th',
19241                 cls: 'prev',
19242                 html: '<i class="fa fa-arrow-left"/>'
19243             },
19244             {
19245                 tag: 'th',
19246                 cls: 'switch',
19247                 colspan: '5'
19248             },
19249             {
19250                 tag: 'th',
19251                 cls: 'next',
19252                 html: '<i class="fa fa-arrow-right"/>'
19253             }
19254
19255             ]
19256         }
19257         ]
19258     },
19259     
19260     content : {
19261         tag: 'tbody',
19262         cn: [
19263         {
19264             tag: 'tr',
19265             cn: [
19266             {
19267                 tag: 'td',
19268                 colspan: '7'
19269             }
19270             ]
19271         }
19272         ]
19273     },
19274     
19275     footer : {
19276         tag: 'tfoot',
19277         cn: [
19278         {
19279             tag: 'tr',
19280             cn: [
19281             {
19282                 tag: 'th',
19283                 colspan: '7',
19284                 cls: 'today'
19285             }
19286                     
19287             ]
19288         }
19289         ]
19290     },
19291     
19292     dates:{
19293         en: {
19294             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19295             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19296             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19297             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19298             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19299             today: "Today"
19300         }
19301     },
19302     
19303     modes: [
19304     {
19305         clsName: 'days',
19306         navFnc: 'Month',
19307         navStep: 1
19308     },
19309     {
19310         clsName: 'months',
19311         navFnc: 'FullYear',
19312         navStep: 1
19313     },
19314     {
19315         clsName: 'years',
19316         navFnc: 'FullYear',
19317         navStep: 10
19318     }]
19319 });
19320
19321 Roo.apply(Roo.bootstrap.DateField,  {
19322   
19323     template : {
19324         tag: 'div',
19325         cls: 'datepicker dropdown-menu roo-dynamic',
19326         cn: [
19327         {
19328             tag: 'div',
19329             cls: 'datepicker-days',
19330             cn: [
19331             {
19332                 tag: 'table',
19333                 cls: 'table-condensed',
19334                 cn:[
19335                 Roo.bootstrap.DateField.head,
19336                 {
19337                     tag: 'tbody'
19338                 },
19339                 Roo.bootstrap.DateField.footer
19340                 ]
19341             }
19342             ]
19343         },
19344         {
19345             tag: 'div',
19346             cls: 'datepicker-months',
19347             cn: [
19348             {
19349                 tag: 'table',
19350                 cls: 'table-condensed',
19351                 cn:[
19352                 Roo.bootstrap.DateField.head,
19353                 Roo.bootstrap.DateField.content,
19354                 Roo.bootstrap.DateField.footer
19355                 ]
19356             }
19357             ]
19358         },
19359         {
19360             tag: 'div',
19361             cls: 'datepicker-years',
19362             cn: [
19363             {
19364                 tag: 'table',
19365                 cls: 'table-condensed',
19366                 cn:[
19367                 Roo.bootstrap.DateField.head,
19368                 Roo.bootstrap.DateField.content,
19369                 Roo.bootstrap.DateField.footer
19370                 ]
19371             }
19372             ]
19373         }
19374         ]
19375     }
19376 });
19377
19378  
19379
19380  /*
19381  * - LGPL
19382  *
19383  * TimeField
19384  * 
19385  */
19386
19387 /**
19388  * @class Roo.bootstrap.TimeField
19389  * @extends Roo.bootstrap.Input
19390  * Bootstrap DateField class
19391  * 
19392  * 
19393  * @constructor
19394  * Create a new TimeField
19395  * @param {Object} config The config object
19396  */
19397
19398 Roo.bootstrap.TimeField = function(config){
19399     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19400     this.addEvents({
19401             /**
19402              * @event show
19403              * Fires when this field show.
19404              * @param {Roo.bootstrap.DateField} thisthis
19405              * @param {Mixed} date The date value
19406              */
19407             show : true,
19408             /**
19409              * @event show
19410              * Fires when this field hide.
19411              * @param {Roo.bootstrap.DateField} this
19412              * @param {Mixed} date The date value
19413              */
19414             hide : true,
19415             /**
19416              * @event select
19417              * Fires when select a date.
19418              * @param {Roo.bootstrap.DateField} this
19419              * @param {Mixed} date The date value
19420              */
19421             select : true
19422         });
19423 };
19424
19425 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
19426     
19427     /**
19428      * @cfg {String} format
19429      * The default time format string which can be overriden for localization support.  The format must be
19430      * valid according to {@link Date#parseDate} (defaults to 'H:i').
19431      */
19432     format : "H:i",
19433        
19434     onRender: function(ct, position)
19435     {
19436         
19437         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19438                 
19439         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19440         
19441         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19442         
19443         this.pop = this.picker().select('>.datepicker-time',true).first();
19444         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19445         
19446         this.picker().on('mousedown', this.onMousedown, this);
19447         this.picker().on('click', this.onClick, this);
19448         
19449         this.picker().addClass('datepicker-dropdown');
19450     
19451         this.fillTime();
19452         this.update();
19453             
19454         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19455         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19456         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19457         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19458         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19459         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19460
19461     },
19462     
19463     fireKey: function(e){
19464         if (!this.picker().isVisible()){
19465             if (e.keyCode == 27) { // allow escape to hide and re-show picker
19466                 this.show();
19467             }
19468             return;
19469         }
19470
19471         e.preventDefault();
19472         
19473         switch(e.keyCode){
19474             case 27: // escape
19475                 this.hide();
19476                 break;
19477             case 37: // left
19478             case 39: // right
19479                 this.onTogglePeriod();
19480                 break;
19481             case 38: // up
19482                 this.onIncrementMinutes();
19483                 break;
19484             case 40: // down
19485                 this.onDecrementMinutes();
19486                 break;
19487             case 13: // enter
19488             case 9: // tab
19489                 this.setTime();
19490                 break;
19491         }
19492     },
19493     
19494     onClick: function(e) {
19495         e.stopPropagation();
19496         e.preventDefault();
19497     },
19498     
19499     picker : function()
19500     {
19501         return this.el.select('.datepicker', true).first();
19502     },
19503     
19504     fillTime: function()
19505     {    
19506         var time = this.pop.select('tbody', true).first();
19507         
19508         time.dom.innerHTML = '';
19509         
19510         time.createChild({
19511             tag: 'tr',
19512             cn: [
19513                 {
19514                     tag: 'td',
19515                     cn: [
19516                         {
19517                             tag: 'a',
19518                             href: '#',
19519                             cls: 'btn',
19520                             cn: [
19521                                 {
19522                                     tag: 'span',
19523                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
19524                                 }
19525                             ]
19526                         } 
19527                     ]
19528                 },
19529                 {
19530                     tag: 'td',
19531                     cls: 'separator'
19532                 },
19533                 {
19534                     tag: 'td',
19535                     cn: [
19536                         {
19537                             tag: 'a',
19538                             href: '#',
19539                             cls: 'btn',
19540                             cn: [
19541                                 {
19542                                     tag: 'span',
19543                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
19544                                 }
19545                             ]
19546                         }
19547                     ]
19548                 },
19549                 {
19550                     tag: 'td',
19551                     cls: 'separator'
19552                 }
19553             ]
19554         });
19555         
19556         time.createChild({
19557             tag: 'tr',
19558             cn: [
19559                 {
19560                     tag: 'td',
19561                     cn: [
19562                         {
19563                             tag: 'span',
19564                             cls: 'timepicker-hour',
19565                             html: '00'
19566                         }  
19567                     ]
19568                 },
19569                 {
19570                     tag: 'td',
19571                     cls: 'separator',
19572                     html: ':'
19573                 },
19574                 {
19575                     tag: 'td',
19576                     cn: [
19577                         {
19578                             tag: 'span',
19579                             cls: 'timepicker-minute',
19580                             html: '00'
19581                         }  
19582                     ]
19583                 },
19584                 {
19585                     tag: 'td',
19586                     cls: 'separator'
19587                 },
19588                 {
19589                     tag: 'td',
19590                     cn: [
19591                         {
19592                             tag: 'button',
19593                             type: 'button',
19594                             cls: 'btn btn-primary period',
19595                             html: 'AM'
19596                             
19597                         }
19598                     ]
19599                 }
19600             ]
19601         });
19602         
19603         time.createChild({
19604             tag: 'tr',
19605             cn: [
19606                 {
19607                     tag: 'td',
19608                     cn: [
19609                         {
19610                             tag: 'a',
19611                             href: '#',
19612                             cls: 'btn',
19613                             cn: [
19614                                 {
19615                                     tag: 'span',
19616                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
19617                                 }
19618                             ]
19619                         }
19620                     ]
19621                 },
19622                 {
19623                     tag: 'td',
19624                     cls: 'separator'
19625                 },
19626                 {
19627                     tag: 'td',
19628                     cn: [
19629                         {
19630                             tag: 'a',
19631                             href: '#',
19632                             cls: 'btn',
19633                             cn: [
19634                                 {
19635                                     tag: 'span',
19636                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
19637                                 }
19638                             ]
19639                         }
19640                     ]
19641                 },
19642                 {
19643                     tag: 'td',
19644                     cls: 'separator'
19645                 }
19646             ]
19647         });
19648         
19649     },
19650     
19651     update: function()
19652     {
19653         
19654         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19655         
19656         this.fill();
19657     },
19658     
19659     fill: function() 
19660     {
19661         var hours = this.time.getHours();
19662         var minutes = this.time.getMinutes();
19663         var period = 'AM';
19664         
19665         if(hours > 11){
19666             period = 'PM';
19667         }
19668         
19669         if(hours == 0){
19670             hours = 12;
19671         }
19672         
19673         
19674         if(hours > 12){
19675             hours = hours - 12;
19676         }
19677         
19678         if(hours < 10){
19679             hours = '0' + hours;
19680         }
19681         
19682         if(minutes < 10){
19683             minutes = '0' + minutes;
19684         }
19685         
19686         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19687         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19688         this.pop.select('button', true).first().dom.innerHTML = period;
19689         
19690     },
19691     
19692     place: function()
19693     {   
19694         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19695         
19696         var cls = ['bottom'];
19697         
19698         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19699             cls.pop();
19700             cls.push('top');
19701         }
19702         
19703         cls.push('right');
19704         
19705         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19706             cls.pop();
19707             cls.push('left');
19708         }
19709         
19710         this.picker().addClass(cls.join('-'));
19711         
19712         var _this = this;
19713         
19714         Roo.each(cls, function(c){
19715             if(c == 'bottom'){
19716                 _this.picker().setTop(_this.inputEl().getHeight());
19717                 return;
19718             }
19719             if(c == 'top'){
19720                 _this.picker().setTop(0 - _this.picker().getHeight());
19721                 return;
19722             }
19723             
19724             if(c == 'left'){
19725                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19726                 return;
19727             }
19728             if(c == 'right'){
19729                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19730                 return;
19731             }
19732         });
19733         
19734     },
19735   
19736     onFocus : function()
19737     {
19738         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19739         this.show();
19740     },
19741     
19742     onBlur : function()
19743     {
19744         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19745         this.hide();
19746     },
19747     
19748     show : function()
19749     {
19750         this.picker().show();
19751         this.pop.show();
19752         this.update();
19753         this.place();
19754         
19755         this.fireEvent('show', this, this.date);
19756     },
19757     
19758     hide : function()
19759     {
19760         this.picker().hide();
19761         this.pop.hide();
19762         
19763         this.fireEvent('hide', this, this.date);
19764     },
19765     
19766     setTime : function()
19767     {
19768         this.hide();
19769         this.setValue(this.time.format(this.format));
19770         
19771         this.fireEvent('select', this, this.date);
19772         
19773         
19774     },
19775     
19776     onMousedown: function(e){
19777         e.stopPropagation();
19778         e.preventDefault();
19779     },
19780     
19781     onIncrementHours: function()
19782     {
19783         Roo.log('onIncrementHours');
19784         this.time = this.time.add(Date.HOUR, 1);
19785         this.update();
19786         
19787     },
19788     
19789     onDecrementHours: function()
19790     {
19791         Roo.log('onDecrementHours');
19792         this.time = this.time.add(Date.HOUR, -1);
19793         this.update();
19794     },
19795     
19796     onIncrementMinutes: function()
19797     {
19798         Roo.log('onIncrementMinutes');
19799         this.time = this.time.add(Date.MINUTE, 1);
19800         this.update();
19801     },
19802     
19803     onDecrementMinutes: function()
19804     {
19805         Roo.log('onDecrementMinutes');
19806         this.time = this.time.add(Date.MINUTE, -1);
19807         this.update();
19808     },
19809     
19810     onTogglePeriod: function()
19811     {
19812         Roo.log('onTogglePeriod');
19813         this.time = this.time.add(Date.HOUR, 12);
19814         this.update();
19815     }
19816     
19817    
19818 });
19819
19820 Roo.apply(Roo.bootstrap.TimeField,  {
19821     
19822     content : {
19823         tag: 'tbody',
19824         cn: [
19825             {
19826                 tag: 'tr',
19827                 cn: [
19828                 {
19829                     tag: 'td',
19830                     colspan: '7'
19831                 }
19832                 ]
19833             }
19834         ]
19835     },
19836     
19837     footer : {
19838         tag: 'tfoot',
19839         cn: [
19840             {
19841                 tag: 'tr',
19842                 cn: [
19843                 {
19844                     tag: 'th',
19845                     colspan: '7',
19846                     cls: '',
19847                     cn: [
19848                         {
19849                             tag: 'button',
19850                             cls: 'btn btn-info ok',
19851                             html: 'OK'
19852                         }
19853                     ]
19854                 }
19855
19856                 ]
19857             }
19858         ]
19859     }
19860 });
19861
19862 Roo.apply(Roo.bootstrap.TimeField,  {
19863   
19864     template : {
19865         tag: 'div',
19866         cls: 'datepicker dropdown-menu',
19867         cn: [
19868             {
19869                 tag: 'div',
19870                 cls: 'datepicker-time',
19871                 cn: [
19872                 {
19873                     tag: 'table',
19874                     cls: 'table-condensed',
19875                     cn:[
19876                     Roo.bootstrap.TimeField.content,
19877                     Roo.bootstrap.TimeField.footer
19878                     ]
19879                 }
19880                 ]
19881             }
19882         ]
19883     }
19884 });
19885
19886  
19887
19888  /*
19889  * - LGPL
19890  *
19891  * MonthField
19892  * 
19893  */
19894
19895 /**
19896  * @class Roo.bootstrap.MonthField
19897  * @extends Roo.bootstrap.Input
19898  * Bootstrap MonthField class
19899  * 
19900  * @cfg {String} language default en
19901  * 
19902  * @constructor
19903  * Create a new MonthField
19904  * @param {Object} config The config object
19905  */
19906
19907 Roo.bootstrap.MonthField = function(config){
19908     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19909     
19910     this.addEvents({
19911         /**
19912          * @event show
19913          * Fires when this field show.
19914          * @param {Roo.bootstrap.MonthField} this
19915          * @param {Mixed} date The date value
19916          */
19917         show : true,
19918         /**
19919          * @event show
19920          * Fires when this field hide.
19921          * @param {Roo.bootstrap.MonthField} this
19922          * @param {Mixed} date The date value
19923          */
19924         hide : true,
19925         /**
19926          * @event select
19927          * Fires when select a date.
19928          * @param {Roo.bootstrap.MonthField} this
19929          * @param {String} oldvalue The old value
19930          * @param {String} newvalue The new value
19931          */
19932         select : true
19933     });
19934 };
19935
19936 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
19937     
19938     onRender: function(ct, position)
19939     {
19940         
19941         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19942         
19943         this.language = this.language || 'en';
19944         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19945         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19946         
19947         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19948         this.isInline = false;
19949         this.isInput = true;
19950         this.component = this.el.select('.add-on', true).first() || false;
19951         this.component = (this.component && this.component.length === 0) ? false : this.component;
19952         this.hasInput = this.component && this.inputEL().length;
19953         
19954         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19955         
19956         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19957         
19958         this.picker().on('mousedown', this.onMousedown, this);
19959         this.picker().on('click', this.onClick, this);
19960         
19961         this.picker().addClass('datepicker-dropdown');
19962         
19963         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19964             v.setStyle('width', '189px');
19965         });
19966         
19967         this.fillMonths();
19968         
19969         this.update();
19970         
19971         if(this.isInline) {
19972             this.show();
19973         }
19974         
19975     },
19976     
19977     setValue: function(v, suppressEvent)
19978     {   
19979         var o = this.getValue();
19980         
19981         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19982         
19983         this.update();
19984
19985         if(suppressEvent !== true){
19986             this.fireEvent('select', this, o, v);
19987         }
19988         
19989     },
19990     
19991     getValue: function()
19992     {
19993         return this.value;
19994     },
19995     
19996     onClick: function(e) 
19997     {
19998         e.stopPropagation();
19999         e.preventDefault();
20000         
20001         var target = e.getTarget();
20002         
20003         if(target.nodeName.toLowerCase() === 'i'){
20004             target = Roo.get(target).dom.parentNode;
20005         }
20006         
20007         var nodeName = target.nodeName;
20008         var className = target.className;
20009         var html = target.innerHTML;
20010         
20011         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20012             return;
20013         }
20014         
20015         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20016         
20017         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20018         
20019         this.hide();
20020                         
20021     },
20022     
20023     picker : function()
20024     {
20025         return this.pickerEl;
20026     },
20027     
20028     fillMonths: function()
20029     {    
20030         var i = 0;
20031         var months = this.picker().select('>.datepicker-months td', true).first();
20032         
20033         months.dom.innerHTML = '';
20034         
20035         while (i < 12) {
20036             var month = {
20037                 tag: 'span',
20038                 cls: 'month',
20039                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20040             };
20041             
20042             months.createChild(month);
20043         }
20044         
20045     },
20046     
20047     update: function()
20048     {
20049         var _this = this;
20050         
20051         if(typeof(this.vIndex) == 'undefined' && this.value.length){
20052             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20053         }
20054         
20055         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20056             e.removeClass('active');
20057             
20058             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20059                 e.addClass('active');
20060             }
20061         })
20062     },
20063     
20064     place: function()
20065     {
20066         if(this.isInline) {
20067             return;
20068         }
20069         
20070         this.picker().removeClass(['bottom', 'top']);
20071         
20072         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20073             /*
20074              * place to the top of element!
20075              *
20076              */
20077             
20078             this.picker().addClass('top');
20079             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20080             
20081             return;
20082         }
20083         
20084         this.picker().addClass('bottom');
20085         
20086         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20087     },
20088     
20089     onFocus : function()
20090     {
20091         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20092         this.show();
20093     },
20094     
20095     onBlur : function()
20096     {
20097         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20098         
20099         var d = this.inputEl().getValue();
20100         
20101         this.setValue(d);
20102                 
20103         this.hide();
20104     },
20105     
20106     show : function()
20107     {
20108         this.picker().show();
20109         this.picker().select('>.datepicker-months', true).first().show();
20110         this.update();
20111         this.place();
20112         
20113         this.fireEvent('show', this, this.date);
20114     },
20115     
20116     hide : function()
20117     {
20118         if(this.isInline) {
20119             return;
20120         }
20121         this.picker().hide();
20122         this.fireEvent('hide', this, this.date);
20123         
20124     },
20125     
20126     onMousedown: function(e)
20127     {
20128         e.stopPropagation();
20129         e.preventDefault();
20130     },
20131     
20132     keyup: function(e)
20133     {
20134         Roo.bootstrap.MonthField.superclass.keyup.call(this);
20135         this.update();
20136     },
20137
20138     fireKey: function(e)
20139     {
20140         if (!this.picker().isVisible()){
20141             if (e.keyCode == 27)   {// allow escape to hide and re-show picker
20142                 this.show();
20143             }
20144             return;
20145         }
20146         
20147         var dir;
20148         
20149         switch(e.keyCode){
20150             case 27: // escape
20151                 this.hide();
20152                 e.preventDefault();
20153                 break;
20154             case 37: // left
20155             case 39: // right
20156                 dir = e.keyCode == 37 ? -1 : 1;
20157                 
20158                 this.vIndex = this.vIndex + dir;
20159                 
20160                 if(this.vIndex < 0){
20161                     this.vIndex = 0;
20162                 }
20163                 
20164                 if(this.vIndex > 11){
20165                     this.vIndex = 11;
20166                 }
20167                 
20168                 if(isNaN(this.vIndex)){
20169                     this.vIndex = 0;
20170                 }
20171                 
20172                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20173                 
20174                 break;
20175             case 38: // up
20176             case 40: // down
20177                 
20178                 dir = e.keyCode == 38 ? -1 : 1;
20179                 
20180                 this.vIndex = this.vIndex + dir * 4;
20181                 
20182                 if(this.vIndex < 0){
20183                     this.vIndex = 0;
20184                 }
20185                 
20186                 if(this.vIndex > 11){
20187                     this.vIndex = 11;
20188                 }
20189                 
20190                 if(isNaN(this.vIndex)){
20191                     this.vIndex = 0;
20192                 }
20193                 
20194                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20195                 break;
20196                 
20197             case 13: // enter
20198                 
20199                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20200                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20201                 }
20202                 
20203                 this.hide();
20204                 e.preventDefault();
20205                 break;
20206             case 9: // tab
20207                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20208                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20209                 }
20210                 this.hide();
20211                 break;
20212             case 16: // shift
20213             case 17: // ctrl
20214             case 18: // alt
20215                 break;
20216             default :
20217                 this.hide();
20218                 
20219         }
20220     },
20221     
20222     remove: function() 
20223     {
20224         this.picker().remove();
20225     }
20226    
20227 });
20228
20229 Roo.apply(Roo.bootstrap.MonthField,  {
20230     
20231     content : {
20232         tag: 'tbody',
20233         cn: [
20234         {
20235             tag: 'tr',
20236             cn: [
20237             {
20238                 tag: 'td',
20239                 colspan: '7'
20240             }
20241             ]
20242         }
20243         ]
20244     },
20245     
20246     dates:{
20247         en: {
20248             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20249             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20250         }
20251     }
20252 });
20253
20254 Roo.apply(Roo.bootstrap.MonthField,  {
20255   
20256     template : {
20257         tag: 'div',
20258         cls: 'datepicker dropdown-menu roo-dynamic',
20259         cn: [
20260             {
20261                 tag: 'div',
20262                 cls: 'datepicker-months',
20263                 cn: [
20264                 {
20265                     tag: 'table',
20266                     cls: 'table-condensed',
20267                     cn:[
20268                         Roo.bootstrap.DateField.content
20269                     ]
20270                 }
20271                 ]
20272             }
20273         ]
20274     }
20275 });
20276
20277  
20278
20279  
20280  /*
20281  * - LGPL
20282  *
20283  * CheckBox
20284  * 
20285  */
20286
20287 /**
20288  * @class Roo.bootstrap.CheckBox
20289  * @extends Roo.bootstrap.Input
20290  * Bootstrap CheckBox class
20291  * 
20292  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20293  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20294  * @cfg {String} boxLabel The text that appears beside the checkbox
20295  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20296  * @cfg {Boolean} checked initnal the element
20297  * @cfg {Boolean} inline inline the element (default false)
20298  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20299  * @cfg {String} tooltip label tooltip
20300  * 
20301  * @constructor
20302  * Create a new CheckBox
20303  * @param {Object} config The config object
20304  */
20305
20306 Roo.bootstrap.CheckBox = function(config){
20307     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20308    
20309     this.addEvents({
20310         /**
20311         * @event check
20312         * Fires when the element is checked or unchecked.
20313         * @param {Roo.bootstrap.CheckBox} this This input
20314         * @param {Boolean} checked The new checked value
20315         */
20316        check : true,
20317        /**
20318         * @event click
20319         * Fires when the element is click.
20320         * @param {Roo.bootstrap.CheckBox} this This input
20321         */
20322        click : true
20323     });
20324     
20325 };
20326
20327 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
20328   
20329     inputType: 'checkbox',
20330     inputValue: 1,
20331     valueOff: 0,
20332     boxLabel: false,
20333     checked: false,
20334     weight : false,
20335     inline: false,
20336     tooltip : '',
20337     
20338     getAutoCreate : function()
20339     {
20340         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20341         
20342         var id = Roo.id();
20343         
20344         var cfg = {};
20345         
20346         cfg.cls = 'form-group ' + this.inputType; //input-group
20347         
20348         if(this.inline){
20349             cfg.cls += ' ' + this.inputType + '-inline';
20350         }
20351         
20352         var input =  {
20353             tag: 'input',
20354             id : id,
20355             type : this.inputType,
20356             value : this.inputValue,
20357             cls : 'roo-' + this.inputType, //'form-box',
20358             placeholder : this.placeholder || ''
20359             
20360         };
20361         
20362         if(this.inputType != 'radio'){
20363             var hidden =  {
20364                 tag: 'input',
20365                 type : 'hidden',
20366                 cls : 'roo-hidden-value',
20367                 value : this.checked ? this.inputValue : this.valueOff
20368             };
20369         }
20370         
20371             
20372         if (this.weight) { // Validity check?
20373             cfg.cls += " " + this.inputType + "-" + this.weight;
20374         }
20375         
20376         if (this.disabled) {
20377             input.disabled=true;
20378         }
20379         
20380         if(this.checked){
20381             input.checked = this.checked;
20382         }
20383         
20384         if (this.name) {
20385             
20386             input.name = this.name;
20387             
20388             if(this.inputType != 'radio'){
20389                 hidden.name = this.name;
20390                 input.name = '_hidden_' + this.name;
20391             }
20392         }
20393         
20394         if (this.size) {
20395             input.cls += ' input-' + this.size;
20396         }
20397         
20398         var settings=this;
20399         
20400         ['xs','sm','md','lg'].map(function(size){
20401             if (settings[size]) {
20402                 cfg.cls += ' col-' + size + '-' + settings[size];
20403             }
20404         });
20405         
20406         var inputblock = input;
20407          
20408         if (this.before || this.after) {
20409             
20410             inputblock = {
20411                 cls : 'input-group',
20412                 cn :  [] 
20413             };
20414             
20415             if (this.before) {
20416                 inputblock.cn.push({
20417                     tag :'span',
20418                     cls : 'input-group-addon',
20419                     html : this.before
20420                 });
20421             }
20422             
20423             inputblock.cn.push(input);
20424             
20425             if(this.inputType != 'radio'){
20426                 inputblock.cn.push(hidden);
20427             }
20428             
20429             if (this.after) {
20430                 inputblock.cn.push({
20431                     tag :'span',
20432                     cls : 'input-group-addon',
20433                     html : this.after
20434                 });
20435             }
20436             
20437         }
20438         
20439         if (align ==='left' && this.fieldLabel.length) {
20440 //                Roo.log("left and has label");
20441             cfg.cn = [
20442                 {
20443                     tag: 'label',
20444                     'for' :  id,
20445                     cls : 'control-label',
20446                     html : this.fieldLabel
20447                 },
20448                 {
20449                     cls : "", 
20450                     cn: [
20451                         inputblock
20452                     ]
20453                 }
20454             ];
20455             
20456             if(this.labelWidth > 12){
20457                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20458             }
20459             
20460             if(this.labelWidth < 13 && this.labelmd == 0){
20461                 this.labelmd = this.labelWidth;
20462             }
20463             
20464             if(this.labellg > 0){
20465                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20466                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20467             }
20468             
20469             if(this.labelmd > 0){
20470                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20471                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20472             }
20473             
20474             if(this.labelsm > 0){
20475                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20476                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20477             }
20478             
20479             if(this.labelxs > 0){
20480                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20481                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20482             }
20483             
20484         } else if ( this.fieldLabel.length) {
20485 //                Roo.log(" label");
20486                 cfg.cn = [
20487                    
20488                     {
20489                         tag: this.boxLabel ? 'span' : 'label',
20490                         'for': id,
20491                         cls: 'control-label box-input-label',
20492                         //cls : 'input-group-addon',
20493                         html : this.fieldLabel
20494                     },
20495                     
20496                     inputblock
20497                     
20498                 ];
20499
20500         } else {
20501             
20502 //                Roo.log(" no label && no align");
20503                 cfg.cn = [  inputblock ] ;
20504                 
20505                 
20506         }
20507         
20508         if(this.boxLabel){
20509              var boxLabelCfg = {
20510                 tag: 'label',
20511                 //'for': id, // box label is handled by onclick - so no for...
20512                 cls: 'box-label',
20513                 html: this.boxLabel
20514             };
20515             
20516             if(this.tooltip){
20517                 boxLabelCfg.tooltip = this.tooltip;
20518             }
20519              
20520             cfg.cn.push(boxLabelCfg);
20521         }
20522         
20523         if(this.inputType != 'radio'){
20524             cfg.cn.push(hidden);
20525         }
20526         
20527         return cfg;
20528         
20529     },
20530     
20531     /**
20532      * return the real input element.
20533      */
20534     inputEl: function ()
20535     {
20536         return this.el.select('input.roo-' + this.inputType,true).first();
20537     },
20538     hiddenEl: function ()
20539     {
20540         return this.el.select('input.roo-hidden-value',true).first();
20541     },
20542     
20543     labelEl: function()
20544     {
20545         return this.el.select('label.control-label',true).first();
20546     },
20547     /* depricated... */
20548     
20549     label: function()
20550     {
20551         return this.labelEl();
20552     },
20553     
20554     boxLabelEl: function()
20555     {
20556         return this.el.select('label.box-label',true).first();
20557     },
20558     
20559     initEvents : function()
20560     {
20561 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20562         
20563         this.inputEl().on('click', this.onClick,  this);
20564         
20565         if (this.boxLabel) { 
20566             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
20567         }
20568         
20569         this.startValue = this.getValue();
20570         
20571         if(this.groupId){
20572             Roo.bootstrap.CheckBox.register(this);
20573         }
20574     },
20575     
20576     onClick : function(e)
20577     {   
20578         if(this.fireEvent('click', this, e) !== false){
20579             this.setChecked(!this.checked);
20580         }
20581         
20582     },
20583     
20584     setChecked : function(state,suppressEvent)
20585     {
20586         this.startValue = this.getValue();
20587
20588         if(this.inputType == 'radio'){
20589             
20590             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20591                 e.dom.checked = false;
20592             });
20593             
20594             this.inputEl().dom.checked = true;
20595             
20596             this.inputEl().dom.value = this.inputValue;
20597             
20598             if(suppressEvent !== true){
20599                 this.fireEvent('check', this, true);
20600             }
20601             
20602             this.validate();
20603             
20604             return;
20605         }
20606         
20607         this.checked = state;
20608         
20609         this.inputEl().dom.checked = state;
20610         
20611         
20612         this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20613         
20614         if(suppressEvent !== true){
20615             this.fireEvent('check', this, state);
20616         }
20617         
20618         this.validate();
20619     },
20620     
20621     getValue : function()
20622     {
20623         if(this.inputType == 'radio'){
20624             return this.getGroupValue();
20625         }
20626         
20627         return this.hiddenEl().dom.value;
20628         
20629     },
20630     
20631     getGroupValue : function()
20632     {
20633         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20634             return '';
20635         }
20636         
20637         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20638     },
20639     
20640     setValue : function(v,suppressEvent)
20641     {
20642         if(this.inputType == 'radio'){
20643             this.setGroupValue(v, suppressEvent);
20644             return;
20645         }
20646         
20647         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20648         
20649         this.validate();
20650     },
20651     
20652     setGroupValue : function(v, suppressEvent)
20653     {
20654         this.startValue = this.getValue();
20655         
20656         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20657             e.dom.checked = false;
20658             
20659             if(e.dom.value == v){
20660                 e.dom.checked = true;
20661             }
20662         });
20663         
20664         if(suppressEvent !== true){
20665             this.fireEvent('check', this, true);
20666         }
20667
20668         this.validate();
20669         
20670         return;
20671     },
20672     
20673     validate : function()
20674     {
20675         if(
20676                 this.disabled || 
20677                 (this.inputType == 'radio' && this.validateRadio()) ||
20678                 (this.inputType == 'checkbox' && this.validateCheckbox())
20679         ){
20680             this.markValid();
20681             return true;
20682         }
20683         
20684         this.markInvalid();
20685         return false;
20686     },
20687     
20688     validateRadio : function()
20689     {
20690         if(this.allowBlank){
20691             return true;
20692         }
20693         
20694         var valid = false;
20695         
20696         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20697             if(!e.dom.checked){
20698                 return;
20699             }
20700             
20701             valid = true;
20702             
20703             return false;
20704         });
20705         
20706         return valid;
20707     },
20708     
20709     validateCheckbox : function()
20710     {
20711         if(!this.groupId){
20712             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20713             //return (this.getValue() == this.inputValue) ? true : false;
20714         }
20715         
20716         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20717         
20718         if(!group){
20719             return false;
20720         }
20721         
20722         var r = false;
20723         
20724         for(var i in group){
20725             if(group[i].el.isVisible(true)){
20726                 r = false;
20727                 break;
20728             }
20729             
20730             r = true;
20731         }
20732         
20733         for(var i in group){
20734             if(r){
20735                 break;
20736             }
20737             
20738             r = (group[i].getValue() == group[i].inputValue) ? true : false;
20739         }
20740         
20741         return r;
20742     },
20743     
20744     /**
20745      * Mark this field as valid
20746      */
20747     markValid : function()
20748     {
20749         var _this = this;
20750         
20751         this.fireEvent('valid', this);
20752         
20753         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20754         
20755         if(this.groupId){
20756             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20757         }
20758         
20759         if(label){
20760             label.markValid();
20761         }
20762
20763         if(this.inputType == 'radio'){
20764             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20765                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20766                 e.findParent('.form-group', false, true).addClass(_this.validClass);
20767             });
20768             
20769             return;
20770         }
20771
20772         if(!this.groupId){
20773             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20774             this.el.findParent('.form-group', false, true).addClass(this.validClass);
20775             return;
20776         }
20777         
20778         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20779         
20780         if(!group){
20781             return;
20782         }
20783         
20784         for(var i in group){
20785             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20786             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20787         }
20788     },
20789     
20790      /**
20791      * Mark this field as invalid
20792      * @param {String} msg The validation message
20793      */
20794     markInvalid : function(msg)
20795     {
20796         if(this.allowBlank){
20797             return;
20798         }
20799         
20800         var _this = this;
20801         
20802         this.fireEvent('invalid', this, msg);
20803         
20804         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20805         
20806         if(this.groupId){
20807             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20808         }
20809         
20810         if(label){
20811             label.markInvalid();
20812         }
20813             
20814         if(this.inputType == 'radio'){
20815             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20816                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20817                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20818             });
20819             
20820             return;
20821         }
20822         
20823         if(!this.groupId){
20824             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20825             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20826             return;
20827         }
20828         
20829         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20830         
20831         if(!group){
20832             return;
20833         }
20834         
20835         for(var i in group){
20836             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20837             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20838         }
20839         
20840     },
20841     
20842     clearInvalid : function()
20843     {
20844         Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20845         
20846         // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20847         
20848         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20849         
20850         if (label && label.iconEl) {
20851             label.iconEl.removeClass(label.validClass);
20852             label.iconEl.removeClass(label.invalidClass);
20853         }
20854     },
20855     
20856     disable : function()
20857     {
20858         if(this.inputType != 'radio'){
20859             Roo.bootstrap.CheckBox.superclass.disable.call(this);
20860             return;
20861         }
20862         
20863         var _this = this;
20864         
20865         if(this.rendered){
20866             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20867                 _this.getActionEl().addClass(this.disabledClass);
20868                 e.dom.disabled = true;
20869             });
20870         }
20871         
20872         this.disabled = true;
20873         this.fireEvent("disable", this);
20874         return this;
20875     },
20876
20877     enable : function()
20878     {
20879         if(this.inputType != 'radio'){
20880             Roo.bootstrap.CheckBox.superclass.enable.call(this);
20881             return;
20882         }
20883         
20884         var _this = this;
20885         
20886         if(this.rendered){
20887             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20888                 _this.getActionEl().removeClass(this.disabledClass);
20889                 e.dom.disabled = false;
20890             });
20891         }
20892         
20893         this.disabled = false;
20894         this.fireEvent("enable", this);
20895         return this;
20896     },
20897     
20898     setBoxLabel : function(v)
20899     {
20900         this.boxLabel = v;
20901         
20902         if(this.rendered){
20903             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20904         }
20905     }
20906
20907 });
20908
20909 Roo.apply(Roo.bootstrap.CheckBox, {
20910     
20911     groups: {},
20912     
20913      /**
20914     * register a CheckBox Group
20915     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20916     */
20917     register : function(checkbox)
20918     {
20919         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20920             this.groups[checkbox.groupId] = {};
20921         }
20922         
20923         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20924             return;
20925         }
20926         
20927         this.groups[checkbox.groupId][checkbox.name] = checkbox;
20928         
20929     },
20930     /**
20931     * fetch a CheckBox Group based on the group ID
20932     * @param {string} the group ID
20933     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20934     */
20935     get: function(groupId) {
20936         if (typeof(this.groups[groupId]) == 'undefined') {
20937             return false;
20938         }
20939         
20940         return this.groups[groupId] ;
20941     }
20942     
20943     
20944 });
20945 /*
20946  * - LGPL
20947  *
20948  * RadioItem
20949  * 
20950  */
20951
20952 /**
20953  * @class Roo.bootstrap.Radio
20954  * @extends Roo.bootstrap.Component
20955  * Bootstrap Radio class
20956  * @cfg {String} boxLabel - the label associated
20957  * @cfg {String} value - the value of radio
20958  * 
20959  * @constructor
20960  * Create a new Radio
20961  * @param {Object} config The config object
20962  */
20963 Roo.bootstrap.Radio = function(config){
20964     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20965     
20966 };
20967
20968 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20969     
20970     boxLabel : '',
20971     
20972     value : '',
20973     
20974     getAutoCreate : function()
20975     {
20976         var cfg = {
20977             tag : 'div',
20978             cls : 'form-group radio',
20979             cn : [
20980                 {
20981                     tag : 'label',
20982                     cls : 'box-label',
20983                     html : this.boxLabel
20984                 }
20985             ]
20986         };
20987         
20988         return cfg;
20989     },
20990     
20991     initEvents : function() 
20992     {
20993         this.parent().register(this);
20994         
20995         this.el.on('click', this.onClick, this);
20996         
20997     },
20998     
20999     onClick : function(e)
21000     {
21001         if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21002             this.setChecked(true);
21003         }
21004     },
21005     
21006     setChecked : function(state, suppressEvent)
21007     {
21008         this.parent().setValue(this.value, suppressEvent);
21009         
21010     },
21011     
21012     setBoxLabel : function(v)
21013     {
21014         this.boxLabel = v;
21015         
21016         if(this.rendered){
21017             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21018         }
21019     }
21020     
21021 });
21022  
21023
21024  /*
21025  * - LGPL
21026  *
21027  * Input
21028  * 
21029  */
21030
21031 /**
21032  * @class Roo.bootstrap.SecurePass
21033  * @extends Roo.bootstrap.Input
21034  * Bootstrap SecurePass class
21035  *
21036  * 
21037  * @constructor
21038  * Create a new SecurePass
21039  * @param {Object} config The config object
21040  */
21041  
21042 Roo.bootstrap.SecurePass = function (config) {
21043     // these go here, so the translation tool can replace them..
21044     this.errors = {
21045         PwdEmpty: "Please type a password, and then retype it to confirm.",
21046         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21047         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21048         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21049         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21050         FNInPwd: "Your password can't contain your first name. Please type a different password.",
21051         LNInPwd: "Your password can't contain your last name. Please type a different password.",
21052         TooWeak: "Your password is Too Weak."
21053     },
21054     this.meterLabel = "Password strength:";
21055     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21056     this.meterClass = [
21057         "roo-password-meter-tooweak", 
21058         "roo-password-meter-weak", 
21059         "roo-password-meter-medium", 
21060         "roo-password-meter-strong", 
21061         "roo-password-meter-grey"
21062     ];
21063     
21064     this.errors = {};
21065     
21066     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21067 }
21068
21069 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21070     /**
21071      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21072      * {
21073      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
21074      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21075      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21076      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21077      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21078      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
21079      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
21080      * })
21081      */
21082     // private
21083     
21084     meterWidth: 300,
21085     errorMsg :'',    
21086     errors: false,
21087     imageRoot: '/',
21088     /**
21089      * @cfg {String/Object} Label for the strength meter (defaults to
21090      * 'Password strength:')
21091      */
21092     // private
21093     meterLabel: '',
21094     /**
21095      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21096      * ['Weak', 'Medium', 'Strong'])
21097      */
21098     // private    
21099     pwdStrengths: false,    
21100     // private
21101     strength: 0,
21102     // private
21103     _lastPwd: null,
21104     // private
21105     kCapitalLetter: 0,
21106     kSmallLetter: 1,
21107     kDigit: 2,
21108     kPunctuation: 3,
21109     
21110     insecure: false,
21111     // private
21112     initEvents: function ()
21113     {
21114         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21115
21116         if (this.el.is('input[type=password]') && Roo.isSafari) {
21117             this.el.on('keydown', this.SafariOnKeyDown, this);
21118         }
21119
21120         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21121     },
21122     // private
21123     onRender: function (ct, position)
21124     {
21125         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21126         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21127         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21128
21129         this.trigger.createChild({
21130                    cn: [
21131                     {
21132                     //id: 'PwdMeter',
21133                     tag: 'div',
21134                     cls: 'roo-password-meter-grey col-xs-12',
21135                     style: {
21136                         //width: 0,
21137                         //width: this.meterWidth + 'px'                                                
21138                         }
21139                     },
21140                     {                            
21141                          cls: 'roo-password-meter-text'                          
21142                     }
21143                 ]            
21144         });
21145
21146          
21147         if (this.hideTrigger) {
21148             this.trigger.setDisplayed(false);
21149         }
21150         this.setSize(this.width || '', this.height || '');
21151     },
21152     // private
21153     onDestroy: function ()
21154     {
21155         if (this.trigger) {
21156             this.trigger.removeAllListeners();
21157             this.trigger.remove();
21158         }
21159         if (this.wrap) {
21160             this.wrap.remove();
21161         }
21162         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21163     },
21164     // private
21165     checkStrength: function ()
21166     {
21167         var pwd = this.inputEl().getValue();
21168         if (pwd == this._lastPwd) {
21169             return;
21170         }
21171
21172         var strength;
21173         if (this.ClientSideStrongPassword(pwd)) {
21174             strength = 3;
21175         } else if (this.ClientSideMediumPassword(pwd)) {
21176             strength = 2;
21177         } else if (this.ClientSideWeakPassword(pwd)) {
21178             strength = 1;
21179         } else {
21180             strength = 0;
21181         }
21182         
21183         Roo.log('strength1: ' + strength);
21184         
21185         //var pm = this.trigger.child('div/div/div').dom;
21186         var pm = this.trigger.child('div/div');
21187         pm.removeClass(this.meterClass);
21188         pm.addClass(this.meterClass[strength]);
21189                 
21190         
21191         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21192                 
21193         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21194         
21195         this._lastPwd = pwd;
21196     },
21197     reset: function ()
21198     {
21199         Roo.bootstrap.SecurePass.superclass.reset.call(this);
21200         
21201         this._lastPwd = '';
21202         
21203         var pm = this.trigger.child('div/div');
21204         pm.removeClass(this.meterClass);
21205         pm.addClass('roo-password-meter-grey');        
21206         
21207         
21208         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21209         
21210         pt.innerHTML = '';
21211         this.inputEl().dom.type='password';
21212     },
21213     // private
21214     validateValue: function (value)
21215     {
21216         
21217         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21218             return false;
21219         }
21220         if (value.length == 0) {
21221             if (this.allowBlank) {
21222                 this.clearInvalid();
21223                 return true;
21224             }
21225
21226             this.markInvalid(this.errors.PwdEmpty);
21227             this.errorMsg = this.errors.PwdEmpty;
21228             return false;
21229         }
21230         
21231         if(this.insecure){
21232             return true;
21233         }
21234         
21235         if ('[\x21-\x7e]*'.match(value)) {
21236             this.markInvalid(this.errors.PwdBadChar);
21237             this.errorMsg = this.errors.PwdBadChar;
21238             return false;
21239         }
21240         if (value.length < 6) {
21241             this.markInvalid(this.errors.PwdShort);
21242             this.errorMsg = this.errors.PwdShort;
21243             return false;
21244         }
21245         if (value.length > 16) {
21246             this.markInvalid(this.errors.PwdLong);
21247             this.errorMsg = this.errors.PwdLong;
21248             return false;
21249         }
21250         var strength;
21251         if (this.ClientSideStrongPassword(value)) {
21252             strength = 3;
21253         } else if (this.ClientSideMediumPassword(value)) {
21254             strength = 2;
21255         } else if (this.ClientSideWeakPassword(value)) {
21256             strength = 1;
21257         } else {
21258             strength = 0;
21259         }
21260
21261         
21262         if (strength < 2) {
21263             //this.markInvalid(this.errors.TooWeak);
21264             this.errorMsg = this.errors.TooWeak;
21265             //return false;
21266         }
21267         
21268         
21269         console.log('strength2: ' + strength);
21270         
21271         //var pm = this.trigger.child('div/div/div').dom;
21272         
21273         var pm = this.trigger.child('div/div');
21274         pm.removeClass(this.meterClass);
21275         pm.addClass(this.meterClass[strength]);
21276                 
21277         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21278                 
21279         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21280         
21281         this.errorMsg = ''; 
21282         return true;
21283     },
21284     // private
21285     CharacterSetChecks: function (type)
21286     {
21287         this.type = type;
21288         this.fResult = false;
21289     },
21290     // private
21291     isctype: function (character, type)
21292     {
21293         switch (type) {  
21294             case this.kCapitalLetter:
21295                 if (character >= 'A' && character <= 'Z') {
21296                     return true;
21297                 }
21298                 break;
21299             
21300             case this.kSmallLetter:
21301                 if (character >= 'a' && character <= 'z') {
21302                     return true;
21303                 }
21304                 break;
21305             
21306             case this.kDigit:
21307                 if (character >= '0' && character <= '9') {
21308                     return true;
21309                 }
21310                 break;
21311             
21312             case this.kPunctuation:
21313                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21314                     return true;
21315                 }
21316                 break;
21317             
21318             default:
21319                 return false;
21320         }
21321
21322     },
21323     // private
21324     IsLongEnough: function (pwd, size)
21325     {
21326         return !(pwd == null || isNaN(size) || pwd.length < size);
21327     },
21328     // private
21329     SpansEnoughCharacterSets: function (word, nb)
21330     {
21331         if (!this.IsLongEnough(word, nb))
21332         {
21333             return false;
21334         }
21335
21336         var characterSetChecks = new Array(
21337             new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21338             new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21339         );
21340         
21341         for (var index = 0; index < word.length; ++index) {
21342             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21343                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21344                     characterSetChecks[nCharSet].fResult = true;
21345                     break;
21346                 }
21347             }
21348         }
21349
21350         var nCharSets = 0;
21351         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21352             if (characterSetChecks[nCharSet].fResult) {
21353                 ++nCharSets;
21354             }
21355         }
21356
21357         if (nCharSets < nb) {
21358             return false;
21359         }
21360         return true;
21361     },
21362     // private
21363     ClientSideStrongPassword: function (pwd)
21364     {
21365         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21366     },
21367     // private
21368     ClientSideMediumPassword: function (pwd)
21369     {
21370         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21371     },
21372     // private
21373     ClientSideWeakPassword: function (pwd)
21374     {
21375         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21376     }
21377           
21378 })//<script type="text/javascript">
21379
21380 /*
21381  * Based  Ext JS Library 1.1.1
21382  * Copyright(c) 2006-2007, Ext JS, LLC.
21383  * LGPL
21384  *
21385  */
21386  
21387 /**
21388  * @class Roo.HtmlEditorCore
21389  * @extends Roo.Component
21390  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21391  *
21392  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21393  */
21394
21395 Roo.HtmlEditorCore = function(config){
21396     
21397     
21398     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21399     
21400     
21401     this.addEvents({
21402         /**
21403          * @event initialize
21404          * Fires when the editor is fully initialized (including the iframe)
21405          * @param {Roo.HtmlEditorCore} this
21406          */
21407         initialize: true,
21408         /**
21409          * @event activate
21410          * Fires when the editor is first receives the focus. Any insertion must wait
21411          * until after this event.
21412          * @param {Roo.HtmlEditorCore} this
21413          */
21414         activate: true,
21415          /**
21416          * @event beforesync
21417          * Fires before the textarea is updated with content from the editor iframe. Return false
21418          * to cancel the sync.
21419          * @param {Roo.HtmlEditorCore} this
21420          * @param {String} html
21421          */
21422         beforesync: true,
21423          /**
21424          * @event beforepush
21425          * Fires before the iframe editor is updated with content from the textarea. Return false
21426          * to cancel the push.
21427          * @param {Roo.HtmlEditorCore} this
21428          * @param {String} html
21429          */
21430         beforepush: true,
21431          /**
21432          * @event sync
21433          * Fires when the textarea is updated with content from the editor iframe.
21434          * @param {Roo.HtmlEditorCore} this
21435          * @param {String} html
21436          */
21437         sync: true,
21438          /**
21439          * @event push
21440          * Fires when the iframe editor is updated with content from the textarea.
21441          * @param {Roo.HtmlEditorCore} this
21442          * @param {String} html
21443          */
21444         push: true,
21445         
21446         /**
21447          * @event editorevent
21448          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21449          * @param {Roo.HtmlEditorCore} this
21450          */
21451         editorevent: true
21452         
21453     });
21454     
21455     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21456     
21457     // defaults : white / black...
21458     this.applyBlacklists();
21459     
21460     
21461     
21462 };
21463
21464
21465 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
21466
21467
21468      /**
21469      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
21470      */
21471     
21472     owner : false,
21473     
21474      /**
21475      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
21476      *                        Roo.resizable.
21477      */
21478     resizable : false,
21479      /**
21480      * @cfg {Number} height (in pixels)
21481      */   
21482     height: 300,
21483    /**
21484      * @cfg {Number} width (in pixels)
21485      */   
21486     width: 500,
21487     
21488     /**
21489      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21490      * 
21491      */
21492     stylesheets: false,
21493     
21494     // id of frame..
21495     frameId: false,
21496     
21497     // private properties
21498     validationEvent : false,
21499     deferHeight: true,
21500     initialized : false,
21501     activated : false,
21502     sourceEditMode : false,
21503     onFocus : Roo.emptyFn,
21504     iframePad:3,
21505     hideMode:'offsets',
21506     
21507     clearUp: true,
21508     
21509     // blacklist + whitelisted elements..
21510     black: false,
21511     white: false,
21512      
21513     bodyCls : '',
21514
21515     /**
21516      * Protected method that will not generally be called directly. It
21517      * is called when the editor initializes the iframe with HTML contents. Override this method if you
21518      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21519      */
21520     getDocMarkup : function(){
21521         // body styles..
21522         var st = '';
21523         
21524         // inherit styels from page...?? 
21525         if (this.stylesheets === false) {
21526             
21527             Roo.get(document.head).select('style').each(function(node) {
21528                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21529             });
21530             
21531             Roo.get(document.head).select('link').each(function(node) { 
21532                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21533             });
21534             
21535         } else if (!this.stylesheets.length) {
21536                 // simple..
21537                 st = '<style type="text/css">' +
21538                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21539                    '</style>';
21540         } else { 
21541             st = '<style type="text/css">' +
21542                     this.stylesheets +
21543                 '</style>';
21544         }
21545         
21546         st +=  '<style type="text/css">' +
21547             'IMG { cursor: pointer } ' +
21548         '</style>';
21549
21550         var cls = 'roo-htmleditor-body';
21551         
21552         if(this.bodyCls.length){
21553             cls += ' ' + this.bodyCls;
21554         }
21555         
21556         return '<html><head>' + st  +
21557             //<style type="text/css">' +
21558             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21559             //'</style>' +
21560             ' </head><body class="' +  cls + '"></body></html>';
21561     },
21562
21563     // private
21564     onRender : function(ct, position)
21565     {
21566         var _t = this;
21567         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21568         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21569         
21570         
21571         this.el.dom.style.border = '0 none';
21572         this.el.dom.setAttribute('tabIndex', -1);
21573         this.el.addClass('x-hidden hide');
21574         
21575         
21576         
21577         if(Roo.isIE){ // fix IE 1px bogus margin
21578             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21579         }
21580        
21581         
21582         this.frameId = Roo.id();
21583         
21584          
21585         
21586         var iframe = this.owner.wrap.createChild({
21587             tag: 'iframe',
21588             cls: 'form-control', // bootstrap..
21589             id: this.frameId,
21590             name: this.frameId,
21591             frameBorder : 'no',
21592             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
21593         }, this.el
21594         );
21595         
21596         
21597         this.iframe = iframe.dom;
21598
21599          this.assignDocWin();
21600         
21601         this.doc.designMode = 'on';
21602        
21603         this.doc.open();
21604         this.doc.write(this.getDocMarkup());
21605         this.doc.close();
21606
21607         
21608         var task = { // must defer to wait for browser to be ready
21609             run : function(){
21610                 //console.log("run task?" + this.doc.readyState);
21611                 this.assignDocWin();
21612                 if(this.doc.body || this.doc.readyState == 'complete'){
21613                     try {
21614                         this.doc.designMode="on";
21615                     } catch (e) {
21616                         return;
21617                     }
21618                     Roo.TaskMgr.stop(task);
21619                     this.initEditor.defer(10, this);
21620                 }
21621             },
21622             interval : 10,
21623             duration: 10000,
21624             scope: this
21625         };
21626         Roo.TaskMgr.start(task);
21627
21628     },
21629
21630     // private
21631     onResize : function(w, h)
21632     {
21633          Roo.log('resize: ' +w + ',' + h );
21634         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21635         if(!this.iframe){
21636             return;
21637         }
21638         if(typeof w == 'number'){
21639             
21640             this.iframe.style.width = w + 'px';
21641         }
21642         if(typeof h == 'number'){
21643             
21644             this.iframe.style.height = h + 'px';
21645             if(this.doc){
21646                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21647             }
21648         }
21649         
21650     },
21651
21652     /**
21653      * Toggles the editor between standard and source edit mode.
21654      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21655      */
21656     toggleSourceEdit : function(sourceEditMode){
21657         
21658         this.sourceEditMode = sourceEditMode === true;
21659         
21660         if(this.sourceEditMode){
21661  
21662             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
21663             
21664         }else{
21665             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21666             //this.iframe.className = '';
21667             this.deferFocus();
21668         }
21669         //this.setSize(this.owner.wrap.getSize());
21670         //this.fireEvent('editmodechange', this, this.sourceEditMode);
21671     },
21672
21673     
21674   
21675
21676     /**
21677      * Protected method that will not generally be called directly. If you need/want
21678      * custom HTML cleanup, this is the method you should override.
21679      * @param {String} html The HTML to be cleaned
21680      * return {String} The cleaned HTML
21681      */
21682     cleanHtml : function(html){
21683         html = String(html);
21684         if(html.length > 5){
21685             if(Roo.isSafari){ // strip safari nonsense
21686                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21687             }
21688         }
21689         if(html == '&nbsp;'){
21690             html = '';
21691         }
21692         return html;
21693     },
21694
21695     /**
21696      * HTML Editor -> Textarea
21697      * Protected method that will not generally be called directly. Syncs the contents
21698      * of the editor iframe with the textarea.
21699      */
21700     syncValue : function(){
21701         if(this.initialized){
21702             var bd = (this.doc.body || this.doc.documentElement);
21703             //this.cleanUpPaste(); -- this is done else where and causes havoc..
21704             var html = bd.innerHTML;
21705             if(Roo.isSafari){
21706                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21707                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21708                 if(m && m[1]){
21709                     html = '<div style="'+m[0]+'">' + html + '</div>';
21710                 }
21711             }
21712             html = this.cleanHtml(html);
21713             // fix up the special chars.. normaly like back quotes in word...
21714             // however we do not want to do this with chinese..
21715             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21716                 var cc = b.charCodeAt();
21717                 if (
21718                     (cc >= 0x4E00 && cc < 0xA000 ) ||
21719                     (cc >= 0x3400 && cc < 0x4E00 ) ||
21720                     (cc >= 0xf900 && cc < 0xfb00 )
21721                 ) {
21722                         return b;
21723                 }
21724                 return "&#"+cc+";" 
21725             });
21726             if(this.owner.fireEvent('beforesync', this, html) !== false){
21727                 this.el.dom.value = html;
21728                 this.owner.fireEvent('sync', this, html);
21729             }
21730         }
21731     },
21732
21733     /**
21734      * Protected method that will not generally be called directly. Pushes the value of the textarea
21735      * into the iframe editor.
21736      */
21737     pushValue : function(){
21738         if(this.initialized){
21739             var v = this.el.dom.value.trim();
21740             
21741 //            if(v.length < 1){
21742 //                v = '&#160;';
21743 //            }
21744             
21745             if(this.owner.fireEvent('beforepush', this, v) !== false){
21746                 var d = (this.doc.body || this.doc.documentElement);
21747                 d.innerHTML = v;
21748                 this.cleanUpPaste();
21749                 this.el.dom.value = d.innerHTML;
21750                 this.owner.fireEvent('push', this, v);
21751             }
21752         }
21753     },
21754
21755     // private
21756     deferFocus : function(){
21757         this.focus.defer(10, this);
21758     },
21759
21760     // doc'ed in Field
21761     focus : function(){
21762         if(this.win && !this.sourceEditMode){
21763             this.win.focus();
21764         }else{
21765             this.el.focus();
21766         }
21767     },
21768     
21769     assignDocWin: function()
21770     {
21771         var iframe = this.iframe;
21772         
21773          if(Roo.isIE){
21774             this.doc = iframe.contentWindow.document;
21775             this.win = iframe.contentWindow;
21776         } else {
21777 //            if (!Roo.get(this.frameId)) {
21778 //                return;
21779 //            }
21780 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21781 //            this.win = Roo.get(this.frameId).dom.contentWindow;
21782             
21783             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21784                 return;
21785             }
21786             
21787             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21788             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21789         }
21790     },
21791     
21792     // private
21793     initEditor : function(){
21794         //console.log("INIT EDITOR");
21795         this.assignDocWin();
21796         
21797         
21798         
21799         this.doc.designMode="on";
21800         this.doc.open();
21801         this.doc.write(this.getDocMarkup());
21802         this.doc.close();
21803         
21804         var dbody = (this.doc.body || this.doc.documentElement);
21805         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21806         // this copies styles from the containing element into thsi one..
21807         // not sure why we need all of this..
21808         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21809         
21810         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21811         //ss['background-attachment'] = 'fixed'; // w3c
21812         dbody.bgProperties = 'fixed'; // ie
21813         //Roo.DomHelper.applyStyles(dbody, ss);
21814         Roo.EventManager.on(this.doc, {
21815             //'mousedown': this.onEditorEvent,
21816             'mouseup': this.onEditorEvent,
21817             'dblclick': this.onEditorEvent,
21818             'click': this.onEditorEvent,
21819             'keyup': this.onEditorEvent,
21820             buffer:100,
21821             scope: this
21822         });
21823         if(Roo.isGecko){
21824             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21825         }
21826         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21827             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21828         }
21829         this.initialized = true;
21830
21831         this.owner.fireEvent('initialize', this);
21832         this.pushValue();
21833     },
21834
21835     // private
21836     onDestroy : function(){
21837         
21838         
21839         
21840         if(this.rendered){
21841             
21842             //for (var i =0; i < this.toolbars.length;i++) {
21843             //    // fixme - ask toolbars for heights?
21844             //    this.toolbars[i].onDestroy();
21845            // }
21846             
21847             //this.wrap.dom.innerHTML = '';
21848             //this.wrap.remove();
21849         }
21850     },
21851
21852     // private
21853     onFirstFocus : function(){
21854         
21855         this.assignDocWin();
21856         
21857         
21858         this.activated = true;
21859          
21860     
21861         if(Roo.isGecko){ // prevent silly gecko errors
21862             this.win.focus();
21863             var s = this.win.getSelection();
21864             if(!s.focusNode || s.focusNode.nodeType != 3){
21865                 var r = s.getRangeAt(0);
21866                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21867                 r.collapse(true);
21868                 this.deferFocus();
21869             }
21870             try{
21871                 this.execCmd('useCSS', true);
21872                 this.execCmd('styleWithCSS', false);
21873             }catch(e){}
21874         }
21875         this.owner.fireEvent('activate', this);
21876     },
21877
21878     // private
21879     adjustFont: function(btn){
21880         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21881         //if(Roo.isSafari){ // safari
21882         //    adjust *= 2;
21883        // }
21884         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21885         if(Roo.isSafari){ // safari
21886             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21887             v =  (v < 10) ? 10 : v;
21888             v =  (v > 48) ? 48 : v;
21889             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21890             
21891         }
21892         
21893         
21894         v = Math.max(1, v+adjust);
21895         
21896         this.execCmd('FontSize', v  );
21897     },
21898
21899     onEditorEvent : function(e)
21900     {
21901         this.owner.fireEvent('editorevent', this, e);
21902       //  this.updateToolbar();
21903         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21904     },
21905
21906     insertTag : function(tg)
21907     {
21908         // could be a bit smarter... -> wrap the current selected tRoo..
21909         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21910             
21911             range = this.createRange(this.getSelection());
21912             var wrappingNode = this.doc.createElement(tg.toLowerCase());
21913             wrappingNode.appendChild(range.extractContents());
21914             range.insertNode(wrappingNode);
21915
21916             return;
21917             
21918             
21919             
21920         }
21921         this.execCmd("formatblock",   tg);
21922         
21923     },
21924     
21925     insertText : function(txt)
21926     {
21927         
21928         
21929         var range = this.createRange();
21930         range.deleteContents();
21931                //alert(Sender.getAttribute('label'));
21932                
21933         range.insertNode(this.doc.createTextNode(txt));
21934     } ,
21935     
21936      
21937
21938     /**
21939      * Executes a Midas editor command on the editor document and performs necessary focus and
21940      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21941      * @param {String} cmd The Midas command
21942      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21943      */
21944     relayCmd : function(cmd, value){
21945         this.win.focus();
21946         this.execCmd(cmd, value);
21947         this.owner.fireEvent('editorevent', this);
21948         //this.updateToolbar();
21949         this.owner.deferFocus();
21950     },
21951
21952     /**
21953      * Executes a Midas editor command directly on the editor document.
21954      * For visual commands, you should use {@link #relayCmd} instead.
21955      * <b>This should only be called after the editor is initialized.</b>
21956      * @param {String} cmd The Midas command
21957      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21958      */
21959     execCmd : function(cmd, value){
21960         this.doc.execCommand(cmd, false, value === undefined ? null : value);
21961         this.syncValue();
21962     },
21963  
21964  
21965    
21966     /**
21967      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21968      * to insert tRoo.
21969      * @param {String} text | dom node.. 
21970      */
21971     insertAtCursor : function(text)
21972     {
21973         
21974         if(!this.activated){
21975             return;
21976         }
21977         /*
21978         if(Roo.isIE){
21979             this.win.focus();
21980             var r = this.doc.selection.createRange();
21981             if(r){
21982                 r.collapse(true);
21983                 r.pasteHTML(text);
21984                 this.syncValue();
21985                 this.deferFocus();
21986             
21987             }
21988             return;
21989         }
21990         */
21991         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21992             this.win.focus();
21993             
21994             
21995             // from jquery ui (MIT licenced)
21996             var range, node;
21997             var win = this.win;
21998             
21999             if (win.getSelection && win.getSelection().getRangeAt) {
22000                 range = win.getSelection().getRangeAt(0);
22001                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22002                 range.insertNode(node);
22003             } else if (win.document.selection && win.document.selection.createRange) {
22004                 // no firefox support
22005                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22006                 win.document.selection.createRange().pasteHTML(txt);
22007             } else {
22008                 // no firefox support
22009                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22010                 this.execCmd('InsertHTML', txt);
22011             } 
22012             
22013             this.syncValue();
22014             
22015             this.deferFocus();
22016         }
22017     },
22018  // private
22019     mozKeyPress : function(e){
22020         if(e.ctrlKey){
22021             var c = e.getCharCode(), cmd;
22022           
22023             if(c > 0){
22024                 c = String.fromCharCode(c).toLowerCase();
22025                 switch(c){
22026                     case 'b':
22027                         cmd = 'bold';
22028                         break;
22029                     case 'i':
22030                         cmd = 'italic';
22031                         break;
22032                     
22033                     case 'u':
22034                         cmd = 'underline';
22035                         break;
22036                     
22037                     case 'v':
22038                         this.cleanUpPaste.defer(100, this);
22039                         return;
22040                         
22041                 }
22042                 if(cmd){
22043                     this.win.focus();
22044                     this.execCmd(cmd);
22045                     this.deferFocus();
22046                     e.preventDefault();
22047                 }
22048                 
22049             }
22050         }
22051     },
22052
22053     // private
22054     fixKeys : function(){ // load time branching for fastest keydown performance
22055         if(Roo.isIE){
22056             return function(e){
22057                 var k = e.getKey(), r;
22058                 if(k == e.TAB){
22059                     e.stopEvent();
22060                     r = this.doc.selection.createRange();
22061                     if(r){
22062                         r.collapse(true);
22063                         r.pasteHTML('&#160;&#160;&#160;&#160;');
22064                         this.deferFocus();
22065                     }
22066                     return;
22067                 }
22068                 
22069                 if(k == e.ENTER){
22070                     r = this.doc.selection.createRange();
22071                     if(r){
22072                         var target = r.parentElement();
22073                         if(!target || target.tagName.toLowerCase() != 'li'){
22074                             e.stopEvent();
22075                             r.pasteHTML('<br />');
22076                             r.collapse(false);
22077                             r.select();
22078                         }
22079                     }
22080                 }
22081                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22082                     this.cleanUpPaste.defer(100, this);
22083                     return;
22084                 }
22085                 
22086                 
22087             };
22088         }else if(Roo.isOpera){
22089             return function(e){
22090                 var k = e.getKey();
22091                 if(k == e.TAB){
22092                     e.stopEvent();
22093                     this.win.focus();
22094                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
22095                     this.deferFocus();
22096                 }
22097                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22098                     this.cleanUpPaste.defer(100, this);
22099                     return;
22100                 }
22101                 
22102             };
22103         }else if(Roo.isSafari){
22104             return function(e){
22105                 var k = e.getKey();
22106                 
22107                 if(k == e.TAB){
22108                     e.stopEvent();
22109                     this.execCmd('InsertText','\t');
22110                     this.deferFocus();
22111                     return;
22112                 }
22113                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22114                     this.cleanUpPaste.defer(100, this);
22115                     return;
22116                 }
22117                 
22118              };
22119         }
22120     }(),
22121     
22122     getAllAncestors: function()
22123     {
22124         var p = this.getSelectedNode();
22125         var a = [];
22126         if (!p) {
22127             a.push(p); // push blank onto stack..
22128             p = this.getParentElement();
22129         }
22130         
22131         
22132         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22133             a.push(p);
22134             p = p.parentNode;
22135         }
22136         a.push(this.doc.body);
22137         return a;
22138     },
22139     lastSel : false,
22140     lastSelNode : false,
22141     
22142     
22143     getSelection : function() 
22144     {
22145         this.assignDocWin();
22146         return Roo.isIE ? this.doc.selection : this.win.getSelection();
22147     },
22148     
22149     getSelectedNode: function() 
22150     {
22151         // this may only work on Gecko!!!
22152         
22153         // should we cache this!!!!
22154         
22155         
22156         
22157          
22158         var range = this.createRange(this.getSelection()).cloneRange();
22159         
22160         if (Roo.isIE) {
22161             var parent = range.parentElement();
22162             while (true) {
22163                 var testRange = range.duplicate();
22164                 testRange.moveToElementText(parent);
22165                 if (testRange.inRange(range)) {
22166                     break;
22167                 }
22168                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22169                     break;
22170                 }
22171                 parent = parent.parentElement;
22172             }
22173             return parent;
22174         }
22175         
22176         // is ancestor a text element.
22177         var ac =  range.commonAncestorContainer;
22178         if (ac.nodeType == 3) {
22179             ac = ac.parentNode;
22180         }
22181         
22182         var ar = ac.childNodes;
22183          
22184         var nodes = [];
22185         var other_nodes = [];
22186         var has_other_nodes = false;
22187         for (var i=0;i<ar.length;i++) {
22188             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
22189                 continue;
22190             }
22191             // fullly contained node.
22192             
22193             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22194                 nodes.push(ar[i]);
22195                 continue;
22196             }
22197             
22198             // probably selected..
22199             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22200                 other_nodes.push(ar[i]);
22201                 continue;
22202             }
22203             // outer..
22204             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
22205                 continue;
22206             }
22207             
22208             
22209             has_other_nodes = true;
22210         }
22211         if (!nodes.length && other_nodes.length) {
22212             nodes= other_nodes;
22213         }
22214         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22215             return false;
22216         }
22217         
22218         return nodes[0];
22219     },
22220     createRange: function(sel)
22221     {
22222         // this has strange effects when using with 
22223         // top toolbar - not sure if it's a great idea.
22224         //this.editor.contentWindow.focus();
22225         if (typeof sel != "undefined") {
22226             try {
22227                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22228             } catch(e) {
22229                 return this.doc.createRange();
22230             }
22231         } else {
22232             return this.doc.createRange();
22233         }
22234     },
22235     getParentElement: function()
22236     {
22237         
22238         this.assignDocWin();
22239         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22240         
22241         var range = this.createRange(sel);
22242          
22243         try {
22244             var p = range.commonAncestorContainer;
22245             while (p.nodeType == 3) { // text node
22246                 p = p.parentNode;
22247             }
22248             return p;
22249         } catch (e) {
22250             return null;
22251         }
22252     
22253     },
22254     /***
22255      *
22256      * Range intersection.. the hard stuff...
22257      *  '-1' = before
22258      *  '0' = hits..
22259      *  '1' = after.
22260      *         [ -- selected range --- ]
22261      *   [fail]                        [fail]
22262      *
22263      *    basically..
22264      *      if end is before start or  hits it. fail.
22265      *      if start is after end or hits it fail.
22266      *
22267      *   if either hits (but other is outside. - then it's not 
22268      *   
22269      *    
22270      **/
22271     
22272     
22273     // @see http://www.thismuchiknow.co.uk/?p=64.
22274     rangeIntersectsNode : function(range, node)
22275     {
22276         var nodeRange = node.ownerDocument.createRange();
22277         try {
22278             nodeRange.selectNode(node);
22279         } catch (e) {
22280             nodeRange.selectNodeContents(node);
22281         }
22282     
22283         var rangeStartRange = range.cloneRange();
22284         rangeStartRange.collapse(true);
22285     
22286         var rangeEndRange = range.cloneRange();
22287         rangeEndRange.collapse(false);
22288     
22289         var nodeStartRange = nodeRange.cloneRange();
22290         nodeStartRange.collapse(true);
22291     
22292         var nodeEndRange = nodeRange.cloneRange();
22293         nodeEndRange.collapse(false);
22294     
22295         return rangeStartRange.compareBoundaryPoints(
22296                  Range.START_TO_START, nodeEndRange) == -1 &&
22297                rangeEndRange.compareBoundaryPoints(
22298                  Range.START_TO_START, nodeStartRange) == 1;
22299         
22300          
22301     },
22302     rangeCompareNode : function(range, node)
22303     {
22304         var nodeRange = node.ownerDocument.createRange();
22305         try {
22306             nodeRange.selectNode(node);
22307         } catch (e) {
22308             nodeRange.selectNodeContents(node);
22309         }
22310         
22311         
22312         range.collapse(true);
22313     
22314         nodeRange.collapse(true);
22315      
22316         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22317         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
22318          
22319         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22320         
22321         var nodeIsBefore   =  ss == 1;
22322         var nodeIsAfter    = ee == -1;
22323         
22324         if (nodeIsBefore && nodeIsAfter) {
22325             return 0; // outer
22326         }
22327         if (!nodeIsBefore && nodeIsAfter) {
22328             return 1; //right trailed.
22329         }
22330         
22331         if (nodeIsBefore && !nodeIsAfter) {
22332             return 2;  // left trailed.
22333         }
22334         // fully contined.
22335         return 3;
22336     },
22337
22338     // private? - in a new class?
22339     cleanUpPaste :  function()
22340     {
22341         // cleans up the whole document..
22342         Roo.log('cleanuppaste');
22343         
22344         this.cleanUpChildren(this.doc.body);
22345         var clean = this.cleanWordChars(this.doc.body.innerHTML);
22346         if (clean != this.doc.body.innerHTML) {
22347             this.doc.body.innerHTML = clean;
22348         }
22349         
22350     },
22351     
22352     cleanWordChars : function(input) {// change the chars to hex code
22353         var he = Roo.HtmlEditorCore;
22354         
22355         var output = input;
22356         Roo.each(he.swapCodes, function(sw) { 
22357             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22358             
22359             output = output.replace(swapper, sw[1]);
22360         });
22361         
22362         return output;
22363     },
22364     
22365     
22366     cleanUpChildren : function (n)
22367     {
22368         if (!n.childNodes.length) {
22369             return;
22370         }
22371         for (var i = n.childNodes.length-1; i > -1 ; i--) {
22372            this.cleanUpChild(n.childNodes[i]);
22373         }
22374     },
22375     
22376     
22377         
22378     
22379     cleanUpChild : function (node)
22380     {
22381         var ed = this;
22382         //console.log(node);
22383         if (node.nodeName == "#text") {
22384             // clean up silly Windows -- stuff?
22385             return; 
22386         }
22387         if (node.nodeName == "#comment") {
22388             node.parentNode.removeChild(node);
22389             // clean up silly Windows -- stuff?
22390             return; 
22391         }
22392         var lcname = node.tagName.toLowerCase();
22393         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22394         // whitelist of tags..
22395         
22396         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22397             // remove node.
22398             node.parentNode.removeChild(node);
22399             return;
22400             
22401         }
22402         
22403         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22404         
22405         // remove <a name=....> as rendering on yahoo mailer is borked with this.
22406         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22407         
22408         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22409         //    remove_keep_children = true;
22410         //}
22411         
22412         if (remove_keep_children) {
22413             this.cleanUpChildren(node);
22414             // inserts everything just before this node...
22415             while (node.childNodes.length) {
22416                 var cn = node.childNodes[0];
22417                 node.removeChild(cn);
22418                 node.parentNode.insertBefore(cn, node);
22419             }
22420             node.parentNode.removeChild(node);
22421             return;
22422         }
22423         
22424         if (!node.attributes || !node.attributes.length) {
22425             this.cleanUpChildren(node);
22426             return;
22427         }
22428         
22429         function cleanAttr(n,v)
22430         {
22431             
22432             if (v.match(/^\./) || v.match(/^\//)) {
22433                 return;
22434             }
22435             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22436                 return;
22437             }
22438             if (v.match(/^#/)) {
22439                 return;
22440             }
22441 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22442             node.removeAttribute(n);
22443             
22444         }
22445         
22446         var cwhite = this.cwhite;
22447         var cblack = this.cblack;
22448             
22449         function cleanStyle(n,v)
22450         {
22451             if (v.match(/expression/)) { //XSS?? should we even bother..
22452                 node.removeAttribute(n);
22453                 return;
22454             }
22455             
22456             var parts = v.split(/;/);
22457             var clean = [];
22458             
22459             Roo.each(parts, function(p) {
22460                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22461                 if (!p.length) {
22462                     return true;
22463                 }
22464                 var l = p.split(':').shift().replace(/\s+/g,'');
22465                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22466                 
22467                 if ( cwhite.length && cblack.indexOf(l) > -1) {
22468 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22469                     //node.removeAttribute(n);
22470                     return true;
22471                 }
22472                 //Roo.log()
22473                 // only allow 'c whitelisted system attributes'
22474                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
22475 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22476                     //node.removeAttribute(n);
22477                     return true;
22478                 }
22479                 
22480                 
22481                  
22482                 
22483                 clean.push(p);
22484                 return true;
22485             });
22486             if (clean.length) { 
22487                 node.setAttribute(n, clean.join(';'));
22488             } else {
22489                 node.removeAttribute(n);
22490             }
22491             
22492         }
22493         
22494         
22495         for (var i = node.attributes.length-1; i > -1 ; i--) {
22496             var a = node.attributes[i];
22497             //console.log(a);
22498             
22499             if (a.name.toLowerCase().substr(0,2)=='on')  {
22500                 node.removeAttribute(a.name);
22501                 continue;
22502             }
22503             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22504                 node.removeAttribute(a.name);
22505                 continue;
22506             }
22507             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22508                 cleanAttr(a.name,a.value); // fixme..
22509                 continue;
22510             }
22511             if (a.name == 'style') {
22512                 cleanStyle(a.name,a.value);
22513                 continue;
22514             }
22515             /// clean up MS crap..
22516             // tecnically this should be a list of valid class'es..
22517             
22518             
22519             if (a.name == 'class') {
22520                 if (a.value.match(/^Mso/)) {
22521                     node.className = '';
22522                 }
22523                 
22524                 if (a.value.match(/^body$/)) {
22525                     node.className = '';
22526                 }
22527                 continue;
22528             }
22529             
22530             // style cleanup!?
22531             // class cleanup?
22532             
22533         }
22534         
22535         
22536         this.cleanUpChildren(node);
22537         
22538         
22539     },
22540     
22541     /**
22542      * Clean up MS wordisms...
22543      */
22544     cleanWord : function(node)
22545     {
22546         
22547         
22548         if (!node) {
22549             this.cleanWord(this.doc.body);
22550             return;
22551         }
22552         if (node.nodeName == "#text") {
22553             // clean up silly Windows -- stuff?
22554             return; 
22555         }
22556         if (node.nodeName == "#comment") {
22557             node.parentNode.removeChild(node);
22558             // clean up silly Windows -- stuff?
22559             return; 
22560         }
22561         
22562         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22563             node.parentNode.removeChild(node);
22564             return;
22565         }
22566         
22567         // remove - but keep children..
22568         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22569             while (node.childNodes.length) {
22570                 var cn = node.childNodes[0];
22571                 node.removeChild(cn);
22572                 node.parentNode.insertBefore(cn, node);
22573             }
22574             node.parentNode.removeChild(node);
22575             this.iterateChildren(node, this.cleanWord);
22576             return;
22577         }
22578         // clean styles
22579         if (node.className.length) {
22580             
22581             var cn = node.className.split(/\W+/);
22582             var cna = [];
22583             Roo.each(cn, function(cls) {
22584                 if (cls.match(/Mso[a-zA-Z]+/)) {
22585                     return;
22586                 }
22587                 cna.push(cls);
22588             });
22589             node.className = cna.length ? cna.join(' ') : '';
22590             if (!cna.length) {
22591                 node.removeAttribute("class");
22592             }
22593         }
22594         
22595         if (node.hasAttribute("lang")) {
22596             node.removeAttribute("lang");
22597         }
22598         
22599         if (node.hasAttribute("style")) {
22600             
22601             var styles = node.getAttribute("style").split(";");
22602             var nstyle = [];
22603             Roo.each(styles, function(s) {
22604                 if (!s.match(/:/)) {
22605                     return;
22606                 }
22607                 var kv = s.split(":");
22608                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22609                     return;
22610                 }
22611                 // what ever is left... we allow.
22612                 nstyle.push(s);
22613             });
22614             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22615             if (!nstyle.length) {
22616                 node.removeAttribute('style');
22617             }
22618         }
22619         this.iterateChildren(node, this.cleanWord);
22620         
22621         
22622         
22623     },
22624     /**
22625      * iterateChildren of a Node, calling fn each time, using this as the scole..
22626      * @param {DomNode} node node to iterate children of.
22627      * @param {Function} fn method of this class to call on each item.
22628      */
22629     iterateChildren : function(node, fn)
22630     {
22631         if (!node.childNodes.length) {
22632                 return;
22633         }
22634         for (var i = node.childNodes.length-1; i > -1 ; i--) {
22635            fn.call(this, node.childNodes[i])
22636         }
22637     },
22638     
22639     
22640     /**
22641      * cleanTableWidths.
22642      *
22643      * Quite often pasting from word etc.. results in tables with column and widths.
22644      * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22645      *
22646      */
22647     cleanTableWidths : function(node)
22648     {
22649          
22650          
22651         if (!node) {
22652             this.cleanTableWidths(this.doc.body);
22653             return;
22654         }
22655         
22656         // ignore list...
22657         if (node.nodeName == "#text" || node.nodeName == "#comment") {
22658             return; 
22659         }
22660         Roo.log(node.tagName);
22661         if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22662             this.iterateChildren(node, this.cleanTableWidths);
22663             return;
22664         }
22665         if (node.hasAttribute('width')) {
22666             node.removeAttribute('width');
22667         }
22668         
22669          
22670         if (node.hasAttribute("style")) {
22671             // pretty basic...
22672             
22673             var styles = node.getAttribute("style").split(";");
22674             var nstyle = [];
22675             Roo.each(styles, function(s) {
22676                 if (!s.match(/:/)) {
22677                     return;
22678                 }
22679                 var kv = s.split(":");
22680                 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22681                     return;
22682                 }
22683                 // what ever is left... we allow.
22684                 nstyle.push(s);
22685             });
22686             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22687             if (!nstyle.length) {
22688                 node.removeAttribute('style');
22689             }
22690         }
22691         
22692         this.iterateChildren(node, this.cleanTableWidths);
22693         
22694         
22695     },
22696     
22697     
22698     
22699     
22700     domToHTML : function(currentElement, depth, nopadtext) {
22701         
22702         depth = depth || 0;
22703         nopadtext = nopadtext || false;
22704     
22705         if (!currentElement) {
22706             return this.domToHTML(this.doc.body);
22707         }
22708         
22709         //Roo.log(currentElement);
22710         var j;
22711         var allText = false;
22712         var nodeName = currentElement.nodeName;
22713         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22714         
22715         if  (nodeName == '#text') {
22716             
22717             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22718         }
22719         
22720         
22721         var ret = '';
22722         if (nodeName != 'BODY') {
22723              
22724             var i = 0;
22725             // Prints the node tagName, such as <A>, <IMG>, etc
22726             if (tagName) {
22727                 var attr = [];
22728                 for(i = 0; i < currentElement.attributes.length;i++) {
22729                     // quoting?
22730                     var aname = currentElement.attributes.item(i).name;
22731                     if (!currentElement.attributes.item(i).value.length) {
22732                         continue;
22733                     }
22734                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22735                 }
22736                 
22737                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22738             } 
22739             else {
22740                 
22741                 // eack
22742             }
22743         } else {
22744             tagName = false;
22745         }
22746         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22747             return ret;
22748         }
22749         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22750             nopadtext = true;
22751         }
22752         
22753         
22754         // Traverse the tree
22755         i = 0;
22756         var currentElementChild = currentElement.childNodes.item(i);
22757         var allText = true;
22758         var innerHTML  = '';
22759         lastnode = '';
22760         while (currentElementChild) {
22761             // Formatting code (indent the tree so it looks nice on the screen)
22762             var nopad = nopadtext;
22763             if (lastnode == 'SPAN') {
22764                 nopad  = true;
22765             }
22766             // text
22767             if  (currentElementChild.nodeName == '#text') {
22768                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22769                 toadd = nopadtext ? toadd : toadd.trim();
22770                 if (!nopad && toadd.length > 80) {
22771                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
22772                 }
22773                 innerHTML  += toadd;
22774                 
22775                 i++;
22776                 currentElementChild = currentElement.childNodes.item(i);
22777                 lastNode = '';
22778                 continue;
22779             }
22780             allText = false;
22781             
22782             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
22783                 
22784             // Recursively traverse the tree structure of the child node
22785             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
22786             lastnode = currentElementChild.nodeName;
22787             i++;
22788             currentElementChild=currentElement.childNodes.item(i);
22789         }
22790         
22791         ret += innerHTML;
22792         
22793         if (!allText) {
22794                 // The remaining code is mostly for formatting the tree
22795             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
22796         }
22797         
22798         
22799         if (tagName) {
22800             ret+= "</"+tagName+">";
22801         }
22802         return ret;
22803         
22804     },
22805         
22806     applyBlacklists : function()
22807     {
22808         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
22809         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
22810         
22811         this.white = [];
22812         this.black = [];
22813         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22814             if (b.indexOf(tag) > -1) {
22815                 return;
22816             }
22817             this.white.push(tag);
22818             
22819         }, this);
22820         
22821         Roo.each(w, function(tag) {
22822             if (b.indexOf(tag) > -1) {
22823                 return;
22824             }
22825             if (this.white.indexOf(tag) > -1) {
22826                 return;
22827             }
22828             this.white.push(tag);
22829             
22830         }, this);
22831         
22832         
22833         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22834             if (w.indexOf(tag) > -1) {
22835                 return;
22836             }
22837             this.black.push(tag);
22838             
22839         }, this);
22840         
22841         Roo.each(b, function(tag) {
22842             if (w.indexOf(tag) > -1) {
22843                 return;
22844             }
22845             if (this.black.indexOf(tag) > -1) {
22846                 return;
22847             }
22848             this.black.push(tag);
22849             
22850         }, this);
22851         
22852         
22853         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
22854         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
22855         
22856         this.cwhite = [];
22857         this.cblack = [];
22858         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22859             if (b.indexOf(tag) > -1) {
22860                 return;
22861             }
22862             this.cwhite.push(tag);
22863             
22864         }, this);
22865         
22866         Roo.each(w, function(tag) {
22867             if (b.indexOf(tag) > -1) {
22868                 return;
22869             }
22870             if (this.cwhite.indexOf(tag) > -1) {
22871                 return;
22872             }
22873             this.cwhite.push(tag);
22874             
22875         }, this);
22876         
22877         
22878         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22879             if (w.indexOf(tag) > -1) {
22880                 return;
22881             }
22882             this.cblack.push(tag);
22883             
22884         }, this);
22885         
22886         Roo.each(b, function(tag) {
22887             if (w.indexOf(tag) > -1) {
22888                 return;
22889             }
22890             if (this.cblack.indexOf(tag) > -1) {
22891                 return;
22892             }
22893             this.cblack.push(tag);
22894             
22895         }, this);
22896     },
22897     
22898     setStylesheets : function(stylesheets)
22899     {
22900         if(typeof(stylesheets) == 'string'){
22901             Roo.get(this.iframe.contentDocument.head).createChild({
22902                 tag : 'link',
22903                 rel : 'stylesheet',
22904                 type : 'text/css',
22905                 href : stylesheets
22906             });
22907             
22908             return;
22909         }
22910         var _this = this;
22911      
22912         Roo.each(stylesheets, function(s) {
22913             if(!s.length){
22914                 return;
22915             }
22916             
22917             Roo.get(_this.iframe.contentDocument.head).createChild({
22918                 tag : 'link',
22919                 rel : 'stylesheet',
22920                 type : 'text/css',
22921                 href : s
22922             });
22923         });
22924
22925         
22926     },
22927     
22928     removeStylesheets : function()
22929     {
22930         var _this = this;
22931         
22932         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22933             s.remove();
22934         });
22935     },
22936     
22937     setStyle : function(style)
22938     {
22939         Roo.get(this.iframe.contentDocument.head).createChild({
22940             tag : 'style',
22941             type : 'text/css',
22942             html : style
22943         });
22944
22945         return;
22946     }
22947     
22948     // hide stuff that is not compatible
22949     /**
22950      * @event blur
22951      * @hide
22952      */
22953     /**
22954      * @event change
22955      * @hide
22956      */
22957     /**
22958      * @event focus
22959      * @hide
22960      */
22961     /**
22962      * @event specialkey
22963      * @hide
22964      */
22965     /**
22966      * @cfg {String} fieldClass @hide
22967      */
22968     /**
22969      * @cfg {String} focusClass @hide
22970      */
22971     /**
22972      * @cfg {String} autoCreate @hide
22973      */
22974     /**
22975      * @cfg {String} inputType @hide
22976      */
22977     /**
22978      * @cfg {String} invalidClass @hide
22979      */
22980     /**
22981      * @cfg {String} invalidText @hide
22982      */
22983     /**
22984      * @cfg {String} msgFx @hide
22985      */
22986     /**
22987      * @cfg {String} validateOnBlur @hide
22988      */
22989 });
22990
22991 Roo.HtmlEditorCore.white = [
22992         'area', 'br', 'img', 'input', 'hr', 'wbr',
22993         
22994        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
22995        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
22996        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
22997        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
22998        'table',   'ul',         'xmp', 
22999        
23000        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
23001       'thead',   'tr', 
23002      
23003       'dir', 'menu', 'ol', 'ul', 'dl',
23004        
23005       'embed',  'object'
23006 ];
23007
23008
23009 Roo.HtmlEditorCore.black = [
23010     //    'embed',  'object', // enable - backend responsiblity to clean thiese
23011         'applet', // 
23012         'base',   'basefont', 'bgsound', 'blink',  'body', 
23013         'frame',  'frameset', 'head',    'html',   'ilayer', 
23014         'iframe', 'layer',  'link',     'meta',    'object',   
23015         'script', 'style' ,'title',  'xml' // clean later..
23016 ];
23017 Roo.HtmlEditorCore.clean = [
23018     'script', 'style', 'title', 'xml'
23019 ];
23020 Roo.HtmlEditorCore.remove = [
23021     'font'
23022 ];
23023 // attributes..
23024
23025 Roo.HtmlEditorCore.ablack = [
23026     'on'
23027 ];
23028     
23029 Roo.HtmlEditorCore.aclean = [ 
23030     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
23031 ];
23032
23033 // protocols..
23034 Roo.HtmlEditorCore.pwhite= [
23035         'http',  'https',  'mailto'
23036 ];
23037
23038 // white listed style attributes.
23039 Roo.HtmlEditorCore.cwhite= [
23040       //  'text-align', /// default is to allow most things..
23041       
23042          
23043 //        'font-size'//??
23044 ];
23045
23046 // black listed style attributes.
23047 Roo.HtmlEditorCore.cblack= [
23048       //  'font-size' -- this can be set by the project 
23049 ];
23050
23051
23052 Roo.HtmlEditorCore.swapCodes   =[ 
23053     [    8211, "--" ], 
23054     [    8212, "--" ], 
23055     [    8216,  "'" ],  
23056     [    8217, "'" ],  
23057     [    8220, '"' ],  
23058     [    8221, '"' ],  
23059     [    8226, "*" ],  
23060     [    8230, "..." ]
23061 ]; 
23062
23063     /*
23064  * - LGPL
23065  *
23066  * HtmlEditor
23067  * 
23068  */
23069
23070 /**
23071  * @class Roo.bootstrap.HtmlEditor
23072  * @extends Roo.bootstrap.TextArea
23073  * Bootstrap HtmlEditor class
23074
23075  * @constructor
23076  * Create a new HtmlEditor
23077  * @param {Object} config The config object
23078  */
23079
23080 Roo.bootstrap.HtmlEditor = function(config){
23081     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23082     if (!this.toolbars) {
23083         this.toolbars = [];
23084     }
23085     
23086     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23087     this.addEvents({
23088             /**
23089              * @event initialize
23090              * Fires when the editor is fully initialized (including the iframe)
23091              * @param {HtmlEditor} this
23092              */
23093             initialize: true,
23094             /**
23095              * @event activate
23096              * Fires when the editor is first receives the focus. Any insertion must wait
23097              * until after this event.
23098              * @param {HtmlEditor} this
23099              */
23100             activate: true,
23101              /**
23102              * @event beforesync
23103              * Fires before the textarea is updated with content from the editor iframe. Return false
23104              * to cancel the sync.
23105              * @param {HtmlEditor} this
23106              * @param {String} html
23107              */
23108             beforesync: true,
23109              /**
23110              * @event beforepush
23111              * Fires before the iframe editor is updated with content from the textarea. Return false
23112              * to cancel the push.
23113              * @param {HtmlEditor} this
23114              * @param {String} html
23115              */
23116             beforepush: true,
23117              /**
23118              * @event sync
23119              * Fires when the textarea is updated with content from the editor iframe.
23120              * @param {HtmlEditor} this
23121              * @param {String} html
23122              */
23123             sync: true,
23124              /**
23125              * @event push
23126              * Fires when the iframe editor is updated with content from the textarea.
23127              * @param {HtmlEditor} this
23128              * @param {String} html
23129              */
23130             push: true,
23131              /**
23132              * @event editmodechange
23133              * Fires when the editor switches edit modes
23134              * @param {HtmlEditor} this
23135              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23136              */
23137             editmodechange: true,
23138             /**
23139              * @event editorevent
23140              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23141              * @param {HtmlEditor} this
23142              */
23143             editorevent: true,
23144             /**
23145              * @event firstfocus
23146              * Fires when on first focus - needed by toolbars..
23147              * @param {HtmlEditor} this
23148              */
23149             firstfocus: true,
23150             /**
23151              * @event autosave
23152              * Auto save the htmlEditor value as a file into Events
23153              * @param {HtmlEditor} this
23154              */
23155             autosave: true,
23156             /**
23157              * @event savedpreview
23158              * preview the saved version of htmlEditor
23159              * @param {HtmlEditor} this
23160              */
23161             savedpreview: true
23162         });
23163 };
23164
23165
23166 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
23167     
23168     
23169       /**
23170      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23171      */
23172     toolbars : false,
23173     
23174      /**
23175     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23176     */
23177     btns : [],
23178    
23179      /**
23180      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
23181      *                        Roo.resizable.
23182      */
23183     resizable : false,
23184      /**
23185      * @cfg {Number} height (in pixels)
23186      */   
23187     height: 300,
23188    /**
23189      * @cfg {Number} width (in pixels)
23190      */   
23191     width: false,
23192     
23193     /**
23194      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23195      * 
23196      */
23197     stylesheets: false,
23198     
23199     // id of frame..
23200     frameId: false,
23201     
23202     // private properties
23203     validationEvent : false,
23204     deferHeight: true,
23205     initialized : false,
23206     activated : false,
23207     
23208     onFocus : Roo.emptyFn,
23209     iframePad:3,
23210     hideMode:'offsets',
23211     
23212     tbContainer : false,
23213     
23214     bodyCls : '',
23215     
23216     toolbarContainer :function() {
23217         return this.wrap.select('.x-html-editor-tb',true).first();
23218     },
23219
23220     /**
23221      * Protected method that will not generally be called directly. It
23222      * is called when the editor creates its toolbar. Override this method if you need to
23223      * add custom toolbar buttons.
23224      * @param {HtmlEditor} editor
23225      */
23226     createToolbar : function(){
23227         Roo.log('renewing');
23228         Roo.log("create toolbars");
23229         
23230         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23231         this.toolbars[0].render(this.toolbarContainer());
23232         
23233         return;
23234         
23235 //        if (!editor.toolbars || !editor.toolbars.length) {
23236 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23237 //        }
23238 //        
23239 //        for (var i =0 ; i < editor.toolbars.length;i++) {
23240 //            editor.toolbars[i] = Roo.factory(
23241 //                    typeof(editor.toolbars[i]) == 'string' ?
23242 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
23243 //                Roo.bootstrap.HtmlEditor);
23244 //            editor.toolbars[i].init(editor);
23245 //        }
23246     },
23247
23248      
23249     // private
23250     onRender : function(ct, position)
23251     {
23252        // Roo.log("Call onRender: " + this.xtype);
23253         var _t = this;
23254         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23255       
23256         this.wrap = this.inputEl().wrap({
23257             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23258         });
23259         
23260         this.editorcore.onRender(ct, position);
23261          
23262         if (this.resizable) {
23263             this.resizeEl = new Roo.Resizable(this.wrap, {
23264                 pinned : true,
23265                 wrap: true,
23266                 dynamic : true,
23267                 minHeight : this.height,
23268                 height: this.height,
23269                 handles : this.resizable,
23270                 width: this.width,
23271                 listeners : {
23272                     resize : function(r, w, h) {
23273                         _t.onResize(w,h); // -something
23274                     }
23275                 }
23276             });
23277             
23278         }
23279         this.createToolbar(this);
23280        
23281         
23282         if(!this.width && this.resizable){
23283             this.setSize(this.wrap.getSize());
23284         }
23285         if (this.resizeEl) {
23286             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23287             // should trigger onReize..
23288         }
23289         
23290     },
23291
23292     // private
23293     onResize : function(w, h)
23294     {
23295         Roo.log('resize: ' +w + ',' + h );
23296         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23297         var ew = false;
23298         var eh = false;
23299         
23300         if(this.inputEl() ){
23301             if(typeof w == 'number'){
23302                 var aw = w - this.wrap.getFrameWidth('lr');
23303                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23304                 ew = aw;
23305             }
23306             if(typeof h == 'number'){
23307                  var tbh = -11;  // fixme it needs to tool bar size!
23308                 for (var i =0; i < this.toolbars.length;i++) {
23309                     // fixme - ask toolbars for heights?
23310                     tbh += this.toolbars[i].el.getHeight();
23311                     //if (this.toolbars[i].footer) {
23312                     //    tbh += this.toolbars[i].footer.el.getHeight();
23313                     //}
23314                 }
23315               
23316                 
23317                 
23318                 
23319                 
23320                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23321                 ah -= 5; // knock a few pixes off for look..
23322                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23323                 var eh = ah;
23324             }
23325         }
23326         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23327         this.editorcore.onResize(ew,eh);
23328         
23329     },
23330
23331     /**
23332      * Toggles the editor between standard and source edit mode.
23333      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23334      */
23335     toggleSourceEdit : function(sourceEditMode)
23336     {
23337         this.editorcore.toggleSourceEdit(sourceEditMode);
23338         
23339         if(this.editorcore.sourceEditMode){
23340             Roo.log('editor - showing textarea');
23341             
23342 //            Roo.log('in');
23343 //            Roo.log(this.syncValue());
23344             this.syncValue();
23345             this.inputEl().removeClass(['hide', 'x-hidden']);
23346             this.inputEl().dom.removeAttribute('tabIndex');
23347             this.inputEl().focus();
23348         }else{
23349             Roo.log('editor - hiding textarea');
23350 //            Roo.log('out')
23351 //            Roo.log(this.pushValue()); 
23352             this.pushValue();
23353             
23354             this.inputEl().addClass(['hide', 'x-hidden']);
23355             this.inputEl().dom.setAttribute('tabIndex', -1);
23356             //this.deferFocus();
23357         }
23358          
23359         if(this.resizable){
23360             this.setSize(this.wrap.getSize());
23361         }
23362         
23363         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23364     },
23365  
23366     // private (for BoxComponent)
23367     adjustSize : Roo.BoxComponent.prototype.adjustSize,
23368
23369     // private (for BoxComponent)
23370     getResizeEl : function(){
23371         return this.wrap;
23372     },
23373
23374     // private (for BoxComponent)
23375     getPositionEl : function(){
23376         return this.wrap;
23377     },
23378
23379     // private
23380     initEvents : function(){
23381         this.originalValue = this.getValue();
23382     },
23383
23384 //    /**
23385 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23386 //     * @method
23387 //     */
23388 //    markInvalid : Roo.emptyFn,
23389 //    /**
23390 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23391 //     * @method
23392 //     */
23393 //    clearInvalid : Roo.emptyFn,
23394
23395     setValue : function(v){
23396         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23397         this.editorcore.pushValue();
23398     },
23399
23400      
23401     // private
23402     deferFocus : function(){
23403         this.focus.defer(10, this);
23404     },
23405
23406     // doc'ed in Field
23407     focus : function(){
23408         this.editorcore.focus();
23409         
23410     },
23411       
23412
23413     // private
23414     onDestroy : function(){
23415         
23416         
23417         
23418         if(this.rendered){
23419             
23420             for (var i =0; i < this.toolbars.length;i++) {
23421                 // fixme - ask toolbars for heights?
23422                 this.toolbars[i].onDestroy();
23423             }
23424             
23425             this.wrap.dom.innerHTML = '';
23426             this.wrap.remove();
23427         }
23428     },
23429
23430     // private
23431     onFirstFocus : function(){
23432         //Roo.log("onFirstFocus");
23433         this.editorcore.onFirstFocus();
23434          for (var i =0; i < this.toolbars.length;i++) {
23435             this.toolbars[i].onFirstFocus();
23436         }
23437         
23438     },
23439     
23440     // private
23441     syncValue : function()
23442     {   
23443         this.editorcore.syncValue();
23444     },
23445     
23446     pushValue : function()
23447     {   
23448         this.editorcore.pushValue();
23449     }
23450      
23451     
23452     // hide stuff that is not compatible
23453     /**
23454      * @event blur
23455      * @hide
23456      */
23457     /**
23458      * @event change
23459      * @hide
23460      */
23461     /**
23462      * @event focus
23463      * @hide
23464      */
23465     /**
23466      * @event specialkey
23467      * @hide
23468      */
23469     /**
23470      * @cfg {String} fieldClass @hide
23471      */
23472     /**
23473      * @cfg {String} focusClass @hide
23474      */
23475     /**
23476      * @cfg {String} autoCreate @hide
23477      */
23478     /**
23479      * @cfg {String} inputType @hide
23480      */
23481     /**
23482      * @cfg {String} invalidClass @hide
23483      */
23484     /**
23485      * @cfg {String} invalidText @hide
23486      */
23487     /**
23488      * @cfg {String} msgFx @hide
23489      */
23490     /**
23491      * @cfg {String} validateOnBlur @hide
23492      */
23493 });
23494  
23495     
23496    
23497    
23498    
23499       
23500 Roo.namespace('Roo.bootstrap.htmleditor');
23501 /**
23502  * @class Roo.bootstrap.HtmlEditorToolbar1
23503  * Basic Toolbar
23504  * 
23505  * Usage:
23506  *
23507  new Roo.bootstrap.HtmlEditor({
23508     ....
23509     toolbars : [
23510         new Roo.bootstrap.HtmlEditorToolbar1({
23511             disable : { fonts: 1 , format: 1, ..., ... , ...],
23512             btns : [ .... ]
23513         })
23514     }
23515      
23516  * 
23517  * @cfg {Object} disable List of elements to disable..
23518  * @cfg {Array} btns List of additional buttons.
23519  * 
23520  * 
23521  * NEEDS Extra CSS? 
23522  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23523  */
23524  
23525 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23526 {
23527     
23528     Roo.apply(this, config);
23529     
23530     // default disabled, based on 'good practice'..
23531     this.disable = this.disable || {};
23532     Roo.applyIf(this.disable, {
23533         fontSize : true,
23534         colors : true,
23535         specialElements : true
23536     });
23537     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23538     
23539     this.editor = config.editor;
23540     this.editorcore = config.editor.editorcore;
23541     
23542     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23543     
23544     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23545     // dont call parent... till later.
23546 }
23547 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
23548      
23549     bar : true,
23550     
23551     editor : false,
23552     editorcore : false,
23553     
23554     
23555     formats : [
23556         "p" ,  
23557         "h1","h2","h3","h4","h5","h6", 
23558         "pre", "code", 
23559         "abbr", "acronym", "address", "cite", "samp", "var",
23560         'div','span'
23561     ],
23562     
23563     onRender : function(ct, position)
23564     {
23565        // Roo.log("Call onRender: " + this.xtype);
23566         
23567        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23568        Roo.log(this.el);
23569        this.el.dom.style.marginBottom = '0';
23570        var _this = this;
23571        var editorcore = this.editorcore;
23572        var editor= this.editor;
23573        
23574        var children = [];
23575        var btn = function(id,cmd , toggle, handler, html){
23576        
23577             var  event = toggle ? 'toggle' : 'click';
23578        
23579             var a = {
23580                 size : 'sm',
23581                 xtype: 'Button',
23582                 xns: Roo.bootstrap,
23583                 glyphicon : id,
23584                 cmd : id || cmd,
23585                 enableToggle:toggle !== false,
23586                 html : html || '',
23587                 pressed : toggle ? false : null,
23588                 listeners : {}
23589             };
23590             a.listeners[toggle ? 'toggle' : 'click'] = function() {
23591                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
23592             };
23593             children.push(a);
23594             return a;
23595        }
23596        
23597     //    var cb_box = function...
23598         
23599         var style = {
23600                 xtype: 'Button',
23601                 size : 'sm',
23602                 xns: Roo.bootstrap,
23603                 glyphicon : 'font',
23604                 //html : 'submit'
23605                 menu : {
23606                     xtype: 'Menu',
23607                     xns: Roo.bootstrap,
23608                     items:  []
23609                 }
23610         };
23611         Roo.each(this.formats, function(f) {
23612             style.menu.items.push({
23613                 xtype :'MenuItem',
23614                 xns: Roo.bootstrap,
23615                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23616                 tagname : f,
23617                 listeners : {
23618                     click : function()
23619                     {
23620                         editorcore.insertTag(this.tagname);
23621                         editor.focus();
23622                     }
23623                 }
23624                 
23625             });
23626         });
23627         children.push(style);   
23628         
23629         btn('bold',false,true);
23630         btn('italic',false,true);
23631         btn('align-left', 'justifyleft',true);
23632         btn('align-center', 'justifycenter',true);
23633         btn('align-right' , 'justifyright',true);
23634         btn('link', false, false, function(btn) {
23635             //Roo.log("create link?");
23636             var url = prompt(this.createLinkText, this.defaultLinkValue);
23637             if(url && url != 'http:/'+'/'){
23638                 this.editorcore.relayCmd('createlink', url);
23639             }
23640         }),
23641         btn('list','insertunorderedlist',true);
23642         btn('pencil', false,true, function(btn){
23643                 Roo.log(this);
23644                 this.toggleSourceEdit(btn.pressed);
23645         });
23646         
23647         if (this.editor.btns.length > 0) {
23648             for (var i = 0; i<this.editor.btns.length; i++) {
23649                 children.push(this.editor.btns[i]);
23650             }
23651         }
23652         
23653         /*
23654         var cog = {
23655                 xtype: 'Button',
23656                 size : 'sm',
23657                 xns: Roo.bootstrap,
23658                 glyphicon : 'cog',
23659                 //html : 'submit'
23660                 menu : {
23661                     xtype: 'Menu',
23662                     xns: Roo.bootstrap,
23663                     items:  []
23664                 }
23665         };
23666         
23667         cog.menu.items.push({
23668             xtype :'MenuItem',
23669             xns: Roo.bootstrap,
23670             html : Clean styles,
23671             tagname : f,
23672             listeners : {
23673                 click : function()
23674                 {
23675                     editorcore.insertTag(this.tagname);
23676                     editor.focus();
23677                 }
23678             }
23679             
23680         });
23681        */
23682         
23683          
23684        this.xtype = 'NavSimplebar';
23685         
23686         for(var i=0;i< children.length;i++) {
23687             
23688             this.buttons.add(this.addxtypeChild(children[i]));
23689             
23690         }
23691         
23692         editor.on('editorevent', this.updateToolbar, this);
23693     },
23694     onBtnClick : function(id)
23695     {
23696        this.editorcore.relayCmd(id);
23697        this.editorcore.focus();
23698     },
23699     
23700     /**
23701      * Protected method that will not generally be called directly. It triggers
23702      * a toolbar update by reading the markup state of the current selection in the editor.
23703      */
23704     updateToolbar: function(){
23705
23706         if(!this.editorcore.activated){
23707             this.editor.onFirstFocus(); // is this neeed?
23708             return;
23709         }
23710
23711         var btns = this.buttons; 
23712         var doc = this.editorcore.doc;
23713         btns.get('bold').setActive(doc.queryCommandState('bold'));
23714         btns.get('italic').setActive(doc.queryCommandState('italic'));
23715         //btns.get('underline').setActive(doc.queryCommandState('underline'));
23716         
23717         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23718         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23719         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23720         
23721         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23722         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23723          /*
23724         
23725         var ans = this.editorcore.getAllAncestors();
23726         if (this.formatCombo) {
23727             
23728             
23729             var store = this.formatCombo.store;
23730             this.formatCombo.setValue("");
23731             for (var i =0; i < ans.length;i++) {
23732                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23733                     // select it..
23734                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23735                     break;
23736                 }
23737             }
23738         }
23739         
23740         
23741         
23742         // hides menus... - so this cant be on a menu...
23743         Roo.bootstrap.MenuMgr.hideAll();
23744         */
23745         Roo.bootstrap.MenuMgr.hideAll();
23746         //this.editorsyncValue();
23747     },
23748     onFirstFocus: function() {
23749         this.buttons.each(function(item){
23750            item.enable();
23751         });
23752     },
23753     toggleSourceEdit : function(sourceEditMode){
23754         
23755           
23756         if(sourceEditMode){
23757             Roo.log("disabling buttons");
23758            this.buttons.each( function(item){
23759                 if(item.cmd != 'pencil'){
23760                     item.disable();
23761                 }
23762             });
23763           
23764         }else{
23765             Roo.log("enabling buttons");
23766             if(this.editorcore.initialized){
23767                 this.buttons.each( function(item){
23768                     item.enable();
23769                 });
23770             }
23771             
23772         }
23773         Roo.log("calling toggole on editor");
23774         // tell the editor that it's been pressed..
23775         this.editor.toggleSourceEdit(sourceEditMode);
23776        
23777     }
23778 });
23779
23780
23781
23782
23783
23784 /**
23785  * @class Roo.bootstrap.Table.AbstractSelectionModel
23786  * @extends Roo.util.Observable
23787  * Abstract base class for grid SelectionModels.  It provides the interface that should be
23788  * implemented by descendant classes.  This class should not be directly instantiated.
23789  * @constructor
23790  */
23791 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23792     this.locked = false;
23793     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23794 };
23795
23796
23797 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
23798     /** @ignore Called by the grid automatically. Do not call directly. */
23799     init : function(grid){
23800         this.grid = grid;
23801         this.initEvents();
23802     },
23803
23804     /**
23805      * Locks the selections.
23806      */
23807     lock : function(){
23808         this.locked = true;
23809     },
23810
23811     /**
23812      * Unlocks the selections.
23813      */
23814     unlock : function(){
23815         this.locked = false;
23816     },
23817
23818     /**
23819      * Returns true if the selections are locked.
23820      * @return {Boolean}
23821      */
23822     isLocked : function(){
23823         return this.locked;
23824     }
23825 });
23826 /**
23827  * @extends Roo.bootstrap.Table.AbstractSelectionModel
23828  * @class Roo.bootstrap.Table.RowSelectionModel
23829  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23830  * It supports multiple selections and keyboard selection/navigation. 
23831  * @constructor
23832  * @param {Object} config
23833  */
23834
23835 Roo.bootstrap.Table.RowSelectionModel = function(config){
23836     Roo.apply(this, config);
23837     this.selections = new Roo.util.MixedCollection(false, function(o){
23838         return o.id;
23839     });
23840
23841     this.last = false;
23842     this.lastActive = false;
23843
23844     this.addEvents({
23845         /**
23846              * @event selectionchange
23847              * Fires when the selection changes
23848              * @param {SelectionModel} this
23849              */
23850             "selectionchange" : true,
23851         /**
23852              * @event afterselectionchange
23853              * Fires after the selection changes (eg. by key press or clicking)
23854              * @param {SelectionModel} this
23855              */
23856             "afterselectionchange" : true,
23857         /**
23858              * @event beforerowselect
23859              * Fires when a row is selected being selected, return false to cancel.
23860              * @param {SelectionModel} this
23861              * @param {Number} rowIndex The selected index
23862              * @param {Boolean} keepExisting False if other selections will be cleared
23863              */
23864             "beforerowselect" : true,
23865         /**
23866              * @event rowselect
23867              * Fires when a row is selected.
23868              * @param {SelectionModel} this
23869              * @param {Number} rowIndex The selected index
23870              * @param {Roo.data.Record} r The record
23871              */
23872             "rowselect" : true,
23873         /**
23874              * @event rowdeselect
23875              * Fires when a row is deselected.
23876              * @param {SelectionModel} this
23877              * @param {Number} rowIndex The selected index
23878              */
23879         "rowdeselect" : true
23880     });
23881     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23882     this.locked = false;
23883  };
23884
23885 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
23886     /**
23887      * @cfg {Boolean} singleSelect
23888      * True to allow selection of only one row at a time (defaults to false)
23889      */
23890     singleSelect : false,
23891
23892     // private
23893     initEvents : function()
23894     {
23895
23896         //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23897         //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
23898         //}else{ // allow click to work like normal
23899          //   this.grid.on("rowclick", this.handleDragableRowClick, this);
23900         //}
23901         //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23902         this.grid.on("rowclick", this.handleMouseDown, this);
23903         
23904         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23905             "up" : function(e){
23906                 if(!e.shiftKey){
23907                     this.selectPrevious(e.shiftKey);
23908                 }else if(this.last !== false && this.lastActive !== false){
23909                     var last = this.last;
23910                     this.selectRange(this.last,  this.lastActive-1);
23911                     this.grid.getView().focusRow(this.lastActive);
23912                     if(last !== false){
23913                         this.last = last;
23914                     }
23915                 }else{
23916                     this.selectFirstRow();
23917                 }
23918                 this.fireEvent("afterselectionchange", this);
23919             },
23920             "down" : function(e){
23921                 if(!e.shiftKey){
23922                     this.selectNext(e.shiftKey);
23923                 }else if(this.last !== false && this.lastActive !== false){
23924                     var last = this.last;
23925                     this.selectRange(this.last,  this.lastActive+1);
23926                     this.grid.getView().focusRow(this.lastActive);
23927                     if(last !== false){
23928                         this.last = last;
23929                     }
23930                 }else{
23931                     this.selectFirstRow();
23932                 }
23933                 this.fireEvent("afterselectionchange", this);
23934             },
23935             scope: this
23936         });
23937         this.grid.store.on('load', function(){
23938             this.selections.clear();
23939         },this);
23940         /*
23941         var view = this.grid.view;
23942         view.on("refresh", this.onRefresh, this);
23943         view.on("rowupdated", this.onRowUpdated, this);
23944         view.on("rowremoved", this.onRemove, this);
23945         */
23946     },
23947
23948     // private
23949     onRefresh : function()
23950     {
23951         var ds = this.grid.store, i, v = this.grid.view;
23952         var s = this.selections;
23953         s.each(function(r){
23954             if((i = ds.indexOfId(r.id)) != -1){
23955                 v.onRowSelect(i);
23956             }else{
23957                 s.remove(r);
23958             }
23959         });
23960     },
23961
23962     // private
23963     onRemove : function(v, index, r){
23964         this.selections.remove(r);
23965     },
23966
23967     // private
23968     onRowUpdated : function(v, index, r){
23969         if(this.isSelected(r)){
23970             v.onRowSelect(index);
23971         }
23972     },
23973
23974     /**
23975      * Select records.
23976      * @param {Array} records The records to select
23977      * @param {Boolean} keepExisting (optional) True to keep existing selections
23978      */
23979     selectRecords : function(records, keepExisting)
23980     {
23981         if(!keepExisting){
23982             this.clearSelections();
23983         }
23984             var ds = this.grid.store;
23985         for(var i = 0, len = records.length; i < len; i++){
23986             this.selectRow(ds.indexOf(records[i]), true);
23987         }
23988     },
23989
23990     /**
23991      * Gets the number of selected rows.
23992      * @return {Number}
23993      */
23994     getCount : function(){
23995         return this.selections.length;
23996     },
23997
23998     /**
23999      * Selects the first row in the grid.
24000      */
24001     selectFirstRow : function(){
24002         this.selectRow(0);
24003     },
24004
24005     /**
24006      * Select the last row.
24007      * @param {Boolean} keepExisting (optional) True to keep existing selections
24008      */
24009     selectLastRow : function(keepExisting){
24010         //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24011         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24012     },
24013
24014     /**
24015      * Selects the row immediately following the last selected row.
24016      * @param {Boolean} keepExisting (optional) True to keep existing selections
24017      */
24018     selectNext : function(keepExisting)
24019     {
24020             if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24021             this.selectRow(this.last+1, keepExisting);
24022             this.grid.getView().focusRow(this.last);
24023         }
24024     },
24025
24026     /**
24027      * Selects the row that precedes the last selected row.
24028      * @param {Boolean} keepExisting (optional) True to keep existing selections
24029      */
24030     selectPrevious : function(keepExisting){
24031         if(this.last){
24032             this.selectRow(this.last-1, keepExisting);
24033             this.grid.getView().focusRow(this.last);
24034         }
24035     },
24036
24037     /**
24038      * Returns the selected records
24039      * @return {Array} Array of selected records
24040      */
24041     getSelections : function(){
24042         return [].concat(this.selections.items);
24043     },
24044
24045     /**
24046      * Returns the first selected record.
24047      * @return {Record}
24048      */
24049     getSelected : function(){
24050         return this.selections.itemAt(0);
24051     },
24052
24053
24054     /**
24055      * Clears all selections.
24056      */
24057     clearSelections : function(fast)
24058     {
24059         if(this.locked) {
24060             return;
24061         }
24062         if(fast !== true){
24063                 var ds = this.grid.store;
24064             var s = this.selections;
24065             s.each(function(r){
24066                 this.deselectRow(ds.indexOfId(r.id));
24067             }, this);
24068             s.clear();
24069         }else{
24070             this.selections.clear();
24071         }
24072         this.last = false;
24073     },
24074
24075
24076     /**
24077      * Selects all rows.
24078      */
24079     selectAll : function(){
24080         if(this.locked) {
24081             return;
24082         }
24083         this.selections.clear();
24084         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24085             this.selectRow(i, true);
24086         }
24087     },
24088
24089     /**
24090      * Returns True if there is a selection.
24091      * @return {Boolean}
24092      */
24093     hasSelection : function(){
24094         return this.selections.length > 0;
24095     },
24096
24097     /**
24098      * Returns True if the specified row is selected.
24099      * @param {Number/Record} record The record or index of the record to check
24100      * @return {Boolean}
24101      */
24102     isSelected : function(index){
24103             var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24104         return (r && this.selections.key(r.id) ? true : false);
24105     },
24106
24107     /**
24108      * Returns True if the specified record id is selected.
24109      * @param {String} id The id of record to check
24110      * @return {Boolean}
24111      */
24112     isIdSelected : function(id){
24113         return (this.selections.key(id) ? true : false);
24114     },
24115
24116
24117     // private
24118     handleMouseDBClick : function(e, t){
24119         
24120     },
24121     // private
24122     handleMouseDown : function(e, t)
24123     {
24124             var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24125         if(this.isLocked() || rowIndex < 0 ){
24126             return;
24127         };
24128         if(e.shiftKey && this.last !== false){
24129             var last = this.last;
24130             this.selectRange(last, rowIndex, e.ctrlKey);
24131             this.last = last; // reset the last
24132             t.focus();
24133     
24134         }else{
24135             var isSelected = this.isSelected(rowIndex);
24136             //Roo.log("select row:" + rowIndex);
24137             if(isSelected){
24138                 this.deselectRow(rowIndex);
24139             } else {
24140                         this.selectRow(rowIndex, true);
24141             }
24142     
24143             /*
24144                 if(e.button !== 0 && isSelected){
24145                 alert('rowIndex 2: ' + rowIndex);
24146                     view.focusRow(rowIndex);
24147                 }else if(e.ctrlKey && isSelected){
24148                     this.deselectRow(rowIndex);
24149                 }else if(!isSelected){
24150                     this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24151                     view.focusRow(rowIndex);
24152                 }
24153             */
24154         }
24155         this.fireEvent("afterselectionchange", this);
24156     },
24157     // private
24158     handleDragableRowClick :  function(grid, rowIndex, e) 
24159     {
24160         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24161             this.selectRow(rowIndex, false);
24162             grid.view.focusRow(rowIndex);
24163              this.fireEvent("afterselectionchange", this);
24164         }
24165     },
24166     
24167     /**
24168      * Selects multiple rows.
24169      * @param {Array} rows Array of the indexes of the row to select
24170      * @param {Boolean} keepExisting (optional) True to keep existing selections
24171      */
24172     selectRows : function(rows, keepExisting){
24173         if(!keepExisting){
24174             this.clearSelections();
24175         }
24176         for(var i = 0, len = rows.length; i < len; i++){
24177             this.selectRow(rows[i], true);
24178         }
24179     },
24180
24181     /**
24182      * Selects a range of rows. All rows in between startRow and endRow are also selected.
24183      * @param {Number} startRow The index of the first row in the range
24184      * @param {Number} endRow The index of the last row in the range
24185      * @param {Boolean} keepExisting (optional) True to retain existing selections
24186      */
24187     selectRange : function(startRow, endRow, keepExisting){
24188         if(this.locked) {
24189             return;
24190         }
24191         if(!keepExisting){
24192             this.clearSelections();
24193         }
24194         if(startRow <= endRow){
24195             for(var i = startRow; i <= endRow; i++){
24196                 this.selectRow(i, true);
24197             }
24198         }else{
24199             for(var i = startRow; i >= endRow; i--){
24200                 this.selectRow(i, true);
24201             }
24202         }
24203     },
24204
24205     /**
24206      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24207      * @param {Number} startRow The index of the first row in the range
24208      * @param {Number} endRow The index of the last row in the range
24209      */
24210     deselectRange : function(startRow, endRow, preventViewNotify){
24211         if(this.locked) {
24212             return;
24213         }
24214         for(var i = startRow; i <= endRow; i++){
24215             this.deselectRow(i, preventViewNotify);
24216         }
24217     },
24218
24219     /**
24220      * Selects a row.
24221      * @param {Number} row The index of the row to select
24222      * @param {Boolean} keepExisting (optional) True to keep existing selections
24223      */
24224     selectRow : function(index, keepExisting, preventViewNotify)
24225     {
24226             if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24227             return;
24228         }
24229         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24230             if(!keepExisting || this.singleSelect){
24231                 this.clearSelections();
24232             }
24233             
24234             var r = this.grid.store.getAt(index);
24235             //console.log('selectRow - record id :' + r.id);
24236             
24237             this.selections.add(r);
24238             this.last = this.lastActive = index;
24239             if(!preventViewNotify){
24240                 var proxy = new Roo.Element(
24241                                 this.grid.getRowDom(index)
24242                 );
24243                 proxy.addClass('bg-info info');
24244             }
24245             this.fireEvent("rowselect", this, index, r);
24246             this.fireEvent("selectionchange", this);
24247         }
24248     },
24249
24250     /**
24251      * Deselects a row.
24252      * @param {Number} row The index of the row to deselect
24253      */
24254     deselectRow : function(index, preventViewNotify)
24255     {
24256         if(this.locked) {
24257             return;
24258         }
24259         if(this.last == index){
24260             this.last = false;
24261         }
24262         if(this.lastActive == index){
24263             this.lastActive = false;
24264         }
24265         
24266         var r = this.grid.store.getAt(index);
24267         if (!r) {
24268             return;
24269         }
24270         
24271         this.selections.remove(r);
24272         //.console.log('deselectRow - record id :' + r.id);
24273         if(!preventViewNotify){
24274         
24275             var proxy = new Roo.Element(
24276                 this.grid.getRowDom(index)
24277             );
24278             proxy.removeClass('bg-info info');
24279         }
24280         this.fireEvent("rowdeselect", this, index);
24281         this.fireEvent("selectionchange", this);
24282     },
24283
24284     // private
24285     restoreLast : function(){
24286         if(this._last){
24287             this.last = this._last;
24288         }
24289     },
24290
24291     // private
24292     acceptsNav : function(row, col, cm){
24293         return !cm.isHidden(col) && cm.isCellEditable(col, row);
24294     },
24295
24296     // private
24297     onEditorKey : function(field, e){
24298         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24299         if(k == e.TAB){
24300             e.stopEvent();
24301             ed.completeEdit();
24302             if(e.shiftKey){
24303                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24304             }else{
24305                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24306             }
24307         }else if(k == e.ENTER && !e.ctrlKey){
24308             e.stopEvent();
24309             ed.completeEdit();
24310             if(e.shiftKey){
24311                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24312             }else{
24313                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24314             }
24315         }else if(k == e.ESC){
24316             ed.cancelEdit();
24317         }
24318         if(newCell){
24319             g.startEditing(newCell[0], newCell[1]);
24320         }
24321     }
24322 });
24323 /*
24324  * Based on:
24325  * Ext JS Library 1.1.1
24326  * Copyright(c) 2006-2007, Ext JS, LLC.
24327  *
24328  * Originally Released Under LGPL - original licence link has changed is not relivant.
24329  *
24330  * Fork - LGPL
24331  * <script type="text/javascript">
24332  */
24333  
24334 /**
24335  * @class Roo.bootstrap.PagingToolbar
24336  * @extends Roo.bootstrap.NavSimplebar
24337  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24338  * @constructor
24339  * Create a new PagingToolbar
24340  * @param {Object} config The config object
24341  * @param {Roo.data.Store} store
24342  */
24343 Roo.bootstrap.PagingToolbar = function(config)
24344 {
24345     // old args format still supported... - xtype is prefered..
24346         // created from xtype...
24347     
24348     this.ds = config.dataSource;
24349     
24350     if (config.store && !this.ds) {
24351         this.store= Roo.factory(config.store, Roo.data);
24352         this.ds = this.store;
24353         this.ds.xmodule = this.xmodule || false;
24354     }
24355     
24356     this.toolbarItems = [];
24357     if (config.items) {
24358         this.toolbarItems = config.items;
24359     }
24360     
24361     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24362     
24363     this.cursor = 0;
24364     
24365     if (this.ds) { 
24366         this.bind(this.ds);
24367     }
24368     
24369     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24370     
24371 };
24372
24373 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24374     /**
24375      * @cfg {Roo.data.Store} dataSource
24376      * The underlying data store providing the paged data
24377      */
24378     /**
24379      * @cfg {String/HTMLElement/Element} container
24380      * container The id or element that will contain the toolbar
24381      */
24382     /**
24383      * @cfg {Boolean} displayInfo
24384      * True to display the displayMsg (defaults to false)
24385      */
24386     /**
24387      * @cfg {Number} pageSize
24388      * The number of records to display per page (defaults to 20)
24389      */
24390     pageSize: 20,
24391     /**
24392      * @cfg {String} displayMsg
24393      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24394      */
24395     displayMsg : 'Displaying {0} - {1} of {2}',
24396     /**
24397      * @cfg {String} emptyMsg
24398      * The message to display when no records are found (defaults to "No data to display")
24399      */
24400     emptyMsg : 'No data to display',
24401     /**
24402      * Customizable piece of the default paging text (defaults to "Page")
24403      * @type String
24404      */
24405     beforePageText : "Page",
24406     /**
24407      * Customizable piece of the default paging text (defaults to "of %0")
24408      * @type String
24409      */
24410     afterPageText : "of {0}",
24411     /**
24412      * Customizable piece of the default paging text (defaults to "First Page")
24413      * @type String
24414      */
24415     firstText : "First Page",
24416     /**
24417      * Customizable piece of the default paging text (defaults to "Previous Page")
24418      * @type String
24419      */
24420     prevText : "Previous Page",
24421     /**
24422      * Customizable piece of the default paging text (defaults to "Next Page")
24423      * @type String
24424      */
24425     nextText : "Next Page",
24426     /**
24427      * Customizable piece of the default paging text (defaults to "Last Page")
24428      * @type String
24429      */
24430     lastText : "Last Page",
24431     /**
24432      * Customizable piece of the default paging text (defaults to "Refresh")
24433      * @type String
24434      */
24435     refreshText : "Refresh",
24436
24437     buttons : false,
24438     // private
24439     onRender : function(ct, position) 
24440     {
24441         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24442         this.navgroup.parentId = this.id;
24443         this.navgroup.onRender(this.el, null);
24444         // add the buttons to the navgroup
24445         
24446         if(this.displayInfo){
24447             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24448             this.displayEl = this.el.select('.x-paging-info', true).first();
24449 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24450 //            this.displayEl = navel.el.select('span',true).first();
24451         }
24452         
24453         var _this = this;
24454         
24455         if(this.buttons){
24456             Roo.each(_this.buttons, function(e){ // this might need to use render????
24457                Roo.factory(e).onRender(_this.el, null);
24458             });
24459         }
24460             
24461         Roo.each(_this.toolbarItems, function(e) {
24462             _this.navgroup.addItem(e);
24463         });
24464         
24465         
24466         this.first = this.navgroup.addItem({
24467             tooltip: this.firstText,
24468             cls: "prev",
24469             icon : 'fa fa-backward',
24470             disabled: true,
24471             preventDefault: true,
24472             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24473         });
24474         
24475         this.prev =  this.navgroup.addItem({
24476             tooltip: this.prevText,
24477             cls: "prev",
24478             icon : 'fa fa-step-backward',
24479             disabled: true,
24480             preventDefault: true,
24481             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
24482         });
24483     //this.addSeparator();
24484         
24485         
24486         var field = this.navgroup.addItem( {
24487             tagtype : 'span',
24488             cls : 'x-paging-position',
24489             
24490             html : this.beforePageText  +
24491                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24492                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
24493          } ); //?? escaped?
24494         
24495         this.field = field.el.select('input', true).first();
24496         this.field.on("keydown", this.onPagingKeydown, this);
24497         this.field.on("focus", function(){this.dom.select();});
24498     
24499     
24500         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
24501         //this.field.setHeight(18);
24502         //this.addSeparator();
24503         this.next = this.navgroup.addItem({
24504             tooltip: this.nextText,
24505             cls: "next",
24506             html : ' <i class="fa fa-step-forward">',
24507             disabled: true,
24508             preventDefault: true,
24509             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
24510         });
24511         this.last = this.navgroup.addItem({
24512             tooltip: this.lastText,
24513             icon : 'fa fa-forward',
24514             cls: "next",
24515             disabled: true,
24516             preventDefault: true,
24517             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
24518         });
24519     //this.addSeparator();
24520         this.loading = this.navgroup.addItem({
24521             tooltip: this.refreshText,
24522             icon: 'fa fa-refresh',
24523             preventDefault: true,
24524             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24525         });
24526         
24527     },
24528
24529     // private
24530     updateInfo : function(){
24531         if(this.displayEl){
24532             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24533             var msg = count == 0 ?
24534                 this.emptyMsg :
24535                 String.format(
24536                     this.displayMsg,
24537                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
24538                 );
24539             this.displayEl.update(msg);
24540         }
24541     },
24542
24543     // private
24544     onLoad : function(ds, r, o)
24545     {
24546         this.cursor = o.params.start ? o.params.start : 0;
24547         
24548         var d = this.getPageData(),
24549             ap = d.activePage,
24550             ps = d.pages;
24551         
24552         
24553         this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24554         this.field.dom.value = ap;
24555         this.first.setDisabled(ap == 1);
24556         this.prev.setDisabled(ap == 1);
24557         this.next.setDisabled(ap == ps);
24558         this.last.setDisabled(ap == ps);
24559         this.loading.enable();
24560         this.updateInfo();
24561     },
24562
24563     // private
24564     getPageData : function(){
24565         var total = this.ds.getTotalCount();
24566         return {
24567             total : total,
24568             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24569             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24570         };
24571     },
24572
24573     // private
24574     onLoadError : function(){
24575         this.loading.enable();
24576     },
24577
24578     // private
24579     onPagingKeydown : function(e){
24580         var k = e.getKey();
24581         var d = this.getPageData();
24582         if(k == e.RETURN){
24583             var v = this.field.dom.value, pageNum;
24584             if(!v || isNaN(pageNum = parseInt(v, 10))){
24585                 this.field.dom.value = d.activePage;
24586                 return;
24587             }
24588             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24589             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24590             e.stopEvent();
24591         }
24592         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))
24593         {
24594           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24595           this.field.dom.value = pageNum;
24596           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24597           e.stopEvent();
24598         }
24599         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24600         {
24601           var v = this.field.dom.value, pageNum; 
24602           var increment = (e.shiftKey) ? 10 : 1;
24603           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24604                 increment *= -1;
24605           }
24606           if(!v || isNaN(pageNum = parseInt(v, 10))) {
24607             this.field.dom.value = d.activePage;
24608             return;
24609           }
24610           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24611           {
24612             this.field.dom.value = parseInt(v, 10) + increment;
24613             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24614             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24615           }
24616           e.stopEvent();
24617         }
24618     },
24619
24620     // private
24621     beforeLoad : function(){
24622         if(this.loading){
24623             this.loading.disable();
24624         }
24625     },
24626
24627     // private
24628     onClick : function(which){
24629         
24630         var ds = this.ds;
24631         if (!ds) {
24632             return;
24633         }
24634         
24635         switch(which){
24636             case "first":
24637                 ds.load({params:{start: 0, limit: this.pageSize}});
24638             break;
24639             case "prev":
24640                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24641             break;
24642             case "next":
24643                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24644             break;
24645             case "last":
24646                 var total = ds.getTotalCount();
24647                 var extra = total % this.pageSize;
24648                 var lastStart = extra ? (total - extra) : total-this.pageSize;
24649                 ds.load({params:{start: lastStart, limit: this.pageSize}});
24650             break;
24651             case "refresh":
24652                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24653             break;
24654         }
24655     },
24656
24657     /**
24658      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24659      * @param {Roo.data.Store} store The data store to unbind
24660      */
24661     unbind : function(ds){
24662         ds.un("beforeload", this.beforeLoad, this);
24663         ds.un("load", this.onLoad, this);
24664         ds.un("loadexception", this.onLoadError, this);
24665         ds.un("remove", this.updateInfo, this);
24666         ds.un("add", this.updateInfo, this);
24667         this.ds = undefined;
24668     },
24669
24670     /**
24671      * Binds the paging toolbar to the specified {@link Roo.data.Store}
24672      * @param {Roo.data.Store} store The data store to bind
24673      */
24674     bind : function(ds){
24675         ds.on("beforeload", this.beforeLoad, this);
24676         ds.on("load", this.onLoad, this);
24677         ds.on("loadexception", this.onLoadError, this);
24678         ds.on("remove", this.updateInfo, this);
24679         ds.on("add", this.updateInfo, this);
24680         this.ds = ds;
24681     }
24682 });/*
24683  * - LGPL
24684  *
24685  * element
24686  * 
24687  */
24688
24689 /**
24690  * @class Roo.bootstrap.MessageBar
24691  * @extends Roo.bootstrap.Component
24692  * Bootstrap MessageBar class
24693  * @cfg {String} html contents of the MessageBar
24694  * @cfg {String} weight (info | success | warning | danger) default info
24695  * @cfg {String} beforeClass insert the bar before the given class
24696  * @cfg {Boolean} closable (true | false) default false
24697  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24698  * 
24699  * @constructor
24700  * Create a new Element
24701  * @param {Object} config The config object
24702  */
24703
24704 Roo.bootstrap.MessageBar = function(config){
24705     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24706 };
24707
24708 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
24709     
24710     html: '',
24711     weight: 'info',
24712     closable: false,
24713     fixed: false,
24714     beforeClass: 'bootstrap-sticky-wrap',
24715     
24716     getAutoCreate : function(){
24717         
24718         var cfg = {
24719             tag: 'div',
24720             cls: 'alert alert-dismissable alert-' + this.weight,
24721             cn: [
24722                 {
24723                     tag: 'span',
24724                     cls: 'message',
24725                     html: this.html || ''
24726                 }
24727             ]
24728         };
24729         
24730         if(this.fixed){
24731             cfg.cls += ' alert-messages-fixed';
24732         }
24733         
24734         if(this.closable){
24735             cfg.cn.push({
24736                 tag: 'button',
24737                 cls: 'close',
24738                 html: 'x'
24739             });
24740         }
24741         
24742         return cfg;
24743     },
24744     
24745     onRender : function(ct, position)
24746     {
24747         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24748         
24749         if(!this.el){
24750             var cfg = Roo.apply({},  this.getAutoCreate());
24751             cfg.id = Roo.id();
24752             
24753             if (this.cls) {
24754                 cfg.cls += ' ' + this.cls;
24755             }
24756             if (this.style) {
24757                 cfg.style = this.style;
24758             }
24759             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24760             
24761             this.el.setVisibilityMode(Roo.Element.DISPLAY);
24762         }
24763         
24764         this.el.select('>button.close').on('click', this.hide, this);
24765         
24766     },
24767     
24768     show : function()
24769     {
24770         if (!this.rendered) {
24771             this.render();
24772         }
24773         
24774         this.el.show();
24775         
24776         this.fireEvent('show', this);
24777         
24778     },
24779     
24780     hide : function()
24781     {
24782         if (!this.rendered) {
24783             this.render();
24784         }
24785         
24786         this.el.hide();
24787         
24788         this.fireEvent('hide', this);
24789     },
24790     
24791     update : function()
24792     {
24793 //        var e = this.el.dom.firstChild;
24794 //        
24795 //        if(this.closable){
24796 //            e = e.nextSibling;
24797 //        }
24798 //        
24799 //        e.data = this.html || '';
24800
24801         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24802     }
24803    
24804 });
24805
24806  
24807
24808      /*
24809  * - LGPL
24810  *
24811  * Graph
24812  * 
24813  */
24814
24815
24816 /**
24817  * @class Roo.bootstrap.Graph
24818  * @extends Roo.bootstrap.Component
24819  * Bootstrap Graph class
24820 > Prameters
24821  -sm {number} sm 4
24822  -md {number} md 5
24823  @cfg {String} graphtype  bar | vbar | pie
24824  @cfg {number} g_x coodinator | centre x (pie)
24825  @cfg {number} g_y coodinator | centre y (pie)
24826  @cfg {number} g_r radius (pie)
24827  @cfg {number} g_height height of the chart (respected by all elements in the set)
24828  @cfg {number} g_width width of the chart (respected by all elements in the set)
24829  @cfg {Object} title The title of the chart
24830     
24831  -{Array}  values
24832  -opts (object) options for the chart 
24833      o {
24834      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24835      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24836      o vgutter (number)
24837      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.
24838      o stacked (boolean) whether or not to tread values as in a stacked bar chart
24839      o to
24840      o stretch (boolean)
24841      o }
24842  -opts (object) options for the pie
24843      o{
24844      o cut
24845      o startAngle (number)
24846      o endAngle (number)
24847      } 
24848  *
24849  * @constructor
24850  * Create a new Input
24851  * @param {Object} config The config object
24852  */
24853
24854 Roo.bootstrap.Graph = function(config){
24855     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24856     
24857     this.addEvents({
24858         // img events
24859         /**
24860          * @event click
24861          * The img click event for the img.
24862          * @param {Roo.EventObject} e
24863          */
24864         "click" : true
24865     });
24866 };
24867
24868 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
24869     
24870     sm: 4,
24871     md: 5,
24872     graphtype: 'bar',
24873     g_height: 250,
24874     g_width: 400,
24875     g_x: 50,
24876     g_y: 50,
24877     g_r: 30,
24878     opts:{
24879         //g_colors: this.colors,
24880         g_type: 'soft',
24881         g_gutter: '20%'
24882
24883     },
24884     title : false,
24885
24886     getAutoCreate : function(){
24887         
24888         var cfg = {
24889             tag: 'div',
24890             html : null
24891         };
24892         
24893         
24894         return  cfg;
24895     },
24896
24897     onRender : function(ct,position){
24898         
24899         
24900         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24901         
24902         if (typeof(Raphael) == 'undefined') {
24903             Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24904             return;
24905         }
24906         
24907         this.raphael = Raphael(this.el.dom);
24908         
24909                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24910                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24911                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24912                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24913                 /*
24914                 r.text(160, 10, "Single Series Chart").attr(txtattr);
24915                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24916                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24917                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24918                 
24919                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24920                 r.barchart(330, 10, 300, 220, data1);
24921                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24922                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24923                 */
24924                 
24925                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24926                 // r.barchart(30, 30, 560, 250,  xdata, {
24927                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24928                 //     axis : "0 0 1 1",
24929                 //     axisxlabels :  xdata
24930                 //     //yvalues : cols,
24931                    
24932                 // });
24933 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24934 //        
24935 //        this.load(null,xdata,{
24936 //                axis : "0 0 1 1",
24937 //                axisxlabels :  xdata
24938 //                });
24939
24940     },
24941
24942     load : function(graphtype,xdata,opts)
24943     {
24944         this.raphael.clear();
24945         if(!graphtype) {
24946             graphtype = this.graphtype;
24947         }
24948         if(!opts){
24949             opts = this.opts;
24950         }
24951         var r = this.raphael,
24952             fin = function () {
24953                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24954             },
24955             fout = function () {
24956                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24957             },
24958             pfin = function() {
24959                 this.sector.stop();
24960                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24961
24962                 if (this.label) {
24963                     this.label[0].stop();
24964                     this.label[0].attr({ r: 7.5 });
24965                     this.label[1].attr({ "font-weight": 800 });
24966                 }
24967             },
24968             pfout = function() {
24969                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24970
24971                 if (this.label) {
24972                     this.label[0].animate({ r: 5 }, 500, "bounce");
24973                     this.label[1].attr({ "font-weight": 400 });
24974                 }
24975             };
24976
24977         switch(graphtype){
24978             case 'bar':
24979                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24980                 break;
24981             case 'hbar':
24982                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24983                 break;
24984             case 'pie':
24985 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
24986 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24987 //            
24988                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24989                 
24990                 break;
24991
24992         }
24993         
24994         if(this.title){
24995             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24996         }
24997         
24998     },
24999     
25000     setTitle: function(o)
25001     {
25002         this.title = o;
25003     },
25004     
25005     initEvents: function() {
25006         
25007         if(!this.href){
25008             this.el.on('click', this.onClick, this);
25009         }
25010     },
25011     
25012     onClick : function(e)
25013     {
25014         Roo.log('img onclick');
25015         this.fireEvent('click', this, e);
25016     }
25017    
25018 });
25019
25020  
25021 /*
25022  * - LGPL
25023  *
25024  * numberBox
25025  * 
25026  */
25027 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25028
25029 /**
25030  * @class Roo.bootstrap.dash.NumberBox
25031  * @extends Roo.bootstrap.Component
25032  * Bootstrap NumberBox class
25033  * @cfg {String} headline Box headline
25034  * @cfg {String} content Box content
25035  * @cfg {String} icon Box icon
25036  * @cfg {String} footer Footer text
25037  * @cfg {String} fhref Footer href
25038  * 
25039  * @constructor
25040  * Create a new NumberBox
25041  * @param {Object} config The config object
25042  */
25043
25044
25045 Roo.bootstrap.dash.NumberBox = function(config){
25046     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25047     
25048 };
25049
25050 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
25051     
25052     headline : '',
25053     content : '',
25054     icon : '',
25055     footer : '',
25056     fhref : '',
25057     ficon : '',
25058     
25059     getAutoCreate : function(){
25060         
25061         var cfg = {
25062             tag : 'div',
25063             cls : 'small-box ',
25064             cn : [
25065                 {
25066                     tag : 'div',
25067                     cls : 'inner',
25068                     cn :[
25069                         {
25070                             tag : 'h3',
25071                             cls : 'roo-headline',
25072                             html : this.headline
25073                         },
25074                         {
25075                             tag : 'p',
25076                             cls : 'roo-content',
25077                             html : this.content
25078                         }
25079                     ]
25080                 }
25081             ]
25082         };
25083         
25084         if(this.icon){
25085             cfg.cn.push({
25086                 tag : 'div',
25087                 cls : 'icon',
25088                 cn :[
25089                     {
25090                         tag : 'i',
25091                         cls : 'ion ' + this.icon
25092                     }
25093                 ]
25094             });
25095         }
25096         
25097         if(this.footer){
25098             var footer = {
25099                 tag : 'a',
25100                 cls : 'small-box-footer',
25101                 href : this.fhref || '#',
25102                 html : this.footer
25103             };
25104             
25105             cfg.cn.push(footer);
25106             
25107         }
25108         
25109         return  cfg;
25110     },
25111
25112     onRender : function(ct,position){
25113         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25114
25115
25116        
25117                 
25118     },
25119
25120     setHeadline: function (value)
25121     {
25122         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25123     },
25124     
25125     setFooter: function (value, href)
25126     {
25127         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25128         
25129         if(href){
25130             this.el.select('a.small-box-footer',true).first().attr('href', href);
25131         }
25132         
25133     },
25134
25135     setContent: function (value)
25136     {
25137         this.el.select('.roo-content',true).first().dom.innerHTML = value;
25138     },
25139
25140     initEvents: function() 
25141     {   
25142         
25143     }
25144     
25145 });
25146
25147  
25148 /*
25149  * - LGPL
25150  *
25151  * TabBox
25152  * 
25153  */
25154 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25155
25156 /**
25157  * @class Roo.bootstrap.dash.TabBox
25158  * @extends Roo.bootstrap.Component
25159  * Bootstrap TabBox class
25160  * @cfg {String} title Title of the TabBox
25161  * @cfg {String} icon Icon of the TabBox
25162  * @cfg {Boolean} showtabs (true|false) show the tabs default true
25163  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25164  * 
25165  * @constructor
25166  * Create a new TabBox
25167  * @param {Object} config The config object
25168  */
25169
25170
25171 Roo.bootstrap.dash.TabBox = function(config){
25172     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25173     this.addEvents({
25174         // raw events
25175         /**
25176          * @event addpane
25177          * When a pane is added
25178          * @param {Roo.bootstrap.dash.TabPane} pane
25179          */
25180         "addpane" : true,
25181         /**
25182          * @event activatepane
25183          * When a pane is activated
25184          * @param {Roo.bootstrap.dash.TabPane} pane
25185          */
25186         "activatepane" : true
25187         
25188          
25189     });
25190     
25191     this.panes = [];
25192 };
25193
25194 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
25195
25196     title : '',
25197     icon : false,
25198     showtabs : true,
25199     tabScrollable : false,
25200     
25201     getChildContainer : function()
25202     {
25203         return this.el.select('.tab-content', true).first();
25204     },
25205     
25206     getAutoCreate : function(){
25207         
25208         var header = {
25209             tag: 'li',
25210             cls: 'pull-left header',
25211             html: this.title,
25212             cn : []
25213         };
25214         
25215         if(this.icon){
25216             header.cn.push({
25217                 tag: 'i',
25218                 cls: 'fa ' + this.icon
25219             });
25220         }
25221         
25222         var h = {
25223             tag: 'ul',
25224             cls: 'nav nav-tabs pull-right',
25225             cn: [
25226                 header
25227             ]
25228         };
25229         
25230         if(this.tabScrollable){
25231             h = {
25232                 tag: 'div',
25233                 cls: 'tab-header',
25234                 cn: [
25235                     {
25236                         tag: 'ul',
25237                         cls: 'nav nav-tabs pull-right',
25238                         cn: [
25239                             header
25240                         ]
25241                     }
25242                 ]
25243             };
25244         }
25245         
25246         var cfg = {
25247             tag: 'div',
25248             cls: 'nav-tabs-custom',
25249             cn: [
25250                 h,
25251                 {
25252                     tag: 'div',
25253                     cls: 'tab-content no-padding',
25254                     cn: []
25255                 }
25256             ]
25257         };
25258
25259         return  cfg;
25260     },
25261     initEvents : function()
25262     {
25263         //Roo.log('add add pane handler');
25264         this.on('addpane', this.onAddPane, this);
25265     },
25266      /**
25267      * Updates the box title
25268      * @param {String} html to set the title to.
25269      */
25270     setTitle : function(value)
25271     {
25272         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25273     },
25274     onAddPane : function(pane)
25275     {
25276         this.panes.push(pane);
25277         //Roo.log('addpane');
25278         //Roo.log(pane);
25279         // tabs are rendere left to right..
25280         if(!this.showtabs){
25281             return;
25282         }
25283         
25284         var ctr = this.el.select('.nav-tabs', true).first();
25285          
25286          
25287         var existing = ctr.select('.nav-tab',true);
25288         var qty = existing.getCount();;
25289         
25290         
25291         var tab = ctr.createChild({
25292             tag : 'li',
25293             cls : 'nav-tab' + (qty ? '' : ' active'),
25294             cn : [
25295                 {
25296                     tag : 'a',
25297                     href:'#',
25298                     html : pane.title
25299                 }
25300             ]
25301         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25302         pane.tab = tab;
25303         
25304         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25305         if (!qty) {
25306             pane.el.addClass('active');
25307         }
25308         
25309                 
25310     },
25311     onTabClick : function(ev,un,ob,pane)
25312     {
25313         //Roo.log('tab - prev default');
25314         ev.preventDefault();
25315         
25316         
25317         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25318         pane.tab.addClass('active');
25319         //Roo.log(pane.title);
25320         this.getChildContainer().select('.tab-pane',true).removeClass('active');
25321         // technically we should have a deactivate event.. but maybe add later.
25322         // and it should not de-activate the selected tab...
25323         this.fireEvent('activatepane', pane);
25324         pane.el.addClass('active');
25325         pane.fireEvent('activate');
25326         
25327         
25328     },
25329     
25330     getActivePane : function()
25331     {
25332         var r = false;
25333         Roo.each(this.panes, function(p) {
25334             if(p.el.hasClass('active')){
25335                 r = p;
25336                 return false;
25337             }
25338             
25339             return;
25340         });
25341         
25342         return r;
25343     }
25344     
25345     
25346 });
25347
25348  
25349 /*
25350  * - LGPL
25351  *
25352  * Tab pane
25353  * 
25354  */
25355 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25356 /**
25357  * @class Roo.bootstrap.TabPane
25358  * @extends Roo.bootstrap.Component
25359  * Bootstrap TabPane class
25360  * @cfg {Boolean} active (false | true) Default false
25361  * @cfg {String} title title of panel
25362
25363  * 
25364  * @constructor
25365  * Create a new TabPane
25366  * @param {Object} config The config object
25367  */
25368
25369 Roo.bootstrap.dash.TabPane = function(config){
25370     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25371     
25372     this.addEvents({
25373         // raw events
25374         /**
25375          * @event activate
25376          * When a pane is activated
25377          * @param {Roo.bootstrap.dash.TabPane} pane
25378          */
25379         "activate" : true
25380          
25381     });
25382 };
25383
25384 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
25385     
25386     active : false,
25387     title : '',
25388     
25389     // the tabBox that this is attached to.
25390     tab : false,
25391      
25392     getAutoCreate : function() 
25393     {
25394         var cfg = {
25395             tag: 'div',
25396             cls: 'tab-pane'
25397         };
25398         
25399         if(this.active){
25400             cfg.cls += ' active';
25401         }
25402         
25403         return cfg;
25404     },
25405     initEvents  : function()
25406     {
25407         //Roo.log('trigger add pane handler');
25408         this.parent().fireEvent('addpane', this)
25409     },
25410     
25411      /**
25412      * Updates the tab title 
25413      * @param {String} html to set the title to.
25414      */
25415     setTitle: function(str)
25416     {
25417         if (!this.tab) {
25418             return;
25419         }
25420         this.title = str;
25421         this.tab.select('a', true).first().dom.innerHTML = str;
25422         
25423     }
25424     
25425     
25426     
25427 });
25428
25429  
25430
25431
25432  /*
25433  * - LGPL
25434  *
25435  * menu
25436  * 
25437  */
25438 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25439
25440 /**
25441  * @class Roo.bootstrap.menu.Menu
25442  * @extends Roo.bootstrap.Component
25443  * Bootstrap Menu class - container for Menu
25444  * @cfg {String} html Text of the menu
25445  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25446  * @cfg {String} icon Font awesome icon
25447  * @cfg {String} pos Menu align to (top | bottom) default bottom
25448  * 
25449  * 
25450  * @constructor
25451  * Create a new Menu
25452  * @param {Object} config The config object
25453  */
25454
25455
25456 Roo.bootstrap.menu.Menu = function(config){
25457     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25458     
25459     this.addEvents({
25460         /**
25461          * @event beforeshow
25462          * Fires before this menu is displayed
25463          * @param {Roo.bootstrap.menu.Menu} this
25464          */
25465         beforeshow : true,
25466         /**
25467          * @event beforehide
25468          * Fires before this menu is hidden
25469          * @param {Roo.bootstrap.menu.Menu} this
25470          */
25471         beforehide : true,
25472         /**
25473          * @event show
25474          * Fires after this menu is displayed
25475          * @param {Roo.bootstrap.menu.Menu} this
25476          */
25477         show : true,
25478         /**
25479          * @event hide
25480          * Fires after this menu is hidden
25481          * @param {Roo.bootstrap.menu.Menu} this
25482          */
25483         hide : true,
25484         /**
25485          * @event click
25486          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25487          * @param {Roo.bootstrap.menu.Menu} this
25488          * @param {Roo.EventObject} e
25489          */
25490         click : true
25491     });
25492     
25493 };
25494
25495 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
25496     
25497     submenu : false,
25498     html : '',
25499     weight : 'default',
25500     icon : false,
25501     pos : 'bottom',
25502     
25503     
25504     getChildContainer : function() {
25505         if(this.isSubMenu){
25506             return this.el;
25507         }
25508         
25509         return this.el.select('ul.dropdown-menu', true).first();  
25510     },
25511     
25512     getAutoCreate : function()
25513     {
25514         var text = [
25515             {
25516                 tag : 'span',
25517                 cls : 'roo-menu-text',
25518                 html : this.html
25519             }
25520         ];
25521         
25522         if(this.icon){
25523             text.unshift({
25524                 tag : 'i',
25525                 cls : 'fa ' + this.icon
25526             })
25527         }
25528         
25529         
25530         var cfg = {
25531             tag : 'div',
25532             cls : 'btn-group',
25533             cn : [
25534                 {
25535                     tag : 'button',
25536                     cls : 'dropdown-button btn btn-' + this.weight,
25537                     cn : text
25538                 },
25539                 {
25540                     tag : 'button',
25541                     cls : 'dropdown-toggle btn btn-' + this.weight,
25542                     cn : [
25543                         {
25544                             tag : 'span',
25545                             cls : 'caret'
25546                         }
25547                     ]
25548                 },
25549                 {
25550                     tag : 'ul',
25551                     cls : 'dropdown-menu'
25552                 }
25553             ]
25554             
25555         };
25556         
25557         if(this.pos == 'top'){
25558             cfg.cls += ' dropup';
25559         }
25560         
25561         if(this.isSubMenu){
25562             cfg = {
25563                 tag : 'ul',
25564                 cls : 'dropdown-menu'
25565             }
25566         }
25567         
25568         return cfg;
25569     },
25570     
25571     onRender : function(ct, position)
25572     {
25573         this.isSubMenu = ct.hasClass('dropdown-submenu');
25574         
25575         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25576     },
25577     
25578     initEvents : function() 
25579     {
25580         if(this.isSubMenu){
25581             return;
25582         }
25583         
25584         this.hidden = true;
25585         
25586         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25587         this.triggerEl.on('click', this.onTriggerPress, this);
25588         
25589         this.buttonEl = this.el.select('button.dropdown-button', true).first();
25590         this.buttonEl.on('click', this.onClick, this);
25591         
25592     },
25593     
25594     list : function()
25595     {
25596         if(this.isSubMenu){
25597             return this.el;
25598         }
25599         
25600         return this.el.select('ul.dropdown-menu', true).first();
25601     },
25602     
25603     onClick : function(e)
25604     {
25605         this.fireEvent("click", this, e);
25606     },
25607     
25608     onTriggerPress  : function(e)
25609     {   
25610         if (this.isVisible()) {
25611             this.hide();
25612         } else {
25613             this.show();
25614         }
25615     },
25616     
25617     isVisible : function(){
25618         return !this.hidden;
25619     },
25620     
25621     show : function()
25622     {
25623         this.fireEvent("beforeshow", this);
25624         
25625         this.hidden = false;
25626         this.el.addClass('open');
25627         
25628         Roo.get(document).on("mouseup", this.onMouseUp, this);
25629         
25630         this.fireEvent("show", this);
25631         
25632         
25633     },
25634     
25635     hide : function()
25636     {
25637         this.fireEvent("beforehide", this);
25638         
25639         this.hidden = true;
25640         this.el.removeClass('open');
25641         
25642         Roo.get(document).un("mouseup", this.onMouseUp);
25643         
25644         this.fireEvent("hide", this);
25645     },
25646     
25647     onMouseUp : function()
25648     {
25649         this.hide();
25650     }
25651     
25652 });
25653
25654  
25655  /*
25656  * - LGPL
25657  *
25658  * menu item
25659  * 
25660  */
25661 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25662
25663 /**
25664  * @class Roo.bootstrap.menu.Item
25665  * @extends Roo.bootstrap.Component
25666  * Bootstrap MenuItem class
25667  * @cfg {Boolean} submenu (true | false) default false
25668  * @cfg {String} html text of the item
25669  * @cfg {String} href the link
25670  * @cfg {Boolean} disable (true | false) default false
25671  * @cfg {Boolean} preventDefault (true | false) default true
25672  * @cfg {String} icon Font awesome icon
25673  * @cfg {String} pos Submenu align to (left | right) default right 
25674  * 
25675  * 
25676  * @constructor
25677  * Create a new Item
25678  * @param {Object} config The config object
25679  */
25680
25681
25682 Roo.bootstrap.menu.Item = function(config){
25683     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25684     this.addEvents({
25685         /**
25686          * @event mouseover
25687          * Fires when the mouse is hovering over this menu
25688          * @param {Roo.bootstrap.menu.Item} this
25689          * @param {Roo.EventObject} e
25690          */
25691         mouseover : true,
25692         /**
25693          * @event mouseout
25694          * Fires when the mouse exits this menu
25695          * @param {Roo.bootstrap.menu.Item} this
25696          * @param {Roo.EventObject} e
25697          */
25698         mouseout : true,
25699         // raw events
25700         /**
25701          * @event click
25702          * The raw click event for the entire grid.
25703          * @param {Roo.EventObject} e
25704          */
25705         click : true
25706     });
25707 };
25708
25709 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
25710     
25711     submenu : false,
25712     href : '',
25713     html : '',
25714     preventDefault: true,
25715     disable : false,
25716     icon : false,
25717     pos : 'right',
25718     
25719     getAutoCreate : function()
25720     {
25721         var text = [
25722             {
25723                 tag : 'span',
25724                 cls : 'roo-menu-item-text',
25725                 html : this.html
25726             }
25727         ];
25728         
25729         if(this.icon){
25730             text.unshift({
25731                 tag : 'i',
25732                 cls : 'fa ' + this.icon
25733             })
25734         }
25735         
25736         var cfg = {
25737             tag : 'li',
25738             cn : [
25739                 {
25740                     tag : 'a',
25741                     href : this.href || '#',
25742                     cn : text
25743                 }
25744             ]
25745         };
25746         
25747         if(this.disable){
25748             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25749         }
25750         
25751         if(this.submenu){
25752             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25753             
25754             if(this.pos == 'left'){
25755                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25756             }
25757         }
25758         
25759         return cfg;
25760     },
25761     
25762     initEvents : function() 
25763     {
25764         this.el.on('mouseover', this.onMouseOver, this);
25765         this.el.on('mouseout', this.onMouseOut, this);
25766         
25767         this.el.select('a', true).first().on('click', this.onClick, this);
25768         
25769     },
25770     
25771     onClick : function(e)
25772     {
25773         if(this.preventDefault){
25774             e.preventDefault();
25775         }
25776         
25777         this.fireEvent("click", this, e);
25778     },
25779     
25780     onMouseOver : function(e)
25781     {
25782         if(this.submenu && this.pos == 'left'){
25783             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25784         }
25785         
25786         this.fireEvent("mouseover", this, e);
25787     },
25788     
25789     onMouseOut : function(e)
25790     {
25791         this.fireEvent("mouseout", this, e);
25792     }
25793 });
25794
25795  
25796
25797  /*
25798  * - LGPL
25799  *
25800  * menu separator
25801  * 
25802  */
25803 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25804
25805 /**
25806  * @class Roo.bootstrap.menu.Separator
25807  * @extends Roo.bootstrap.Component
25808  * Bootstrap Separator class
25809  * 
25810  * @constructor
25811  * Create a new Separator
25812  * @param {Object} config The config object
25813  */
25814
25815
25816 Roo.bootstrap.menu.Separator = function(config){
25817     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25818 };
25819
25820 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
25821     
25822     getAutoCreate : function(){
25823         var cfg = {
25824             tag : 'li',
25825             cls: 'divider'
25826         };
25827         
25828         return cfg;
25829     }
25830    
25831 });
25832
25833  
25834
25835  /*
25836  * - LGPL
25837  *
25838  * Tooltip
25839  * 
25840  */
25841
25842 /**
25843  * @class Roo.bootstrap.Tooltip
25844  * Bootstrap Tooltip class
25845  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25846  * to determine which dom element triggers the tooltip.
25847  * 
25848  * It needs to add support for additional attributes like tooltip-position
25849  * 
25850  * @constructor
25851  * Create a new Toolti
25852  * @param {Object} config The config object
25853  */
25854
25855 Roo.bootstrap.Tooltip = function(config){
25856     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25857     
25858     this.alignment = Roo.bootstrap.Tooltip.alignment;
25859     
25860     if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25861         this.alignment = config.alignment;
25862     }
25863     
25864 };
25865
25866 Roo.apply(Roo.bootstrap.Tooltip, {
25867     /**
25868      * @function init initialize tooltip monitoring.
25869      * @static
25870      */
25871     currentEl : false,
25872     currentTip : false,
25873     currentRegion : false,
25874     
25875     //  init : delay?
25876     
25877     init : function()
25878     {
25879         Roo.get(document).on('mouseover', this.enter ,this);
25880         Roo.get(document).on('mouseout', this.leave, this);
25881          
25882         
25883         this.currentTip = new Roo.bootstrap.Tooltip();
25884     },
25885     
25886     enter : function(ev)
25887     {
25888         var dom = ev.getTarget();
25889         
25890         //Roo.log(['enter',dom]);
25891         var el = Roo.fly(dom);
25892         if (this.currentEl) {
25893             //Roo.log(dom);
25894             //Roo.log(this.currentEl);
25895             //Roo.log(this.currentEl.contains(dom));
25896             if (this.currentEl == el) {
25897                 return;
25898             }
25899             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25900                 return;
25901             }
25902
25903         }
25904         
25905         if (this.currentTip.el) {
25906             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25907         }    
25908         //Roo.log(ev);
25909         
25910         if(!el || el.dom == document){
25911             return;
25912         }
25913         
25914         var bindEl = el;
25915         
25916         // you can not look for children, as if el is the body.. then everythign is the child..
25917         if (!el.attr('tooltip')) { //
25918             if (!el.select("[tooltip]").elements.length) {
25919                 return;
25920             }
25921             // is the mouse over this child...?
25922             bindEl = el.select("[tooltip]").first();
25923             var xy = ev.getXY();
25924             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25925                 //Roo.log("not in region.");
25926                 return;
25927             }
25928             //Roo.log("child element over..");
25929             
25930         }
25931         this.currentEl = bindEl;
25932         this.currentTip.bind(bindEl);
25933         this.currentRegion = Roo.lib.Region.getRegion(dom);
25934         this.currentTip.enter();
25935         
25936     },
25937     leave : function(ev)
25938     {
25939         var dom = ev.getTarget();
25940         //Roo.log(['leave',dom]);
25941         if (!this.currentEl) {
25942             return;
25943         }
25944         
25945         
25946         if (dom != this.currentEl.dom) {
25947             return;
25948         }
25949         var xy = ev.getXY();
25950         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
25951             return;
25952         }
25953         // only activate leave if mouse cursor is outside... bounding box..
25954         
25955         
25956         
25957         
25958         if (this.currentTip) {
25959             this.currentTip.leave();
25960         }
25961         //Roo.log('clear currentEl');
25962         this.currentEl = false;
25963         
25964         
25965     },
25966     alignment : {
25967         'left' : ['r-l', [-2,0], 'right'],
25968         'right' : ['l-r', [2,0], 'left'],
25969         'bottom' : ['t-b', [0,2], 'top'],
25970         'top' : [ 'b-t', [0,-2], 'bottom']
25971     }
25972     
25973 });
25974
25975
25976 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
25977     
25978     
25979     bindEl : false,
25980     
25981     delay : null, // can be { show : 300 , hide: 500}
25982     
25983     timeout : null,
25984     
25985     hoverState : null, //???
25986     
25987     placement : 'bottom', 
25988     
25989     alignment : false,
25990     
25991     getAutoCreate : function(){
25992     
25993         var cfg = {
25994            cls : 'tooltip',
25995            role : 'tooltip',
25996            cn : [
25997                 {
25998                     cls : 'tooltip-arrow'
25999                 },
26000                 {
26001                     cls : 'tooltip-inner'
26002                 }
26003            ]
26004         };
26005         
26006         return cfg;
26007     },
26008     bind : function(el)
26009     {
26010         this.bindEl = el;
26011     },
26012       
26013     
26014     enter : function () {
26015        
26016         if (this.timeout != null) {
26017             clearTimeout(this.timeout);
26018         }
26019         
26020         this.hoverState = 'in';
26021          //Roo.log("enter - show");
26022         if (!this.delay || !this.delay.show) {
26023             this.show();
26024             return;
26025         }
26026         var _t = this;
26027         this.timeout = setTimeout(function () {
26028             if (_t.hoverState == 'in') {
26029                 _t.show();
26030             }
26031         }, this.delay.show);
26032     },
26033     leave : function()
26034     {
26035         clearTimeout(this.timeout);
26036     
26037         this.hoverState = 'out';
26038          if (!this.delay || !this.delay.hide) {
26039             this.hide();
26040             return;
26041         }
26042        
26043         var _t = this;
26044         this.timeout = setTimeout(function () {
26045             //Roo.log("leave - timeout");
26046             
26047             if (_t.hoverState == 'out') {
26048                 _t.hide();
26049                 Roo.bootstrap.Tooltip.currentEl = false;
26050             }
26051         }, delay);
26052     },
26053     
26054     show : function (msg)
26055     {
26056         if (!this.el) {
26057             this.render(document.body);
26058         }
26059         // set content.
26060         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26061         
26062         var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26063         
26064         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26065         
26066         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26067         
26068         var placement = typeof this.placement == 'function' ?
26069             this.placement.call(this, this.el, on_el) :
26070             this.placement;
26071             
26072         var autoToken = /\s?auto?\s?/i;
26073         var autoPlace = autoToken.test(placement);
26074         if (autoPlace) {
26075             placement = placement.replace(autoToken, '') || 'top';
26076         }
26077         
26078         //this.el.detach()
26079         //this.el.setXY([0,0]);
26080         this.el.show();
26081         //this.el.dom.style.display='block';
26082         
26083         //this.el.appendTo(on_el);
26084         
26085         var p = this.getPosition();
26086         var box = this.el.getBox();
26087         
26088         if (autoPlace) {
26089             // fixme..
26090         }
26091         
26092         var align = this.alignment[placement];
26093         
26094         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26095         
26096         if(placement == 'top' || placement == 'bottom'){
26097             if(xy[0] < 0){
26098                 placement = 'right';
26099             }
26100             
26101             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26102                 placement = 'left';
26103             }
26104             
26105             var scroll = Roo.select('body', true).first().getScroll();
26106             
26107             if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26108                 placement = 'top';
26109             }
26110             
26111         }
26112         
26113         this.el.alignTo(this.bindEl, align[0],align[1]);
26114         //var arrow = this.el.select('.arrow',true).first();
26115         //arrow.set(align[2], 
26116         
26117         this.el.addClass(placement);
26118         
26119         this.el.addClass('in fade');
26120         
26121         this.hoverState = null;
26122         
26123         if (this.el.hasClass('fade')) {
26124             // fade it?
26125         }
26126         
26127     },
26128     hide : function()
26129     {
26130          
26131         if (!this.el) {
26132             return;
26133         }
26134         //this.el.setXY([0,0]);
26135         this.el.removeClass('in');
26136         //this.el.hide();
26137         
26138     }
26139     
26140 });
26141  
26142
26143  /*
26144  * - LGPL
26145  *
26146  * Location Picker
26147  * 
26148  */
26149
26150 /**
26151  * @class Roo.bootstrap.LocationPicker
26152  * @extends Roo.bootstrap.Component
26153  * Bootstrap LocationPicker class
26154  * @cfg {Number} latitude Position when init default 0
26155  * @cfg {Number} longitude Position when init default 0
26156  * @cfg {Number} zoom default 15
26157  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26158  * @cfg {Boolean} mapTypeControl default false
26159  * @cfg {Boolean} disableDoubleClickZoom default false
26160  * @cfg {Boolean} scrollwheel default true
26161  * @cfg {Boolean} streetViewControl default false
26162  * @cfg {Number} radius default 0
26163  * @cfg {String} locationName
26164  * @cfg {Boolean} draggable default true
26165  * @cfg {Boolean} enableAutocomplete default false
26166  * @cfg {Boolean} enableReverseGeocode default true
26167  * @cfg {String} markerTitle
26168  * 
26169  * @constructor
26170  * Create a new LocationPicker
26171  * @param {Object} config The config object
26172  */
26173
26174
26175 Roo.bootstrap.LocationPicker = function(config){
26176     
26177     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26178     
26179     this.addEvents({
26180         /**
26181          * @event initial
26182          * Fires when the picker initialized.
26183          * @param {Roo.bootstrap.LocationPicker} this
26184          * @param {Google Location} location
26185          */
26186         initial : true,
26187         /**
26188          * @event positionchanged
26189          * Fires when the picker position changed.
26190          * @param {Roo.bootstrap.LocationPicker} this
26191          * @param {Google Location} location
26192          */
26193         positionchanged : true,
26194         /**
26195          * @event resize
26196          * Fires when the map resize.
26197          * @param {Roo.bootstrap.LocationPicker} this
26198          */
26199         resize : true,
26200         /**
26201          * @event show
26202          * Fires when the map show.
26203          * @param {Roo.bootstrap.LocationPicker} this
26204          */
26205         show : true,
26206         /**
26207          * @event hide
26208          * Fires when the map hide.
26209          * @param {Roo.bootstrap.LocationPicker} this
26210          */
26211         hide : true,
26212         /**
26213          * @event mapClick
26214          * Fires when click the map.
26215          * @param {Roo.bootstrap.LocationPicker} this
26216          * @param {Map event} e
26217          */
26218         mapClick : true,
26219         /**
26220          * @event mapRightClick
26221          * Fires when right click the map.
26222          * @param {Roo.bootstrap.LocationPicker} this
26223          * @param {Map event} e
26224          */
26225         mapRightClick : true,
26226         /**
26227          * @event markerClick
26228          * Fires when click the marker.
26229          * @param {Roo.bootstrap.LocationPicker} this
26230          * @param {Map event} e
26231          */
26232         markerClick : true,
26233         /**
26234          * @event markerRightClick
26235          * Fires when right click the marker.
26236          * @param {Roo.bootstrap.LocationPicker} this
26237          * @param {Map event} e
26238          */
26239         markerRightClick : true,
26240         /**
26241          * @event OverlayViewDraw
26242          * Fires when OverlayView Draw
26243          * @param {Roo.bootstrap.LocationPicker} this
26244          */
26245         OverlayViewDraw : true,
26246         /**
26247          * @event OverlayViewOnAdd
26248          * Fires when OverlayView Draw
26249          * @param {Roo.bootstrap.LocationPicker} this
26250          */
26251         OverlayViewOnAdd : true,
26252         /**
26253          * @event OverlayViewOnRemove
26254          * Fires when OverlayView Draw
26255          * @param {Roo.bootstrap.LocationPicker} this
26256          */
26257         OverlayViewOnRemove : true,
26258         /**
26259          * @event OverlayViewShow
26260          * Fires when OverlayView Draw
26261          * @param {Roo.bootstrap.LocationPicker} this
26262          * @param {Pixel} cpx
26263          */
26264         OverlayViewShow : true,
26265         /**
26266          * @event OverlayViewHide
26267          * Fires when OverlayView Draw
26268          * @param {Roo.bootstrap.LocationPicker} this
26269          */
26270         OverlayViewHide : true,
26271         /**
26272          * @event loadexception
26273          * Fires when load google lib failed.
26274          * @param {Roo.bootstrap.LocationPicker} this
26275          */
26276         loadexception : true
26277     });
26278         
26279 };
26280
26281 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
26282     
26283     gMapContext: false,
26284     
26285     latitude: 0,
26286     longitude: 0,
26287     zoom: 15,
26288     mapTypeId: false,
26289     mapTypeControl: false,
26290     disableDoubleClickZoom: false,
26291     scrollwheel: true,
26292     streetViewControl: false,
26293     radius: 0,
26294     locationName: '',
26295     draggable: true,
26296     enableAutocomplete: false,
26297     enableReverseGeocode: true,
26298     markerTitle: '',
26299     
26300     getAutoCreate: function()
26301     {
26302
26303         var cfg = {
26304             tag: 'div',
26305             cls: 'roo-location-picker'
26306         };
26307         
26308         return cfg
26309     },
26310     
26311     initEvents: function(ct, position)
26312     {       
26313         if(!this.el.getWidth() || this.isApplied()){
26314             return;
26315         }
26316         
26317         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26318         
26319         this.initial();
26320     },
26321     
26322     initial: function()
26323     {
26324         if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26325             this.fireEvent('loadexception', this);
26326             return;
26327         }
26328         
26329         if(!this.mapTypeId){
26330             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26331         }
26332         
26333         this.gMapContext = this.GMapContext();
26334         
26335         this.initOverlayView();
26336         
26337         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26338         
26339         var _this = this;
26340                 
26341         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26342             _this.setPosition(_this.gMapContext.marker.position);
26343         });
26344         
26345         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26346             _this.fireEvent('mapClick', this, event);
26347             
26348         });
26349
26350         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26351             _this.fireEvent('mapRightClick', this, event);
26352             
26353         });
26354         
26355         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26356             _this.fireEvent('markerClick', this, event);
26357             
26358         });
26359
26360         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26361             _this.fireEvent('markerRightClick', this, event);
26362             
26363         });
26364         
26365         this.setPosition(this.gMapContext.location);
26366         
26367         this.fireEvent('initial', this, this.gMapContext.location);
26368     },
26369     
26370     initOverlayView: function()
26371     {
26372         var _this = this;
26373         
26374         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26375             
26376             draw: function()
26377             {
26378                 _this.fireEvent('OverlayViewDraw', _this);
26379             },
26380             
26381             onAdd: function()
26382             {
26383                 _this.fireEvent('OverlayViewOnAdd', _this);
26384             },
26385             
26386             onRemove: function()
26387             {
26388                 _this.fireEvent('OverlayViewOnRemove', _this);
26389             },
26390             
26391             show: function(cpx)
26392             {
26393                 _this.fireEvent('OverlayViewShow', _this, cpx);
26394             },
26395             
26396             hide: function()
26397             {
26398                 _this.fireEvent('OverlayViewHide', _this);
26399             }
26400             
26401         });
26402     },
26403     
26404     fromLatLngToContainerPixel: function(event)
26405     {
26406         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26407     },
26408     
26409     isApplied: function() 
26410     {
26411         return this.getGmapContext() == false ? false : true;
26412     },
26413     
26414     getGmapContext: function() 
26415     {
26416         return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26417     },
26418     
26419     GMapContext: function() 
26420     {
26421         var position = new google.maps.LatLng(this.latitude, this.longitude);
26422         
26423         var _map = new google.maps.Map(this.el.dom, {
26424             center: position,
26425             zoom: this.zoom,
26426             mapTypeId: this.mapTypeId,
26427             mapTypeControl: this.mapTypeControl,
26428             disableDoubleClickZoom: this.disableDoubleClickZoom,
26429             scrollwheel: this.scrollwheel,
26430             streetViewControl: this.streetViewControl,
26431             locationName: this.locationName,
26432             draggable: this.draggable,
26433             enableAutocomplete: this.enableAutocomplete,
26434             enableReverseGeocode: this.enableReverseGeocode
26435         });
26436         
26437         var _marker = new google.maps.Marker({
26438             position: position,
26439             map: _map,
26440             title: this.markerTitle,
26441             draggable: this.draggable
26442         });
26443         
26444         return {
26445             map: _map,
26446             marker: _marker,
26447             circle: null,
26448             location: position,
26449             radius: this.radius,
26450             locationName: this.locationName,
26451             addressComponents: {
26452                 formatted_address: null,
26453                 addressLine1: null,
26454                 addressLine2: null,
26455                 streetName: null,
26456                 streetNumber: null,
26457                 city: null,
26458                 district: null,
26459                 state: null,
26460                 stateOrProvince: null
26461             },
26462             settings: this,
26463             domContainer: this.el.dom,
26464             geodecoder: new google.maps.Geocoder()
26465         };
26466     },
26467     
26468     drawCircle: function(center, radius, options) 
26469     {
26470         if (this.gMapContext.circle != null) {
26471             this.gMapContext.circle.setMap(null);
26472         }
26473         if (radius > 0) {
26474             radius *= 1;
26475             options = Roo.apply({}, options, {
26476                 strokeColor: "#0000FF",
26477                 strokeOpacity: .35,
26478                 strokeWeight: 2,
26479                 fillColor: "#0000FF",
26480                 fillOpacity: .2
26481             });
26482             
26483             options.map = this.gMapContext.map;
26484             options.radius = radius;
26485             options.center = center;
26486             this.gMapContext.circle = new google.maps.Circle(options);
26487             return this.gMapContext.circle;
26488         }
26489         
26490         return null;
26491     },
26492     
26493     setPosition: function(location) 
26494     {
26495         this.gMapContext.location = location;
26496         this.gMapContext.marker.setPosition(location);
26497         this.gMapContext.map.panTo(location);
26498         this.drawCircle(location, this.gMapContext.radius, {});
26499         
26500         var _this = this;
26501         
26502         if (this.gMapContext.settings.enableReverseGeocode) {
26503             this.gMapContext.geodecoder.geocode({
26504                 latLng: this.gMapContext.location
26505             }, function(results, status) {
26506                 
26507                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26508                     _this.gMapContext.locationName = results[0].formatted_address;
26509                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26510                     
26511                     _this.fireEvent('positionchanged', this, location);
26512                 }
26513             });
26514             
26515             return;
26516         }
26517         
26518         this.fireEvent('positionchanged', this, location);
26519     },
26520     
26521     resize: function()
26522     {
26523         google.maps.event.trigger(this.gMapContext.map, "resize");
26524         
26525         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26526         
26527         this.fireEvent('resize', this);
26528     },
26529     
26530     setPositionByLatLng: function(latitude, longitude)
26531     {
26532         this.setPosition(new google.maps.LatLng(latitude, longitude));
26533     },
26534     
26535     getCurrentPosition: function() 
26536     {
26537         return {
26538             latitude: this.gMapContext.location.lat(),
26539             longitude: this.gMapContext.location.lng()
26540         };
26541     },
26542     
26543     getAddressName: function() 
26544     {
26545         return this.gMapContext.locationName;
26546     },
26547     
26548     getAddressComponents: function() 
26549     {
26550         return this.gMapContext.addressComponents;
26551     },
26552     
26553     address_component_from_google_geocode: function(address_components) 
26554     {
26555         var result = {};
26556         
26557         for (var i = 0; i < address_components.length; i++) {
26558             var component = address_components[i];
26559             if (component.types.indexOf("postal_code") >= 0) {
26560                 result.postalCode = component.short_name;
26561             } else if (component.types.indexOf("street_number") >= 0) {
26562                 result.streetNumber = component.short_name;
26563             } else if (component.types.indexOf("route") >= 0) {
26564                 result.streetName = component.short_name;
26565             } else if (component.types.indexOf("neighborhood") >= 0) {
26566                 result.city = component.short_name;
26567             } else if (component.types.indexOf("locality") >= 0) {
26568                 result.city = component.short_name;
26569             } else if (component.types.indexOf("sublocality") >= 0) {
26570                 result.district = component.short_name;
26571             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26572                 result.stateOrProvince = component.short_name;
26573             } else if (component.types.indexOf("country") >= 0) {
26574                 result.country = component.short_name;
26575             }
26576         }
26577         
26578         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26579         result.addressLine2 = "";
26580         return result;
26581     },
26582     
26583     setZoomLevel: function(zoom)
26584     {
26585         this.gMapContext.map.setZoom(zoom);
26586     },
26587     
26588     show: function()
26589     {
26590         if(!this.el){
26591             return;
26592         }
26593         
26594         this.el.show();
26595         
26596         this.resize();
26597         
26598         this.fireEvent('show', this);
26599     },
26600     
26601     hide: function()
26602     {
26603         if(!this.el){
26604             return;
26605         }
26606         
26607         this.el.hide();
26608         
26609         this.fireEvent('hide', this);
26610     }
26611     
26612 });
26613
26614 Roo.apply(Roo.bootstrap.LocationPicker, {
26615     
26616     OverlayView : function(map, options)
26617     {
26618         options = options || {};
26619         
26620         this.setMap(map);
26621     }
26622     
26623     
26624 });/*
26625  * - LGPL
26626  *
26627  * Alert
26628  * 
26629  */
26630
26631 /**
26632  * @class Roo.bootstrap.Alert
26633  * @extends Roo.bootstrap.Component
26634  * Bootstrap Alert class
26635  * @cfg {String} title The title of alert
26636  * @cfg {String} html The content of alert
26637  * @cfg {String} weight (  success | info | warning | danger )
26638  * @cfg {String} faicon font-awesomeicon
26639  * 
26640  * @constructor
26641  * Create a new alert
26642  * @param {Object} config The config object
26643  */
26644
26645
26646 Roo.bootstrap.Alert = function(config){
26647     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26648     
26649 };
26650
26651 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
26652     
26653     title: '',
26654     html: '',
26655     weight: false,
26656     faicon: false,
26657     
26658     getAutoCreate : function()
26659     {
26660         
26661         var cfg = {
26662             tag : 'div',
26663             cls : 'alert',
26664             cn : [
26665                 {
26666                     tag : 'i',
26667                     cls : 'roo-alert-icon'
26668                     
26669                 },
26670                 {
26671                     tag : 'b',
26672                     cls : 'roo-alert-title',
26673                     html : this.title
26674                 },
26675                 {
26676                     tag : 'span',
26677                     cls : 'roo-alert-text',
26678                     html : this.html
26679                 }
26680             ]
26681         };
26682         
26683         if(this.faicon){
26684             cfg.cn[0].cls += ' fa ' + this.faicon;
26685         }
26686         
26687         if(this.weight){
26688             cfg.cls += ' alert-' + this.weight;
26689         }
26690         
26691         return cfg;
26692     },
26693     
26694     initEvents: function() 
26695     {
26696         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26697     },
26698     
26699     setTitle : function(str)
26700     {
26701         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26702     },
26703     
26704     setText : function(str)
26705     {
26706         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26707     },
26708     
26709     setWeight : function(weight)
26710     {
26711         if(this.weight){
26712             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26713         }
26714         
26715         this.weight = weight;
26716         
26717         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26718     },
26719     
26720     setIcon : function(icon)
26721     {
26722         if(this.faicon){
26723             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26724         }
26725         
26726         this.faicon = icon;
26727         
26728         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26729     },
26730     
26731     hide: function() 
26732     {
26733         this.el.hide();   
26734     },
26735     
26736     show: function() 
26737     {  
26738         this.el.show();   
26739     }
26740     
26741 });
26742
26743  
26744 /*
26745 * Licence: LGPL
26746 */
26747
26748 /**
26749  * @class Roo.bootstrap.UploadCropbox
26750  * @extends Roo.bootstrap.Component
26751  * Bootstrap UploadCropbox class
26752  * @cfg {String} emptyText show when image has been loaded
26753  * @cfg {String} rotateNotify show when image too small to rotate
26754  * @cfg {Number} errorTimeout default 3000
26755  * @cfg {Number} minWidth default 300
26756  * @cfg {Number} minHeight default 300
26757  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26758  * @cfg {Boolean} isDocument (true|false) default false
26759  * @cfg {String} url action url
26760  * @cfg {String} paramName default 'imageUpload'
26761  * @cfg {String} method default POST
26762  * @cfg {Boolean} loadMask (true|false) default true
26763  * @cfg {Boolean} loadingText default 'Loading...'
26764  * 
26765  * @constructor
26766  * Create a new UploadCropbox
26767  * @param {Object} config The config object
26768  */
26769
26770 Roo.bootstrap.UploadCropbox = function(config){
26771     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26772     
26773     this.addEvents({
26774         /**
26775          * @event beforeselectfile
26776          * Fire before select file
26777          * @param {Roo.bootstrap.UploadCropbox} this
26778          */
26779         "beforeselectfile" : true,
26780         /**
26781          * @event initial
26782          * Fire after initEvent
26783          * @param {Roo.bootstrap.UploadCropbox} this
26784          */
26785         "initial" : true,
26786         /**
26787          * @event crop
26788          * Fire after initEvent
26789          * @param {Roo.bootstrap.UploadCropbox} this
26790          * @param {String} data
26791          */
26792         "crop" : true,
26793         /**
26794          * @event prepare
26795          * Fire when preparing the file data
26796          * @param {Roo.bootstrap.UploadCropbox} this
26797          * @param {Object} file
26798          */
26799         "prepare" : true,
26800         /**
26801          * @event exception
26802          * Fire when get exception
26803          * @param {Roo.bootstrap.UploadCropbox} this
26804          * @param {XMLHttpRequest} xhr
26805          */
26806         "exception" : true,
26807         /**
26808          * @event beforeloadcanvas
26809          * Fire before load the canvas
26810          * @param {Roo.bootstrap.UploadCropbox} this
26811          * @param {String} src
26812          */
26813         "beforeloadcanvas" : true,
26814         /**
26815          * @event trash
26816          * Fire when trash image
26817          * @param {Roo.bootstrap.UploadCropbox} this
26818          */
26819         "trash" : true,
26820         /**
26821          * @event download
26822          * Fire when download the image
26823          * @param {Roo.bootstrap.UploadCropbox} this
26824          */
26825         "download" : true,
26826         /**
26827          * @event footerbuttonclick
26828          * Fire when footerbuttonclick
26829          * @param {Roo.bootstrap.UploadCropbox} this
26830          * @param {String} type
26831          */
26832         "footerbuttonclick" : true,
26833         /**
26834          * @event resize
26835          * Fire when resize
26836          * @param {Roo.bootstrap.UploadCropbox} this
26837          */
26838         "resize" : true,
26839         /**
26840          * @event rotate
26841          * Fire when rotate the image
26842          * @param {Roo.bootstrap.UploadCropbox} this
26843          * @param {String} pos
26844          */
26845         "rotate" : true,
26846         /**
26847          * @event inspect
26848          * Fire when inspect the file
26849          * @param {Roo.bootstrap.UploadCropbox} this
26850          * @param {Object} file
26851          */
26852         "inspect" : true,
26853         /**
26854          * @event upload
26855          * Fire when xhr upload the file
26856          * @param {Roo.bootstrap.UploadCropbox} this
26857          * @param {Object} data
26858          */
26859         "upload" : true,
26860         /**
26861          * @event arrange
26862          * Fire when arrange the file data
26863          * @param {Roo.bootstrap.UploadCropbox} this
26864          * @param {Object} formData
26865          */
26866         "arrange" : true
26867     });
26868     
26869     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26870 };
26871
26872 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
26873     
26874     emptyText : 'Click to upload image',
26875     rotateNotify : 'Image is too small to rotate',
26876     errorTimeout : 3000,
26877     scale : 0,
26878     baseScale : 1,
26879     rotate : 0,
26880     dragable : false,
26881     pinching : false,
26882     mouseX : 0,
26883     mouseY : 0,
26884     cropData : false,
26885     minWidth : 300,
26886     minHeight : 300,
26887     file : false,
26888     exif : {},
26889     baseRotate : 1,
26890     cropType : 'image/jpeg',
26891     buttons : false,
26892     canvasLoaded : false,
26893     isDocument : false,
26894     method : 'POST',
26895     paramName : 'imageUpload',
26896     loadMask : true,
26897     loadingText : 'Loading...',
26898     maskEl : false,
26899     
26900     getAutoCreate : function()
26901     {
26902         var cfg = {
26903             tag : 'div',
26904             cls : 'roo-upload-cropbox',
26905             cn : [
26906                 {
26907                     tag : 'input',
26908                     cls : 'roo-upload-cropbox-selector',
26909                     type : 'file'
26910                 },
26911                 {
26912                     tag : 'div',
26913                     cls : 'roo-upload-cropbox-body',
26914                     style : 'cursor:pointer',
26915                     cn : [
26916                         {
26917                             tag : 'div',
26918                             cls : 'roo-upload-cropbox-preview'
26919                         },
26920                         {
26921                             tag : 'div',
26922                             cls : 'roo-upload-cropbox-thumb'
26923                         },
26924                         {
26925                             tag : 'div',
26926                             cls : 'roo-upload-cropbox-empty-notify',
26927                             html : this.emptyText
26928                         },
26929                         {
26930                             tag : 'div',
26931                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26932                             html : this.rotateNotify
26933                         }
26934                     ]
26935                 },
26936                 {
26937                     tag : 'div',
26938                     cls : 'roo-upload-cropbox-footer',
26939                     cn : {
26940                         tag : 'div',
26941                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26942                         cn : []
26943                     }
26944                 }
26945             ]
26946         };
26947         
26948         return cfg;
26949     },
26950     
26951     onRender : function(ct, position)
26952     {
26953         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26954         
26955         if (this.buttons.length) {
26956             
26957             Roo.each(this.buttons, function(bb) {
26958                 
26959                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26960                 
26961                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26962                 
26963             }, this);
26964         }
26965         
26966         if(this.loadMask){
26967             this.maskEl = this.el;
26968         }
26969     },
26970     
26971     initEvents : function()
26972     {
26973         this.urlAPI = (window.createObjectURL && window) || 
26974                                 (window.URL && URL.revokeObjectURL && URL) || 
26975                                 (window.webkitURL && webkitURL);
26976                         
26977         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26978         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26979         
26980         this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26981         this.selectorEl.hide();
26982         
26983         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26984         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26985         
26986         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26987         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26988         this.thumbEl.hide();
26989         
26990         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26991         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26992         
26993         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26994         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26995         this.errorEl.hide();
26996         
26997         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26998         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26999         this.footerEl.hide();
27000         
27001         this.setThumbBoxSize();
27002         
27003         this.bind();
27004         
27005         this.resize();
27006         
27007         this.fireEvent('initial', this);
27008     },
27009
27010     bind : function()
27011     {
27012         var _this = this;
27013         
27014         window.addEventListener("resize", function() { _this.resize(); } );
27015         
27016         this.bodyEl.on('click', this.beforeSelectFile, this);
27017         
27018         if(Roo.isTouch){
27019             this.bodyEl.on('touchstart', this.onTouchStart, this);
27020             this.bodyEl.on('touchmove', this.onTouchMove, this);
27021             this.bodyEl.on('touchend', this.onTouchEnd, this);
27022         }
27023         
27024         if(!Roo.isTouch){
27025             this.bodyEl.on('mousedown', this.onMouseDown, this);
27026             this.bodyEl.on('mousemove', this.onMouseMove, this);
27027             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27028             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27029             Roo.get(document).on('mouseup', this.onMouseUp, this);
27030         }
27031         
27032         this.selectorEl.on('change', this.onFileSelected, this);
27033     },
27034     
27035     reset : function()
27036     {    
27037         this.scale = 0;
27038         this.baseScale = 1;
27039         this.rotate = 0;
27040         this.baseRotate = 1;
27041         this.dragable = false;
27042         this.pinching = false;
27043         this.mouseX = 0;
27044         this.mouseY = 0;
27045         this.cropData = false;
27046         this.notifyEl.dom.innerHTML = this.emptyText;
27047         
27048         this.selectorEl.dom.value = '';
27049         
27050     },
27051     
27052     resize : function()
27053     {
27054         if(this.fireEvent('resize', this) != false){
27055             this.setThumbBoxPosition();
27056             this.setCanvasPosition();
27057         }
27058     },
27059     
27060     onFooterButtonClick : function(e, el, o, type)
27061     {
27062         switch (type) {
27063             case 'rotate-left' :
27064                 this.onRotateLeft(e);
27065                 break;
27066             case 'rotate-right' :
27067                 this.onRotateRight(e);
27068                 break;
27069             case 'picture' :
27070                 this.beforeSelectFile(e);
27071                 break;
27072             case 'trash' :
27073                 this.trash(e);
27074                 break;
27075             case 'crop' :
27076                 this.crop(e);
27077                 break;
27078             case 'download' :
27079                 this.download(e);
27080                 break;
27081             default :
27082                 break;
27083         }
27084         
27085         this.fireEvent('footerbuttonclick', this, type);
27086     },
27087     
27088     beforeSelectFile : function(e)
27089     {
27090         e.preventDefault();
27091         
27092         if(this.fireEvent('beforeselectfile', this) != false){
27093             this.selectorEl.dom.click();
27094         }
27095     },
27096     
27097     onFileSelected : function(e)
27098     {
27099         e.preventDefault();
27100         
27101         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27102             return;
27103         }
27104         
27105         var file = this.selectorEl.dom.files[0];
27106         
27107         if(this.fireEvent('inspect', this, file) != false){
27108             this.prepare(file);
27109         }
27110         
27111     },
27112     
27113     trash : function(e)
27114     {
27115         this.fireEvent('trash', this);
27116     },
27117     
27118     download : function(e)
27119     {
27120         this.fireEvent('download', this);
27121     },
27122     
27123     loadCanvas : function(src)
27124     {   
27125         if(this.fireEvent('beforeloadcanvas', this, src) != false){
27126             
27127             this.reset();
27128             
27129             this.imageEl = document.createElement('img');
27130             
27131             var _this = this;
27132             
27133             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27134             
27135             this.imageEl.src = src;
27136         }
27137     },
27138     
27139     onLoadCanvas : function()
27140     {   
27141         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27142         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27143         
27144         this.bodyEl.un('click', this.beforeSelectFile, this);
27145         
27146         this.notifyEl.hide();
27147         this.thumbEl.show();
27148         this.footerEl.show();
27149         
27150         this.baseRotateLevel();
27151         
27152         if(this.isDocument){
27153             this.setThumbBoxSize();
27154         }
27155         
27156         this.setThumbBoxPosition();
27157         
27158         this.baseScaleLevel();
27159         
27160         this.draw();
27161         
27162         this.resize();
27163         
27164         this.canvasLoaded = true;
27165         
27166         if(this.loadMask){
27167             this.maskEl.unmask();
27168         }
27169         
27170     },
27171     
27172     setCanvasPosition : function()
27173     {   
27174         if(!this.canvasEl){
27175             return;
27176         }
27177         
27178         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27179         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27180         
27181         this.previewEl.setLeft(pw);
27182         this.previewEl.setTop(ph);
27183         
27184     },
27185     
27186     onMouseDown : function(e)
27187     {   
27188         e.stopEvent();
27189         
27190         this.dragable = true;
27191         this.pinching = false;
27192         
27193         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27194             this.dragable = false;
27195             return;
27196         }
27197         
27198         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27199         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27200         
27201     },
27202     
27203     onMouseMove : function(e)
27204     {   
27205         e.stopEvent();
27206         
27207         if(!this.canvasLoaded){
27208             return;
27209         }
27210         
27211         if (!this.dragable){
27212             return;
27213         }
27214         
27215         var minX = Math.ceil(this.thumbEl.getLeft(true));
27216         var minY = Math.ceil(this.thumbEl.getTop(true));
27217         
27218         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27219         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27220         
27221         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27222         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27223         
27224         x = x - this.mouseX;
27225         y = y - this.mouseY;
27226         
27227         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27228         var bgY = Math.ceil(y + this.previewEl.getTop(true));
27229         
27230         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27231         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27232         
27233         this.previewEl.setLeft(bgX);
27234         this.previewEl.setTop(bgY);
27235         
27236         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27237         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27238     },
27239     
27240     onMouseUp : function(e)
27241     {   
27242         e.stopEvent();
27243         
27244         this.dragable = false;
27245     },
27246     
27247     onMouseWheel : function(e)
27248     {   
27249         e.stopEvent();
27250         
27251         this.startScale = this.scale;
27252         
27253         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27254         
27255         if(!this.zoomable()){
27256             this.scale = this.startScale;
27257             return;
27258         }
27259         
27260         this.draw();
27261         
27262         return;
27263     },
27264     
27265     zoomable : function()
27266     {
27267         var minScale = this.thumbEl.getWidth() / this.minWidth;
27268         
27269         if(this.minWidth < this.minHeight){
27270             minScale = this.thumbEl.getHeight() / this.minHeight;
27271         }
27272         
27273         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27274         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27275         
27276         if(
27277                 this.isDocument &&
27278                 (this.rotate == 0 || this.rotate == 180) && 
27279                 (
27280                     width > this.imageEl.OriginWidth || 
27281                     height > this.imageEl.OriginHeight ||
27282                     (width < this.minWidth && height < this.minHeight)
27283                 )
27284         ){
27285             return false;
27286         }
27287         
27288         if(
27289                 this.isDocument &&
27290                 (this.rotate == 90 || this.rotate == 270) && 
27291                 (
27292                     width > this.imageEl.OriginWidth || 
27293                     height > this.imageEl.OriginHeight ||
27294                     (width < this.minHeight && height < this.minWidth)
27295                 )
27296         ){
27297             return false;
27298         }
27299         
27300         if(
27301                 !this.isDocument &&
27302                 (this.rotate == 0 || this.rotate == 180) && 
27303                 (
27304                     width < this.minWidth || 
27305                     width > this.imageEl.OriginWidth || 
27306                     height < this.minHeight || 
27307                     height > this.imageEl.OriginHeight
27308                 )
27309         ){
27310             return false;
27311         }
27312         
27313         if(
27314                 !this.isDocument &&
27315                 (this.rotate == 90 || this.rotate == 270) && 
27316                 (
27317                     width < this.minHeight || 
27318                     width > this.imageEl.OriginWidth || 
27319                     height < this.minWidth || 
27320                     height > this.imageEl.OriginHeight
27321                 )
27322         ){
27323             return false;
27324         }
27325         
27326         return true;
27327         
27328     },
27329     
27330     onRotateLeft : function(e)
27331     {   
27332         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27333             
27334             var minScale = this.thumbEl.getWidth() / this.minWidth;
27335             
27336             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27337             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27338             
27339             this.startScale = this.scale;
27340             
27341             while (this.getScaleLevel() < minScale){
27342             
27343                 this.scale = this.scale + 1;
27344                 
27345                 if(!this.zoomable()){
27346                     break;
27347                 }
27348                 
27349                 if(
27350                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27351                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27352                 ){
27353                     continue;
27354                 }
27355                 
27356                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27357
27358                 this.draw();
27359                 
27360                 return;
27361             }
27362             
27363             this.scale = this.startScale;
27364             
27365             this.onRotateFail();
27366             
27367             return false;
27368         }
27369         
27370         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27371
27372         if(this.isDocument){
27373             this.setThumbBoxSize();
27374             this.setThumbBoxPosition();
27375             this.setCanvasPosition();
27376         }
27377         
27378         this.draw();
27379         
27380         this.fireEvent('rotate', this, 'left');
27381         
27382     },
27383     
27384     onRotateRight : function(e)
27385     {
27386         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27387             
27388             var minScale = this.thumbEl.getWidth() / this.minWidth;
27389         
27390             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27391             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27392             
27393             this.startScale = this.scale;
27394             
27395             while (this.getScaleLevel() < minScale){
27396             
27397                 this.scale = this.scale + 1;
27398                 
27399                 if(!this.zoomable()){
27400                     break;
27401                 }
27402                 
27403                 if(
27404                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27405                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27406                 ){
27407                     continue;
27408                 }
27409                 
27410                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27411
27412                 this.draw();
27413                 
27414                 return;
27415             }
27416             
27417             this.scale = this.startScale;
27418             
27419             this.onRotateFail();
27420             
27421             return false;
27422         }
27423         
27424         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27425
27426         if(this.isDocument){
27427             this.setThumbBoxSize();
27428             this.setThumbBoxPosition();
27429             this.setCanvasPosition();
27430         }
27431         
27432         this.draw();
27433         
27434         this.fireEvent('rotate', this, 'right');
27435     },
27436     
27437     onRotateFail : function()
27438     {
27439         this.errorEl.show(true);
27440         
27441         var _this = this;
27442         
27443         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27444     },
27445     
27446     draw : function()
27447     {
27448         this.previewEl.dom.innerHTML = '';
27449         
27450         var canvasEl = document.createElement("canvas");
27451         
27452         var contextEl = canvasEl.getContext("2d");
27453         
27454         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27455         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27456         var center = this.imageEl.OriginWidth / 2;
27457         
27458         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27459             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27460             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27461             center = this.imageEl.OriginHeight / 2;
27462         }
27463         
27464         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27465         
27466         contextEl.translate(center, center);
27467         contextEl.rotate(this.rotate * Math.PI / 180);
27468
27469         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27470         
27471         this.canvasEl = document.createElement("canvas");
27472         
27473         this.contextEl = this.canvasEl.getContext("2d");
27474         
27475         switch (this.rotate) {
27476             case 0 :
27477                 
27478                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27479                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27480                 
27481                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27482                 
27483                 break;
27484             case 90 : 
27485                 
27486                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27487                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27488                 
27489                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27490                     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);
27491                     break;
27492                 }
27493                 
27494                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27495                 
27496                 break;
27497             case 180 :
27498                 
27499                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27500                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27501                 
27502                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27503                     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);
27504                     break;
27505                 }
27506                 
27507                 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);
27508                 
27509                 break;
27510             case 270 :
27511                 
27512                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27513                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27514         
27515                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27516                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27517                     break;
27518                 }
27519                 
27520                 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);
27521                 
27522                 break;
27523             default : 
27524                 break;
27525         }
27526         
27527         this.previewEl.appendChild(this.canvasEl);
27528         
27529         this.setCanvasPosition();
27530     },
27531     
27532     crop : function()
27533     {
27534         if(!this.canvasLoaded){
27535             return;
27536         }
27537         
27538         var imageCanvas = document.createElement("canvas");
27539         
27540         var imageContext = imageCanvas.getContext("2d");
27541         
27542         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27543         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27544         
27545         var center = imageCanvas.width / 2;
27546         
27547         imageContext.translate(center, center);
27548         
27549         imageContext.rotate(this.rotate * Math.PI / 180);
27550         
27551         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27552         
27553         var canvas = document.createElement("canvas");
27554         
27555         var context = canvas.getContext("2d");
27556                 
27557         canvas.width = this.minWidth;
27558         canvas.height = this.minHeight;
27559
27560         switch (this.rotate) {
27561             case 0 :
27562                 
27563                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27564                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27565                 
27566                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27567                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27568                 
27569                 var targetWidth = this.minWidth - 2 * x;
27570                 var targetHeight = this.minHeight - 2 * y;
27571                 
27572                 var scale = 1;
27573                 
27574                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27575                     scale = targetWidth / width;
27576                 }
27577                 
27578                 if(x > 0 && y == 0){
27579                     scale = targetHeight / height;
27580                 }
27581                 
27582                 if(x > 0 && y > 0){
27583                     scale = targetWidth / width;
27584                     
27585                     if(width < height){
27586                         scale = targetHeight / height;
27587                     }
27588                 }
27589                 
27590                 context.scale(scale, scale);
27591                 
27592                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27593                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27594
27595                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27596                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27597
27598                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27599                 
27600                 break;
27601             case 90 : 
27602                 
27603                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27604                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27605                 
27606                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27607                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27608                 
27609                 var targetWidth = this.minWidth - 2 * x;
27610                 var targetHeight = this.minHeight - 2 * y;
27611                 
27612                 var scale = 1;
27613                 
27614                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27615                     scale = targetWidth / width;
27616                 }
27617                 
27618                 if(x > 0 && y == 0){
27619                     scale = targetHeight / height;
27620                 }
27621                 
27622                 if(x > 0 && y > 0){
27623                     scale = targetWidth / width;
27624                     
27625                     if(width < height){
27626                         scale = targetHeight / height;
27627                     }
27628                 }
27629                 
27630                 context.scale(scale, scale);
27631                 
27632                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27633                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27634
27635                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27636                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27637                 
27638                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27639                 
27640                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27641                 
27642                 break;
27643             case 180 :
27644                 
27645                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27646                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27647                 
27648                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27649                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27650                 
27651                 var targetWidth = this.minWidth - 2 * x;
27652                 var targetHeight = this.minHeight - 2 * y;
27653                 
27654                 var scale = 1;
27655                 
27656                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27657                     scale = targetWidth / width;
27658                 }
27659                 
27660                 if(x > 0 && y == 0){
27661                     scale = targetHeight / height;
27662                 }
27663                 
27664                 if(x > 0 && y > 0){
27665                     scale = targetWidth / width;
27666                     
27667                     if(width < height){
27668                         scale = targetHeight / height;
27669                     }
27670                 }
27671                 
27672                 context.scale(scale, scale);
27673                 
27674                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27675                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27676
27677                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27678                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27679
27680                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27681                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27682                 
27683                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27684                 
27685                 break;
27686             case 270 :
27687                 
27688                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27689                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27690                 
27691                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27692                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27693                 
27694                 var targetWidth = this.minWidth - 2 * x;
27695                 var targetHeight = this.minHeight - 2 * y;
27696                 
27697                 var scale = 1;
27698                 
27699                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27700                     scale = targetWidth / width;
27701                 }
27702                 
27703                 if(x > 0 && y == 0){
27704                     scale = targetHeight / height;
27705                 }
27706                 
27707                 if(x > 0 && y > 0){
27708                     scale = targetWidth / width;
27709                     
27710                     if(width < height){
27711                         scale = targetHeight / height;
27712                     }
27713                 }
27714                 
27715                 context.scale(scale, scale);
27716                 
27717                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27718                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27719
27720                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27721                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27722                 
27723                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27724                 
27725                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27726                 
27727                 break;
27728             default : 
27729                 break;
27730         }
27731         
27732         this.cropData = canvas.toDataURL(this.cropType);
27733         
27734         if(this.fireEvent('crop', this, this.cropData) !== false){
27735             this.process(this.file, this.cropData);
27736         }
27737         
27738         return;
27739         
27740     },
27741     
27742     setThumbBoxSize : function()
27743     {
27744         var width, height;
27745         
27746         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27747             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27748             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27749             
27750             this.minWidth = width;
27751             this.minHeight = height;
27752             
27753             if(this.rotate == 90 || this.rotate == 270){
27754                 this.minWidth = height;
27755                 this.minHeight = width;
27756             }
27757         }
27758         
27759         height = 300;
27760         width = Math.ceil(this.minWidth * height / this.minHeight);
27761         
27762         if(this.minWidth > this.minHeight){
27763             width = 300;
27764             height = Math.ceil(this.minHeight * width / this.minWidth);
27765         }
27766         
27767         this.thumbEl.setStyle({
27768             width : width + 'px',
27769             height : height + 'px'
27770         });
27771
27772         return;
27773             
27774     },
27775     
27776     setThumbBoxPosition : function()
27777     {
27778         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27779         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27780         
27781         this.thumbEl.setLeft(x);
27782         this.thumbEl.setTop(y);
27783         
27784     },
27785     
27786     baseRotateLevel : function()
27787     {
27788         this.baseRotate = 1;
27789         
27790         if(
27791                 typeof(this.exif) != 'undefined' &&
27792                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27793                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27794         ){
27795             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27796         }
27797         
27798         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27799         
27800     },
27801     
27802     baseScaleLevel : function()
27803     {
27804         var width, height;
27805         
27806         if(this.isDocument){
27807             
27808             if(this.baseRotate == 6 || this.baseRotate == 8){
27809             
27810                 height = this.thumbEl.getHeight();
27811                 this.baseScale = height / this.imageEl.OriginWidth;
27812
27813                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27814                     width = this.thumbEl.getWidth();
27815                     this.baseScale = width / this.imageEl.OriginHeight;
27816                 }
27817
27818                 return;
27819             }
27820
27821             height = this.thumbEl.getHeight();
27822             this.baseScale = height / this.imageEl.OriginHeight;
27823
27824             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27825                 width = this.thumbEl.getWidth();
27826                 this.baseScale = width / this.imageEl.OriginWidth;
27827             }
27828
27829             return;
27830         }
27831         
27832         if(this.baseRotate == 6 || this.baseRotate == 8){
27833             
27834             width = this.thumbEl.getHeight();
27835             this.baseScale = width / this.imageEl.OriginHeight;
27836             
27837             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27838                 height = this.thumbEl.getWidth();
27839                 this.baseScale = height / this.imageEl.OriginHeight;
27840             }
27841             
27842             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27843                 height = this.thumbEl.getWidth();
27844                 this.baseScale = height / this.imageEl.OriginHeight;
27845                 
27846                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27847                     width = this.thumbEl.getHeight();
27848                     this.baseScale = width / this.imageEl.OriginWidth;
27849                 }
27850             }
27851             
27852             return;
27853         }
27854         
27855         width = this.thumbEl.getWidth();
27856         this.baseScale = width / this.imageEl.OriginWidth;
27857         
27858         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27859             height = this.thumbEl.getHeight();
27860             this.baseScale = height / this.imageEl.OriginHeight;
27861         }
27862         
27863         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27864             
27865             height = this.thumbEl.getHeight();
27866             this.baseScale = height / this.imageEl.OriginHeight;
27867             
27868             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27869                 width = this.thumbEl.getWidth();
27870                 this.baseScale = width / this.imageEl.OriginWidth;
27871             }
27872             
27873         }
27874         
27875         return;
27876     },
27877     
27878     getScaleLevel : function()
27879     {
27880         return this.baseScale * Math.pow(1.1, this.scale);
27881     },
27882     
27883     onTouchStart : function(e)
27884     {
27885         if(!this.canvasLoaded){
27886             this.beforeSelectFile(e);
27887             return;
27888         }
27889         
27890         var touches = e.browserEvent.touches;
27891         
27892         if(!touches){
27893             return;
27894         }
27895         
27896         if(touches.length == 1){
27897             this.onMouseDown(e);
27898             return;
27899         }
27900         
27901         if(touches.length != 2){
27902             return;
27903         }
27904         
27905         var coords = [];
27906         
27907         for(var i = 0, finger; finger = touches[i]; i++){
27908             coords.push(finger.pageX, finger.pageY);
27909         }
27910         
27911         var x = Math.pow(coords[0] - coords[2], 2);
27912         var y = Math.pow(coords[1] - coords[3], 2);
27913         
27914         this.startDistance = Math.sqrt(x + y);
27915         
27916         this.startScale = this.scale;
27917         
27918         this.pinching = true;
27919         this.dragable = false;
27920         
27921     },
27922     
27923     onTouchMove : function(e)
27924     {
27925         if(!this.pinching && !this.dragable){
27926             return;
27927         }
27928         
27929         var touches = e.browserEvent.touches;
27930         
27931         if(!touches){
27932             return;
27933         }
27934         
27935         if(this.dragable){
27936             this.onMouseMove(e);
27937             return;
27938         }
27939         
27940         var coords = [];
27941         
27942         for(var i = 0, finger; finger = touches[i]; i++){
27943             coords.push(finger.pageX, finger.pageY);
27944         }
27945         
27946         var x = Math.pow(coords[0] - coords[2], 2);
27947         var y = Math.pow(coords[1] - coords[3], 2);
27948         
27949         this.endDistance = Math.sqrt(x + y);
27950         
27951         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27952         
27953         if(!this.zoomable()){
27954             this.scale = this.startScale;
27955             return;
27956         }
27957         
27958         this.draw();
27959         
27960     },
27961     
27962     onTouchEnd : function(e)
27963     {
27964         this.pinching = false;
27965         this.dragable = false;
27966         
27967     },
27968     
27969     process : function(file, crop)
27970     {
27971         if(this.loadMask){
27972             this.maskEl.mask(this.loadingText);
27973         }
27974         
27975         this.xhr = new XMLHttpRequest();
27976         
27977         file.xhr = this.xhr;
27978
27979         this.xhr.open(this.method, this.url, true);
27980         
27981         var headers = {
27982             "Accept": "application/json",
27983             "Cache-Control": "no-cache",
27984             "X-Requested-With": "XMLHttpRequest"
27985         };
27986         
27987         for (var headerName in headers) {
27988             var headerValue = headers[headerName];
27989             if (headerValue) {
27990                 this.xhr.setRequestHeader(headerName, headerValue);
27991             }
27992         }
27993         
27994         var _this = this;
27995         
27996         this.xhr.onload = function()
27997         {
27998             _this.xhrOnLoad(_this.xhr);
27999         }
28000         
28001         this.xhr.onerror = function()
28002         {
28003             _this.xhrOnError(_this.xhr);
28004         }
28005         
28006         var formData = new FormData();
28007
28008         formData.append('returnHTML', 'NO');
28009         
28010         if(crop){
28011             formData.append('crop', crop);
28012         }
28013         
28014         if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28015             formData.append(this.paramName, file, file.name);
28016         }
28017         
28018         if(typeof(file.filename) != 'undefined'){
28019             formData.append('filename', file.filename);
28020         }
28021         
28022         if(typeof(file.mimetype) != 'undefined'){
28023             formData.append('mimetype', file.mimetype);
28024         }
28025         
28026         if(this.fireEvent('arrange', this, formData) != false){
28027             this.xhr.send(formData);
28028         };
28029     },
28030     
28031     xhrOnLoad : function(xhr)
28032     {
28033         if(this.loadMask){
28034             this.maskEl.unmask();
28035         }
28036         
28037         if (xhr.readyState !== 4) {
28038             this.fireEvent('exception', this, xhr);
28039             return;
28040         }
28041
28042         var response = Roo.decode(xhr.responseText);
28043         
28044         if(!response.success){
28045             this.fireEvent('exception', this, xhr);
28046             return;
28047         }
28048         
28049         var response = Roo.decode(xhr.responseText);
28050         
28051         this.fireEvent('upload', this, response);
28052         
28053     },
28054     
28055     xhrOnError : function()
28056     {
28057         if(this.loadMask){
28058             this.maskEl.unmask();
28059         }
28060         
28061         Roo.log('xhr on error');
28062         
28063         var response = Roo.decode(xhr.responseText);
28064           
28065         Roo.log(response);
28066         
28067     },
28068     
28069     prepare : function(file)
28070     {   
28071         if(this.loadMask){
28072             this.maskEl.mask(this.loadingText);
28073         }
28074         
28075         this.file = false;
28076         this.exif = {};
28077         
28078         if(typeof(file) === 'string'){
28079             this.loadCanvas(file);
28080             return;
28081         }
28082         
28083         if(!file || !this.urlAPI){
28084             return;
28085         }
28086         
28087         this.file = file;
28088         this.cropType = file.type;
28089         
28090         var _this = this;
28091         
28092         if(this.fireEvent('prepare', this, this.file) != false){
28093             
28094             var reader = new FileReader();
28095             
28096             reader.onload = function (e) {
28097                 if (e.target.error) {
28098                     Roo.log(e.target.error);
28099                     return;
28100                 }
28101                 
28102                 var buffer = e.target.result,
28103                     dataView = new DataView(buffer),
28104                     offset = 2,
28105                     maxOffset = dataView.byteLength - 4,
28106                     markerBytes,
28107                     markerLength;
28108                 
28109                 if (dataView.getUint16(0) === 0xffd8) {
28110                     while (offset < maxOffset) {
28111                         markerBytes = dataView.getUint16(offset);
28112                         
28113                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28114                             markerLength = dataView.getUint16(offset + 2) + 2;
28115                             if (offset + markerLength > dataView.byteLength) {
28116                                 Roo.log('Invalid meta data: Invalid segment size.');
28117                                 break;
28118                             }
28119                             
28120                             if(markerBytes == 0xffe1){
28121                                 _this.parseExifData(
28122                                     dataView,
28123                                     offset,
28124                                     markerLength
28125                                 );
28126                             }
28127                             
28128                             offset += markerLength;
28129                             
28130                             continue;
28131                         }
28132                         
28133                         break;
28134                     }
28135                     
28136                 }
28137                 
28138                 var url = _this.urlAPI.createObjectURL(_this.file);
28139                 
28140                 _this.loadCanvas(url);
28141                 
28142                 return;
28143             }
28144             
28145             reader.readAsArrayBuffer(this.file);
28146             
28147         }
28148         
28149     },
28150     
28151     parseExifData : function(dataView, offset, length)
28152     {
28153         var tiffOffset = offset + 10,
28154             littleEndian,
28155             dirOffset;
28156     
28157         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28158             // No Exif data, might be XMP data instead
28159             return;
28160         }
28161         
28162         // Check for the ASCII code for "Exif" (0x45786966):
28163         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28164             // No Exif data, might be XMP data instead
28165             return;
28166         }
28167         if (tiffOffset + 8 > dataView.byteLength) {
28168             Roo.log('Invalid Exif data: Invalid segment size.');
28169             return;
28170         }
28171         // Check for the two null bytes:
28172         if (dataView.getUint16(offset + 8) !== 0x0000) {
28173             Roo.log('Invalid Exif data: Missing byte alignment offset.');
28174             return;
28175         }
28176         // Check the byte alignment:
28177         switch (dataView.getUint16(tiffOffset)) {
28178         case 0x4949:
28179             littleEndian = true;
28180             break;
28181         case 0x4D4D:
28182             littleEndian = false;
28183             break;
28184         default:
28185             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28186             return;
28187         }
28188         // Check for the TIFF tag marker (0x002A):
28189         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28190             Roo.log('Invalid Exif data: Missing TIFF marker.');
28191             return;
28192         }
28193         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28194         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28195         
28196         this.parseExifTags(
28197             dataView,
28198             tiffOffset,
28199             tiffOffset + dirOffset,
28200             littleEndian
28201         );
28202     },
28203     
28204     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28205     {
28206         var tagsNumber,
28207             dirEndOffset,
28208             i;
28209         if (dirOffset + 6 > dataView.byteLength) {
28210             Roo.log('Invalid Exif data: Invalid directory offset.');
28211             return;
28212         }
28213         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28214         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28215         if (dirEndOffset + 4 > dataView.byteLength) {
28216             Roo.log('Invalid Exif data: Invalid directory size.');
28217             return;
28218         }
28219         for (i = 0; i < tagsNumber; i += 1) {
28220             this.parseExifTag(
28221                 dataView,
28222                 tiffOffset,
28223                 dirOffset + 2 + 12 * i, // tag offset
28224                 littleEndian
28225             );
28226         }
28227         // Return the offset to the next directory:
28228         return dataView.getUint32(dirEndOffset, littleEndian);
28229     },
28230     
28231     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
28232     {
28233         var tag = dataView.getUint16(offset, littleEndian);
28234         
28235         this.exif[tag] = this.getExifValue(
28236             dataView,
28237             tiffOffset,
28238             offset,
28239             dataView.getUint16(offset + 2, littleEndian), // tag type
28240             dataView.getUint32(offset + 4, littleEndian), // tag length
28241             littleEndian
28242         );
28243     },
28244     
28245     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28246     {
28247         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28248             tagSize,
28249             dataOffset,
28250             values,
28251             i,
28252             str,
28253             c;
28254     
28255         if (!tagType) {
28256             Roo.log('Invalid Exif data: Invalid tag type.');
28257             return;
28258         }
28259         
28260         tagSize = tagType.size * length;
28261         // Determine if the value is contained in the dataOffset bytes,
28262         // or if the value at the dataOffset is a pointer to the actual data:
28263         dataOffset = tagSize > 4 ?
28264                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28265         if (dataOffset + tagSize > dataView.byteLength) {
28266             Roo.log('Invalid Exif data: Invalid data offset.');
28267             return;
28268         }
28269         if (length === 1) {
28270             return tagType.getValue(dataView, dataOffset, littleEndian);
28271         }
28272         values = [];
28273         for (i = 0; i < length; i += 1) {
28274             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28275         }
28276         
28277         if (tagType.ascii) {
28278             str = '';
28279             // Concatenate the chars:
28280             for (i = 0; i < values.length; i += 1) {
28281                 c = values[i];
28282                 // Ignore the terminating NULL byte(s):
28283                 if (c === '\u0000') {
28284                     break;
28285                 }
28286                 str += c;
28287             }
28288             return str;
28289         }
28290         return values;
28291     }
28292     
28293 });
28294
28295 Roo.apply(Roo.bootstrap.UploadCropbox, {
28296     tags : {
28297         'Orientation': 0x0112
28298     },
28299     
28300     Orientation: {
28301             1: 0, //'top-left',
28302 //            2: 'top-right',
28303             3: 180, //'bottom-right',
28304 //            4: 'bottom-left',
28305 //            5: 'left-top',
28306             6: 90, //'right-top',
28307 //            7: 'right-bottom',
28308             8: 270 //'left-bottom'
28309     },
28310     
28311     exifTagTypes : {
28312         // byte, 8-bit unsigned int:
28313         1: {
28314             getValue: function (dataView, dataOffset) {
28315                 return dataView.getUint8(dataOffset);
28316             },
28317             size: 1
28318         },
28319         // ascii, 8-bit byte:
28320         2: {
28321             getValue: function (dataView, dataOffset) {
28322                 return String.fromCharCode(dataView.getUint8(dataOffset));
28323             },
28324             size: 1,
28325             ascii: true
28326         },
28327         // short, 16 bit int:
28328         3: {
28329             getValue: function (dataView, dataOffset, littleEndian) {
28330                 return dataView.getUint16(dataOffset, littleEndian);
28331             },
28332             size: 2
28333         },
28334         // long, 32 bit int:
28335         4: {
28336             getValue: function (dataView, dataOffset, littleEndian) {
28337                 return dataView.getUint32(dataOffset, littleEndian);
28338             },
28339             size: 4
28340         },
28341         // rational = two long values, first is numerator, second is denominator:
28342         5: {
28343             getValue: function (dataView, dataOffset, littleEndian) {
28344                 return dataView.getUint32(dataOffset, littleEndian) /
28345                     dataView.getUint32(dataOffset + 4, littleEndian);
28346             },
28347             size: 8
28348         },
28349         // slong, 32 bit signed int:
28350         9: {
28351             getValue: function (dataView, dataOffset, littleEndian) {
28352                 return dataView.getInt32(dataOffset, littleEndian);
28353             },
28354             size: 4
28355         },
28356         // srational, two slongs, first is numerator, second is denominator:
28357         10: {
28358             getValue: function (dataView, dataOffset, littleEndian) {
28359                 return dataView.getInt32(dataOffset, littleEndian) /
28360                     dataView.getInt32(dataOffset + 4, littleEndian);
28361             },
28362             size: 8
28363         }
28364     },
28365     
28366     footer : {
28367         STANDARD : [
28368             {
28369                 tag : 'div',
28370                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28371                 action : 'rotate-left',
28372                 cn : [
28373                     {
28374                         tag : 'button',
28375                         cls : 'btn btn-default',
28376                         html : '<i class="fa fa-undo"></i>'
28377                     }
28378                 ]
28379             },
28380             {
28381                 tag : 'div',
28382                 cls : 'btn-group roo-upload-cropbox-picture',
28383                 action : 'picture',
28384                 cn : [
28385                     {
28386                         tag : 'button',
28387                         cls : 'btn btn-default',
28388                         html : '<i class="fa fa-picture-o"></i>'
28389                     }
28390                 ]
28391             },
28392             {
28393                 tag : 'div',
28394                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28395                 action : 'rotate-right',
28396                 cn : [
28397                     {
28398                         tag : 'button',
28399                         cls : 'btn btn-default',
28400                         html : '<i class="fa fa-repeat"></i>'
28401                     }
28402                 ]
28403             }
28404         ],
28405         DOCUMENT : [
28406             {
28407                 tag : 'div',
28408                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28409                 action : 'rotate-left',
28410                 cn : [
28411                     {
28412                         tag : 'button',
28413                         cls : 'btn btn-default',
28414                         html : '<i class="fa fa-undo"></i>'
28415                     }
28416                 ]
28417             },
28418             {
28419                 tag : 'div',
28420                 cls : 'btn-group roo-upload-cropbox-download',
28421                 action : 'download',
28422                 cn : [
28423                     {
28424                         tag : 'button',
28425                         cls : 'btn btn-default',
28426                         html : '<i class="fa fa-download"></i>'
28427                     }
28428                 ]
28429             },
28430             {
28431                 tag : 'div',
28432                 cls : 'btn-group roo-upload-cropbox-crop',
28433                 action : 'crop',
28434                 cn : [
28435                     {
28436                         tag : 'button',
28437                         cls : 'btn btn-default',
28438                         html : '<i class="fa fa-crop"></i>'
28439                     }
28440                 ]
28441             },
28442             {
28443                 tag : 'div',
28444                 cls : 'btn-group roo-upload-cropbox-trash',
28445                 action : 'trash',
28446                 cn : [
28447                     {
28448                         tag : 'button',
28449                         cls : 'btn btn-default',
28450                         html : '<i class="fa fa-trash"></i>'
28451                     }
28452                 ]
28453             },
28454             {
28455                 tag : 'div',
28456                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28457                 action : 'rotate-right',
28458                 cn : [
28459                     {
28460                         tag : 'button',
28461                         cls : 'btn btn-default',
28462                         html : '<i class="fa fa-repeat"></i>'
28463                     }
28464                 ]
28465             }
28466         ],
28467         ROTATOR : [
28468             {
28469                 tag : 'div',
28470                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28471                 action : 'rotate-left',
28472                 cn : [
28473                     {
28474                         tag : 'button',
28475                         cls : 'btn btn-default',
28476                         html : '<i class="fa fa-undo"></i>'
28477                     }
28478                 ]
28479             },
28480             {
28481                 tag : 'div',
28482                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28483                 action : 'rotate-right',
28484                 cn : [
28485                     {
28486                         tag : 'button',
28487                         cls : 'btn btn-default',
28488                         html : '<i class="fa fa-repeat"></i>'
28489                     }
28490                 ]
28491             }
28492         ]
28493     }
28494 });
28495
28496 /*
28497 * Licence: LGPL
28498 */
28499
28500 /**
28501  * @class Roo.bootstrap.DocumentManager
28502  * @extends Roo.bootstrap.Component
28503  * Bootstrap DocumentManager class
28504  * @cfg {String} paramName default 'imageUpload'
28505  * @cfg {String} toolTipName default 'filename'
28506  * @cfg {String} method default POST
28507  * @cfg {String} url action url
28508  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28509  * @cfg {Boolean} multiple multiple upload default true
28510  * @cfg {Number} thumbSize default 300
28511  * @cfg {String} fieldLabel
28512  * @cfg {Number} labelWidth default 4
28513  * @cfg {String} labelAlign (left|top) default left
28514  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28515 * @cfg {Number} labellg set the width of label (1-12)
28516  * @cfg {Number} labelmd set the width of label (1-12)
28517  * @cfg {Number} labelsm set the width of label (1-12)
28518  * @cfg {Number} labelxs set the width of label (1-12)
28519  * 
28520  * @constructor
28521  * Create a new DocumentManager
28522  * @param {Object} config The config object
28523  */
28524
28525 Roo.bootstrap.DocumentManager = function(config){
28526     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28527     
28528     this.files = [];
28529     this.delegates = [];
28530     
28531     this.addEvents({
28532         /**
28533          * @event initial
28534          * Fire when initial the DocumentManager
28535          * @param {Roo.bootstrap.DocumentManager} this
28536          */
28537         "initial" : true,
28538         /**
28539          * @event inspect
28540          * inspect selected file
28541          * @param {Roo.bootstrap.DocumentManager} this
28542          * @param {File} file
28543          */
28544         "inspect" : true,
28545         /**
28546          * @event exception
28547          * Fire when xhr load exception
28548          * @param {Roo.bootstrap.DocumentManager} this
28549          * @param {XMLHttpRequest} xhr
28550          */
28551         "exception" : true,
28552         /**
28553          * @event afterupload
28554          * Fire when xhr load exception
28555          * @param {Roo.bootstrap.DocumentManager} this
28556          * @param {XMLHttpRequest} xhr
28557          */
28558         "afterupload" : true,
28559         /**
28560          * @event prepare
28561          * prepare the form data
28562          * @param {Roo.bootstrap.DocumentManager} this
28563          * @param {Object} formData
28564          */
28565         "prepare" : true,
28566         /**
28567          * @event remove
28568          * Fire when remove the file
28569          * @param {Roo.bootstrap.DocumentManager} this
28570          * @param {Object} file
28571          */
28572         "remove" : true,
28573         /**
28574          * @event refresh
28575          * Fire after refresh the file
28576          * @param {Roo.bootstrap.DocumentManager} this
28577          */
28578         "refresh" : true,
28579         /**
28580          * @event click
28581          * Fire after click the image
28582          * @param {Roo.bootstrap.DocumentManager} this
28583          * @param {Object} file
28584          */
28585         "click" : true,
28586         /**
28587          * @event edit
28588          * Fire when upload a image and editable set to true
28589          * @param {Roo.bootstrap.DocumentManager} this
28590          * @param {Object} file
28591          */
28592         "edit" : true,
28593         /**
28594          * @event beforeselectfile
28595          * Fire before select file
28596          * @param {Roo.bootstrap.DocumentManager} this
28597          */
28598         "beforeselectfile" : true,
28599         /**
28600          * @event process
28601          * Fire before process file
28602          * @param {Roo.bootstrap.DocumentManager} this
28603          * @param {Object} file
28604          */
28605         "process" : true,
28606         /**
28607          * @event previewrendered
28608          * Fire when preview rendered
28609          * @param {Roo.bootstrap.DocumentManager} this
28610          * @param {Object} file
28611          */
28612         "previewrendered" : true
28613         
28614     });
28615 };
28616
28617 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
28618     
28619     boxes : 0,
28620     inputName : '',
28621     thumbSize : 300,
28622     multiple : true,
28623     files : false,
28624     method : 'POST',
28625     url : '',
28626     paramName : 'imageUpload',
28627     toolTipName : 'filename',
28628     fieldLabel : '',
28629     labelWidth : 4,
28630     labelAlign : 'left',
28631     editable : true,
28632     delegates : false,
28633     xhr : false, 
28634     
28635     labellg : 0,
28636     labelmd : 0,
28637     labelsm : 0,
28638     labelxs : 0,
28639     
28640     getAutoCreate : function()
28641     {   
28642         var managerWidget = {
28643             tag : 'div',
28644             cls : 'roo-document-manager',
28645             cn : [
28646                 {
28647                     tag : 'input',
28648                     cls : 'roo-document-manager-selector',
28649                     type : 'file'
28650                 },
28651                 {
28652                     tag : 'div',
28653                     cls : 'roo-document-manager-uploader',
28654                     cn : [
28655                         {
28656                             tag : 'div',
28657                             cls : 'roo-document-manager-upload-btn',
28658                             html : '<i class="fa fa-plus"></i>'
28659                         }
28660                     ]
28661                     
28662                 }
28663             ]
28664         };
28665         
28666         var content = [
28667             {
28668                 tag : 'div',
28669                 cls : 'column col-md-12',
28670                 cn : managerWidget
28671             }
28672         ];
28673         
28674         if(this.fieldLabel.length){
28675             
28676             content = [
28677                 {
28678                     tag : 'div',
28679                     cls : 'column col-md-12',
28680                     html : this.fieldLabel
28681                 },
28682                 {
28683                     tag : 'div',
28684                     cls : 'column col-md-12',
28685                     cn : managerWidget
28686                 }
28687             ];
28688
28689             if(this.labelAlign == 'left'){
28690                 content = [
28691                     {
28692                         tag : 'div',
28693                         cls : 'column',
28694                         html : this.fieldLabel
28695                     },
28696                     {
28697                         tag : 'div',
28698                         cls : 'column',
28699                         cn : managerWidget
28700                     }
28701                 ];
28702                 
28703                 if(this.labelWidth > 12){
28704                     content[0].style = "width: " + this.labelWidth + 'px';
28705                 }
28706
28707                 if(this.labelWidth < 13 && this.labelmd == 0){
28708                     this.labelmd = this.labelWidth;
28709                 }
28710
28711                 if(this.labellg > 0){
28712                     content[0].cls += ' col-lg-' + this.labellg;
28713                     content[1].cls += ' col-lg-' + (12 - this.labellg);
28714                 }
28715
28716                 if(this.labelmd > 0){
28717                     content[0].cls += ' col-md-' + this.labelmd;
28718                     content[1].cls += ' col-md-' + (12 - this.labelmd);
28719                 }
28720
28721                 if(this.labelsm > 0){
28722                     content[0].cls += ' col-sm-' + this.labelsm;
28723                     content[1].cls += ' col-sm-' + (12 - this.labelsm);
28724                 }
28725
28726                 if(this.labelxs > 0){
28727                     content[0].cls += ' col-xs-' + this.labelxs;
28728                     content[1].cls += ' col-xs-' + (12 - this.labelxs);
28729                 }
28730                 
28731             }
28732         }
28733         
28734         var cfg = {
28735             tag : 'div',
28736             cls : 'row clearfix',
28737             cn : content
28738         };
28739         
28740         return cfg;
28741         
28742     },
28743     
28744     initEvents : function()
28745     {
28746         this.managerEl = this.el.select('.roo-document-manager', true).first();
28747         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28748         
28749         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28750         this.selectorEl.hide();
28751         
28752         if(this.multiple){
28753             this.selectorEl.attr('multiple', 'multiple');
28754         }
28755         
28756         this.selectorEl.on('change', this.onFileSelected, this);
28757         
28758         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28759         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28760         
28761         this.uploader.on('click', this.onUploaderClick, this);
28762         
28763         this.renderProgressDialog();
28764         
28765         var _this = this;
28766         
28767         window.addEventListener("resize", function() { _this.refresh(); } );
28768         
28769         this.fireEvent('initial', this);
28770     },
28771     
28772     renderProgressDialog : function()
28773     {
28774         var _this = this;
28775         
28776         this.progressDialog = new Roo.bootstrap.Modal({
28777             cls : 'roo-document-manager-progress-dialog',
28778             allow_close : false,
28779             title : '',
28780             buttons : [
28781                 {
28782                     name  :'cancel',
28783                     weight : 'danger',
28784                     html : 'Cancel'
28785                 }
28786             ], 
28787             listeners : { 
28788                 btnclick : function() {
28789                     _this.uploadCancel();
28790                     this.hide();
28791                 }
28792             }
28793         });
28794          
28795         this.progressDialog.render(Roo.get(document.body));
28796          
28797         this.progress = new Roo.bootstrap.Progress({
28798             cls : 'roo-document-manager-progress',
28799             active : true,
28800             striped : true
28801         });
28802         
28803         this.progress.render(this.progressDialog.getChildContainer());
28804         
28805         this.progressBar = new Roo.bootstrap.ProgressBar({
28806             cls : 'roo-document-manager-progress-bar',
28807             aria_valuenow : 0,
28808             aria_valuemin : 0,
28809             aria_valuemax : 12,
28810             panel : 'success'
28811         });
28812         
28813         this.progressBar.render(this.progress.getChildContainer());
28814     },
28815     
28816     onUploaderClick : function(e)
28817     {
28818         e.preventDefault();
28819      
28820         if(this.fireEvent('beforeselectfile', this) != false){
28821             this.selectorEl.dom.click();
28822         }
28823         
28824     },
28825     
28826     onFileSelected : function(e)
28827     {
28828         e.preventDefault();
28829         
28830         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28831             return;
28832         }
28833         
28834         Roo.each(this.selectorEl.dom.files, function(file){
28835             if(this.fireEvent('inspect', this, file) != false){
28836                 this.files.push(file);
28837             }
28838         }, this);
28839         
28840         this.queue();
28841         
28842     },
28843     
28844     queue : function()
28845     {
28846         this.selectorEl.dom.value = '';
28847         
28848         if(!this.files || !this.files.length){
28849             return;
28850         }
28851         
28852         if(this.boxes > 0 && this.files.length > this.boxes){
28853             this.files = this.files.slice(0, this.boxes);
28854         }
28855         
28856         this.uploader.show();
28857         
28858         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28859             this.uploader.hide();
28860         }
28861         
28862         var _this = this;
28863         
28864         var files = [];
28865         
28866         var docs = [];
28867         
28868         Roo.each(this.files, function(file){
28869             
28870             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28871                 var f = this.renderPreview(file);
28872                 files.push(f);
28873                 return;
28874             }
28875             
28876             if(file.type.indexOf('image') != -1){
28877                 this.delegates.push(
28878                     (function(){
28879                         _this.process(file);
28880                     }).createDelegate(this)
28881                 );
28882         
28883                 return;
28884             }
28885             
28886             docs.push(
28887                 (function(){
28888                     _this.process(file);
28889                 }).createDelegate(this)
28890             );
28891             
28892         }, this);
28893         
28894         this.files = files;
28895         
28896         this.delegates = this.delegates.concat(docs);
28897         
28898         if(!this.delegates.length){
28899             this.refresh();
28900             return;
28901         }
28902         
28903         this.progressBar.aria_valuemax = this.delegates.length;
28904         
28905         this.arrange();
28906         
28907         return;
28908     },
28909     
28910     arrange : function()
28911     {
28912         if(!this.delegates.length){
28913             this.progressDialog.hide();
28914             this.refresh();
28915             return;
28916         }
28917         
28918         var delegate = this.delegates.shift();
28919         
28920         this.progressDialog.show();
28921         
28922         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28923         
28924         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28925         
28926         delegate();
28927     },
28928     
28929     refresh : function()
28930     {
28931         this.uploader.show();
28932         
28933         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28934             this.uploader.hide();
28935         }
28936         
28937         Roo.isTouch ? this.closable(false) : this.closable(true);
28938         
28939         this.fireEvent('refresh', this);
28940     },
28941     
28942     onRemove : function(e, el, o)
28943     {
28944         e.preventDefault();
28945         
28946         this.fireEvent('remove', this, o);
28947         
28948     },
28949     
28950     remove : function(o)
28951     {
28952         var files = [];
28953         
28954         Roo.each(this.files, function(file){
28955             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28956                 files.push(file);
28957                 return;
28958             }
28959
28960             o.target.remove();
28961
28962         }, this);
28963         
28964         this.files = files;
28965         
28966         this.refresh();
28967     },
28968     
28969     clear : function()
28970     {
28971         Roo.each(this.files, function(file){
28972             if(!file.target){
28973                 return;
28974             }
28975             
28976             file.target.remove();
28977
28978         }, this);
28979         
28980         this.files = [];
28981         
28982         this.refresh();
28983     },
28984     
28985     onClick : function(e, el, o)
28986     {
28987         e.preventDefault();
28988         
28989         this.fireEvent('click', this, o);
28990         
28991     },
28992     
28993     closable : function(closable)
28994     {
28995         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28996             
28997             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28998             
28999             if(closable){
29000                 el.show();
29001                 return;
29002             }
29003             
29004             el.hide();
29005             
29006         }, this);
29007     },
29008     
29009     xhrOnLoad : function(xhr)
29010     {
29011         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29012             el.remove();
29013         }, this);
29014         
29015         if (xhr.readyState !== 4) {
29016             this.arrange();
29017             this.fireEvent('exception', this, xhr);
29018             return;
29019         }
29020
29021         var response = Roo.decode(xhr.responseText);
29022         
29023         if(!response.success){
29024             this.arrange();
29025             this.fireEvent('exception', this, xhr);
29026             return;
29027         }
29028         
29029         var file = this.renderPreview(response.data);
29030         
29031         this.files.push(file);
29032         
29033         this.arrange();
29034         
29035         this.fireEvent('afterupload', this, xhr);
29036         
29037     },
29038     
29039     xhrOnError : function(xhr)
29040     {
29041         Roo.log('xhr on error');
29042         
29043         var response = Roo.decode(xhr.responseText);
29044           
29045         Roo.log(response);
29046         
29047         this.arrange();
29048     },
29049     
29050     process : function(file)
29051     {
29052         if(this.fireEvent('process', this, file) !== false){
29053             if(this.editable && file.type.indexOf('image') != -1){
29054                 this.fireEvent('edit', this, file);
29055                 return;
29056             }
29057
29058             this.uploadStart(file, false);
29059
29060             return;
29061         }
29062         
29063     },
29064     
29065     uploadStart : function(file, crop)
29066     {
29067         this.xhr = new XMLHttpRequest();
29068         
29069         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29070             this.arrange();
29071             return;
29072         }
29073         
29074         file.xhr = this.xhr;
29075             
29076         this.managerEl.createChild({
29077             tag : 'div',
29078             cls : 'roo-document-manager-loading',
29079             cn : [
29080                 {
29081                     tag : 'div',
29082                     tooltip : file.name,
29083                     cls : 'roo-document-manager-thumb',
29084                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29085                 }
29086             ]
29087
29088         });
29089
29090         this.xhr.open(this.method, this.url, true);
29091         
29092         var headers = {
29093             "Accept": "application/json",
29094             "Cache-Control": "no-cache",
29095             "X-Requested-With": "XMLHttpRequest"
29096         };
29097         
29098         for (var headerName in headers) {
29099             var headerValue = headers[headerName];
29100             if (headerValue) {
29101                 this.xhr.setRequestHeader(headerName, headerValue);
29102             }
29103         }
29104         
29105         var _this = this;
29106         
29107         this.xhr.onload = function()
29108         {
29109             _this.xhrOnLoad(_this.xhr);
29110         }
29111         
29112         this.xhr.onerror = function()
29113         {
29114             _this.xhrOnError(_this.xhr);
29115         }
29116         
29117         var formData = new FormData();
29118
29119         formData.append('returnHTML', 'NO');
29120         
29121         if(crop){
29122             formData.append('crop', crop);
29123         }
29124         
29125         formData.append(this.paramName, file, file.name);
29126         
29127         var options = {
29128             file : file, 
29129             manually : false
29130         };
29131         
29132         if(this.fireEvent('prepare', this, formData, options) != false){
29133             
29134             if(options.manually){
29135                 return;
29136             }
29137             
29138             this.xhr.send(formData);
29139             return;
29140         };
29141         
29142         this.uploadCancel();
29143     },
29144     
29145     uploadCancel : function()
29146     {
29147         if (this.xhr) {
29148             this.xhr.abort();
29149         }
29150         
29151         this.delegates = [];
29152         
29153         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29154             el.remove();
29155         }, this);
29156         
29157         this.arrange();
29158     },
29159     
29160     renderPreview : function(file)
29161     {
29162         if(typeof(file.target) != 'undefined' && file.target){
29163             return file;
29164         }
29165         
29166         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29167         
29168         var previewEl = this.managerEl.createChild({
29169             tag : 'div',
29170             cls : 'roo-document-manager-preview',
29171             cn : [
29172                 {
29173                     tag : 'div',
29174                     tooltip : file[this.toolTipName],
29175                     cls : 'roo-document-manager-thumb',
29176                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29177                 },
29178                 {
29179                     tag : 'button',
29180                     cls : 'close',
29181                     html : '<i class="fa fa-times-circle"></i>'
29182                 }
29183             ]
29184         });
29185
29186         var close = previewEl.select('button.close', true).first();
29187
29188         close.on('click', this.onRemove, this, file);
29189
29190         file.target = previewEl;
29191
29192         var image = previewEl.select('img', true).first();
29193         
29194         var _this = this;
29195         
29196         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29197         
29198         image.on('click', this.onClick, this, file);
29199         
29200         this.fireEvent('previewrendered', this, file);
29201         
29202         return file;
29203         
29204     },
29205     
29206     onPreviewLoad : function(file, image)
29207     {
29208         if(typeof(file.target) == 'undefined' || !file.target){
29209             return;
29210         }
29211         
29212         var width = image.dom.naturalWidth || image.dom.width;
29213         var height = image.dom.naturalHeight || image.dom.height;
29214         
29215         if(width > height){
29216             file.target.addClass('wide');
29217             return;
29218         }
29219         
29220         file.target.addClass('tall');
29221         return;
29222         
29223     },
29224     
29225     uploadFromSource : function(file, crop)
29226     {
29227         this.xhr = new XMLHttpRequest();
29228         
29229         this.managerEl.createChild({
29230             tag : 'div',
29231             cls : 'roo-document-manager-loading',
29232             cn : [
29233                 {
29234                     tag : 'div',
29235                     tooltip : file.name,
29236                     cls : 'roo-document-manager-thumb',
29237                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29238                 }
29239             ]
29240
29241         });
29242
29243         this.xhr.open(this.method, this.url, true);
29244         
29245         var headers = {
29246             "Accept": "application/json",
29247             "Cache-Control": "no-cache",
29248             "X-Requested-With": "XMLHttpRequest"
29249         };
29250         
29251         for (var headerName in headers) {
29252             var headerValue = headers[headerName];
29253             if (headerValue) {
29254                 this.xhr.setRequestHeader(headerName, headerValue);
29255             }
29256         }
29257         
29258         var _this = this;
29259         
29260         this.xhr.onload = function()
29261         {
29262             _this.xhrOnLoad(_this.xhr);
29263         }
29264         
29265         this.xhr.onerror = function()
29266         {
29267             _this.xhrOnError(_this.xhr);
29268         }
29269         
29270         var formData = new FormData();
29271
29272         formData.append('returnHTML', 'NO');
29273         
29274         formData.append('crop', crop);
29275         
29276         if(typeof(file.filename) != 'undefined'){
29277             formData.append('filename', file.filename);
29278         }
29279         
29280         if(typeof(file.mimetype) != 'undefined'){
29281             formData.append('mimetype', file.mimetype);
29282         }
29283         
29284         Roo.log(formData);
29285         
29286         if(this.fireEvent('prepare', this, formData) != false){
29287             this.xhr.send(formData);
29288         };
29289     }
29290 });
29291
29292 /*
29293 * Licence: LGPL
29294 */
29295
29296 /**
29297  * @class Roo.bootstrap.DocumentViewer
29298  * @extends Roo.bootstrap.Component
29299  * Bootstrap DocumentViewer class
29300  * @cfg {Boolean} showDownload (true|false) show download button (default true)
29301  * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29302  * 
29303  * @constructor
29304  * Create a new DocumentViewer
29305  * @param {Object} config The config object
29306  */
29307
29308 Roo.bootstrap.DocumentViewer = function(config){
29309     Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29310     
29311     this.addEvents({
29312         /**
29313          * @event initial
29314          * Fire after initEvent
29315          * @param {Roo.bootstrap.DocumentViewer} this
29316          */
29317         "initial" : true,
29318         /**
29319          * @event click
29320          * Fire after click
29321          * @param {Roo.bootstrap.DocumentViewer} this
29322          */
29323         "click" : true,
29324         /**
29325          * @event download
29326          * Fire after download button
29327          * @param {Roo.bootstrap.DocumentViewer} this
29328          */
29329         "download" : true,
29330         /**
29331          * @event trash
29332          * Fire after trash button
29333          * @param {Roo.bootstrap.DocumentViewer} this
29334          */
29335         "trash" : true
29336         
29337     });
29338 };
29339
29340 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
29341     
29342     showDownload : true,
29343     
29344     showTrash : true,
29345     
29346     getAutoCreate : function()
29347     {
29348         var cfg = {
29349             tag : 'div',
29350             cls : 'roo-document-viewer',
29351             cn : [
29352                 {
29353                     tag : 'div',
29354                     cls : 'roo-document-viewer-body',
29355                     cn : [
29356                         {
29357                             tag : 'div',
29358                             cls : 'roo-document-viewer-thumb',
29359                             cn : [
29360                                 {
29361                                     tag : 'img',
29362                                     cls : 'roo-document-viewer-image'
29363                                 }
29364                             ]
29365                         }
29366                     ]
29367                 },
29368                 {
29369                     tag : 'div',
29370                     cls : 'roo-document-viewer-footer',
29371                     cn : {
29372                         tag : 'div',
29373                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29374                         cn : [
29375                             {
29376                                 tag : 'div',
29377                                 cls : 'btn-group roo-document-viewer-download',
29378                                 cn : [
29379                                     {
29380                                         tag : 'button',
29381                                         cls : 'btn btn-default',
29382                                         html : '<i class="fa fa-download"></i>'
29383                                     }
29384                                 ]
29385                             },
29386                             {
29387                                 tag : 'div',
29388                                 cls : 'btn-group roo-document-viewer-trash',
29389                                 cn : [
29390                                     {
29391                                         tag : 'button',
29392                                         cls : 'btn btn-default',
29393                                         html : '<i class="fa fa-trash"></i>'
29394                                     }
29395                                 ]
29396                             }
29397                         ]
29398                     }
29399                 }
29400             ]
29401         };
29402         
29403         return cfg;
29404     },
29405     
29406     initEvents : function()
29407     {
29408         this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29409         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29410         
29411         this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29412         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29413         
29414         this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29415         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29416         
29417         this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29418         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29419         
29420         this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29421         this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29422         
29423         this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29424         this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29425         
29426         this.bodyEl.on('click', this.onClick, this);
29427         this.downloadBtn.on('click', this.onDownload, this);
29428         this.trashBtn.on('click', this.onTrash, this);
29429         
29430         this.downloadBtn.hide();
29431         this.trashBtn.hide();
29432         
29433         if(this.showDownload){
29434             this.downloadBtn.show();
29435         }
29436         
29437         if(this.showTrash){
29438             this.trashBtn.show();
29439         }
29440         
29441         if(!this.showDownload && !this.showTrash) {
29442             this.footerEl.hide();
29443         }
29444         
29445     },
29446     
29447     initial : function()
29448     {
29449         this.fireEvent('initial', this);
29450         
29451     },
29452     
29453     onClick : function(e)
29454     {
29455         e.preventDefault();
29456         
29457         this.fireEvent('click', this);
29458     },
29459     
29460     onDownload : function(e)
29461     {
29462         e.preventDefault();
29463         
29464         this.fireEvent('download', this);
29465     },
29466     
29467     onTrash : function(e)
29468     {
29469         e.preventDefault();
29470         
29471         this.fireEvent('trash', this);
29472     }
29473     
29474 });
29475 /*
29476  * - LGPL
29477  *
29478  * nav progress bar
29479  * 
29480  */
29481
29482 /**
29483  * @class Roo.bootstrap.NavProgressBar
29484  * @extends Roo.bootstrap.Component
29485  * Bootstrap NavProgressBar class
29486  * 
29487  * @constructor
29488  * Create a new nav progress bar
29489  * @param {Object} config The config object
29490  */
29491
29492 Roo.bootstrap.NavProgressBar = function(config){
29493     Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29494
29495     this.bullets = this.bullets || [];
29496    
29497 //    Roo.bootstrap.NavProgressBar.register(this);
29498      this.addEvents({
29499         /**
29500              * @event changed
29501              * Fires when the active item changes
29502              * @param {Roo.bootstrap.NavProgressBar} this
29503              * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29504              * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
29505          */
29506         'changed': true
29507      });
29508     
29509 };
29510
29511 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
29512     
29513     bullets : [],
29514     barItems : [],
29515     
29516     getAutoCreate : function()
29517     {
29518         var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29519         
29520         cfg = {
29521             tag : 'div',
29522             cls : 'roo-navigation-bar-group',
29523             cn : [
29524                 {
29525                     tag : 'div',
29526                     cls : 'roo-navigation-top-bar'
29527                 },
29528                 {
29529                     tag : 'div',
29530                     cls : 'roo-navigation-bullets-bar',
29531                     cn : [
29532                         {
29533                             tag : 'ul',
29534                             cls : 'roo-navigation-bar'
29535                         }
29536                     ]
29537                 },
29538                 
29539                 {
29540                     tag : 'div',
29541                     cls : 'roo-navigation-bottom-bar'
29542                 }
29543             ]
29544             
29545         };
29546         
29547         return cfg;
29548         
29549     },
29550     
29551     initEvents: function() 
29552     {
29553         
29554     },
29555     
29556     onRender : function(ct, position) 
29557     {
29558         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29559         
29560         if(this.bullets.length){
29561             Roo.each(this.bullets, function(b){
29562                this.addItem(b);
29563             }, this);
29564         }
29565         
29566         this.format();
29567         
29568     },
29569     
29570     addItem : function(cfg)
29571     {
29572         var item = new Roo.bootstrap.NavProgressItem(cfg);
29573         
29574         item.parentId = this.id;
29575         item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29576         
29577         if(cfg.html){
29578             var top = new Roo.bootstrap.Element({
29579                 tag : 'div',
29580                 cls : 'roo-navigation-bar-text'
29581             });
29582             
29583             var bottom = new Roo.bootstrap.Element({
29584                 tag : 'div',
29585                 cls : 'roo-navigation-bar-text'
29586             });
29587             
29588             top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29589             bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29590             
29591             var topText = new Roo.bootstrap.Element({
29592                 tag : 'span',
29593                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29594             });
29595             
29596             var bottomText = new Roo.bootstrap.Element({
29597                 tag : 'span',
29598                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29599             });
29600             
29601             topText.onRender(top.el, null);
29602             bottomText.onRender(bottom.el, null);
29603             
29604             item.topEl = top;
29605             item.bottomEl = bottom;
29606         }
29607         
29608         this.barItems.push(item);
29609         
29610         return item;
29611     },
29612     
29613     getActive : function()
29614     {
29615         var active = false;
29616         
29617         Roo.each(this.barItems, function(v){
29618             
29619             if (!v.isActive()) {
29620                 return;
29621             }
29622             
29623             active = v;
29624             return false;
29625             
29626         });
29627         
29628         return active;
29629     },
29630     
29631     setActiveItem : function(item)
29632     {
29633         var prev = false;
29634         
29635         Roo.each(this.barItems, function(v){
29636             if (v.rid == item.rid) {
29637                 return ;
29638             }
29639             
29640             if (v.isActive()) {
29641                 v.setActive(false);
29642                 prev = v;
29643             }
29644         });
29645
29646         item.setActive(true);
29647         
29648         this.fireEvent('changed', this, item, prev);
29649     },
29650     
29651     getBarItem: function(rid)
29652     {
29653         var ret = false;
29654         
29655         Roo.each(this.barItems, function(e) {
29656             if (e.rid != rid) {
29657                 return;
29658             }
29659             
29660             ret =  e;
29661             return false;
29662         });
29663         
29664         return ret;
29665     },
29666     
29667     indexOfItem : function(item)
29668     {
29669         var index = false;
29670         
29671         Roo.each(this.barItems, function(v, i){
29672             
29673             if (v.rid != item.rid) {
29674                 return;
29675             }
29676             
29677             index = i;
29678             return false
29679         });
29680         
29681         return index;
29682     },
29683     
29684     setActiveNext : function()
29685     {
29686         var i = this.indexOfItem(this.getActive());
29687         
29688         if (i > this.barItems.length) {
29689             return;
29690         }
29691         
29692         this.setActiveItem(this.barItems[i+1]);
29693     },
29694     
29695     setActivePrev : function()
29696     {
29697         var i = this.indexOfItem(this.getActive());
29698         
29699         if (i  < 1) {
29700             return;
29701         }
29702         
29703         this.setActiveItem(this.barItems[i-1]);
29704     },
29705     
29706     format : function()
29707     {
29708         if(!this.barItems.length){
29709             return;
29710         }
29711      
29712         var width = 100 / this.barItems.length;
29713         
29714         Roo.each(this.barItems, function(i){
29715             i.el.setStyle('width', width + '%');
29716             i.topEl.el.setStyle('width', width + '%');
29717             i.bottomEl.el.setStyle('width', width + '%');
29718         }, this);
29719         
29720     }
29721     
29722 });
29723 /*
29724  * - LGPL
29725  *
29726  * Nav Progress Item
29727  * 
29728  */
29729
29730 /**
29731  * @class Roo.bootstrap.NavProgressItem
29732  * @extends Roo.bootstrap.Component
29733  * Bootstrap NavProgressItem class
29734  * @cfg {String} rid the reference id
29735  * @cfg {Boolean} active (true|false) Is item active default false
29736  * @cfg {Boolean} disabled (true|false) Is item active default false
29737  * @cfg {String} html
29738  * @cfg {String} position (top|bottom) text position default bottom
29739  * @cfg {String} icon show icon instead of number
29740  * 
29741  * @constructor
29742  * Create a new NavProgressItem
29743  * @param {Object} config The config object
29744  */
29745 Roo.bootstrap.NavProgressItem = function(config){
29746     Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29747     this.addEvents({
29748         // raw events
29749         /**
29750          * @event click
29751          * The raw click event for the entire grid.
29752          * @param {Roo.bootstrap.NavProgressItem} this
29753          * @param {Roo.EventObject} e
29754          */
29755         "click" : true
29756     });
29757    
29758 };
29759
29760 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
29761     
29762     rid : '',
29763     active : false,
29764     disabled : false,
29765     html : '',
29766     position : 'bottom',
29767     icon : false,
29768     
29769     getAutoCreate : function()
29770     {
29771         var iconCls = 'roo-navigation-bar-item-icon';
29772         
29773         iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29774         
29775         var cfg = {
29776             tag: 'li',
29777             cls: 'roo-navigation-bar-item',
29778             cn : [
29779                 {
29780                     tag : 'i',
29781                     cls : iconCls
29782                 }
29783             ]
29784         };
29785         
29786         if(this.active){
29787             cfg.cls += ' active';
29788         }
29789         if(this.disabled){
29790             cfg.cls += ' disabled';
29791         }
29792         
29793         return cfg;
29794     },
29795     
29796     disable : function()
29797     {
29798         this.setDisabled(true);
29799     },
29800     
29801     enable : function()
29802     {
29803         this.setDisabled(false);
29804     },
29805     
29806     initEvents: function() 
29807     {
29808         this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29809         
29810         this.iconEl.on('click', this.onClick, this);
29811     },
29812     
29813     onClick : function(e)
29814     {
29815         e.preventDefault();
29816         
29817         if(this.disabled){
29818             return;
29819         }
29820         
29821         if(this.fireEvent('click', this, e) === false){
29822             return;
29823         };
29824         
29825         this.parent().setActiveItem(this);
29826     },
29827     
29828     isActive: function () 
29829     {
29830         return this.active;
29831     },
29832     
29833     setActive : function(state)
29834     {
29835         if(this.active == state){
29836             return;
29837         }
29838         
29839         this.active = state;
29840         
29841         if (state) {
29842             this.el.addClass('active');
29843             return;
29844         }
29845         
29846         this.el.removeClass('active');
29847         
29848         return;
29849     },
29850     
29851     setDisabled : function(state)
29852     {
29853         if(this.disabled == state){
29854             return;
29855         }
29856         
29857         this.disabled = state;
29858         
29859         if (state) {
29860             this.el.addClass('disabled');
29861             return;
29862         }
29863         
29864         this.el.removeClass('disabled');
29865     },
29866     
29867     tooltipEl : function()
29868     {
29869         return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29870     }
29871 });
29872  
29873
29874  /*
29875  * - LGPL
29876  *
29877  * FieldLabel
29878  * 
29879  */
29880
29881 /**
29882  * @class Roo.bootstrap.FieldLabel
29883  * @extends Roo.bootstrap.Component
29884  * Bootstrap FieldLabel class
29885  * @cfg {String} html contents of the element
29886  * @cfg {String} tag tag of the element default label
29887  * @cfg {String} cls class of the element
29888  * @cfg {String} target label target 
29889  * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29890  * @cfg {String} invalidClass default "text-warning"
29891  * @cfg {String} validClass default "text-success"
29892  * @cfg {String} iconTooltip default "This field is required"
29893  * @cfg {String} indicatorpos (left|right) default left
29894  * 
29895  * @constructor
29896  * Create a new FieldLabel
29897  * @param {Object} config The config object
29898  */
29899
29900 Roo.bootstrap.FieldLabel = function(config){
29901     Roo.bootstrap.Element.superclass.constructor.call(this, config);
29902     
29903     this.addEvents({
29904             /**
29905              * @event invalid
29906              * Fires after the field has been marked as invalid.
29907              * @param {Roo.form.FieldLabel} this
29908              * @param {String} msg The validation message
29909              */
29910             invalid : true,
29911             /**
29912              * @event valid
29913              * Fires after the field has been validated with no errors.
29914              * @param {Roo.form.FieldLabel} this
29915              */
29916             valid : true
29917         });
29918 };
29919
29920 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
29921     
29922     tag: 'label',
29923     cls: '',
29924     html: '',
29925     target: '',
29926     allowBlank : true,
29927     invalidClass : 'has-warning',
29928     validClass : 'has-success',
29929     iconTooltip : 'This field is required',
29930     indicatorpos : 'left',
29931     
29932     getAutoCreate : function(){
29933         
29934         var cfg = {
29935             tag : this.tag,
29936             cls : 'roo-bootstrap-field-label ' + this.cls,
29937             for : this.target,
29938             cn : [
29939                 {
29940                     tag : 'i',
29941                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29942                     tooltip : this.iconTooltip
29943                 },
29944                 {
29945                     tag : 'span',
29946                     html : this.html
29947                 }
29948             ] 
29949         };
29950         
29951         if(this.indicatorpos == 'right'){
29952             var cfg = {
29953                 tag : this.tag,
29954                 cls : 'roo-bootstrap-field-label ' + this.cls,
29955                 for : this.target,
29956                 cn : [
29957                     {
29958                         tag : 'span',
29959                         html : this.html
29960                     },
29961                     {
29962                         tag : 'i',
29963                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29964                         tooltip : this.iconTooltip
29965                     }
29966                 ] 
29967             };
29968         }
29969         
29970         return cfg;
29971     },
29972     
29973     initEvents: function() 
29974     {
29975         Roo.bootstrap.Element.superclass.initEvents.call(this);
29976         
29977         this.indicator = this.indicatorEl();
29978         
29979         if(this.indicator){
29980             this.indicator.removeClass('visible');
29981             this.indicator.addClass('invisible');
29982         }
29983         
29984         Roo.bootstrap.FieldLabel.register(this);
29985     },
29986     
29987     indicatorEl : function()
29988     {
29989         var indicator = this.el.select('i.roo-required-indicator',true).first();
29990         
29991         if(!indicator){
29992             return false;
29993         }
29994         
29995         return indicator;
29996         
29997     },
29998     
29999     /**
30000      * Mark this field as valid
30001      */
30002     markValid : function()
30003     {
30004         if(this.indicator){
30005             this.indicator.removeClass('visible');
30006             this.indicator.addClass('invisible');
30007         }
30008         
30009         this.el.removeClass(this.invalidClass);
30010         
30011         this.el.addClass(this.validClass);
30012         
30013         this.fireEvent('valid', this);
30014     },
30015     
30016     /**
30017      * Mark this field as invalid
30018      * @param {String} msg The validation message
30019      */
30020     markInvalid : function(msg)
30021     {
30022         if(this.indicator){
30023             this.indicator.removeClass('invisible');
30024             this.indicator.addClass('visible');
30025         }
30026         
30027         this.el.removeClass(this.validClass);
30028         
30029         this.el.addClass(this.invalidClass);
30030         
30031         this.fireEvent('invalid', this, msg);
30032     }
30033     
30034    
30035 });
30036
30037 Roo.apply(Roo.bootstrap.FieldLabel, {
30038     
30039     groups: {},
30040     
30041      /**
30042     * register a FieldLabel Group
30043     * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30044     */
30045     register : function(label)
30046     {
30047         if(this.groups.hasOwnProperty(label.target)){
30048             return;
30049         }
30050      
30051         this.groups[label.target] = label;
30052         
30053     },
30054     /**
30055     * fetch a FieldLabel Group based on the target
30056     * @param {string} target
30057     * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30058     */
30059     get: function(target) {
30060         if (typeof(this.groups[target]) == 'undefined') {
30061             return false;
30062         }
30063         
30064         return this.groups[target] ;
30065     }
30066 });
30067
30068  
30069
30070  /*
30071  * - LGPL
30072  *
30073  * page DateSplitField.
30074  * 
30075  */
30076
30077
30078 /**
30079  * @class Roo.bootstrap.DateSplitField
30080  * @extends Roo.bootstrap.Component
30081  * Bootstrap DateSplitField class
30082  * @cfg {string} fieldLabel - the label associated
30083  * @cfg {Number} labelWidth set the width of label (0-12)
30084  * @cfg {String} labelAlign (top|left)
30085  * @cfg {Boolean} dayAllowBlank (true|false) default false
30086  * @cfg {Boolean} monthAllowBlank (true|false) default false
30087  * @cfg {Boolean} yearAllowBlank (true|false) default false
30088  * @cfg {string} dayPlaceholder 
30089  * @cfg {string} monthPlaceholder
30090  * @cfg {string} yearPlaceholder
30091  * @cfg {string} dayFormat default 'd'
30092  * @cfg {string} monthFormat default 'm'
30093  * @cfg {string} yearFormat default 'Y'
30094  * @cfg {Number} labellg set the width of label (1-12)
30095  * @cfg {Number} labelmd set the width of label (1-12)
30096  * @cfg {Number} labelsm set the width of label (1-12)
30097  * @cfg {Number} labelxs set the width of label (1-12)
30098
30099  *     
30100  * @constructor
30101  * Create a new DateSplitField
30102  * @param {Object} config The config object
30103  */
30104
30105 Roo.bootstrap.DateSplitField = function(config){
30106     Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30107     
30108     this.addEvents({
30109         // raw events
30110          /**
30111          * @event years
30112          * getting the data of years
30113          * @param {Roo.bootstrap.DateSplitField} this
30114          * @param {Object} years
30115          */
30116         "years" : true,
30117         /**
30118          * @event days
30119          * getting the data of days
30120          * @param {Roo.bootstrap.DateSplitField} this
30121          * @param {Object} days
30122          */
30123         "days" : true,
30124         /**
30125          * @event invalid
30126          * Fires after the field has been marked as invalid.
30127          * @param {Roo.form.Field} this
30128          * @param {String} msg The validation message
30129          */
30130         invalid : true,
30131        /**
30132          * @event valid
30133          * Fires after the field has been validated with no errors.
30134          * @param {Roo.form.Field} this
30135          */
30136         valid : true
30137     });
30138 };
30139
30140 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
30141     
30142     fieldLabel : '',
30143     labelAlign : 'top',
30144     labelWidth : 3,
30145     dayAllowBlank : false,
30146     monthAllowBlank : false,
30147     yearAllowBlank : false,
30148     dayPlaceholder : '',
30149     monthPlaceholder : '',
30150     yearPlaceholder : '',
30151     dayFormat : 'd',
30152     monthFormat : 'm',
30153     yearFormat : 'Y',
30154     isFormField : true,
30155     labellg : 0,
30156     labelmd : 0,
30157     labelsm : 0,
30158     labelxs : 0,
30159     
30160     getAutoCreate : function()
30161     {
30162         var cfg = {
30163             tag : 'div',
30164             cls : 'row roo-date-split-field-group',
30165             cn : [
30166                 {
30167                     tag : 'input',
30168                     type : 'hidden',
30169                     cls : 'form-hidden-field roo-date-split-field-group-value',
30170                     name : this.name
30171                 }
30172             ]
30173         };
30174         
30175         var labelCls = 'col-md-12';
30176         var contentCls = 'col-md-4';
30177         
30178         if(this.fieldLabel){
30179             
30180             var label = {
30181                 tag : 'div',
30182                 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30183                 cn : [
30184                     {
30185                         tag : 'label',
30186                         html : this.fieldLabel
30187                     }
30188                 ]
30189             };
30190             
30191             if(this.labelAlign == 'left'){
30192             
30193                 if(this.labelWidth > 12){
30194                     label.style = "width: " + this.labelWidth + 'px';
30195                 }
30196
30197                 if(this.labelWidth < 13 && this.labelmd == 0){
30198                     this.labelmd = this.labelWidth;
30199                 }
30200
30201                 if(this.labellg > 0){
30202                     labelCls = ' col-lg-' + this.labellg;
30203                     contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30204                 }
30205
30206                 if(this.labelmd > 0){
30207                     labelCls = ' col-md-' + this.labelmd;
30208                     contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30209                 }
30210
30211                 if(this.labelsm > 0){
30212                     labelCls = ' col-sm-' + this.labelsm;
30213                     contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30214                 }
30215
30216                 if(this.labelxs > 0){
30217                     labelCls = ' col-xs-' + this.labelxs;
30218                     contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30219                 }
30220             }
30221             
30222             label.cls += ' ' + labelCls;
30223             
30224             cfg.cn.push(label);
30225         }
30226         
30227         Roo.each(['day', 'month', 'year'], function(t){
30228             cfg.cn.push({
30229                 tag : 'div',
30230                 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30231             });
30232         }, this);
30233         
30234         return cfg;
30235     },
30236     
30237     inputEl: function ()
30238     {
30239         return this.el.select('.roo-date-split-field-group-value', true).first();
30240     },
30241     
30242     onRender : function(ct, position) 
30243     {
30244         var _this = this;
30245         
30246         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30247         
30248         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30249         
30250         this.dayField = new Roo.bootstrap.ComboBox({
30251             allowBlank : this.dayAllowBlank,
30252             alwaysQuery : true,
30253             displayField : 'value',
30254             editable : false,
30255             fieldLabel : '',
30256             forceSelection : true,
30257             mode : 'local',
30258             placeholder : this.dayPlaceholder,
30259             selectOnFocus : true,
30260             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30261             triggerAction : 'all',
30262             typeAhead : true,
30263             valueField : 'value',
30264             store : new Roo.data.SimpleStore({
30265                 data : (function() {    
30266                     var days = [];
30267                     _this.fireEvent('days', _this, days);
30268                     return days;
30269                 })(),
30270                 fields : [ 'value' ]
30271             }),
30272             listeners : {
30273                 select : function (_self, record, index)
30274                 {
30275                     _this.setValue(_this.getValue());
30276                 }
30277             }
30278         });
30279
30280         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30281         
30282         this.monthField = new Roo.bootstrap.MonthField({
30283             after : '<i class=\"fa fa-calendar\"></i>',
30284             allowBlank : this.monthAllowBlank,
30285             placeholder : this.monthPlaceholder,
30286             readOnly : true,
30287             listeners : {
30288                 render : function (_self)
30289                 {
30290                     this.el.select('span.input-group-addon', true).first().on('click', function(e){
30291                         e.preventDefault();
30292                         _self.focus();
30293                     });
30294                 },
30295                 select : function (_self, oldvalue, newvalue)
30296                 {
30297                     _this.setValue(_this.getValue());
30298                 }
30299             }
30300         });
30301         
30302         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30303         
30304         this.yearField = new Roo.bootstrap.ComboBox({
30305             allowBlank : this.yearAllowBlank,
30306             alwaysQuery : true,
30307             displayField : 'value',
30308             editable : false,
30309             fieldLabel : '',
30310             forceSelection : true,
30311             mode : 'local',
30312             placeholder : this.yearPlaceholder,
30313             selectOnFocus : true,
30314             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30315             triggerAction : 'all',
30316             typeAhead : true,
30317             valueField : 'value',
30318             store : new Roo.data.SimpleStore({
30319                 data : (function() {
30320                     var years = [];
30321                     _this.fireEvent('years', _this, years);
30322                     return years;
30323                 })(),
30324                 fields : [ 'value' ]
30325             }),
30326             listeners : {
30327                 select : function (_self, record, index)
30328                 {
30329                     _this.setValue(_this.getValue());
30330                 }
30331             }
30332         });
30333
30334         this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30335     },
30336     
30337     setValue : function(v, format)
30338     {
30339         this.inputEl.dom.value = v;
30340         
30341         var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30342         
30343         var d = Date.parseDate(v, f);
30344         
30345         if(!d){
30346             this.validate();
30347             return;
30348         }
30349         
30350         this.setDay(d.format(this.dayFormat));
30351         this.setMonth(d.format(this.monthFormat));
30352         this.setYear(d.format(this.yearFormat));
30353         
30354         this.validate();
30355         
30356         return;
30357     },
30358     
30359     setDay : function(v)
30360     {
30361         this.dayField.setValue(v);
30362         this.inputEl.dom.value = this.getValue();
30363         this.validate();
30364         return;
30365     },
30366     
30367     setMonth : function(v)
30368     {
30369         this.monthField.setValue(v, true);
30370         this.inputEl.dom.value = this.getValue();
30371         this.validate();
30372         return;
30373     },
30374     
30375     setYear : function(v)
30376     {
30377         this.yearField.setValue(v);
30378         this.inputEl.dom.value = this.getValue();
30379         this.validate();
30380         return;
30381     },
30382     
30383     getDay : function()
30384     {
30385         return this.dayField.getValue();
30386     },
30387     
30388     getMonth : function()
30389     {
30390         return this.monthField.getValue();
30391     },
30392     
30393     getYear : function()
30394     {
30395         return this.yearField.getValue();
30396     },
30397     
30398     getValue : function()
30399     {
30400         var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30401         
30402         var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30403         
30404         return date;
30405     },
30406     
30407     reset : function()
30408     {
30409         this.setDay('');
30410         this.setMonth('');
30411         this.setYear('');
30412         this.inputEl.dom.value = '';
30413         this.validate();
30414         return;
30415     },
30416     
30417     validate : function()
30418     {
30419         var d = this.dayField.validate();
30420         var m = this.monthField.validate();
30421         var y = this.yearField.validate();
30422         
30423         var valid = true;
30424         
30425         if(
30426                 (!this.dayAllowBlank && !d) ||
30427                 (!this.monthAllowBlank && !m) ||
30428                 (!this.yearAllowBlank && !y)
30429         ){
30430             valid = false;
30431         }
30432         
30433         if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30434             return valid;
30435         }
30436         
30437         if(valid){
30438             this.markValid();
30439             return valid;
30440         }
30441         
30442         this.markInvalid();
30443         
30444         return valid;
30445     },
30446     
30447     markValid : function()
30448     {
30449         
30450         var label = this.el.select('label', true).first();
30451         var icon = this.el.select('i.fa-star', true).first();
30452
30453         if(label && icon){
30454             icon.remove();
30455         }
30456         
30457         this.fireEvent('valid', this);
30458     },
30459     
30460      /**
30461      * Mark this field as invalid
30462      * @param {String} msg The validation message
30463      */
30464     markInvalid : function(msg)
30465     {
30466         
30467         var label = this.el.select('label', true).first();
30468         var icon = this.el.select('i.fa-star', true).first();
30469
30470         if(label && !icon){
30471             this.el.select('.roo-date-split-field-label', true).createChild({
30472                 tag : 'i',
30473                 cls : 'text-danger fa fa-lg fa-star',
30474                 tooltip : 'This field is required',
30475                 style : 'margin-right:5px;'
30476             }, label, true);
30477         }
30478         
30479         this.fireEvent('invalid', this, msg);
30480     },
30481     
30482     clearInvalid : function()
30483     {
30484         var label = this.el.select('label', true).first();
30485         var icon = this.el.select('i.fa-star', true).first();
30486
30487         if(label && icon){
30488             icon.remove();
30489         }
30490         
30491         this.fireEvent('valid', this);
30492     },
30493     
30494     getName: function()
30495     {
30496         return this.name;
30497     }
30498     
30499 });
30500
30501  /**
30502  *
30503  * This is based on 
30504  * http://masonry.desandro.com
30505  *
30506  * The idea is to render all the bricks based on vertical width...
30507  *
30508  * The original code extends 'outlayer' - we might need to use that....
30509  * 
30510  */
30511
30512
30513 /**
30514  * @class Roo.bootstrap.LayoutMasonry
30515  * @extends Roo.bootstrap.Component
30516  * Bootstrap Layout Masonry class
30517  * 
30518  * @constructor
30519  * Create a new Element
30520  * @param {Object} config The config object
30521  */
30522
30523 Roo.bootstrap.LayoutMasonry = function(config){
30524     
30525     Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30526     
30527     this.bricks = [];
30528     
30529     Roo.bootstrap.LayoutMasonry.register(this);
30530     
30531     this.addEvents({
30532         // raw events
30533         /**
30534          * @event layout
30535          * Fire after layout the items
30536          * @param {Roo.bootstrap.LayoutMasonry} this
30537          * @param {Roo.EventObject} e
30538          */
30539         "layout" : true
30540     });
30541     
30542 };
30543
30544 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component,  {
30545     
30546     /**
30547      * @cfg {Boolean} isLayoutInstant = no animation?
30548      */   
30549     isLayoutInstant : false, // needed?
30550    
30551     /**
30552      * @cfg {Number} boxWidth  width of the columns
30553      */   
30554     boxWidth : 450,
30555     
30556       /**
30557      * @cfg {Number} boxHeight  - 0 for square, or fix it at a certian height
30558      */   
30559     boxHeight : 0,
30560     
30561     /**
30562      * @cfg {Number} padWidth padding below box..
30563      */   
30564     padWidth : 10, 
30565     
30566     /**
30567      * @cfg {Number} gutter gutter width..
30568      */   
30569     gutter : 10,
30570     
30571      /**
30572      * @cfg {Number} maxCols maximum number of columns
30573      */   
30574     
30575     maxCols: 0,
30576     
30577     /**
30578      * @cfg {Boolean} isAutoInitial defalut true
30579      */   
30580     isAutoInitial : true, 
30581     
30582     containerWidth: 0,
30583     
30584     /**
30585      * @cfg {Boolean} isHorizontal defalut false
30586      */   
30587     isHorizontal : false, 
30588
30589     currentSize : null,
30590     
30591     tag: 'div',
30592     
30593     cls: '',
30594     
30595     bricks: null, //CompositeElement
30596     
30597     cols : 1,
30598     
30599     _isLayoutInited : false,
30600     
30601 //    isAlternative : false, // only use for vertical layout...
30602     
30603     /**
30604      * @cfg {Number} alternativePadWidth padding below box..
30605      */   
30606     alternativePadWidth : 50,
30607     
30608     selectedBrick : [],
30609     
30610     getAutoCreate : function(){
30611         
30612         var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30613         
30614         var cfg = {
30615             tag: this.tag,
30616             cls: 'blog-masonary-wrapper ' + this.cls,
30617             cn : {
30618                 cls : 'mas-boxes masonary'
30619             }
30620         };
30621         
30622         return cfg;
30623     },
30624     
30625     getChildContainer: function( )
30626     {
30627         if (this.boxesEl) {
30628             return this.boxesEl;
30629         }
30630         
30631         this.boxesEl = this.el.select('.mas-boxes').first();
30632         
30633         return this.boxesEl;
30634     },
30635     
30636     
30637     initEvents : function()
30638     {
30639         var _this = this;
30640         
30641         if(this.isAutoInitial){
30642             Roo.log('hook children rendered');
30643             this.on('childrenrendered', function() {
30644                 Roo.log('children rendered');
30645                 _this.initial();
30646             } ,this);
30647         }
30648     },
30649     
30650     initial : function()
30651     {
30652         this.selectedBrick = [];
30653         
30654         this.currentSize = this.el.getBox(true);
30655         
30656         Roo.EventManager.onWindowResize(this.resize, this); 
30657
30658         if(!this.isAutoInitial){
30659             this.layout();
30660             return;
30661         }
30662         
30663         this.layout();
30664         
30665         return;
30666         //this.layout.defer(500,this);
30667         
30668     },
30669     
30670     resize : function()
30671     {
30672         var cs = this.el.getBox(true);
30673         
30674         if (
30675                 this.currentSize.width == cs.width && 
30676                 this.currentSize.x == cs.x && 
30677                 this.currentSize.height == cs.height && 
30678                 this.currentSize.y == cs.y 
30679         ) {
30680             Roo.log("no change in with or X or Y");
30681             return;
30682         }
30683         
30684         this.currentSize = cs;
30685         
30686         this.layout();
30687         
30688     },
30689     
30690     layout : function()
30691     {   
30692         this._resetLayout();
30693         
30694         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30695         
30696         this.layoutItems( isInstant );
30697       
30698         this._isLayoutInited = true;
30699         
30700         this.fireEvent('layout', this);
30701         
30702     },
30703     
30704     _resetLayout : function()
30705     {
30706         if(this.isHorizontal){
30707             this.horizontalMeasureColumns();
30708             return;
30709         }
30710         
30711         this.verticalMeasureColumns();
30712         
30713     },
30714     
30715     verticalMeasureColumns : function()
30716     {
30717         this.getContainerWidth();
30718         
30719 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30720 //            this.colWidth = Math.floor(this.containerWidth * 0.8);
30721 //            return;
30722 //        }
30723         
30724         var boxWidth = this.boxWidth + this.padWidth;
30725         
30726         if(this.containerWidth < this.boxWidth){
30727             boxWidth = this.containerWidth
30728         }
30729         
30730         var containerWidth = this.containerWidth;
30731         
30732         var cols = Math.floor(containerWidth / boxWidth);
30733         
30734         this.cols = Math.max( cols, 1 );
30735         
30736         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30737         
30738         var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30739         
30740         var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30741         
30742         this.colWidth = boxWidth + avail - this.padWidth;
30743         
30744         this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30745         this.unitHeight = this.boxHeight > 0 ? this.boxHeight  : this.unitWidth;
30746     },
30747     
30748     horizontalMeasureColumns : function()
30749     {
30750         this.getContainerWidth();
30751         
30752         var boxWidth = this.boxWidth;
30753         
30754         if(this.containerWidth < boxWidth){
30755             boxWidth = this.containerWidth;
30756         }
30757         
30758         this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30759         
30760         this.el.setHeight(boxWidth);
30761         
30762     },
30763     
30764     getContainerWidth : function()
30765     {
30766         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
30767     },
30768     
30769     layoutItems : function( isInstant )
30770     {
30771         Roo.log(this.bricks);
30772         
30773         var items = Roo.apply([], this.bricks);
30774         
30775         if(this.isHorizontal){
30776             this._horizontalLayoutItems( items , isInstant );
30777             return;
30778         }
30779         
30780 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30781 //            this._verticalAlternativeLayoutItems( items , isInstant );
30782 //            return;
30783 //        }
30784         
30785         this._verticalLayoutItems( items , isInstant );
30786         
30787     },
30788     
30789     _verticalLayoutItems : function ( items , isInstant)
30790     {
30791         if ( !items || !items.length ) {
30792             return;
30793         }
30794         
30795         var standard = [
30796             ['xs', 'xs', 'xs', 'tall'],
30797             ['xs', 'xs', 'tall'],
30798             ['xs', 'xs', 'sm'],
30799             ['xs', 'xs', 'xs'],
30800             ['xs', 'tall'],
30801             ['xs', 'sm'],
30802             ['xs', 'xs'],
30803             ['xs'],
30804             
30805             ['sm', 'xs', 'xs'],
30806             ['sm', 'xs'],
30807             ['sm'],
30808             
30809             ['tall', 'xs', 'xs', 'xs'],
30810             ['tall', 'xs', 'xs'],
30811             ['tall', 'xs'],
30812             ['tall']
30813             
30814         ];
30815         
30816         var queue = [];
30817         
30818         var boxes = [];
30819         
30820         var box = [];
30821         
30822         Roo.each(items, function(item, k){
30823             
30824             switch (item.size) {
30825                 // these layouts take up a full box,
30826                 case 'md' :
30827                 case 'md-left' :
30828                 case 'md-right' :
30829                 case 'wide' :
30830                     
30831                     if(box.length){
30832                         boxes.push(box);
30833                         box = [];
30834                     }
30835                     
30836                     boxes.push([item]);
30837                     
30838                     break;
30839                     
30840                 case 'xs' :
30841                 case 'sm' :
30842                 case 'tall' :
30843                     
30844                     box.push(item);
30845                     
30846                     break;
30847                 default :
30848                     break;
30849                     
30850             }
30851             
30852         }, this);
30853         
30854         if(box.length){
30855             boxes.push(box);
30856             box = [];
30857         }
30858         
30859         var filterPattern = function(box, length)
30860         {
30861             if(!box.length){
30862                 return;
30863             }
30864             
30865             var match = false;
30866             
30867             var pattern = box.slice(0, length);
30868             
30869             var format = [];
30870             
30871             Roo.each(pattern, function(i){
30872                 format.push(i.size);
30873             }, this);
30874             
30875             Roo.each(standard, function(s){
30876                 
30877                 if(String(s) != String(format)){
30878                     return;
30879                 }
30880                 
30881                 match = true;
30882                 return false;
30883                 
30884             }, this);
30885             
30886             if(!match && length == 1){
30887                 return;
30888             }
30889             
30890             if(!match){
30891                 filterPattern(box, length - 1);
30892                 return;
30893             }
30894                 
30895             queue.push(pattern);
30896
30897             box = box.slice(length, box.length);
30898
30899             filterPattern(box, 4);
30900
30901             return;
30902             
30903         }
30904         
30905         Roo.each(boxes, function(box, k){
30906             
30907             if(!box.length){
30908                 return;
30909             }
30910             
30911             if(box.length == 1){
30912                 queue.push(box);
30913                 return;
30914             }
30915             
30916             filterPattern(box, 4);
30917             
30918         }, this);
30919         
30920         this._processVerticalLayoutQueue( queue, isInstant );
30921         
30922     },
30923     
30924 //    _verticalAlternativeLayoutItems : function( items , isInstant )
30925 //    {
30926 //        if ( !items || !items.length ) {
30927 //            return;
30928 //        }
30929 //
30930 //        this._processVerticalAlternativeLayoutQueue( items, isInstant );
30931 //        
30932 //    },
30933     
30934     _horizontalLayoutItems : function ( items , isInstant)
30935     {
30936         if ( !items || !items.length || items.length < 3) {
30937             return;
30938         }
30939         
30940         items.reverse();
30941         
30942         var eItems = items.slice(0, 3);
30943         
30944         items = items.slice(3, items.length);
30945         
30946         var standard = [
30947             ['xs', 'xs', 'xs', 'wide'],
30948             ['xs', 'xs', 'wide'],
30949             ['xs', 'xs', 'sm'],
30950             ['xs', 'xs', 'xs'],
30951             ['xs', 'wide'],
30952             ['xs', 'sm'],
30953             ['xs', 'xs'],
30954             ['xs'],
30955             
30956             ['sm', 'xs', 'xs'],
30957             ['sm', 'xs'],
30958             ['sm'],
30959             
30960             ['wide', 'xs', 'xs', 'xs'],
30961             ['wide', 'xs', 'xs'],
30962             ['wide', 'xs'],
30963             ['wide'],
30964             
30965             ['wide-thin']
30966         ];
30967         
30968         var queue = [];
30969         
30970         var boxes = [];
30971         
30972         var box = [];
30973         
30974         Roo.each(items, function(item, k){
30975             
30976             switch (item.size) {
30977                 case 'md' :
30978                 case 'md-left' :
30979                 case 'md-right' :
30980                 case 'tall' :
30981                     
30982                     if(box.length){
30983                         boxes.push(box);
30984                         box = [];
30985                     }
30986                     
30987                     boxes.push([item]);
30988                     
30989                     break;
30990                     
30991                 case 'xs' :
30992                 case 'sm' :
30993                 case 'wide' :
30994                 case 'wide-thin' :
30995                     
30996                     box.push(item);
30997                     
30998                     break;
30999                 default :
31000                     break;
31001                     
31002             }
31003             
31004         }, this);
31005         
31006         if(box.length){
31007             boxes.push(box);
31008             box = [];
31009         }
31010         
31011         var filterPattern = function(box, length)
31012         {
31013             if(!box.length){
31014                 return;
31015             }
31016             
31017             var match = false;
31018             
31019             var pattern = box.slice(0, length);
31020             
31021             var format = [];
31022             
31023             Roo.each(pattern, function(i){
31024                 format.push(i.size);
31025             }, this);
31026             
31027             Roo.each(standard, function(s){
31028                 
31029                 if(String(s) != String(format)){
31030                     return;
31031                 }
31032                 
31033                 match = true;
31034                 return false;
31035                 
31036             }, this);
31037             
31038             if(!match && length == 1){
31039                 return;
31040             }
31041             
31042             if(!match){
31043                 filterPattern(box, length - 1);
31044                 return;
31045             }
31046                 
31047             queue.push(pattern);
31048
31049             box = box.slice(length, box.length);
31050
31051             filterPattern(box, 4);
31052
31053             return;
31054             
31055         }
31056         
31057         Roo.each(boxes, function(box, k){
31058             
31059             if(!box.length){
31060                 return;
31061             }
31062             
31063             if(box.length == 1){
31064                 queue.push(box);
31065                 return;
31066             }
31067             
31068             filterPattern(box, 4);
31069             
31070         }, this);
31071         
31072         
31073         var prune = [];
31074         
31075         var pos = this.el.getBox(true);
31076         
31077         var minX = pos.x;
31078         
31079         var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31080         
31081         var hit_end = false;
31082         
31083         Roo.each(queue, function(box){
31084             
31085             if(hit_end){
31086                 
31087                 Roo.each(box, function(b){
31088                 
31089                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31090                     b.el.hide();
31091
31092                 }, this);
31093
31094                 return;
31095             }
31096             
31097             var mx = 0;
31098             
31099             Roo.each(box, function(b){
31100                 
31101                 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31102                 b.el.show();
31103
31104                 mx = Math.max(mx, b.x);
31105                 
31106             }, this);
31107             
31108             maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31109             
31110             if(maxX < minX){
31111                 
31112                 Roo.each(box, function(b){
31113                 
31114                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31115                     b.el.hide();
31116                     
31117                 }, this);
31118                 
31119                 hit_end = true;
31120                 
31121                 return;
31122             }
31123             
31124             prune.push(box);
31125             
31126         }, this);
31127         
31128         this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31129     },
31130     
31131     /** Sets position of item in DOM
31132     * @param {Element} item
31133     * @param {Number} x - horizontal position
31134     * @param {Number} y - vertical position
31135     * @param {Boolean} isInstant - disables transitions
31136     */
31137     _processVerticalLayoutQueue : function( queue, isInstant )
31138     {
31139         var pos = this.el.getBox(true);
31140         var x = pos.x;
31141         var y = pos.y;
31142         var maxY = [];
31143         
31144         for (var i = 0; i < this.cols; i++){
31145             maxY[i] = pos.y;
31146         }
31147         
31148         Roo.each(queue, function(box, k){
31149             
31150             var col = k % this.cols;
31151             
31152             Roo.each(box, function(b,kk){
31153                 
31154                 b.el.position('absolute');
31155                 
31156                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31157                 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31158                 
31159                 if(b.size == 'md-left' || b.size == 'md-right'){
31160                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31161                     height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31162                 }
31163                 
31164                 b.el.setWidth(width);
31165                 b.el.setHeight(height);
31166                 // iframe?
31167                 b.el.select('iframe',true).setSize(width,height);
31168                 
31169             }, this);
31170             
31171             for (var i = 0; i < this.cols; i++){
31172                 
31173                 if(maxY[i] < maxY[col]){
31174                     col = i;
31175                     continue;
31176                 }
31177                 
31178                 col = Math.min(col, i);
31179                 
31180             }
31181             
31182             x = pos.x + col * (this.colWidth + this.padWidth);
31183             
31184             y = maxY[col];
31185             
31186             var positions = [];
31187             
31188             switch (box.length){
31189                 case 1 :
31190                     positions = this.getVerticalOneBoxColPositions(x, y, box);
31191                     break;
31192                 case 2 :
31193                     positions = this.getVerticalTwoBoxColPositions(x, y, box);
31194                     break;
31195                 case 3 :
31196                     positions = this.getVerticalThreeBoxColPositions(x, y, box);
31197                     break;
31198                 case 4 :
31199                     positions = this.getVerticalFourBoxColPositions(x, y, box);
31200                     break;
31201                 default :
31202                     break;
31203             }
31204             
31205             Roo.each(box, function(b,kk){
31206                 
31207                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31208                 
31209                 var sz = b.el.getSize();
31210                 
31211                 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31212                 
31213             }, this);
31214             
31215         }, this);
31216         
31217         var mY = 0;
31218         
31219         for (var i = 0; i < this.cols; i++){
31220             mY = Math.max(mY, maxY[i]);
31221         }
31222         
31223         this.el.setHeight(mY - pos.y);
31224         
31225     },
31226     
31227 //    _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31228 //    {
31229 //        var pos = this.el.getBox(true);
31230 //        var x = pos.x;
31231 //        var y = pos.y;
31232 //        var maxX = pos.right;
31233 //        
31234 //        var maxHeight = 0;
31235 //        
31236 //        Roo.each(items, function(item, k){
31237 //            
31238 //            var c = k % 2;
31239 //            
31240 //            item.el.position('absolute');
31241 //                
31242 //            var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31243 //
31244 //            item.el.setWidth(width);
31245 //
31246 //            var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31247 //
31248 //            item.el.setHeight(height);
31249 //            
31250 //            if(c == 0){
31251 //                item.el.setXY([x, y], isInstant ? false : true);
31252 //            } else {
31253 //                item.el.setXY([maxX - width, y], isInstant ? false : true);
31254 //            }
31255 //            
31256 //            y = y + height + this.alternativePadWidth;
31257 //            
31258 //            maxHeight = maxHeight + height + this.alternativePadWidth;
31259 //            
31260 //        }, this);
31261 //        
31262 //        this.el.setHeight(maxHeight);
31263 //        
31264 //    },
31265     
31266     _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31267     {
31268         var pos = this.el.getBox(true);
31269         
31270         var minX = pos.x;
31271         var minY = pos.y;
31272         
31273         var maxX = pos.right;
31274         
31275         this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31276         
31277         var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31278         
31279         Roo.each(queue, function(box, k){
31280             
31281             Roo.each(box, function(b, kk){
31282                 
31283                 b.el.position('absolute');
31284                 
31285                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31286                 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31287                 
31288                 if(b.size == 'md-left' || b.size == 'md-right'){
31289                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31290                     height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31291                 }
31292                 
31293                 b.el.setWidth(width);
31294                 b.el.setHeight(height);
31295                 
31296             }, this);
31297             
31298             if(!box.length){
31299                 return;
31300             }
31301             
31302             var positions = [];
31303             
31304             switch (box.length){
31305                 case 1 :
31306                     positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31307                     break;
31308                 case 2 :
31309                     positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31310                     break;
31311                 case 3 :
31312                     positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31313                     break;
31314                 case 4 :
31315                     positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31316                     break;
31317                 default :
31318                     break;
31319             }
31320             
31321             Roo.each(box, function(b,kk){
31322                 
31323                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31324                 
31325                 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31326                 
31327             }, this);
31328             
31329         }, this);
31330         
31331     },
31332     
31333     _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31334     {
31335         Roo.each(eItems, function(b,k){
31336             
31337             b.size = (k == 0) ? 'sm' : 'xs';
31338             b.x = (k == 0) ? 2 : 1;
31339             b.y = (k == 0) ? 2 : 1;
31340             
31341             b.el.position('absolute');
31342             
31343             var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31344                 
31345             b.el.setWidth(width);
31346             
31347             var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31348             
31349             b.el.setHeight(height);
31350             
31351         }, this);
31352
31353         var positions = [];
31354         
31355         positions.push({
31356             x : maxX - this.unitWidth * 2 - this.gutter,
31357             y : minY
31358         });
31359         
31360         positions.push({
31361             x : maxX - this.unitWidth,
31362             y : minY + (this.unitWidth + this.gutter) * 2
31363         });
31364         
31365         positions.push({
31366             x : maxX - this.unitWidth * 3 - this.gutter * 2,
31367             y : minY
31368         });
31369         
31370         Roo.each(eItems, function(b,k){
31371             
31372             b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31373
31374         }, this);
31375         
31376     },
31377     
31378     getVerticalOneBoxColPositions : function(x, y, box)
31379     {
31380         var pos = [];
31381         
31382         var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31383         
31384         if(box[0].size == 'md-left'){
31385             rand = 0;
31386         }
31387         
31388         if(box[0].size == 'md-right'){
31389             rand = 1;
31390         }
31391         
31392         pos.push({
31393             x : x + (this.unitWidth + this.gutter) * rand,
31394             y : y
31395         });
31396         
31397         return pos;
31398     },
31399     
31400     getVerticalTwoBoxColPositions : function(x, y, box)
31401     {
31402         var pos = [];
31403         
31404         if(box[0].size == 'xs'){
31405             
31406             pos.push({
31407                 x : x,
31408                 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31409             });
31410
31411             pos.push({
31412                 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31413                 y : y
31414             });
31415             
31416             return pos;
31417             
31418         }
31419         
31420         pos.push({
31421             x : x,
31422             y : y
31423         });
31424
31425         pos.push({
31426             x : x + (this.unitWidth + this.gutter) * 2,
31427             y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31428         });
31429         
31430         return pos;
31431         
31432     },
31433     
31434     getVerticalThreeBoxColPositions : function(x, y, box)
31435     {
31436         var pos = [];
31437         
31438         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31439             
31440             pos.push({
31441                 x : x,
31442                 y : y
31443             });
31444
31445             pos.push({
31446                 x : x + (this.unitWidth + this.gutter) * 1,
31447                 y : y
31448             });
31449             
31450             pos.push({
31451                 x : x + (this.unitWidth + this.gutter) * 2,
31452                 y : y
31453             });
31454             
31455             return pos;
31456             
31457         }
31458         
31459         if(box[0].size == 'xs' && box[1].size == 'xs'){
31460             
31461             pos.push({
31462                 x : x,
31463                 y : y
31464             });
31465
31466             pos.push({
31467                 x : x,
31468                 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31469             });
31470             
31471             pos.push({
31472                 x : x + (this.unitWidth + this.gutter) * 1,
31473                 y : y
31474             });
31475             
31476             return pos;
31477             
31478         }
31479         
31480         pos.push({
31481             x : x,
31482             y : y
31483         });
31484
31485         pos.push({
31486             x : x + (this.unitWidth + this.gutter) * 2,
31487             y : y
31488         });
31489
31490         pos.push({
31491             x : x + (this.unitWidth + this.gutter) * 2,
31492             y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31493         });
31494             
31495         return pos;
31496         
31497     },
31498     
31499     getVerticalFourBoxColPositions : function(x, y, box)
31500     {
31501         var pos = [];
31502         
31503         if(box[0].size == 'xs'){
31504             
31505             pos.push({
31506                 x : x,
31507                 y : y
31508             });
31509
31510             pos.push({
31511                 x : x,
31512                 y : y + (this.unitHeight + this.gutter) * 1
31513             });
31514             
31515             pos.push({
31516                 x : x,
31517                 y : y + (this.unitHeight + this.gutter) * 2
31518             });
31519             
31520             pos.push({
31521                 x : x + (this.unitWidth + this.gutter) * 1,
31522                 y : y
31523             });
31524             
31525             return pos;
31526             
31527         }
31528         
31529         pos.push({
31530             x : x,
31531             y : y
31532         });
31533
31534         pos.push({
31535             x : x + (this.unitWidth + this.gutter) * 2,
31536             y : y
31537         });
31538
31539         pos.push({
31540             x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31541             y : y + (this.unitHeight + this.gutter) * 1
31542         });
31543
31544         pos.push({
31545             x : x + (this.unitWidth + this.gutter) * 2,
31546             y : y + (this.unitWidth + this.gutter) * 2
31547         });
31548
31549         return pos;
31550         
31551     },
31552     
31553     getHorizontalOneBoxColPositions : function(maxX, minY, box)
31554     {
31555         var pos = [];
31556         
31557         if(box[0].size == 'md-left'){
31558             pos.push({
31559                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31560                 y : minY
31561             });
31562             
31563             return pos;
31564         }
31565         
31566         if(box[0].size == 'md-right'){
31567             pos.push({
31568                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31569                 y : minY + (this.unitWidth + this.gutter) * 1
31570             });
31571             
31572             return pos;
31573         }
31574         
31575         var rand = Math.floor(Math.random() * (4 - box[0].y));
31576         
31577         pos.push({
31578             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31579             y : minY + (this.unitWidth + this.gutter) * rand
31580         });
31581         
31582         return pos;
31583         
31584     },
31585     
31586     getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31587     {
31588         var pos = [];
31589         
31590         if(box[0].size == 'xs'){
31591             
31592             pos.push({
31593                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31594                 y : minY
31595             });
31596
31597             pos.push({
31598                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31599                 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31600             });
31601             
31602             return pos;
31603             
31604         }
31605         
31606         pos.push({
31607             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31608             y : minY
31609         });
31610
31611         pos.push({
31612             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31613             y : minY + (this.unitWidth + this.gutter) * 2
31614         });
31615         
31616         return pos;
31617         
31618     },
31619     
31620     getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31621     {
31622         var pos = [];
31623         
31624         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31625             
31626             pos.push({
31627                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31628                 y : minY
31629             });
31630
31631             pos.push({
31632                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31633                 y : minY + (this.unitWidth + this.gutter) * 1
31634             });
31635             
31636             pos.push({
31637                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31638                 y : minY + (this.unitWidth + this.gutter) * 2
31639             });
31640             
31641             return pos;
31642             
31643         }
31644         
31645         if(box[0].size == 'xs' && box[1].size == 'xs'){
31646             
31647             pos.push({
31648                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31649                 y : minY
31650             });
31651
31652             pos.push({
31653                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31654                 y : minY
31655             });
31656             
31657             pos.push({
31658                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31659                 y : minY + (this.unitWidth + this.gutter) * 1
31660             });
31661             
31662             return pos;
31663             
31664         }
31665         
31666         pos.push({
31667             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31668             y : minY
31669         });
31670
31671         pos.push({
31672             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31673             y : minY + (this.unitWidth + this.gutter) * 2
31674         });
31675
31676         pos.push({
31677             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31678             y : minY + (this.unitWidth + this.gutter) * 2
31679         });
31680             
31681         return pos;
31682         
31683     },
31684     
31685     getHorizontalFourBoxColPositions : function(maxX, minY, box)
31686     {
31687         var pos = [];
31688         
31689         if(box[0].size == 'xs'){
31690             
31691             pos.push({
31692                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31693                 y : minY
31694             });
31695
31696             pos.push({
31697                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31698                 y : minY
31699             });
31700             
31701             pos.push({
31702                 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),
31703                 y : minY
31704             });
31705             
31706             pos.push({
31707                 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31708                 y : minY + (this.unitWidth + this.gutter) * 1
31709             });
31710             
31711             return pos;
31712             
31713         }
31714         
31715         pos.push({
31716             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31717             y : minY
31718         });
31719         
31720         pos.push({
31721             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31722             y : minY + (this.unitWidth + this.gutter) * 2
31723         });
31724         
31725         pos.push({
31726             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31727             y : minY + (this.unitWidth + this.gutter) * 2
31728         });
31729         
31730         pos.push({
31731             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),
31732             y : minY + (this.unitWidth + this.gutter) * 2
31733         });
31734
31735         return pos;
31736         
31737     },
31738     
31739     /**
31740     * remove a Masonry Brick
31741     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31742     */
31743     removeBrick : function(brick_id)
31744     {
31745         if (!brick_id) {
31746             return;
31747         }
31748         
31749         for (var i = 0; i<this.bricks.length; i++) {
31750             if (this.bricks[i].id == brick_id) {
31751                 this.bricks.splice(i,1);
31752                 this.el.dom.removeChild(Roo.get(brick_id).dom);
31753                 this.initial();
31754             }
31755         }
31756     },
31757     
31758     /**
31759     * adds a Masonry Brick
31760     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31761     */
31762     addBrick : function(cfg)
31763     {
31764         var cn = new Roo.bootstrap.MasonryBrick(cfg);
31765         //this.register(cn);
31766         cn.parentId = this.id;
31767         cn.onRender(this.el, null);
31768         return cn;
31769     },
31770     
31771     /**
31772     * register a Masonry Brick
31773     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31774     */
31775     
31776     register : function(brick)
31777     {
31778         this.bricks.push(brick);
31779         brick.masonryId = this.id;
31780     },
31781     
31782     /**
31783     * clear all the Masonry Brick
31784     */
31785     clearAll : function()
31786     {
31787         this.bricks = [];
31788         //this.getChildContainer().dom.innerHTML = "";
31789         this.el.dom.innerHTML = '';
31790     },
31791     
31792     getSelected : function()
31793     {
31794         if (!this.selectedBrick) {
31795             return false;
31796         }
31797         
31798         return this.selectedBrick;
31799     }
31800 });
31801
31802 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31803     
31804     groups: {},
31805      /**
31806     * register a Masonry Layout
31807     * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31808     */
31809     
31810     register : function(layout)
31811     {
31812         this.groups[layout.id] = layout;
31813     },
31814     /**
31815     * fetch a  Masonry Layout based on the masonry layout ID
31816     * @param {string} the masonry layout to add
31817     * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31818     */
31819     
31820     get: function(layout_id) {
31821         if (typeof(this.groups[layout_id]) == 'undefined') {
31822             return false;
31823         }
31824         return this.groups[layout_id] ;
31825     }
31826     
31827     
31828     
31829 });
31830
31831  
31832
31833  /**
31834  *
31835  * This is based on 
31836  * http://masonry.desandro.com
31837  *
31838  * The idea is to render all the bricks based on vertical width...
31839  *
31840  * The original code extends 'outlayer' - we might need to use that....
31841  * 
31842  */
31843
31844
31845 /**
31846  * @class Roo.bootstrap.LayoutMasonryAuto
31847  * @extends Roo.bootstrap.Component
31848  * Bootstrap Layout Masonry class
31849  * 
31850  * @constructor
31851  * Create a new Element
31852  * @param {Object} config The config object
31853  */
31854
31855 Roo.bootstrap.LayoutMasonryAuto = function(config){
31856     Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31857 };
31858
31859 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component,  {
31860     
31861       /**
31862      * @cfg {Boolean} isFitWidth  - resize the width..
31863      */   
31864     isFitWidth : false,  // options..
31865     /**
31866      * @cfg {Boolean} isOriginLeft = left align?
31867      */   
31868     isOriginLeft : true,
31869     /**
31870      * @cfg {Boolean} isOriginTop = top align?
31871      */   
31872     isOriginTop : false,
31873     /**
31874      * @cfg {Boolean} isLayoutInstant = no animation?
31875      */   
31876     isLayoutInstant : false, // needed?
31877     /**
31878      * @cfg {Boolean} isResizingContainer = not sure if this is used..
31879      */   
31880     isResizingContainer : true,
31881     /**
31882      * @cfg {Number} columnWidth  width of the columns 
31883      */   
31884     
31885     columnWidth : 0,
31886     
31887     /**
31888      * @cfg {Number} maxCols maximum number of columns
31889      */   
31890     
31891     maxCols: 0,
31892     /**
31893      * @cfg {Number} padHeight padding below box..
31894      */   
31895     
31896     padHeight : 10, 
31897     
31898     /**
31899      * @cfg {Boolean} isAutoInitial defalut true
31900      */   
31901     
31902     isAutoInitial : true, 
31903     
31904     // private?
31905     gutter : 0,
31906     
31907     containerWidth: 0,
31908     initialColumnWidth : 0,
31909     currentSize : null,
31910     
31911     colYs : null, // array.
31912     maxY : 0,
31913     padWidth: 10,
31914     
31915     
31916     tag: 'div',
31917     cls: '',
31918     bricks: null, //CompositeElement
31919     cols : 0, // array?
31920     // element : null, // wrapped now this.el
31921     _isLayoutInited : null, 
31922     
31923     
31924     getAutoCreate : function(){
31925         
31926         var cfg = {
31927             tag: this.tag,
31928             cls: 'blog-masonary-wrapper ' + this.cls,
31929             cn : {
31930                 cls : 'mas-boxes masonary'
31931             }
31932         };
31933         
31934         return cfg;
31935     },
31936     
31937     getChildContainer: function( )
31938     {
31939         if (this.boxesEl) {
31940             return this.boxesEl;
31941         }
31942         
31943         this.boxesEl = this.el.select('.mas-boxes').first();
31944         
31945         return this.boxesEl;
31946     },
31947     
31948     
31949     initEvents : function()
31950     {
31951         var _this = this;
31952         
31953         if(this.isAutoInitial){
31954             Roo.log('hook children rendered');
31955             this.on('childrenrendered', function() {
31956                 Roo.log('children rendered');
31957                 _this.initial();
31958             } ,this);
31959         }
31960         
31961     },
31962     
31963     initial : function()
31964     {
31965         this.reloadItems();
31966
31967         this.currentSize = this.el.getBox(true);
31968
31969         /// was window resize... - let's see if this works..
31970         Roo.EventManager.onWindowResize(this.resize, this); 
31971
31972         if(!this.isAutoInitial){
31973             this.layout();
31974             return;
31975         }
31976         
31977         this.layout.defer(500,this);
31978     },
31979     
31980     reloadItems: function()
31981     {
31982         this.bricks = this.el.select('.masonry-brick', true);
31983         
31984         this.bricks.each(function(b) {
31985             //Roo.log(b.getSize());
31986             if (!b.attr('originalwidth')) {
31987                 b.attr('originalwidth',  b.getSize().width);
31988             }
31989             
31990         });
31991         
31992         Roo.log(this.bricks.elements.length);
31993     },
31994     
31995     resize : function()
31996     {
31997         Roo.log('resize');
31998         var cs = this.el.getBox(true);
31999         
32000         if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32001             Roo.log("no change in with or X");
32002             return;
32003         }
32004         this.currentSize = cs;
32005         this.layout();
32006     },
32007     
32008     layout : function()
32009     {
32010          Roo.log('layout');
32011         this._resetLayout();
32012         //this._manageStamps();
32013       
32014         // don't animate first layout
32015         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32016         this.layoutItems( isInstant );
32017       
32018         // flag for initalized
32019         this._isLayoutInited = true;
32020     },
32021     
32022     layoutItems : function( isInstant )
32023     {
32024         //var items = this._getItemsForLayout( this.items );
32025         // original code supports filtering layout items.. we just ignore it..
32026         
32027         this._layoutItems( this.bricks , isInstant );
32028       
32029         this._postLayout();
32030     },
32031     _layoutItems : function ( items , isInstant)
32032     {
32033        //this.fireEvent( 'layout', this, items );
32034     
32035
32036         if ( !items || !items.elements.length ) {
32037           // no items, emit event with empty array
32038             return;
32039         }
32040
32041         var queue = [];
32042         items.each(function(item) {
32043             Roo.log("layout item");
32044             Roo.log(item);
32045             // get x/y object from method
32046             var position = this._getItemLayoutPosition( item );
32047             // enqueue
32048             position.item = item;
32049             position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32050             queue.push( position );
32051         }, this);
32052       
32053         this._processLayoutQueue( queue );
32054     },
32055     /** Sets position of item in DOM
32056     * @param {Element} item
32057     * @param {Number} x - horizontal position
32058     * @param {Number} y - vertical position
32059     * @param {Boolean} isInstant - disables transitions
32060     */
32061     _processLayoutQueue : function( queue )
32062     {
32063         for ( var i=0, len = queue.length; i < len; i++ ) {
32064             var obj = queue[i];
32065             obj.item.position('absolute');
32066             obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32067         }
32068     },
32069       
32070     
32071     /**
32072     * Any logic you want to do after each layout,
32073     * i.e. size the container
32074     */
32075     _postLayout : function()
32076     {
32077         this.resizeContainer();
32078     },
32079     
32080     resizeContainer : function()
32081     {
32082         if ( !this.isResizingContainer ) {
32083             return;
32084         }
32085         var size = this._getContainerSize();
32086         if ( size ) {
32087             this.el.setSize(size.width,size.height);
32088             this.boxesEl.setSize(size.width,size.height);
32089         }
32090     },
32091     
32092     
32093     
32094     _resetLayout : function()
32095     {
32096         //this.getSize();  // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32097         this.colWidth = this.el.getWidth();
32098         //this.gutter = this.el.getWidth(); 
32099         
32100         this.measureColumns();
32101
32102         // reset column Y
32103         var i = this.cols;
32104         this.colYs = [];
32105         while (i--) {
32106             this.colYs.push( 0 );
32107         }
32108     
32109         this.maxY = 0;
32110     },
32111
32112     measureColumns : function()
32113     {
32114         this.getContainerWidth();
32115       // if columnWidth is 0, default to outerWidth of first item
32116         if ( !this.columnWidth ) {
32117             var firstItem = this.bricks.first();
32118             Roo.log(firstItem);
32119             this.columnWidth  = this.containerWidth;
32120             if (firstItem && firstItem.attr('originalwidth') ) {
32121                 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32122             }
32123             // columnWidth fall back to item of first element
32124             Roo.log("set column width?");
32125                         this.initialColumnWidth = this.columnWidth  ;
32126
32127             // if first elem has no width, default to size of container
32128             
32129         }
32130         
32131         
32132         if (this.initialColumnWidth) {
32133             this.columnWidth = this.initialColumnWidth;
32134         }
32135         
32136         
32137             
32138         // column width is fixed at the top - however if container width get's smaller we should
32139         // reduce it...
32140         
32141         // this bit calcs how man columns..
32142             
32143         var columnWidth = this.columnWidth += this.gutter;
32144       
32145         // calculate columns
32146         var containerWidth = this.containerWidth + this.gutter;
32147         
32148         var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32149         // fix rounding errors, typically with gutters
32150         var excess = columnWidth - containerWidth % columnWidth;
32151         
32152         
32153         // if overshoot is less than a pixel, round up, otherwise floor it
32154         var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32155         cols = Math[ mathMethod ]( cols );
32156         this.cols = Math.max( cols, 1 );
32157         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32158         
32159          // padding positioning..
32160         var totalColWidth = this.cols * this.columnWidth;
32161         var padavail = this.containerWidth - totalColWidth;
32162         // so for 2 columns - we need 3 'pads'
32163         
32164         var padNeeded = (1+this.cols) * this.padWidth;
32165         
32166         var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32167         
32168         this.columnWidth += padExtra
32169         //this.padWidth = Math.floor(padavail /  ( this.cols));
32170         
32171         // adjust colum width so that padding is fixed??
32172         
32173         // we have 3 columns ... total = width * 3
32174         // we have X left over... that should be used by 
32175         
32176         //if (this.expandC) {
32177             
32178         //}
32179         
32180         
32181         
32182     },
32183     
32184     getContainerWidth : function()
32185     {
32186        /* // container is parent if fit width
32187         var container = this.isFitWidth ? this.element.parentNode : this.element;
32188         // check that this.size and size are there
32189         // IE8 triggers resize on body size change, so they might not be
32190         
32191         var size = getSize( container );  //FIXME
32192         this.containerWidth = size && size.innerWidth; //FIXME
32193         */
32194          
32195         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
32196         
32197     },
32198     
32199     _getItemLayoutPosition : function( item )  // what is item?
32200     {
32201         // we resize the item to our columnWidth..
32202       
32203         item.setWidth(this.columnWidth);
32204         item.autoBoxAdjust  = false;
32205         
32206         var sz = item.getSize();
32207  
32208         // how many columns does this brick span
32209         var remainder = this.containerWidth % this.columnWidth;
32210         
32211         var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32212         // round if off by 1 pixel, otherwise use ceil
32213         var colSpan = Math[ mathMethod ]( sz.width  / this.columnWidth );
32214         colSpan = Math.min( colSpan, this.cols );
32215         
32216         // normally this should be '1' as we dont' currently allow multi width columns..
32217         
32218         var colGroup = this._getColGroup( colSpan );
32219         // get the minimum Y value from the columns
32220         var minimumY = Math.min.apply( Math, colGroup );
32221         Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32222         
32223         var shortColIndex = colGroup.indexOf(  minimumY ); // broken on ie8..?? probably...
32224          
32225         // position the brick
32226         var position = {
32227             x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32228             y: this.currentSize.y + minimumY + this.padHeight
32229         };
32230         
32231         Roo.log(position);
32232         // apply setHeight to necessary columns
32233         var setHeight = minimumY + sz.height + this.padHeight;
32234         //Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32235         
32236         var setSpan = this.cols + 1 - colGroup.length;
32237         for ( var i = 0; i < setSpan; i++ ) {
32238           this.colYs[ shortColIndex + i ] = setHeight ;
32239         }
32240       
32241         return position;
32242     },
32243     
32244     /**
32245      * @param {Number} colSpan - number of columns the element spans
32246      * @returns {Array} colGroup
32247      */
32248     _getColGroup : function( colSpan )
32249     {
32250         if ( colSpan < 2 ) {
32251           // if brick spans only one column, use all the column Ys
32252           return this.colYs;
32253         }
32254       
32255         var colGroup = [];
32256         // how many different places could this brick fit horizontally
32257         var groupCount = this.cols + 1 - colSpan;
32258         // for each group potential horizontal position
32259         for ( var i = 0; i < groupCount; i++ ) {
32260           // make an array of colY values for that one group
32261           var groupColYs = this.colYs.slice( i, i + colSpan );
32262           // and get the max value of the array
32263           colGroup[i] = Math.max.apply( Math, groupColYs );
32264         }
32265         return colGroup;
32266     },
32267     /*
32268     _manageStamp : function( stamp )
32269     {
32270         var stampSize =  stamp.getSize();
32271         var offset = stamp.getBox();
32272         // get the columns that this stamp affects
32273         var firstX = this.isOriginLeft ? offset.x : offset.right;
32274         var lastX = firstX + stampSize.width;
32275         var firstCol = Math.floor( firstX / this.columnWidth );
32276         firstCol = Math.max( 0, firstCol );
32277         
32278         var lastCol = Math.floor( lastX / this.columnWidth );
32279         // lastCol should not go over if multiple of columnWidth #425
32280         lastCol -= lastX % this.columnWidth ? 0 : 1;
32281         lastCol = Math.min( this.cols - 1, lastCol );
32282         
32283         // set colYs to bottom of the stamp
32284         var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32285             stampSize.height;
32286             
32287         for ( var i = firstCol; i <= lastCol; i++ ) {
32288           this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32289         }
32290     },
32291     */
32292     
32293     _getContainerSize : function()
32294     {
32295         this.maxY = Math.max.apply( Math, this.colYs );
32296         var size = {
32297             height: this.maxY
32298         };
32299       
32300         if ( this.isFitWidth ) {
32301             size.width = this._getContainerFitWidth();
32302         }
32303       
32304         return size;
32305     },
32306     
32307     _getContainerFitWidth : function()
32308     {
32309         var unusedCols = 0;
32310         // count unused columns
32311         var i = this.cols;
32312         while ( --i ) {
32313           if ( this.colYs[i] !== 0 ) {
32314             break;
32315           }
32316           unusedCols++;
32317         }
32318         // fit container to columns that have been used
32319         return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32320     },
32321     
32322     needsResizeLayout : function()
32323     {
32324         var previousWidth = this.containerWidth;
32325         this.getContainerWidth();
32326         return previousWidth !== this.containerWidth;
32327     }
32328  
32329 });
32330
32331  
32332
32333  /*
32334  * - LGPL
32335  *
32336  * element
32337  * 
32338  */
32339
32340 /**
32341  * @class Roo.bootstrap.MasonryBrick
32342  * @extends Roo.bootstrap.Component
32343  * Bootstrap MasonryBrick class
32344  * 
32345  * @constructor
32346  * Create a new MasonryBrick
32347  * @param {Object} config The config object
32348  */
32349
32350 Roo.bootstrap.MasonryBrick = function(config){
32351     
32352     Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32353     
32354     Roo.bootstrap.MasonryBrick.register(this);
32355     
32356     this.addEvents({
32357         // raw events
32358         /**
32359          * @event click
32360          * When a MasonryBrick is clcik
32361          * @param {Roo.bootstrap.MasonryBrick} this
32362          * @param {Roo.EventObject} e
32363          */
32364         "click" : true
32365     });
32366 };
32367
32368 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component,  {
32369     
32370     /**
32371      * @cfg {String} title
32372      */   
32373     title : '',
32374     /**
32375      * @cfg {String} html
32376      */   
32377     html : '',
32378     /**
32379      * @cfg {String} bgimage
32380      */   
32381     bgimage : '',
32382     /**
32383      * @cfg {String} videourl
32384      */   
32385     videourl : '',
32386     /**
32387      * @cfg {String} cls
32388      */   
32389     cls : '',
32390     /**
32391      * @cfg {String} href
32392      */   
32393     href : '',
32394     /**
32395      * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32396      */   
32397     size : 'xs',
32398     
32399     /**
32400      * @cfg {String} placetitle (center|bottom)
32401      */   
32402     placetitle : '',
32403     
32404     /**
32405      * @cfg {Boolean} isFitContainer defalut true
32406      */   
32407     isFitContainer : true, 
32408     
32409     /**
32410      * @cfg {Boolean} preventDefault defalut false
32411      */   
32412     preventDefault : false, 
32413     
32414     /**
32415      * @cfg {Boolean} inverse defalut false
32416      */   
32417     maskInverse : false, 
32418     
32419     getAutoCreate : function()
32420     {
32421         if(!this.isFitContainer){
32422             return this.getSplitAutoCreate();
32423         }
32424         
32425         var cls = 'masonry-brick masonry-brick-full';
32426         
32427         if(this.href.length){
32428             cls += ' masonry-brick-link';
32429         }
32430         
32431         if(this.bgimage.length){
32432             cls += ' masonry-brick-image';
32433         }
32434         
32435         if(this.maskInverse){
32436             cls += ' mask-inverse';
32437         }
32438         
32439         if(!this.html.length && !this.maskInverse && !this.videourl.length){
32440             cls += ' enable-mask';
32441         }
32442         
32443         if(this.size){
32444             cls += ' masonry-' + this.size + '-brick';
32445         }
32446         
32447         if(this.placetitle.length){
32448             
32449             switch (this.placetitle) {
32450                 case 'center' :
32451                     cls += ' masonry-center-title';
32452                     break;
32453                 case 'bottom' :
32454                     cls += ' masonry-bottom-title';
32455                     break;
32456                 default:
32457                     break;
32458             }
32459             
32460         } else {
32461             if(!this.html.length && !this.bgimage.length){
32462                 cls += ' masonry-center-title';
32463             }
32464
32465             if(!this.html.length && this.bgimage.length){
32466                 cls += ' masonry-bottom-title';
32467             }
32468         }
32469         
32470         if(this.cls){
32471             cls += ' ' + this.cls;
32472         }
32473         
32474         var cfg = {
32475             tag: (this.href.length) ? 'a' : 'div',
32476             cls: cls,
32477             cn: [
32478                 {
32479                     tag: 'div',
32480                     cls: 'masonry-brick-mask'
32481                 },
32482                 {
32483                     tag: 'div',
32484                     cls: 'masonry-brick-paragraph',
32485                     cn: []
32486                 }
32487             ]
32488         };
32489         
32490         if(this.href.length){
32491             cfg.href = this.href;
32492         }
32493         
32494         var cn = cfg.cn[1].cn;
32495         
32496         if(this.title.length){
32497             cn.push({
32498                 tag: 'h4',
32499                 cls: 'masonry-brick-title',
32500                 html: this.title
32501             });
32502         }
32503         
32504         if(this.html.length){
32505             cn.push({
32506                 tag: 'p',
32507                 cls: 'masonry-brick-text',
32508                 html: this.html
32509             });
32510         }
32511         
32512         if (!this.title.length && !this.html.length) {
32513             cfg.cn[1].cls += ' hide';
32514         }
32515         
32516         if(this.bgimage.length){
32517             cfg.cn.push({
32518                 tag: 'img',
32519                 cls: 'masonry-brick-image-view',
32520                 src: this.bgimage
32521             });
32522         }
32523         
32524         if(this.videourl.length){
32525             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32526             // youtube support only?
32527             cfg.cn.push({
32528                 tag: 'iframe',
32529                 cls: 'masonry-brick-image-view',
32530                 src: vurl,
32531                 frameborder : 0,
32532                 allowfullscreen : true
32533             });
32534         }
32535         
32536         return cfg;
32537         
32538     },
32539     
32540     getSplitAutoCreate : function()
32541     {
32542         var cls = 'masonry-brick masonry-brick-split';
32543         
32544         if(this.href.length){
32545             cls += ' masonry-brick-link';
32546         }
32547         
32548         if(this.bgimage.length){
32549             cls += ' masonry-brick-image';
32550         }
32551         
32552         if(this.size){
32553             cls += ' masonry-' + this.size + '-brick';
32554         }
32555         
32556         switch (this.placetitle) {
32557             case 'center' :
32558                 cls += ' masonry-center-title';
32559                 break;
32560             case 'bottom' :
32561                 cls += ' masonry-bottom-title';
32562                 break;
32563             default:
32564                 if(!this.bgimage.length){
32565                     cls += ' masonry-center-title';
32566                 }
32567
32568                 if(this.bgimage.length){
32569                     cls += ' masonry-bottom-title';
32570                 }
32571                 break;
32572         }
32573         
32574         if(this.cls){
32575             cls += ' ' + this.cls;
32576         }
32577         
32578         var cfg = {
32579             tag: (this.href.length) ? 'a' : 'div',
32580             cls: cls,
32581             cn: [
32582                 {
32583                     tag: 'div',
32584                     cls: 'masonry-brick-split-head',
32585                     cn: [
32586                         {
32587                             tag: 'div',
32588                             cls: 'masonry-brick-paragraph',
32589                             cn: []
32590                         }
32591                     ]
32592                 },
32593                 {
32594                     tag: 'div',
32595                     cls: 'masonry-brick-split-body',
32596                     cn: []
32597                 }
32598             ]
32599         };
32600         
32601         if(this.href.length){
32602             cfg.href = this.href;
32603         }
32604         
32605         if(this.title.length){
32606             cfg.cn[0].cn[0].cn.push({
32607                 tag: 'h4',
32608                 cls: 'masonry-brick-title',
32609                 html: this.title
32610             });
32611         }
32612         
32613         if(this.html.length){
32614             cfg.cn[1].cn.push({
32615                 tag: 'p',
32616                 cls: 'masonry-brick-text',
32617                 html: this.html
32618             });
32619         }
32620
32621         if(this.bgimage.length){
32622             cfg.cn[0].cn.push({
32623                 tag: 'img',
32624                 cls: 'masonry-brick-image-view',
32625                 src: this.bgimage
32626             });
32627         }
32628         
32629         if(this.videourl.length){
32630             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32631             // youtube support only?
32632             cfg.cn[0].cn.cn.push({
32633                 tag: 'iframe',
32634                 cls: 'masonry-brick-image-view',
32635                 src: vurl,
32636                 frameborder : 0,
32637                 allowfullscreen : true
32638             });
32639         }
32640         
32641         return cfg;
32642     },
32643     
32644     initEvents: function() 
32645     {
32646         switch (this.size) {
32647             case 'xs' :
32648                 this.x = 1;
32649                 this.y = 1;
32650                 break;
32651             case 'sm' :
32652                 this.x = 2;
32653                 this.y = 2;
32654                 break;
32655             case 'md' :
32656             case 'md-left' :
32657             case 'md-right' :
32658                 this.x = 3;
32659                 this.y = 3;
32660                 break;
32661             case 'tall' :
32662                 this.x = 2;
32663                 this.y = 3;
32664                 break;
32665             case 'wide' :
32666                 this.x = 3;
32667                 this.y = 2;
32668                 break;
32669             case 'wide-thin' :
32670                 this.x = 3;
32671                 this.y = 1;
32672                 break;
32673                         
32674             default :
32675                 break;
32676         }
32677         
32678         if(Roo.isTouch){
32679             this.el.on('touchstart', this.onTouchStart, this);
32680             this.el.on('touchmove', this.onTouchMove, this);
32681             this.el.on('touchend', this.onTouchEnd, this);
32682             this.el.on('contextmenu', this.onContextMenu, this);
32683         } else {
32684             this.el.on('mouseenter'  ,this.enter, this);
32685             this.el.on('mouseleave', this.leave, this);
32686             this.el.on('click', this.onClick, this);
32687         }
32688         
32689         if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32690             this.parent().bricks.push(this);   
32691         }
32692         
32693     },
32694     
32695     onClick: function(e, el)
32696     {
32697         var time = this.endTimer - this.startTimer;
32698         // Roo.log(e.preventDefault());
32699         if(Roo.isTouch){
32700             if(time > 1000){
32701                 e.preventDefault();
32702                 return;
32703             }
32704         }
32705         
32706         if(!this.preventDefault){
32707             return;
32708         }
32709         
32710         e.preventDefault();
32711         
32712         if (this.activcClass != '') {
32713             this.selectBrick();
32714         }
32715         
32716         this.fireEvent('click', this);
32717     },
32718     
32719     enter: function(e, el)
32720     {
32721         e.preventDefault();
32722         
32723         if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32724             return;
32725         }
32726         
32727         if(this.bgimage.length && this.html.length){
32728             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32729         }
32730     },
32731     
32732     leave: function(e, el)
32733     {
32734         e.preventDefault();
32735         
32736         if(!this.isFitContainer || this.maskInverse  || this.videourl.length){
32737             return;
32738         }
32739         
32740         if(this.bgimage.length && this.html.length){
32741             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32742         }
32743     },
32744     
32745     onTouchStart: function(e, el)
32746     {
32747 //        e.preventDefault();
32748         
32749         this.touchmoved = false;
32750         
32751         if(!this.isFitContainer){
32752             return;
32753         }
32754         
32755         if(!this.bgimage.length || !this.html.length){
32756             return;
32757         }
32758         
32759         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32760         
32761         this.timer = new Date().getTime();
32762         
32763     },
32764     
32765     onTouchMove: function(e, el)
32766     {
32767         this.touchmoved = true;
32768     },
32769     
32770     onContextMenu : function(e,el)
32771     {
32772         e.preventDefault();
32773         e.stopPropagation();
32774         return false;
32775     },
32776     
32777     onTouchEnd: function(e, el)
32778     {
32779 //        e.preventDefault();
32780         
32781         if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32782         
32783             this.leave(e,el);
32784             
32785             return;
32786         }
32787         
32788         if(!this.bgimage.length || !this.html.length){
32789             
32790             if(this.href.length){
32791                 window.location.href = this.href;
32792             }
32793             
32794             return;
32795         }
32796         
32797         if(!this.isFitContainer){
32798             return;
32799         }
32800         
32801         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32802         
32803         window.location.href = this.href;
32804     },
32805     
32806     //selection on single brick only
32807     selectBrick : function() {
32808         
32809         if (!this.parentId) {
32810             return;
32811         }
32812         
32813         var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32814         var index = m.selectedBrick.indexOf(this.id);
32815         
32816         if ( index > -1) {
32817             m.selectedBrick.splice(index,1);
32818             this.el.removeClass(this.activeClass);
32819             return;
32820         }
32821         
32822         for(var i = 0; i < m.selectedBrick.length; i++) {
32823             var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32824             b.el.removeClass(b.activeClass);
32825         }
32826         
32827         m.selectedBrick = [];
32828         
32829         m.selectedBrick.push(this.id);
32830         this.el.addClass(this.activeClass);
32831         return;
32832     }
32833     
32834 });
32835
32836 Roo.apply(Roo.bootstrap.MasonryBrick, {
32837     
32838     //groups: {},
32839     groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32840      /**
32841     * register a Masonry Brick
32842     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32843     */
32844     
32845     register : function(brick)
32846     {
32847         //this.groups[brick.id] = brick;
32848         this.groups.add(brick.id, brick);
32849     },
32850     /**
32851     * fetch a  masonry brick based on the masonry brick ID
32852     * @param {string} the masonry brick to add
32853     * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32854     */
32855     
32856     get: function(brick_id) 
32857     {
32858         // if (typeof(this.groups[brick_id]) == 'undefined') {
32859         //     return false;
32860         // }
32861         // return this.groups[brick_id] ;
32862         
32863         if(this.groups.key(brick_id)) {
32864             return this.groups.key(brick_id);
32865         }
32866         
32867         return false;
32868     }
32869     
32870     
32871     
32872 });
32873
32874  /*
32875  * - LGPL
32876  *
32877  * element
32878  * 
32879  */
32880
32881 /**
32882  * @class Roo.bootstrap.Brick
32883  * @extends Roo.bootstrap.Component
32884  * Bootstrap Brick class
32885  * 
32886  * @constructor
32887  * Create a new Brick
32888  * @param {Object} config The config object
32889  */
32890
32891 Roo.bootstrap.Brick = function(config){
32892     Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32893     
32894     this.addEvents({
32895         // raw events
32896         /**
32897          * @event click
32898          * When a Brick is click
32899          * @param {Roo.bootstrap.Brick} this
32900          * @param {Roo.EventObject} e
32901          */
32902         "click" : true
32903     });
32904 };
32905
32906 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
32907     
32908     /**
32909      * @cfg {String} title
32910      */   
32911     title : '',
32912     /**
32913      * @cfg {String} html
32914      */   
32915     html : '',
32916     /**
32917      * @cfg {String} bgimage
32918      */   
32919     bgimage : '',
32920     /**
32921      * @cfg {String} cls
32922      */   
32923     cls : '',
32924     /**
32925      * @cfg {String} href
32926      */   
32927     href : '',
32928     /**
32929      * @cfg {String} video
32930      */   
32931     video : '',
32932     /**
32933      * @cfg {Boolean} square
32934      */   
32935     square : true,
32936     
32937     getAutoCreate : function()
32938     {
32939         var cls = 'roo-brick';
32940         
32941         if(this.href.length){
32942             cls += ' roo-brick-link';
32943         }
32944         
32945         if(this.bgimage.length){
32946             cls += ' roo-brick-image';
32947         }
32948         
32949         if(!this.html.length && !this.bgimage.length){
32950             cls += ' roo-brick-center-title';
32951         }
32952         
32953         if(!this.html.length && this.bgimage.length){
32954             cls += ' roo-brick-bottom-title';
32955         }
32956         
32957         if(this.cls){
32958             cls += ' ' + this.cls;
32959         }
32960         
32961         var cfg = {
32962             tag: (this.href.length) ? 'a' : 'div',
32963             cls: cls,
32964             cn: [
32965                 {
32966                     tag: 'div',
32967                     cls: 'roo-brick-paragraph',
32968                     cn: []
32969                 }
32970             ]
32971         };
32972         
32973         if(this.href.length){
32974             cfg.href = this.href;
32975         }
32976         
32977         var cn = cfg.cn[0].cn;
32978         
32979         if(this.title.length){
32980             cn.push({
32981                 tag: 'h4',
32982                 cls: 'roo-brick-title',
32983                 html: this.title
32984             });
32985         }
32986         
32987         if(this.html.length){
32988             cn.push({
32989                 tag: 'p',
32990                 cls: 'roo-brick-text',
32991                 html: this.html
32992             });
32993         } else {
32994             cn.cls += ' hide';
32995         }
32996         
32997         if(this.bgimage.length){
32998             cfg.cn.push({
32999                 tag: 'img',
33000                 cls: 'roo-brick-image-view',
33001                 src: this.bgimage
33002             });
33003         }
33004         
33005         return cfg;
33006     },
33007     
33008     initEvents: function() 
33009     {
33010         if(this.title.length || this.html.length){
33011             this.el.on('mouseenter'  ,this.enter, this);
33012             this.el.on('mouseleave', this.leave, this);
33013         }
33014         
33015         Roo.EventManager.onWindowResize(this.resize, this); 
33016         
33017         if(this.bgimage.length){
33018             this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33019             this.imageEl.on('load', this.onImageLoad, this);
33020             return;
33021         }
33022         
33023         this.resize();
33024     },
33025     
33026     onImageLoad : function()
33027     {
33028         this.resize();
33029     },
33030     
33031     resize : function()
33032     {
33033         var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33034         
33035         paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33036         
33037         if(this.bgimage.length){
33038             var image = this.el.select('.roo-brick-image-view', true).first();
33039             
33040             image.setWidth(paragraph.getWidth());
33041             
33042             if(this.square){
33043                 image.setHeight(paragraph.getWidth());
33044             }
33045             
33046             this.el.setHeight(image.getHeight());
33047             paragraph.setHeight(image.getHeight());
33048             
33049         }
33050         
33051     },
33052     
33053     enter: function(e, el)
33054     {
33055         e.preventDefault();
33056         
33057         if(this.bgimage.length){
33058             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33059             this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33060         }
33061     },
33062     
33063     leave: function(e, el)
33064     {
33065         e.preventDefault();
33066         
33067         if(this.bgimage.length){
33068             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33069             this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33070         }
33071     }
33072     
33073 });
33074
33075  
33076
33077  /*
33078  * - LGPL
33079  *
33080  * Number field 
33081  */
33082
33083 /**
33084  * @class Roo.bootstrap.NumberField
33085  * @extends Roo.bootstrap.Input
33086  * Bootstrap NumberField class
33087  * 
33088  * 
33089  * 
33090  * 
33091  * @constructor
33092  * Create a new NumberField
33093  * @param {Object} config The config object
33094  */
33095
33096 Roo.bootstrap.NumberField = function(config){
33097     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33098 };
33099
33100 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33101     
33102     /**
33103      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33104      */
33105     allowDecimals : true,
33106     /**
33107      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33108      */
33109     decimalSeparator : ".",
33110     /**
33111      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33112      */
33113     decimalPrecision : 2,
33114     /**
33115      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33116      */
33117     allowNegative : true,
33118     
33119     /**
33120      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33121      */
33122     allowZero: true,
33123     /**
33124      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33125      */
33126     minValue : Number.NEGATIVE_INFINITY,
33127     /**
33128      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33129      */
33130     maxValue : Number.MAX_VALUE,
33131     /**
33132      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33133      */
33134     minText : "The minimum value for this field is {0}",
33135     /**
33136      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33137      */
33138     maxText : "The maximum value for this field is {0}",
33139     /**
33140      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
33141      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33142      */
33143     nanText : "{0} is not a valid number",
33144     /**
33145      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33146      */
33147     castInt : true,
33148     /**
33149      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33150      */
33151     thousandsDelimiter : false,
33152     /**
33153      * @cfg {String} valueAlign alignment of value
33154      */
33155     valueAlign : "left",
33156
33157     getAutoCreate : function()
33158     {
33159         var hiddenInput = {
33160             tag: 'input',
33161             type: 'hidden',
33162             id: Roo.id(),
33163             cls: 'hidden-number-input'
33164         };
33165         
33166         if (this.name) {
33167             hiddenInput.name = this.name;
33168         }
33169         
33170         this.name = '';
33171         
33172         var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33173         
33174         this.name = hiddenInput.name;
33175         
33176         if(cfg.cn.length > 0) {
33177             cfg.cn.push(hiddenInput);
33178         }
33179         
33180         return cfg;
33181     },
33182
33183     // private
33184     initEvents : function()
33185     {   
33186         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33187         
33188         var allowed = "0123456789";
33189         
33190         if(this.allowDecimals){
33191             allowed += this.decimalSeparator;
33192         }
33193         
33194         if(this.allowNegative){
33195             allowed += "-";
33196         }
33197         
33198         if(this.thousandsDelimiter) {
33199             allowed += ",";
33200         }
33201         
33202         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33203         
33204         var keyPress = function(e){
33205             
33206             var k = e.getKey();
33207             
33208             var c = e.getCharCode();
33209             
33210             if(
33211                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33212                     allowed.indexOf(String.fromCharCode(c)) === -1
33213             ){
33214                 e.stopEvent();
33215                 return;
33216             }
33217             
33218             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33219                 return;
33220             }
33221             
33222             if(allowed.indexOf(String.fromCharCode(c)) === -1){
33223                 e.stopEvent();
33224             }
33225         };
33226         
33227         this.el.on("keypress", keyPress, this);
33228     },
33229     
33230     validateValue : function(value)
33231     {
33232         
33233         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33234             return false;
33235         }
33236         
33237         var num = this.parseValue(value);
33238         
33239         if(isNaN(num)){
33240             this.markInvalid(String.format(this.nanText, value));
33241             return false;
33242         }
33243         
33244         if(num < this.minValue){
33245             this.markInvalid(String.format(this.minText, this.minValue));
33246             return false;
33247         }
33248         
33249         if(num > this.maxValue){
33250             this.markInvalid(String.format(this.maxText, this.maxValue));
33251             return false;
33252         }
33253         
33254         return true;
33255     },
33256
33257     getValue : function()
33258     {
33259         var v = this.hiddenEl().getValue();
33260         
33261         return this.fixPrecision(this.parseValue(v));
33262     },
33263
33264     parseValue : function(value)
33265     {
33266         if(this.thousandsDelimiter) {
33267             value += "";
33268             r = new RegExp(",", "g");
33269             value = value.replace(r, "");
33270         }
33271         
33272         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33273         return isNaN(value) ? '' : value;
33274     },
33275
33276     fixPrecision : function(value)
33277     {
33278         if(this.thousandsDelimiter) {
33279             value += "";
33280             r = new RegExp(",", "g");
33281             value = value.replace(r, "");
33282         }
33283         
33284         var nan = isNaN(value);
33285         
33286         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33287             return nan ? '' : value;
33288         }
33289         return parseFloat(value).toFixed(this.decimalPrecision);
33290     },
33291
33292     setValue : function(v)
33293     {
33294         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33295         
33296         this.value = v;
33297         
33298         if(this.rendered){
33299             
33300             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33301             
33302             this.inputEl().dom.value = (v == '') ? '' :
33303                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33304             
33305             if(!this.allowZero && v === '0') {
33306                 this.hiddenEl().dom.value = '';
33307                 this.inputEl().dom.value = '';
33308             }
33309             
33310             this.validate();
33311         }
33312     },
33313
33314     decimalPrecisionFcn : function(v)
33315     {
33316         return Math.floor(v);
33317     },
33318
33319     beforeBlur : function()
33320     {
33321         if(!this.castInt){
33322             return;
33323         }
33324         
33325         var v = this.parseValue(this.getRawValue());
33326         
33327         if(v || v === 0){
33328             this.setValue(v);
33329         }
33330     },
33331     
33332     hiddenEl : function()
33333     {
33334         return this.el.select('input.hidden-number-input',true).first();
33335     }
33336     
33337 });
33338
33339  
33340
33341 /*
33342 * Licence: LGPL
33343 */
33344
33345 /**
33346  * @class Roo.bootstrap.DocumentSlider
33347  * @extends Roo.bootstrap.Component
33348  * Bootstrap DocumentSlider class
33349  * 
33350  * @constructor
33351  * Create a new DocumentViewer
33352  * @param {Object} config The config object
33353  */
33354
33355 Roo.bootstrap.DocumentSlider = function(config){
33356     Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33357     
33358     this.files = [];
33359     
33360     this.addEvents({
33361         /**
33362          * @event initial
33363          * Fire after initEvent
33364          * @param {Roo.bootstrap.DocumentSlider} this
33365          */
33366         "initial" : true,
33367         /**
33368          * @event update
33369          * Fire after update
33370          * @param {Roo.bootstrap.DocumentSlider} this
33371          */
33372         "update" : true,
33373         /**
33374          * @event click
33375          * Fire after click
33376          * @param {Roo.bootstrap.DocumentSlider} this
33377          */
33378         "click" : true
33379     });
33380 };
33381
33382 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
33383     
33384     files : false,
33385     
33386     indicator : 0,
33387     
33388     getAutoCreate : function()
33389     {
33390         var cfg = {
33391             tag : 'div',
33392             cls : 'roo-document-slider',
33393             cn : [
33394                 {
33395                     tag : 'div',
33396                     cls : 'roo-document-slider-header',
33397                     cn : [
33398                         {
33399                             tag : 'div',
33400                             cls : 'roo-document-slider-header-title'
33401                         }
33402                     ]
33403                 },
33404                 {
33405                     tag : 'div',
33406                     cls : 'roo-document-slider-body',
33407                     cn : [
33408                         {
33409                             tag : 'div',
33410                             cls : 'roo-document-slider-prev',
33411                             cn : [
33412                                 {
33413                                     tag : 'i',
33414                                     cls : 'fa fa-chevron-left'
33415                                 }
33416                             ]
33417                         },
33418                         {
33419                             tag : 'div',
33420                             cls : 'roo-document-slider-thumb',
33421                             cn : [
33422                                 {
33423                                     tag : 'img',
33424                                     cls : 'roo-document-slider-image'
33425                                 }
33426                             ]
33427                         },
33428                         {
33429                             tag : 'div',
33430                             cls : 'roo-document-slider-next',
33431                             cn : [
33432                                 {
33433                                     tag : 'i',
33434                                     cls : 'fa fa-chevron-right'
33435                                 }
33436                             ]
33437                         }
33438                     ]
33439                 }
33440             ]
33441         };
33442         
33443         return cfg;
33444     },
33445     
33446     initEvents : function()
33447     {
33448         this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33449         this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33450         
33451         this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33452         this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33453         
33454         this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33455         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33456         
33457         this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33458         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33459         
33460         this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33461         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33462         
33463         this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33464         this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33465         
33466         this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33467         this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33468         
33469         this.thumbEl.on('click', this.onClick, this);
33470         
33471         this.prevIndicator.on('click', this.prev, this);
33472         
33473         this.nextIndicator.on('click', this.next, this);
33474         
33475     },
33476     
33477     initial : function()
33478     {
33479         if(this.files.length){
33480             this.indicator = 1;
33481             this.update()
33482         }
33483         
33484         this.fireEvent('initial', this);
33485     },
33486     
33487     update : function()
33488     {
33489         this.imageEl.attr('src', this.files[this.indicator - 1]);
33490         
33491         this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33492         
33493         this.prevIndicator.show();
33494         
33495         if(this.indicator == 1){
33496             this.prevIndicator.hide();
33497         }
33498         
33499         this.nextIndicator.show();
33500         
33501         if(this.indicator == this.files.length){
33502             this.nextIndicator.hide();
33503         }
33504         
33505         this.thumbEl.scrollTo('top');
33506         
33507         this.fireEvent('update', this);
33508     },
33509     
33510     onClick : function(e)
33511     {
33512         e.preventDefault();
33513         
33514         this.fireEvent('click', this);
33515     },
33516     
33517     prev : function(e)
33518     {
33519         e.preventDefault();
33520         
33521         this.indicator = Math.max(1, this.indicator - 1);
33522         
33523         this.update();
33524     },
33525     
33526     next : function(e)
33527     {
33528         e.preventDefault();
33529         
33530         this.indicator = Math.min(this.files.length, this.indicator + 1);
33531         
33532         this.update();
33533     }
33534 });
33535 /*
33536  * - LGPL
33537  *
33538  * RadioSet
33539  *
33540  *
33541  */
33542
33543 /**
33544  * @class Roo.bootstrap.RadioSet
33545  * @extends Roo.bootstrap.Input
33546  * Bootstrap RadioSet class
33547  * @cfg {String} indicatorpos (left|right) default left
33548  * @cfg {Boolean} inline (true|false) inline the element (default true)
33549  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33550  * @constructor
33551  * Create a new RadioSet
33552  * @param {Object} config The config object
33553  */
33554
33555 Roo.bootstrap.RadioSet = function(config){
33556     
33557     Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33558     
33559     this.radioes = [];
33560     
33561     Roo.bootstrap.RadioSet.register(this);
33562     
33563     this.addEvents({
33564         /**
33565         * @event check
33566         * Fires when the element is checked or unchecked.
33567         * @param {Roo.bootstrap.RadioSet} this This radio
33568         * @param {Roo.bootstrap.Radio} item The checked item
33569         */
33570        check : true,
33571        /**
33572         * @event click
33573         * Fires when the element is click.
33574         * @param {Roo.bootstrap.RadioSet} this This radio set
33575         * @param {Roo.bootstrap.Radio} item The checked item
33576         * @param {Roo.EventObject} e The event object
33577         */
33578        click : true
33579     });
33580     
33581 };
33582
33583 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
33584
33585     radioes : false,
33586     
33587     inline : true,
33588     
33589     weight : '',
33590     
33591     indicatorpos : 'left',
33592     
33593     getAutoCreate : function()
33594     {
33595         var label = {
33596             tag : 'label',
33597             cls : 'roo-radio-set-label',
33598             cn : [
33599                 {
33600                     tag : 'span',
33601                     html : this.fieldLabel
33602                 }
33603             ]
33604         };
33605         
33606         if(this.indicatorpos == 'left'){
33607             label.cn.unshift({
33608                 tag : 'i',
33609                 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33610                 tooltip : 'This field is required'
33611             });
33612         } else {
33613             label.cn.push({
33614                 tag : 'i',
33615                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33616                 tooltip : 'This field is required'
33617             });
33618         }
33619         
33620         var items = {
33621             tag : 'div',
33622             cls : 'roo-radio-set-items'
33623         };
33624         
33625         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33626         
33627         if (align === 'left' && this.fieldLabel.length) {
33628             
33629             items = {
33630                 cls : "roo-radio-set-right", 
33631                 cn: [
33632                     items
33633                 ]
33634             };
33635             
33636             if(this.labelWidth > 12){
33637                 label.style = "width: " + this.labelWidth + 'px';
33638             }
33639             
33640             if(this.labelWidth < 13 && this.labelmd == 0){
33641                 this.labelmd = this.labelWidth;
33642             }
33643             
33644             if(this.labellg > 0){
33645                 label.cls += ' col-lg-' + this.labellg;
33646                 items.cls += ' col-lg-' + (12 - this.labellg);
33647             }
33648             
33649             if(this.labelmd > 0){
33650                 label.cls += ' col-md-' + this.labelmd;
33651                 items.cls += ' col-md-' + (12 - this.labelmd);
33652             }
33653             
33654             if(this.labelsm > 0){
33655                 label.cls += ' col-sm-' + this.labelsm;
33656                 items.cls += ' col-sm-' + (12 - this.labelsm);
33657             }
33658             
33659             if(this.labelxs > 0){
33660                 label.cls += ' col-xs-' + this.labelxs;
33661                 items.cls += ' col-xs-' + (12 - this.labelxs);
33662             }
33663         }
33664         
33665         var cfg = {
33666             tag : 'div',
33667             cls : 'roo-radio-set',
33668             cn : [
33669                 {
33670                     tag : 'input',
33671                     cls : 'roo-radio-set-input',
33672                     type : 'hidden',
33673                     name : this.name,
33674                     value : this.value ? this.value :  ''
33675                 },
33676                 label,
33677                 items
33678             ]
33679         };
33680         
33681         if(this.weight.length){
33682             cfg.cls += ' roo-radio-' + this.weight;
33683         }
33684         
33685         if(this.inline) {
33686             cfg.cls += ' roo-radio-set-inline';
33687         }
33688         
33689         var settings=this;
33690         ['xs','sm','md','lg'].map(function(size){
33691             if (settings[size]) {
33692                 cfg.cls += ' col-' + size + '-' + settings[size];
33693             }
33694         });
33695         
33696         return cfg;
33697         
33698     },
33699
33700     initEvents : function()
33701     {
33702         this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33703         this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33704         
33705         if(!this.fieldLabel.length){
33706             this.labelEl.hide();
33707         }
33708         
33709         this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33710         this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33711         
33712         this.indicatorEl().addClass('invisible');
33713         
33714         this.originalValue = this.getValue();
33715         
33716     },
33717     
33718     inputEl: function ()
33719     {
33720         return this.el.select('.roo-radio-set-input', true).first();
33721     },
33722     
33723     getChildContainer : function()
33724     {
33725         return this.itemsEl;
33726     },
33727     
33728     register : function(item)
33729     {
33730         this.radioes.push(item);
33731         
33732     },
33733     
33734     validate : function()
33735     {   
33736         var valid = false;
33737         
33738         Roo.each(this.radioes, function(i){
33739             if(!i.checked){
33740                 return;
33741             }
33742             
33743             valid = true;
33744             return false;
33745         });
33746         
33747         if(this.allowBlank) {
33748             return true;
33749         }
33750         
33751         if(this.disabled || valid){
33752             this.markValid();
33753             return true;
33754         }
33755         
33756         this.markInvalid();
33757         return false;
33758         
33759     },
33760     
33761     markValid : function()
33762     {
33763         if(this.labelEl.isVisible(true)){
33764             this.indicatorEl().removeClass('visible');
33765             this.indicatorEl().addClass('invisible');
33766         }
33767         
33768         this.el.removeClass([this.invalidClass, this.validClass]);
33769         this.el.addClass(this.validClass);
33770         
33771         this.fireEvent('valid', this);
33772     },
33773     
33774     markInvalid : function(msg)
33775     {
33776         if(this.allowBlank || this.disabled){
33777             return;
33778         }
33779         
33780         if(this.labelEl.isVisible(true)){
33781             this.indicatorEl().removeClass('invisible');
33782             this.indicatorEl().addClass('visible');
33783         }
33784         
33785         this.el.removeClass([this.invalidClass, this.validClass]);
33786         this.el.addClass(this.invalidClass);
33787         
33788         this.fireEvent('invalid', this, msg);
33789         
33790     },
33791     
33792     setValue : function(v, suppressEvent)
33793     {   
33794         if(this.value === v){
33795             return;
33796         }
33797         
33798         this.value = v;
33799         
33800         if(this.rendered){
33801             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33802         }
33803         
33804         Roo.each(this.radioes, function(i){
33805             i.checked = false;
33806             i.el.removeClass('checked');
33807         });
33808         
33809         Roo.each(this.radioes, function(i){
33810             
33811             if(i.value === v || i.value.toString() === v.toString()){
33812                 i.checked = true;
33813                 i.el.addClass('checked');
33814                 
33815                 if(suppressEvent !== true){
33816                     this.fireEvent('check', this, i);
33817                 }
33818                 
33819                 return false;
33820             }
33821             
33822         }, this);
33823         
33824         this.validate();
33825     },
33826     
33827     clearInvalid : function(){
33828         
33829         if(!this.el || this.preventMark){
33830             return;
33831         }
33832         
33833         this.el.removeClass([this.invalidClass]);
33834         
33835         this.fireEvent('valid', this);
33836     }
33837     
33838 });
33839
33840 Roo.apply(Roo.bootstrap.RadioSet, {
33841     
33842     groups: {},
33843     
33844     register : function(set)
33845     {
33846         this.groups[set.name] = set;
33847     },
33848     
33849     get: function(name) 
33850     {
33851         if (typeof(this.groups[name]) == 'undefined') {
33852             return false;
33853         }
33854         
33855         return this.groups[name] ;
33856     }
33857     
33858 });
33859 /*
33860  * Based on:
33861  * Ext JS Library 1.1.1
33862  * Copyright(c) 2006-2007, Ext JS, LLC.
33863  *
33864  * Originally Released Under LGPL - original licence link has changed is not relivant.
33865  *
33866  * Fork - LGPL
33867  * <script type="text/javascript">
33868  */
33869
33870
33871 /**
33872  * @class Roo.bootstrap.SplitBar
33873  * @extends Roo.util.Observable
33874  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33875  * <br><br>
33876  * Usage:
33877  * <pre><code>
33878 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33879                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33880 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33881 split.minSize = 100;
33882 split.maxSize = 600;
33883 split.animate = true;
33884 split.on('moved', splitterMoved);
33885 </code></pre>
33886  * @constructor
33887  * Create a new SplitBar
33888  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
33889  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
33890  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33891  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
33892                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33893                         position of the SplitBar).
33894  */
33895 Roo.bootstrap.SplitBar = function(cfg){
33896     
33897     /** @private */
33898     
33899     //{
33900     //  dragElement : elm
33901     //  resizingElement: el,
33902         // optional..
33903     //    orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33904     //    placement : Roo.bootstrap.SplitBar.LEFT  ,
33905         // existingProxy ???
33906     //}
33907     
33908     this.el = Roo.get(cfg.dragElement, true);
33909     this.el.dom.unselectable = "on";
33910     /** @private */
33911     this.resizingEl = Roo.get(cfg.resizingElement, true);
33912
33913     /**
33914      * @private
33915      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33916      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33917      * @type Number
33918      */
33919     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33920     
33921     /**
33922      * The minimum size of the resizing element. (Defaults to 0)
33923      * @type Number
33924      */
33925     this.minSize = 0;
33926     
33927     /**
33928      * The maximum size of the resizing element. (Defaults to 2000)
33929      * @type Number
33930      */
33931     this.maxSize = 2000;
33932     
33933     /**
33934      * Whether to animate the transition to the new size
33935      * @type Boolean
33936      */
33937     this.animate = false;
33938     
33939     /**
33940      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33941      * @type Boolean
33942      */
33943     this.useShim = false;
33944     
33945     /** @private */
33946     this.shim = null;
33947     
33948     if(!cfg.existingProxy){
33949         /** @private */
33950         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33951     }else{
33952         this.proxy = Roo.get(cfg.existingProxy).dom;
33953     }
33954     /** @private */
33955     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33956     
33957     /** @private */
33958     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33959     
33960     /** @private */
33961     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33962     
33963     /** @private */
33964     this.dragSpecs = {};
33965     
33966     /**
33967      * @private The adapter to use to positon and resize elements
33968      */
33969     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33970     this.adapter.init(this);
33971     
33972     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33973         /** @private */
33974         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33975         this.el.addClass("roo-splitbar-h");
33976     }else{
33977         /** @private */
33978         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33979         this.el.addClass("roo-splitbar-v");
33980     }
33981     
33982     this.addEvents({
33983         /**
33984          * @event resize
33985          * Fires when the splitter is moved (alias for {@link #event-moved})
33986          * @param {Roo.bootstrap.SplitBar} this
33987          * @param {Number} newSize the new width or height
33988          */
33989         "resize" : true,
33990         /**
33991          * @event moved
33992          * Fires when the splitter is moved
33993          * @param {Roo.bootstrap.SplitBar} this
33994          * @param {Number} newSize the new width or height
33995          */
33996         "moved" : true,
33997         /**
33998          * @event beforeresize
33999          * Fires before the splitter is dragged
34000          * @param {Roo.bootstrap.SplitBar} this
34001          */
34002         "beforeresize" : true,
34003
34004         "beforeapply" : true
34005     });
34006
34007     Roo.util.Observable.call(this);
34008 };
34009
34010 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34011     onStartProxyDrag : function(x, y){
34012         this.fireEvent("beforeresize", this);
34013         if(!this.overlay){
34014             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "roo-drag-overlay", html: "&#160;"}, true);
34015             o.unselectable();
34016             o.enableDisplayMode("block");
34017             // all splitbars share the same overlay
34018             Roo.bootstrap.SplitBar.prototype.overlay = o;
34019         }
34020         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34021         this.overlay.show();
34022         Roo.get(this.proxy).setDisplayed("block");
34023         var size = this.adapter.getElementSize(this);
34024         this.activeMinSize = this.getMinimumSize();;
34025         this.activeMaxSize = this.getMaximumSize();;
34026         var c1 = size - this.activeMinSize;
34027         var c2 = Math.max(this.activeMaxSize - size, 0);
34028         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34029             this.dd.resetConstraints();
34030             this.dd.setXConstraint(
34031                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
34032                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34033             );
34034             this.dd.setYConstraint(0, 0);
34035         }else{
34036             this.dd.resetConstraints();
34037             this.dd.setXConstraint(0, 0);
34038             this.dd.setYConstraint(
34039                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
34040                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34041             );
34042          }
34043         this.dragSpecs.startSize = size;
34044         this.dragSpecs.startPoint = [x, y];
34045         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34046     },
34047     
34048     /** 
34049      * @private Called after the drag operation by the DDProxy
34050      */
34051     onEndProxyDrag : function(e){
34052         Roo.get(this.proxy).setDisplayed(false);
34053         var endPoint = Roo.lib.Event.getXY(e);
34054         if(this.overlay){
34055             this.overlay.hide();
34056         }
34057         var newSize;
34058         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34059             newSize = this.dragSpecs.startSize + 
34060                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34061                     endPoint[0] - this.dragSpecs.startPoint[0] :
34062                     this.dragSpecs.startPoint[0] - endPoint[0]
34063                 );
34064         }else{
34065             newSize = this.dragSpecs.startSize + 
34066                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34067                     endPoint[1] - this.dragSpecs.startPoint[1] :
34068                     this.dragSpecs.startPoint[1] - endPoint[1]
34069                 );
34070         }
34071         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34072         if(newSize != this.dragSpecs.startSize){
34073             if(this.fireEvent('beforeapply', this, newSize) !== false){
34074                 this.adapter.setElementSize(this, newSize);
34075                 this.fireEvent("moved", this, newSize);
34076                 this.fireEvent("resize", this, newSize);
34077             }
34078         }
34079     },
34080     
34081     /**
34082      * Get the adapter this SplitBar uses
34083      * @return The adapter object
34084      */
34085     getAdapter : function(){
34086         return this.adapter;
34087     },
34088     
34089     /**
34090      * Set the adapter this SplitBar uses
34091      * @param {Object} adapter A SplitBar adapter object
34092      */
34093     setAdapter : function(adapter){
34094         this.adapter = adapter;
34095         this.adapter.init(this);
34096     },
34097     
34098     /**
34099      * Gets the minimum size for the resizing element
34100      * @return {Number} The minimum size
34101      */
34102     getMinimumSize : function(){
34103         return this.minSize;
34104     },
34105     
34106     /**
34107      * Sets the minimum size for the resizing element
34108      * @param {Number} minSize The minimum size
34109      */
34110     setMinimumSize : function(minSize){
34111         this.minSize = minSize;
34112     },
34113     
34114     /**
34115      * Gets the maximum size for the resizing element
34116      * @return {Number} The maximum size
34117      */
34118     getMaximumSize : function(){
34119         return this.maxSize;
34120     },
34121     
34122     /**
34123      * Sets the maximum size for the resizing element
34124      * @param {Number} maxSize The maximum size
34125      */
34126     setMaximumSize : function(maxSize){
34127         this.maxSize = maxSize;
34128     },
34129     
34130     /**
34131      * Sets the initialize size for the resizing element
34132      * @param {Number} size The initial size
34133      */
34134     setCurrentSize : function(size){
34135         var oldAnimate = this.animate;
34136         this.animate = false;
34137         this.adapter.setElementSize(this, size);
34138         this.animate = oldAnimate;
34139     },
34140     
34141     /**
34142      * Destroy this splitbar. 
34143      * @param {Boolean} removeEl True to remove the element
34144      */
34145     destroy : function(removeEl){
34146         if(this.shim){
34147             this.shim.remove();
34148         }
34149         this.dd.unreg();
34150         this.proxy.parentNode.removeChild(this.proxy);
34151         if(removeEl){
34152             this.el.remove();
34153         }
34154     }
34155 });
34156
34157 /**
34158  * @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.
34159  */
34160 Roo.bootstrap.SplitBar.createProxy = function(dir){
34161     var proxy = new Roo.Element(document.createElement("div"));
34162     proxy.unselectable();
34163     var cls = 'roo-splitbar-proxy';
34164     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34165     document.body.appendChild(proxy.dom);
34166     return proxy.dom;
34167 };
34168
34169 /** 
34170  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34171  * Default Adapter. It assumes the splitter and resizing element are not positioned
34172  * elements and only gets/sets the width of the element. Generally used for table based layouts.
34173  */
34174 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34175 };
34176
34177 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34178     // do nothing for now
34179     init : function(s){
34180     
34181     },
34182     /**
34183      * Called before drag operations to get the current size of the resizing element. 
34184      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34185      */
34186      getElementSize : function(s){
34187         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34188             return s.resizingEl.getWidth();
34189         }else{
34190             return s.resizingEl.getHeight();
34191         }
34192     },
34193     
34194     /**
34195      * Called after drag operations to set the size of the resizing element.
34196      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34197      * @param {Number} newSize The new size to set
34198      * @param {Function} onComplete A function to be invoked when resizing is complete
34199      */
34200     setElementSize : function(s, newSize, onComplete){
34201         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34202             if(!s.animate){
34203                 s.resizingEl.setWidth(newSize);
34204                 if(onComplete){
34205                     onComplete(s, newSize);
34206                 }
34207             }else{
34208                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34209             }
34210         }else{
34211             
34212             if(!s.animate){
34213                 s.resizingEl.setHeight(newSize);
34214                 if(onComplete){
34215                     onComplete(s, newSize);
34216                 }
34217             }else{
34218                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34219             }
34220         }
34221     }
34222 };
34223
34224 /** 
34225  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34226  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34227  * Adapter that  moves the splitter element to align with the resized sizing element. 
34228  * Used with an absolute positioned SplitBar.
34229  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34230  * document.body, make sure you assign an id to the body element.
34231  */
34232 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34233     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34234     this.container = Roo.get(container);
34235 };
34236
34237 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34238     init : function(s){
34239         this.basic.init(s);
34240     },
34241     
34242     getElementSize : function(s){
34243         return this.basic.getElementSize(s);
34244     },
34245     
34246     setElementSize : function(s, newSize, onComplete){
34247         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34248     },
34249     
34250     moveSplitter : function(s){
34251         var yes = Roo.bootstrap.SplitBar;
34252         switch(s.placement){
34253             case yes.LEFT:
34254                 s.el.setX(s.resizingEl.getRight());
34255                 break;
34256             case yes.RIGHT:
34257                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34258                 break;
34259             case yes.TOP:
34260                 s.el.setY(s.resizingEl.getBottom());
34261                 break;
34262             case yes.BOTTOM:
34263                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34264                 break;
34265         }
34266     }
34267 };
34268
34269 /**
34270  * Orientation constant - Create a vertical SplitBar
34271  * @static
34272  * @type Number
34273  */
34274 Roo.bootstrap.SplitBar.VERTICAL = 1;
34275
34276 /**
34277  * Orientation constant - Create a horizontal SplitBar
34278  * @static
34279  * @type Number
34280  */
34281 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34282
34283 /**
34284  * Placement constant - The resizing element is to the left of the splitter element
34285  * @static
34286  * @type Number
34287  */
34288 Roo.bootstrap.SplitBar.LEFT = 1;
34289
34290 /**
34291  * Placement constant - The resizing element is to the right of the splitter element
34292  * @static
34293  * @type Number
34294  */
34295 Roo.bootstrap.SplitBar.RIGHT = 2;
34296
34297 /**
34298  * Placement constant - The resizing element is positioned above the splitter element
34299  * @static
34300  * @type Number
34301  */
34302 Roo.bootstrap.SplitBar.TOP = 3;
34303
34304 /**
34305  * Placement constant - The resizing element is positioned under splitter element
34306  * @static
34307  * @type Number
34308  */
34309 Roo.bootstrap.SplitBar.BOTTOM = 4;
34310 Roo.namespace("Roo.bootstrap.layout");/*
34311  * Based on:
34312  * Ext JS Library 1.1.1
34313  * Copyright(c) 2006-2007, Ext JS, LLC.
34314  *
34315  * Originally Released Under LGPL - original licence link has changed is not relivant.
34316  *
34317  * Fork - LGPL
34318  * <script type="text/javascript">
34319  */
34320
34321 /**
34322  * @class Roo.bootstrap.layout.Manager
34323  * @extends Roo.bootstrap.Component
34324  * Base class for layout managers.
34325  */
34326 Roo.bootstrap.layout.Manager = function(config)
34327 {
34328     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34329
34330
34331
34332
34333
34334     /** false to disable window resize monitoring @type Boolean */
34335     this.monitorWindowResize = true;
34336     this.regions = {};
34337     this.addEvents({
34338         /**
34339          * @event layout
34340          * Fires when a layout is performed.
34341          * @param {Roo.LayoutManager} this
34342          */
34343         "layout" : true,
34344         /**
34345          * @event regionresized
34346          * Fires when the user resizes a region.
34347          * @param {Roo.LayoutRegion} region The resized region
34348          * @param {Number} newSize The new size (width for east/west, height for north/south)
34349          */
34350         "regionresized" : true,
34351         /**
34352          * @event regioncollapsed
34353          * Fires when a region is collapsed.
34354          * @param {Roo.LayoutRegion} region The collapsed region
34355          */
34356         "regioncollapsed" : true,
34357         /**
34358          * @event regionexpanded
34359          * Fires when a region is expanded.
34360          * @param {Roo.LayoutRegion} region The expanded region
34361          */
34362         "regionexpanded" : true
34363     });
34364     this.updating = false;
34365
34366     if (config.el) {
34367         this.el = Roo.get(config.el);
34368         this.initEvents();
34369     }
34370
34371 };
34372
34373 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34374
34375
34376     regions : null,
34377
34378     monitorWindowResize : true,
34379
34380
34381     updating : false,
34382
34383
34384     onRender : function(ct, position)
34385     {
34386         if(!this.el){
34387             this.el = Roo.get(ct);
34388             this.initEvents();
34389         }
34390         //this.fireEvent('render',this);
34391     },
34392
34393
34394     initEvents: function()
34395     {
34396
34397
34398         // ie scrollbar fix
34399         if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34400             document.body.scroll = "no";
34401         }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34402             this.el.position('relative');
34403         }
34404         this.id = this.el.id;
34405         this.el.addClass("roo-layout-container");
34406         Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34407         if(this.el.dom != document.body ) {
34408             this.el.on('resize', this.layout,this);
34409             this.el.on('show', this.layout,this);
34410         }
34411
34412     },
34413
34414     /**
34415      * Returns true if this layout is currently being updated
34416      * @return {Boolean}
34417      */
34418     isUpdating : function(){
34419         return this.updating;
34420     },
34421
34422     /**
34423      * Suspend the LayoutManager from doing auto-layouts while
34424      * making multiple add or remove calls
34425      */
34426     beginUpdate : function(){
34427         this.updating = true;
34428     },
34429
34430     /**
34431      * Restore auto-layouts and optionally disable the manager from performing a layout
34432      * @param {Boolean} noLayout true to disable a layout update
34433      */
34434     endUpdate : function(noLayout){
34435         this.updating = false;
34436         if(!noLayout){
34437             this.layout();
34438         }
34439     },
34440
34441     layout: function(){
34442         // abstract...
34443     },
34444
34445     onRegionResized : function(region, newSize){
34446         this.fireEvent("regionresized", region, newSize);
34447         this.layout();
34448     },
34449
34450     onRegionCollapsed : function(region){
34451         this.fireEvent("regioncollapsed", region);
34452     },
34453
34454     onRegionExpanded : function(region){
34455         this.fireEvent("regionexpanded", region);
34456     },
34457
34458     /**
34459      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34460      * performs box-model adjustments.
34461      * @return {Object} The size as an object {width: (the width), height: (the height)}
34462      */
34463     getViewSize : function()
34464     {
34465         var size;
34466         if(this.el.dom != document.body){
34467             size = this.el.getSize();
34468         }else{
34469             size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34470         }
34471         size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34472         size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34473         return size;
34474     },
34475
34476     /**
34477      * Returns the Element this layout is bound to.
34478      * @return {Roo.Element}
34479      */
34480     getEl : function(){
34481         return this.el;
34482     },
34483
34484     /**
34485      * Returns the specified region.
34486      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34487      * @return {Roo.LayoutRegion}
34488      */
34489     getRegion : function(target){
34490         return this.regions[target.toLowerCase()];
34491     },
34492
34493     onWindowResize : function(){
34494         if(this.monitorWindowResize){
34495             this.layout();
34496         }
34497     }
34498 });
34499 /*
34500  * Based on:
34501  * Ext JS Library 1.1.1
34502  * Copyright(c) 2006-2007, Ext JS, LLC.
34503  *
34504  * Originally Released Under LGPL - original licence link has changed is not relivant.
34505  *
34506  * Fork - LGPL
34507  * <script type="text/javascript">
34508  */
34509 /**
34510  * @class Roo.bootstrap.layout.Border
34511  * @extends Roo.bootstrap.layout.Manager
34512  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34513  * please see: examples/bootstrap/nested.html<br><br>
34514  
34515 <b>The container the layout is rendered into can be either the body element or any other element.
34516 If it is not the body element, the container needs to either be an absolute positioned element,
34517 or you will need to add "position:relative" to the css of the container.  You will also need to specify
34518 the container size if it is not the body element.</b>
34519
34520 * @constructor
34521 * Create a new Border
34522 * @param {Object} config Configuration options
34523  */
34524 Roo.bootstrap.layout.Border = function(config){
34525     config = config || {};
34526     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34527     
34528     
34529     
34530     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34531         if(config[region]){
34532             config[region].region = region;
34533             this.addRegion(config[region]);
34534         }
34535     },this);
34536     
34537 };
34538
34539 Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
34540
34541 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34542     /**
34543      * Creates and adds a new region if it doesn't already exist.
34544      * @param {String} target The target region key (north, south, east, west or center).
34545      * @param {Object} config The regions config object
34546      * @return {BorderLayoutRegion} The new region
34547      */
34548     addRegion : function(config)
34549     {
34550         if(!this.regions[config.region]){
34551             var r = this.factory(config);
34552             this.bindRegion(r);
34553         }
34554         return this.regions[config.region];
34555     },
34556
34557     // private (kinda)
34558     bindRegion : function(r){
34559         this.regions[r.config.region] = r;
34560         
34561         r.on("visibilitychange",    this.layout, this);
34562         r.on("paneladded",          this.layout, this);
34563         r.on("panelremoved",        this.layout, this);
34564         r.on("invalidated",         this.layout, this);
34565         r.on("resized",             this.onRegionResized, this);
34566         r.on("collapsed",           this.onRegionCollapsed, this);
34567         r.on("expanded",            this.onRegionExpanded, this);
34568     },
34569
34570     /**
34571      * Performs a layout update.
34572      */
34573     layout : function()
34574     {
34575         if(this.updating) {
34576             return;
34577         }
34578         
34579         // render all the rebions if they have not been done alreayd?
34580         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34581             if(this.regions[region] && !this.regions[region].bodyEl){
34582                 this.regions[region].onRender(this.el)
34583             }
34584         },this);
34585         
34586         var size = this.getViewSize();
34587         var w = size.width;
34588         var h = size.height;
34589         var centerW = w;
34590         var centerH = h;
34591         var centerY = 0;
34592         var centerX = 0;
34593         //var x = 0, y = 0;
34594
34595         var rs = this.regions;
34596         var north = rs["north"];
34597         var south = rs["south"]; 
34598         var west = rs["west"];
34599         var east = rs["east"];
34600         var center = rs["center"];
34601         //if(this.hideOnLayout){ // not supported anymore
34602             //c.el.setStyle("display", "none");
34603         //}
34604         if(north && north.isVisible()){
34605             var b = north.getBox();
34606             var m = north.getMargins();
34607             b.width = w - (m.left+m.right);
34608             b.x = m.left;
34609             b.y = m.top;
34610             centerY = b.height + b.y + m.bottom;
34611             centerH -= centerY;
34612             north.updateBox(this.safeBox(b));
34613         }
34614         if(south && south.isVisible()){
34615             var b = south.getBox();
34616             var m = south.getMargins();
34617             b.width = w - (m.left+m.right);
34618             b.x = m.left;
34619             var totalHeight = (b.height + m.top + m.bottom);
34620             b.y = h - totalHeight + m.top;
34621             centerH -= totalHeight;
34622             south.updateBox(this.safeBox(b));
34623         }
34624         if(west && west.isVisible()){
34625             var b = west.getBox();
34626             var m = west.getMargins();
34627             b.height = centerH - (m.top+m.bottom);
34628             b.x = m.left;
34629             b.y = centerY + m.top;
34630             var totalWidth = (b.width + m.left + m.right);
34631             centerX += totalWidth;
34632             centerW -= totalWidth;
34633             west.updateBox(this.safeBox(b));
34634         }
34635         if(east && east.isVisible()){
34636             var b = east.getBox();
34637             var m = east.getMargins();
34638             b.height = centerH - (m.top+m.bottom);
34639             var totalWidth = (b.width + m.left + m.right);
34640             b.x = w - totalWidth + m.left;
34641             b.y = centerY + m.top;
34642             centerW -= totalWidth;
34643             east.updateBox(this.safeBox(b));
34644         }
34645         if(center){
34646             var m = center.getMargins();
34647             var centerBox = {
34648                 x: centerX + m.left,
34649                 y: centerY + m.top,
34650                 width: centerW - (m.left+m.right),
34651                 height: centerH - (m.top+m.bottom)
34652             };
34653             //if(this.hideOnLayout){
34654                 //center.el.setStyle("display", "block");
34655             //}
34656             center.updateBox(this.safeBox(centerBox));
34657         }
34658         this.el.repaint();
34659         this.fireEvent("layout", this);
34660     },
34661
34662     // private
34663     safeBox : function(box){
34664         box.width = Math.max(0, box.width);
34665         box.height = Math.max(0, box.height);
34666         return box;
34667     },
34668
34669     /**
34670      * Adds a ContentPanel (or subclass) to this layout.
34671      * @param {String} target The target region key (north, south, east, west or center).
34672      * @param {Roo.ContentPanel} panel The panel to add
34673      * @return {Roo.ContentPanel} The added panel
34674      */
34675     add : function(target, panel){
34676          
34677         target = target.toLowerCase();
34678         return this.regions[target].add(panel);
34679     },
34680
34681     /**
34682      * Remove a ContentPanel (or subclass) to this layout.
34683      * @param {String} target The target region key (north, south, east, west or center).
34684      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34685      * @return {Roo.ContentPanel} The removed panel
34686      */
34687     remove : function(target, panel){
34688         target = target.toLowerCase();
34689         return this.regions[target].remove(panel);
34690     },
34691
34692     /**
34693      * Searches all regions for a panel with the specified id
34694      * @param {String} panelId
34695      * @return {Roo.ContentPanel} The panel or null if it wasn't found
34696      */
34697     findPanel : function(panelId){
34698         var rs = this.regions;
34699         for(var target in rs){
34700             if(typeof rs[target] != "function"){
34701                 var p = rs[target].getPanel(panelId);
34702                 if(p){
34703                     return p;
34704                 }
34705             }
34706         }
34707         return null;
34708     },
34709
34710     /**
34711      * Searches all regions for a panel with the specified id and activates (shows) it.
34712      * @param {String/ContentPanel} panelId The panels id or the panel itself
34713      * @return {Roo.ContentPanel} The shown panel or null
34714      */
34715     showPanel : function(panelId) {
34716       var rs = this.regions;
34717       for(var target in rs){
34718          var r = rs[target];
34719          if(typeof r != "function"){
34720             if(r.hasPanel(panelId)){
34721                return r.showPanel(panelId);
34722             }
34723          }
34724       }
34725       return null;
34726    },
34727
34728    /**
34729      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34730      * @param {Roo.state.Provider} provider (optional) An alternate state provider
34731      */
34732    /*
34733     restoreState : function(provider){
34734         if(!provider){
34735             provider = Roo.state.Manager;
34736         }
34737         var sm = new Roo.LayoutStateManager();
34738         sm.init(this, provider);
34739     },
34740 */
34741  
34742  
34743     /**
34744      * Adds a xtype elements to the layout.
34745      * <pre><code>
34746
34747 layout.addxtype({
34748        xtype : 'ContentPanel',
34749        region: 'west',
34750        items: [ .... ]
34751    }
34752 );
34753
34754 layout.addxtype({
34755         xtype : 'NestedLayoutPanel',
34756         region: 'west',
34757         layout: {
34758            center: { },
34759            west: { }   
34760         },
34761         items : [ ... list of content panels or nested layout panels.. ]
34762    }
34763 );
34764 </code></pre>
34765      * @param {Object} cfg Xtype definition of item to add.
34766      */
34767     addxtype : function(cfg)
34768     {
34769         // basically accepts a pannel...
34770         // can accept a layout region..!?!?
34771         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34772         
34773         
34774         // theory?  children can only be panels??
34775         
34776         //if (!cfg.xtype.match(/Panel$/)) {
34777         //    return false;
34778         //}
34779         var ret = false;
34780         
34781         if (typeof(cfg.region) == 'undefined') {
34782             Roo.log("Failed to add Panel, region was not set");
34783             Roo.log(cfg);
34784             return false;
34785         }
34786         var region = cfg.region;
34787         delete cfg.region;
34788         
34789           
34790         var xitems = [];
34791         if (cfg.items) {
34792             xitems = cfg.items;
34793             delete cfg.items;
34794         }
34795         var nb = false;
34796         
34797         switch(cfg.xtype) 
34798         {
34799             case 'Content':  // ContentPanel (el, cfg)
34800             case 'Scroll':  // ContentPanel (el, cfg)
34801             case 'View': 
34802                 cfg.autoCreate = true;
34803                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34804                 //} else {
34805                 //    var el = this.el.createChild();
34806                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34807                 //}
34808                 
34809                 this.add(region, ret);
34810                 break;
34811             
34812             /*
34813             case 'TreePanel': // our new panel!
34814                 cfg.el = this.el.createChild();
34815                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34816                 this.add(region, ret);
34817                 break;
34818             */
34819             
34820             case 'Nest': 
34821                 // create a new Layout (which is  a Border Layout...
34822                 
34823                 var clayout = cfg.layout;
34824                 clayout.el  = this.el.createChild();
34825                 clayout.items   = clayout.items  || [];
34826                 
34827                 delete cfg.layout;
34828                 
34829                 // replace this exitems with the clayout ones..
34830                 xitems = clayout.items;
34831                  
34832                 // force background off if it's in center...
34833                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34834                     cfg.background = false;
34835                 }
34836                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
34837                 
34838                 
34839                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34840                 //console.log('adding nested layout panel '  + cfg.toSource());
34841                 this.add(region, ret);
34842                 nb = {}; /// find first...
34843                 break;
34844             
34845             case 'Grid':
34846                 
34847                 // needs grid and region
34848                 
34849                 //var el = this.getRegion(region).el.createChild();
34850                 /*
34851                  *var el = this.el.createChild();
34852                 // create the grid first...
34853                 cfg.grid.container = el;
34854                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34855                 */
34856                 
34857                 if (region == 'center' && this.active ) {
34858                     cfg.background = false;
34859                 }
34860                 
34861                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34862                 
34863                 this.add(region, ret);
34864                 /*
34865                 if (cfg.background) {
34866                     // render grid on panel activation (if panel background)
34867                     ret.on('activate', function(gp) {
34868                         if (!gp.grid.rendered) {
34869                     //        gp.grid.render(el);
34870                         }
34871                     });
34872                 } else {
34873                   //  cfg.grid.render(el);
34874                 }
34875                 */
34876                 break;
34877            
34878            
34879             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34880                 // it was the old xcomponent building that caused this before.
34881                 // espeically if border is the top element in the tree.
34882                 ret = this;
34883                 break; 
34884                 
34885                     
34886                 
34887                 
34888                 
34889             default:
34890                 /*
34891                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34892                     
34893                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34894                     this.add(region, ret);
34895                 } else {
34896                 */
34897                     Roo.log(cfg);
34898                     throw "Can not add '" + cfg.xtype + "' to Border";
34899                     return null;
34900              
34901                                 
34902              
34903         }
34904         this.beginUpdate();
34905         // add children..
34906         var region = '';
34907         var abn = {};
34908         Roo.each(xitems, function(i)  {
34909             region = nb && i.region ? i.region : false;
34910             
34911             var add = ret.addxtype(i);
34912            
34913             if (region) {
34914                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34915                 if (!i.background) {
34916                     abn[region] = nb[region] ;
34917                 }
34918             }
34919             
34920         });
34921         this.endUpdate();
34922
34923         // make the last non-background panel active..
34924         //if (nb) { Roo.log(abn); }
34925         if (nb) {
34926             
34927             for(var r in abn) {
34928                 region = this.getRegion(r);
34929                 if (region) {
34930                     // tried using nb[r], but it does not work..
34931                      
34932                     region.showPanel(abn[r]);
34933                    
34934                 }
34935             }
34936         }
34937         return ret;
34938         
34939     },
34940     
34941     
34942 // private
34943     factory : function(cfg)
34944     {
34945         
34946         var validRegions = Roo.bootstrap.layout.Border.regions;
34947
34948         var target = cfg.region;
34949         cfg.mgr = this;
34950         
34951         var r = Roo.bootstrap.layout;
34952         Roo.log(target);
34953         switch(target){
34954             case "north":
34955                 return new r.North(cfg);
34956             case "south":
34957                 return new r.South(cfg);
34958             case "east":
34959                 return new r.East(cfg);
34960             case "west":
34961                 return new r.West(cfg);
34962             case "center":
34963                 return new r.Center(cfg);
34964         }
34965         throw 'Layout region "'+target+'" not supported.';
34966     }
34967     
34968     
34969 });
34970  /*
34971  * Based on:
34972  * Ext JS Library 1.1.1
34973  * Copyright(c) 2006-2007, Ext JS, LLC.
34974  *
34975  * Originally Released Under LGPL - original licence link has changed is not relivant.
34976  *
34977  * Fork - LGPL
34978  * <script type="text/javascript">
34979  */
34980  
34981 /**
34982  * @class Roo.bootstrap.layout.Basic
34983  * @extends Roo.util.Observable
34984  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34985  * and does not have a titlebar, tabs or any other features. All it does is size and position 
34986  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34987  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
34988  * @cfg {string}   region  the region that it inhabits..
34989  * @cfg {bool}   skipConfig skip config?
34990  * 
34991
34992  */
34993 Roo.bootstrap.layout.Basic = function(config){
34994     
34995     this.mgr = config.mgr;
34996     
34997     this.position = config.region;
34998     
34999     var skipConfig = config.skipConfig;
35000     
35001     this.events = {
35002         /**
35003          * @scope Roo.BasicLayoutRegion
35004          */
35005         
35006         /**
35007          * @event beforeremove
35008          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35009          * @param {Roo.LayoutRegion} this
35010          * @param {Roo.ContentPanel} panel The panel
35011          * @param {Object} e The cancel event object
35012          */
35013         "beforeremove" : true,
35014         /**
35015          * @event invalidated
35016          * Fires when the layout for this region is changed.
35017          * @param {Roo.LayoutRegion} this
35018          */
35019         "invalidated" : true,
35020         /**
35021          * @event visibilitychange
35022          * Fires when this region is shown or hidden 
35023          * @param {Roo.LayoutRegion} this
35024          * @param {Boolean} visibility true or false
35025          */
35026         "visibilitychange" : true,
35027         /**
35028          * @event paneladded
35029          * Fires when a panel is added. 
35030          * @param {Roo.LayoutRegion} this
35031          * @param {Roo.ContentPanel} panel The panel
35032          */
35033         "paneladded" : true,
35034         /**
35035          * @event panelremoved
35036          * Fires when a panel is removed. 
35037          * @param {Roo.LayoutRegion} this
35038          * @param {Roo.ContentPanel} panel The panel
35039          */
35040         "panelremoved" : true,
35041         /**
35042          * @event beforecollapse
35043          * Fires when this region before collapse.
35044          * @param {Roo.LayoutRegion} this
35045          */
35046         "beforecollapse" : true,
35047         /**
35048          * @event collapsed
35049          * Fires when this region is collapsed.
35050          * @param {Roo.LayoutRegion} this
35051          */
35052         "collapsed" : true,
35053         /**
35054          * @event expanded
35055          * Fires when this region is expanded.
35056          * @param {Roo.LayoutRegion} this
35057          */
35058         "expanded" : true,
35059         /**
35060          * @event slideshow
35061          * Fires when this region is slid into view.
35062          * @param {Roo.LayoutRegion} this
35063          */
35064         "slideshow" : true,
35065         /**
35066          * @event slidehide
35067          * Fires when this region slides out of view. 
35068          * @param {Roo.LayoutRegion} this
35069          */
35070         "slidehide" : true,
35071         /**
35072          * @event panelactivated
35073          * Fires when a panel is activated. 
35074          * @param {Roo.LayoutRegion} this
35075          * @param {Roo.ContentPanel} panel The activated panel
35076          */
35077         "panelactivated" : true,
35078         /**
35079          * @event resized
35080          * Fires when the user resizes this region. 
35081          * @param {Roo.LayoutRegion} this
35082          * @param {Number} newSize The new size (width for east/west, height for north/south)
35083          */
35084         "resized" : true
35085     };
35086     /** A collection of panels in this region. @type Roo.util.MixedCollection */
35087     this.panels = new Roo.util.MixedCollection();
35088     this.panels.getKey = this.getPanelId.createDelegate(this);
35089     this.box = null;
35090     this.activePanel = null;
35091     // ensure listeners are added...
35092     
35093     if (config.listeners || config.events) {
35094         Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35095             listeners : config.listeners || {},
35096             events : config.events || {}
35097         });
35098     }
35099     
35100     if(skipConfig !== true){
35101         this.applyConfig(config);
35102     }
35103 };
35104
35105 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35106 {
35107     getPanelId : function(p){
35108         return p.getId();
35109     },
35110     
35111     applyConfig : function(config){
35112         this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35113         this.config = config;
35114         
35115     },
35116     
35117     /**
35118      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
35119      * the width, for horizontal (north, south) the height.
35120      * @param {Number} newSize The new width or height
35121      */
35122     resizeTo : function(newSize){
35123         var el = this.el ? this.el :
35124                  (this.activePanel ? this.activePanel.getEl() : null);
35125         if(el){
35126             switch(this.position){
35127                 case "east":
35128                 case "west":
35129                     el.setWidth(newSize);
35130                     this.fireEvent("resized", this, newSize);
35131                 break;
35132                 case "north":
35133                 case "south":
35134                     el.setHeight(newSize);
35135                     this.fireEvent("resized", this, newSize);
35136                 break;                
35137             }
35138         }
35139     },
35140     
35141     getBox : function(){
35142         return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35143     },
35144     
35145     getMargins : function(){
35146         return this.margins;
35147     },
35148     
35149     updateBox : function(box){
35150         this.box = box;
35151         var el = this.activePanel.getEl();
35152         el.dom.style.left = box.x + "px";
35153         el.dom.style.top = box.y + "px";
35154         this.activePanel.setSize(box.width, box.height);
35155     },
35156     
35157     /**
35158      * Returns the container element for this region.
35159      * @return {Roo.Element}
35160      */
35161     getEl : function(){
35162         return this.activePanel;
35163     },
35164     
35165     /**
35166      * Returns true if this region is currently visible.
35167      * @return {Boolean}
35168      */
35169     isVisible : function(){
35170         return this.activePanel ? true : false;
35171     },
35172     
35173     setActivePanel : function(panel){
35174         panel = this.getPanel(panel);
35175         if(this.activePanel && this.activePanel != panel){
35176             this.activePanel.setActiveState(false);
35177             this.activePanel.getEl().setLeftTop(-10000,-10000);
35178         }
35179         this.activePanel = panel;
35180         panel.setActiveState(true);
35181         if(this.box){
35182             panel.setSize(this.box.width, this.box.height);
35183         }
35184         this.fireEvent("panelactivated", this, panel);
35185         this.fireEvent("invalidated");
35186     },
35187     
35188     /**
35189      * Show the specified panel.
35190      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35191      * @return {Roo.ContentPanel} The shown panel or null
35192      */
35193     showPanel : function(panel){
35194         panel = this.getPanel(panel);
35195         if(panel){
35196             this.setActivePanel(panel);
35197         }
35198         return panel;
35199     },
35200     
35201     /**
35202      * Get the active panel for this region.
35203      * @return {Roo.ContentPanel} The active panel or null
35204      */
35205     getActivePanel : function(){
35206         return this.activePanel;
35207     },
35208     
35209     /**
35210      * Add the passed ContentPanel(s)
35211      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35212      * @return {Roo.ContentPanel} The panel added (if only one was added)
35213      */
35214     add : function(panel){
35215         if(arguments.length > 1){
35216             for(var i = 0, len = arguments.length; i < len; i++) {
35217                 this.add(arguments[i]);
35218             }
35219             return null;
35220         }
35221         if(this.hasPanel(panel)){
35222             this.showPanel(panel);
35223             return panel;
35224         }
35225         var el = panel.getEl();
35226         if(el.dom.parentNode != this.mgr.el.dom){
35227             this.mgr.el.dom.appendChild(el.dom);
35228         }
35229         if(panel.setRegion){
35230             panel.setRegion(this);
35231         }
35232         this.panels.add(panel);
35233         el.setStyle("position", "absolute");
35234         if(!panel.background){
35235             this.setActivePanel(panel);
35236             if(this.config.initialSize && this.panels.getCount()==1){
35237                 this.resizeTo(this.config.initialSize);
35238             }
35239         }
35240         this.fireEvent("paneladded", this, panel);
35241         return panel;
35242     },
35243     
35244     /**
35245      * Returns true if the panel is in this region.
35246      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35247      * @return {Boolean}
35248      */
35249     hasPanel : function(panel){
35250         if(typeof panel == "object"){ // must be panel obj
35251             panel = panel.getId();
35252         }
35253         return this.getPanel(panel) ? true : false;
35254     },
35255     
35256     /**
35257      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35258      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35259      * @param {Boolean} preservePanel Overrides the config preservePanel option
35260      * @return {Roo.ContentPanel} The panel that was removed
35261      */
35262     remove : function(panel, preservePanel){
35263         panel = this.getPanel(panel);
35264         if(!panel){
35265             return null;
35266         }
35267         var e = {};
35268         this.fireEvent("beforeremove", this, panel, e);
35269         if(e.cancel === true){
35270             return null;
35271         }
35272         var panelId = panel.getId();
35273         this.panels.removeKey(panelId);
35274         return panel;
35275     },
35276     
35277     /**
35278      * Returns the panel specified or null if it's not in this region.
35279      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35280      * @return {Roo.ContentPanel}
35281      */
35282     getPanel : function(id){
35283         if(typeof id == "object"){ // must be panel obj
35284             return id;
35285         }
35286         return this.panels.get(id);
35287     },
35288     
35289     /**
35290      * Returns this regions position (north/south/east/west/center).
35291      * @return {String} 
35292      */
35293     getPosition: function(){
35294         return this.position;    
35295     }
35296 });/*
35297  * Based on:
35298  * Ext JS Library 1.1.1
35299  * Copyright(c) 2006-2007, Ext JS, LLC.
35300  *
35301  * Originally Released Under LGPL - original licence link has changed is not relivant.
35302  *
35303  * Fork - LGPL
35304  * <script type="text/javascript">
35305  */
35306  
35307 /**
35308  * @class Roo.bootstrap.layout.Region
35309  * @extends Roo.bootstrap.layout.Basic
35310  * This class represents a region in a layout manager.
35311  
35312  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35313  * @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})
35314  * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
35315  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
35316  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
35317  * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
35318  * @cfg {String}    title           The title for the region (overrides panel titles)
35319  * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
35320  * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35321  * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
35322  * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35323  * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
35324  * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35325  *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
35326  * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
35327  * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
35328  * @cfg {String}    overflow       (hidden|visible) if you have menus in the region, then you need to set this to visible.
35329
35330  * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
35331  * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
35332  * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
35333  * @cfg {Number}    width           For East/West panels
35334  * @cfg {Number}    height          For North/South panels
35335  * @cfg {Boolean}   split           To show the splitter
35336  * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
35337  * 
35338  * @cfg {string}   cls             Extra CSS classes to add to region
35339  * 
35340  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35341  * @cfg {string}   region  the region that it inhabits..
35342  *
35343
35344  * @xxxcfg {Boolean}   collapsible     DISABLED False to disable collapsing (defaults to true)
35345  * @xxxcfg {Boolean}   collapsed       DISABLED True to set the initial display to collapsed (defaults to false)
35346
35347  * @xxxcfg {String}    collapsedTitle  DISABLED Optional string message to display in the collapsed block of a north or south region
35348  * @xxxxcfg {Boolean}   floatable       DISABLED False to disable floating (defaults to true)
35349  * @xxxxcfg {Boolean}   showPin         True to show a pin button NOT SUPPORTED YET
35350  */
35351 Roo.bootstrap.layout.Region = function(config)
35352 {
35353     this.applyConfig(config);
35354
35355     var mgr = config.mgr;
35356     var pos = config.region;
35357     config.skipConfig = true;
35358     Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35359     
35360     if (mgr.el) {
35361         this.onRender(mgr.el);   
35362     }
35363      
35364     this.visible = true;
35365     this.collapsed = false;
35366     this.unrendered_panels = [];
35367 };
35368
35369 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35370
35371     position: '', // set by wrapper (eg. north/south etc..)
35372     unrendered_panels : null,  // unrendered panels.
35373     createBody : function(){
35374         /** This region's body element 
35375         * @type Roo.Element */
35376         this.bodyEl = this.el.createChild({
35377                 tag: "div",
35378                 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35379         });
35380     },
35381
35382     onRender: function(ctr, pos)
35383     {
35384         var dh = Roo.DomHelper;
35385         /** This region's container element 
35386         * @type Roo.Element */
35387         this.el = dh.append(ctr.dom, {
35388                 tag: "div",
35389                 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35390             }, true);
35391         /** This region's title element 
35392         * @type Roo.Element */
35393     
35394         this.titleEl = dh.append(this.el.dom,
35395             {
35396                     tag: "div",
35397                     unselectable: "on",
35398                     cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35399                     children:[
35400                         {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
35401                         {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35402                     ]}, true);
35403         
35404         this.titleEl.enableDisplayMode();
35405         /** This region's title text element 
35406         * @type HTMLElement */
35407         this.titleTextEl = this.titleEl.dom.firstChild;
35408         this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35409         /*
35410         this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35411         this.closeBtn.enableDisplayMode();
35412         this.closeBtn.on("click", this.closeClicked, this);
35413         this.closeBtn.hide();
35414     */
35415         this.createBody(this.config);
35416         if(this.config.hideWhenEmpty){
35417             this.hide();
35418             this.on("paneladded", this.validateVisibility, this);
35419             this.on("panelremoved", this.validateVisibility, this);
35420         }
35421         if(this.autoScroll){
35422             this.bodyEl.setStyle("overflow", "auto");
35423         }else{
35424             this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35425         }
35426         //if(c.titlebar !== false){
35427             if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35428                 this.titleEl.hide();
35429             }else{
35430                 this.titleEl.show();
35431                 if(this.config.title){
35432                     this.titleTextEl.innerHTML = this.config.title;
35433                 }
35434             }
35435         //}
35436         if(this.config.collapsed){
35437             this.collapse(true);
35438         }
35439         if(this.config.hidden){
35440             this.hide();
35441         }
35442         
35443         if (this.unrendered_panels && this.unrendered_panels.length) {
35444             for (var i =0;i< this.unrendered_panels.length; i++) {
35445                 this.add(this.unrendered_panels[i]);
35446             }
35447             this.unrendered_panels = null;
35448             
35449         }
35450         
35451     },
35452     
35453     applyConfig : function(c)
35454     {
35455         /*
35456          *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35457             var dh = Roo.DomHelper;
35458             if(c.titlebar !== false){
35459                 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35460                 this.collapseBtn.on("click", this.collapse, this);
35461                 this.collapseBtn.enableDisplayMode();
35462                 /*
35463                 if(c.showPin === true || this.showPin){
35464                     this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35465                     this.stickBtn.enableDisplayMode();
35466                     this.stickBtn.on("click", this.expand, this);
35467                     this.stickBtn.hide();
35468                 }
35469                 
35470             }
35471             */
35472             /** This region's collapsed element
35473             * @type Roo.Element */
35474             /*
35475              *
35476             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35477                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35478             ]}, true);
35479             
35480             if(c.floatable !== false){
35481                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35482                this.collapsedEl.on("click", this.collapseClick, this);
35483             }
35484
35485             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35486                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35487                    id: "message", unselectable: "on", style:{"float":"left"}});
35488                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35489              }
35490             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35491             this.expandBtn.on("click", this.expand, this);
35492             
35493         }
35494         
35495         if(this.collapseBtn){
35496             this.collapseBtn.setVisible(c.collapsible == true);
35497         }
35498         
35499         this.cmargins = c.cmargins || this.cmargins ||
35500                          (this.position == "west" || this.position == "east" ?
35501                              {top: 0, left: 2, right:2, bottom: 0} :
35502                              {top: 2, left: 0, right:0, bottom: 2});
35503         */
35504         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35505         
35506         
35507         this.bottomTabs = c.tabPosition != "top";
35508         
35509         this.autoScroll = c.autoScroll || false;
35510         
35511         
35512        
35513         
35514         this.duration = c.duration || .30;
35515         this.slideDuration = c.slideDuration || .45;
35516         this.config = c;
35517        
35518     },
35519     /**
35520      * Returns true if this region is currently visible.
35521      * @return {Boolean}
35522      */
35523     isVisible : function(){
35524         return this.visible;
35525     },
35526
35527     /**
35528      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35529      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
35530      */
35531     //setCollapsedTitle : function(title){
35532     //    title = title || "&#160;";
35533      //   if(this.collapsedTitleTextEl){
35534       //      this.collapsedTitleTextEl.innerHTML = title;
35535        // }
35536     //},
35537
35538     getBox : function(){
35539         var b;
35540       //  if(!this.collapsed){
35541             b = this.el.getBox(false, true);
35542        // }else{
35543           //  b = this.collapsedEl.getBox(false, true);
35544         //}
35545         return b;
35546     },
35547
35548     getMargins : function(){
35549         return this.margins;
35550         //return this.collapsed ? this.cmargins : this.margins;
35551     },
35552 /*
35553     highlight : function(){
35554         this.el.addClass("x-layout-panel-dragover");
35555     },
35556
35557     unhighlight : function(){
35558         this.el.removeClass("x-layout-panel-dragover");
35559     },
35560 */
35561     updateBox : function(box)
35562     {
35563         if (!this.bodyEl) {
35564             return; // not rendered yet..
35565         }
35566         
35567         this.box = box;
35568         if(!this.collapsed){
35569             this.el.dom.style.left = box.x + "px";
35570             this.el.dom.style.top = box.y + "px";
35571             this.updateBody(box.width, box.height);
35572         }else{
35573             this.collapsedEl.dom.style.left = box.x + "px";
35574             this.collapsedEl.dom.style.top = box.y + "px";
35575             this.collapsedEl.setSize(box.width, box.height);
35576         }
35577         if(this.tabs){
35578             this.tabs.autoSizeTabs();
35579         }
35580     },
35581
35582     updateBody : function(w, h)
35583     {
35584         if(w !== null){
35585             this.el.setWidth(w);
35586             w -= this.el.getBorderWidth("rl");
35587             if(this.config.adjustments){
35588                 w += this.config.adjustments[0];
35589             }
35590         }
35591         if(h !== null && h > 0){
35592             this.el.setHeight(h);
35593             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35594             h -= this.el.getBorderWidth("tb");
35595             if(this.config.adjustments){
35596                 h += this.config.adjustments[1];
35597             }
35598             this.bodyEl.setHeight(h);
35599             if(this.tabs){
35600                 h = this.tabs.syncHeight(h);
35601             }
35602         }
35603         if(this.panelSize){
35604             w = w !== null ? w : this.panelSize.width;
35605             h = h !== null ? h : this.panelSize.height;
35606         }
35607         if(this.activePanel){
35608             var el = this.activePanel.getEl();
35609             w = w !== null ? w : el.getWidth();
35610             h = h !== null ? h : el.getHeight();
35611             this.panelSize = {width: w, height: h};
35612             this.activePanel.setSize(w, h);
35613         }
35614         if(Roo.isIE && this.tabs){
35615             this.tabs.el.repaint();
35616         }
35617     },
35618
35619     /**
35620      * Returns the container element for this region.
35621      * @return {Roo.Element}
35622      */
35623     getEl : function(){
35624         return this.el;
35625     },
35626
35627     /**
35628      * Hides this region.
35629      */
35630     hide : function(){
35631         //if(!this.collapsed){
35632             this.el.dom.style.left = "-2000px";
35633             this.el.hide();
35634         //}else{
35635          //   this.collapsedEl.dom.style.left = "-2000px";
35636          //   this.collapsedEl.hide();
35637        // }
35638         this.visible = false;
35639         this.fireEvent("visibilitychange", this, false);
35640     },
35641
35642     /**
35643      * Shows this region if it was previously hidden.
35644      */
35645     show : function(){
35646         //if(!this.collapsed){
35647             this.el.show();
35648         //}else{
35649         //    this.collapsedEl.show();
35650        // }
35651         this.visible = true;
35652         this.fireEvent("visibilitychange", this, true);
35653     },
35654 /*
35655     closeClicked : function(){
35656         if(this.activePanel){
35657             this.remove(this.activePanel);
35658         }
35659     },
35660
35661     collapseClick : function(e){
35662         if(this.isSlid){
35663            e.stopPropagation();
35664            this.slideIn();
35665         }else{
35666            e.stopPropagation();
35667            this.slideOut();
35668         }
35669     },
35670 */
35671     /**
35672      * Collapses this region.
35673      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35674      */
35675     /*
35676     collapse : function(skipAnim, skipCheck = false){
35677         if(this.collapsed) {
35678             return;
35679         }
35680         
35681         if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35682             
35683             this.collapsed = true;
35684             if(this.split){
35685                 this.split.el.hide();
35686             }
35687             if(this.config.animate && skipAnim !== true){
35688                 this.fireEvent("invalidated", this);
35689                 this.animateCollapse();
35690             }else{
35691                 this.el.setLocation(-20000,-20000);
35692                 this.el.hide();
35693                 this.collapsedEl.show();
35694                 this.fireEvent("collapsed", this);
35695                 this.fireEvent("invalidated", this);
35696             }
35697         }
35698         
35699     },
35700 */
35701     animateCollapse : function(){
35702         // overridden
35703     },
35704
35705     /**
35706      * Expands this region if it was previously collapsed.
35707      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35708      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35709      */
35710     /*
35711     expand : function(e, skipAnim){
35712         if(e) {
35713             e.stopPropagation();
35714         }
35715         if(!this.collapsed || this.el.hasActiveFx()) {
35716             return;
35717         }
35718         if(this.isSlid){
35719             this.afterSlideIn();
35720             skipAnim = true;
35721         }
35722         this.collapsed = false;
35723         if(this.config.animate && skipAnim !== true){
35724             this.animateExpand();
35725         }else{
35726             this.el.show();
35727             if(this.split){
35728                 this.split.el.show();
35729             }
35730             this.collapsedEl.setLocation(-2000,-2000);
35731             this.collapsedEl.hide();
35732             this.fireEvent("invalidated", this);
35733             this.fireEvent("expanded", this);
35734         }
35735     },
35736 */
35737     animateExpand : function(){
35738         // overridden
35739     },
35740
35741     initTabs : function()
35742     {
35743         //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35744         
35745         var ts = new Roo.bootstrap.panel.Tabs({
35746                 el: this.bodyEl.dom,
35747                 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35748                 disableTooltips: this.config.disableTabTips,
35749                 toolbar : this.config.toolbar
35750             });
35751         
35752         if(this.config.hideTabs){
35753             ts.stripWrap.setDisplayed(false);
35754         }
35755         this.tabs = ts;
35756         ts.resizeTabs = this.config.resizeTabs === true;
35757         ts.minTabWidth = this.config.minTabWidth || 40;
35758         ts.maxTabWidth = this.config.maxTabWidth || 250;
35759         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35760         ts.monitorResize = false;
35761         //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35762         ts.bodyEl.addClass('roo-layout-tabs-body');
35763         this.panels.each(this.initPanelAsTab, this);
35764     },
35765
35766     initPanelAsTab : function(panel){
35767         var ti = this.tabs.addTab(
35768             panel.getEl().id,
35769             panel.getTitle(),
35770             null,
35771             this.config.closeOnTab && panel.isClosable(),
35772             panel.tpl
35773         );
35774         if(panel.tabTip !== undefined){
35775             ti.setTooltip(panel.tabTip);
35776         }
35777         ti.on("activate", function(){
35778               this.setActivePanel(panel);
35779         }, this);
35780         
35781         if(this.config.closeOnTab){
35782             ti.on("beforeclose", function(t, e){
35783                 e.cancel = true;
35784                 this.remove(panel);
35785             }, this);
35786         }
35787         
35788         panel.tabItem = ti;
35789         
35790         return ti;
35791     },
35792
35793     updatePanelTitle : function(panel, title)
35794     {
35795         if(this.activePanel == panel){
35796             this.updateTitle(title);
35797         }
35798         if(this.tabs){
35799             var ti = this.tabs.getTab(panel.getEl().id);
35800             ti.setText(title);
35801             if(panel.tabTip !== undefined){
35802                 ti.setTooltip(panel.tabTip);
35803             }
35804         }
35805     },
35806
35807     updateTitle : function(title){
35808         if(this.titleTextEl && !this.config.title){
35809             this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
35810         }
35811     },
35812
35813     setActivePanel : function(panel)
35814     {
35815         panel = this.getPanel(panel);
35816         if(this.activePanel && this.activePanel != panel){
35817             if(this.activePanel.setActiveState(false) === false){
35818                 return;
35819             }
35820         }
35821         this.activePanel = panel;
35822         panel.setActiveState(true);
35823         if(this.panelSize){
35824             panel.setSize(this.panelSize.width, this.panelSize.height);
35825         }
35826         if(this.closeBtn){
35827             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35828         }
35829         this.updateTitle(panel.getTitle());
35830         if(this.tabs){
35831             this.fireEvent("invalidated", this);
35832         }
35833         this.fireEvent("panelactivated", this, panel);
35834     },
35835
35836     /**
35837      * Shows the specified panel.
35838      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35839      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35840      */
35841     showPanel : function(panel)
35842     {
35843         panel = this.getPanel(panel);
35844         if(panel){
35845             if(this.tabs){
35846                 var tab = this.tabs.getTab(panel.getEl().id);
35847                 if(tab.isHidden()){
35848                     this.tabs.unhideTab(tab.id);
35849                 }
35850                 tab.activate();
35851             }else{
35852                 this.setActivePanel(panel);
35853             }
35854         }
35855         return panel;
35856     },
35857
35858     /**
35859      * Get the active panel for this region.
35860      * @return {Roo.ContentPanel} The active panel or null
35861      */
35862     getActivePanel : function(){
35863         return this.activePanel;
35864     },
35865
35866     validateVisibility : function(){
35867         if(this.panels.getCount() < 1){
35868             this.updateTitle("&#160;");
35869             this.closeBtn.hide();
35870             this.hide();
35871         }else{
35872             if(!this.isVisible()){
35873                 this.show();
35874             }
35875         }
35876     },
35877
35878     /**
35879      * Adds the passed ContentPanel(s) to this region.
35880      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35881      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35882      */
35883     add : function(panel)
35884     {
35885         if(arguments.length > 1){
35886             for(var i = 0, len = arguments.length; i < len; i++) {
35887                 this.add(arguments[i]);
35888             }
35889             return null;
35890         }
35891         
35892         // if we have not been rendered yet, then we can not really do much of this..
35893         if (!this.bodyEl) {
35894             this.unrendered_panels.push(panel);
35895             return panel;
35896         }
35897         
35898         
35899         
35900         
35901         if(this.hasPanel(panel)){
35902             this.showPanel(panel);
35903             return panel;
35904         }
35905         panel.setRegion(this);
35906         this.panels.add(panel);
35907        /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35908             // sinle panel - no tab...?? would it not be better to render it with the tabs,
35909             // and hide them... ???
35910             this.bodyEl.dom.appendChild(panel.getEl().dom);
35911             if(panel.background !== true){
35912                 this.setActivePanel(panel);
35913             }
35914             this.fireEvent("paneladded", this, panel);
35915             return panel;
35916         }
35917         */
35918         if(!this.tabs){
35919             this.initTabs();
35920         }else{
35921             this.initPanelAsTab(panel);
35922         }
35923         
35924         
35925         if(panel.background !== true){
35926             this.tabs.activate(panel.getEl().id);
35927         }
35928         this.fireEvent("paneladded", this, panel);
35929         return panel;
35930     },
35931
35932     /**
35933      * Hides the tab for the specified panel.
35934      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35935      */
35936     hidePanel : function(panel){
35937         if(this.tabs && (panel = this.getPanel(panel))){
35938             this.tabs.hideTab(panel.getEl().id);
35939         }
35940     },
35941
35942     /**
35943      * Unhides the tab for a previously hidden panel.
35944      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35945      */
35946     unhidePanel : function(panel){
35947         if(this.tabs && (panel = this.getPanel(panel))){
35948             this.tabs.unhideTab(panel.getEl().id);
35949         }
35950     },
35951
35952     clearPanels : function(){
35953         while(this.panels.getCount() > 0){
35954              this.remove(this.panels.first());
35955         }
35956     },
35957
35958     /**
35959      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35960      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35961      * @param {Boolean} preservePanel Overrides the config preservePanel option
35962      * @return {Roo.ContentPanel} The panel that was removed
35963      */
35964     remove : function(panel, preservePanel)
35965     {
35966         panel = this.getPanel(panel);
35967         if(!panel){
35968             return null;
35969         }
35970         var e = {};
35971         this.fireEvent("beforeremove", this, panel, e);
35972         if(e.cancel === true){
35973             return null;
35974         }
35975         preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35976         var panelId = panel.getId();
35977         this.panels.removeKey(panelId);
35978         if(preservePanel){
35979             document.body.appendChild(panel.getEl().dom);
35980         }
35981         if(this.tabs){
35982             this.tabs.removeTab(panel.getEl().id);
35983         }else if (!preservePanel){
35984             this.bodyEl.dom.removeChild(panel.getEl().dom);
35985         }
35986         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35987             var p = this.panels.first();
35988             var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35989             tempEl.appendChild(p.getEl().dom);
35990             this.bodyEl.update("");
35991             this.bodyEl.dom.appendChild(p.getEl().dom);
35992             tempEl = null;
35993             this.updateTitle(p.getTitle());
35994             this.tabs = null;
35995             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35996             this.setActivePanel(p);
35997         }
35998         panel.setRegion(null);
35999         if(this.activePanel == panel){
36000             this.activePanel = null;
36001         }
36002         if(this.config.autoDestroy !== false && preservePanel !== true){
36003             try{panel.destroy();}catch(e){}
36004         }
36005         this.fireEvent("panelremoved", this, panel);
36006         return panel;
36007     },
36008
36009     /**
36010      * Returns the TabPanel component used by this region
36011      * @return {Roo.TabPanel}
36012      */
36013     getTabs : function(){
36014         return this.tabs;
36015     },
36016
36017     createTool : function(parentEl, className){
36018         var btn = Roo.DomHelper.append(parentEl, {
36019             tag: "div",
36020             cls: "x-layout-tools-button",
36021             children: [ {
36022                 tag: "div",
36023                 cls: "roo-layout-tools-button-inner " + className,
36024                 html: "&#160;"
36025             }]
36026         }, true);
36027         btn.addClassOnOver("roo-layout-tools-button-over");
36028         return btn;
36029     }
36030 });/*
36031  * Based on:
36032  * Ext JS Library 1.1.1
36033  * Copyright(c) 2006-2007, Ext JS, LLC.
36034  *
36035  * Originally Released Under LGPL - original licence link has changed is not relivant.
36036  *
36037  * Fork - LGPL
36038  * <script type="text/javascript">
36039  */
36040  
36041
36042
36043 /**
36044  * @class Roo.SplitLayoutRegion
36045  * @extends Roo.LayoutRegion
36046  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36047  */
36048 Roo.bootstrap.layout.Split = function(config){
36049     this.cursor = config.cursor;
36050     Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36051 };
36052
36053 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36054 {
36055     splitTip : "Drag to resize.",
36056     collapsibleSplitTip : "Drag to resize. Double click to hide.",
36057     useSplitTips : false,
36058
36059     applyConfig : function(config){
36060         Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36061     },
36062     
36063     onRender : function(ctr,pos) {
36064         
36065         Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36066         if(!this.config.split){
36067             return;
36068         }
36069         if(!this.split){
36070             
36071             var splitEl = Roo.DomHelper.append(ctr.dom,  {
36072                             tag: "div",
36073                             id: this.el.id + "-split",
36074                             cls: "roo-layout-split roo-layout-split-"+this.position,
36075                             html: "&#160;"
36076             });
36077             /** The SplitBar for this region 
36078             * @type Roo.SplitBar */
36079             // does not exist yet...
36080             Roo.log([this.position, this.orientation]);
36081             
36082             this.split = new Roo.bootstrap.SplitBar({
36083                 dragElement : splitEl,
36084                 resizingElement: this.el,
36085                 orientation : this.orientation
36086             });
36087             
36088             this.split.on("moved", this.onSplitMove, this);
36089             this.split.useShim = this.config.useShim === true;
36090             this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36091             if(this.useSplitTips){
36092                 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36093             }
36094             //if(config.collapsible){
36095             //    this.split.el.on("dblclick", this.collapse,  this);
36096             //}
36097         }
36098         if(typeof this.config.minSize != "undefined"){
36099             this.split.minSize = this.config.minSize;
36100         }
36101         if(typeof this.config.maxSize != "undefined"){
36102             this.split.maxSize = this.config.maxSize;
36103         }
36104         if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36105             this.hideSplitter();
36106         }
36107         
36108     },
36109
36110     getHMaxSize : function(){
36111          var cmax = this.config.maxSize || 10000;
36112          var center = this.mgr.getRegion("center");
36113          return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36114     },
36115
36116     getVMaxSize : function(){
36117          var cmax = this.config.maxSize || 10000;
36118          var center = this.mgr.getRegion("center");
36119          return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36120     },
36121
36122     onSplitMove : function(split, newSize){
36123         this.fireEvent("resized", this, newSize);
36124     },
36125     
36126     /** 
36127      * Returns the {@link Roo.SplitBar} for this region.
36128      * @return {Roo.SplitBar}
36129      */
36130     getSplitBar : function(){
36131         return this.split;
36132     },
36133     
36134     hide : function(){
36135         this.hideSplitter();
36136         Roo.bootstrap.layout.Split.superclass.hide.call(this);
36137     },
36138
36139     hideSplitter : function(){
36140         if(this.split){
36141             this.split.el.setLocation(-2000,-2000);
36142             this.split.el.hide();
36143         }
36144     },
36145
36146     show : function(){
36147         if(this.split){
36148             this.split.el.show();
36149         }
36150         Roo.bootstrap.layout.Split.superclass.show.call(this);
36151     },
36152     
36153     beforeSlide: function(){
36154         if(Roo.isGecko){// firefox overflow auto bug workaround
36155             this.bodyEl.clip();
36156             if(this.tabs) {
36157                 this.tabs.bodyEl.clip();
36158             }
36159             if(this.activePanel){
36160                 this.activePanel.getEl().clip();
36161                 
36162                 if(this.activePanel.beforeSlide){
36163                     this.activePanel.beforeSlide();
36164                 }
36165             }
36166         }
36167     },
36168     
36169     afterSlide : function(){
36170         if(Roo.isGecko){// firefox overflow auto bug workaround
36171             this.bodyEl.unclip();
36172             if(this.tabs) {
36173                 this.tabs.bodyEl.unclip();
36174             }
36175             if(this.activePanel){
36176                 this.activePanel.getEl().unclip();
36177                 if(this.activePanel.afterSlide){
36178                     this.activePanel.afterSlide();
36179                 }
36180             }
36181         }
36182     },
36183
36184     initAutoHide : function(){
36185         if(this.autoHide !== false){
36186             if(!this.autoHideHd){
36187                 var st = new Roo.util.DelayedTask(this.slideIn, this);
36188                 this.autoHideHd = {
36189                     "mouseout": function(e){
36190                         if(!e.within(this.el, true)){
36191                             st.delay(500);
36192                         }
36193                     },
36194                     "mouseover" : function(e){
36195                         st.cancel();
36196                     },
36197                     scope : this
36198                 };
36199             }
36200             this.el.on(this.autoHideHd);
36201         }
36202     },
36203
36204     clearAutoHide : function(){
36205         if(this.autoHide !== false){
36206             this.el.un("mouseout", this.autoHideHd.mouseout);
36207             this.el.un("mouseover", this.autoHideHd.mouseover);
36208         }
36209     },
36210
36211     clearMonitor : function(){
36212         Roo.get(document).un("click", this.slideInIf, this);
36213     },
36214
36215     // these names are backwards but not changed for compat
36216     slideOut : function(){
36217         if(this.isSlid || this.el.hasActiveFx()){
36218             return;
36219         }
36220         this.isSlid = true;
36221         if(this.collapseBtn){
36222             this.collapseBtn.hide();
36223         }
36224         this.closeBtnState = this.closeBtn.getStyle('display');
36225         this.closeBtn.hide();
36226         if(this.stickBtn){
36227             this.stickBtn.show();
36228         }
36229         this.el.show();
36230         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36231         this.beforeSlide();
36232         this.el.setStyle("z-index", 10001);
36233         this.el.slideIn(this.getSlideAnchor(), {
36234             callback: function(){
36235                 this.afterSlide();
36236                 this.initAutoHide();
36237                 Roo.get(document).on("click", this.slideInIf, this);
36238                 this.fireEvent("slideshow", this);
36239             },
36240             scope: this,
36241             block: true
36242         });
36243     },
36244
36245     afterSlideIn : function(){
36246         this.clearAutoHide();
36247         this.isSlid = false;
36248         this.clearMonitor();
36249         this.el.setStyle("z-index", "");
36250         if(this.collapseBtn){
36251             this.collapseBtn.show();
36252         }
36253         this.closeBtn.setStyle('display', this.closeBtnState);
36254         if(this.stickBtn){
36255             this.stickBtn.hide();
36256         }
36257         this.fireEvent("slidehide", this);
36258     },
36259
36260     slideIn : function(cb){
36261         if(!this.isSlid || this.el.hasActiveFx()){
36262             Roo.callback(cb);
36263             return;
36264         }
36265         this.isSlid = false;
36266         this.beforeSlide();
36267         this.el.slideOut(this.getSlideAnchor(), {
36268             callback: function(){
36269                 this.el.setLeftTop(-10000, -10000);
36270                 this.afterSlide();
36271                 this.afterSlideIn();
36272                 Roo.callback(cb);
36273             },
36274             scope: this,
36275             block: true
36276         });
36277     },
36278     
36279     slideInIf : function(e){
36280         if(!e.within(this.el)){
36281             this.slideIn();
36282         }
36283     },
36284
36285     animateCollapse : function(){
36286         this.beforeSlide();
36287         this.el.setStyle("z-index", 20000);
36288         var anchor = this.getSlideAnchor();
36289         this.el.slideOut(anchor, {
36290             callback : function(){
36291                 this.el.setStyle("z-index", "");
36292                 this.collapsedEl.slideIn(anchor, {duration:.3});
36293                 this.afterSlide();
36294                 this.el.setLocation(-10000,-10000);
36295                 this.el.hide();
36296                 this.fireEvent("collapsed", this);
36297             },
36298             scope: this,
36299             block: true
36300         });
36301     },
36302
36303     animateExpand : function(){
36304         this.beforeSlide();
36305         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36306         this.el.setStyle("z-index", 20000);
36307         this.collapsedEl.hide({
36308             duration:.1
36309         });
36310         this.el.slideIn(this.getSlideAnchor(), {
36311             callback : function(){
36312                 this.el.setStyle("z-index", "");
36313                 this.afterSlide();
36314                 if(this.split){
36315                     this.split.el.show();
36316                 }
36317                 this.fireEvent("invalidated", this);
36318                 this.fireEvent("expanded", this);
36319             },
36320             scope: this,
36321             block: true
36322         });
36323     },
36324
36325     anchors : {
36326         "west" : "left",
36327         "east" : "right",
36328         "north" : "top",
36329         "south" : "bottom"
36330     },
36331
36332     sanchors : {
36333         "west" : "l",
36334         "east" : "r",
36335         "north" : "t",
36336         "south" : "b"
36337     },
36338
36339     canchors : {
36340         "west" : "tl-tr",
36341         "east" : "tr-tl",
36342         "north" : "tl-bl",
36343         "south" : "bl-tl"
36344     },
36345
36346     getAnchor : function(){
36347         return this.anchors[this.position];
36348     },
36349
36350     getCollapseAnchor : function(){
36351         return this.canchors[this.position];
36352     },
36353
36354     getSlideAnchor : function(){
36355         return this.sanchors[this.position];
36356     },
36357
36358     getAlignAdj : function(){
36359         var cm = this.cmargins;
36360         switch(this.position){
36361             case "west":
36362                 return [0, 0];
36363             break;
36364             case "east":
36365                 return [0, 0];
36366             break;
36367             case "north":
36368                 return [0, 0];
36369             break;
36370             case "south":
36371                 return [0, 0];
36372             break;
36373         }
36374     },
36375
36376     getExpandAdj : function(){
36377         var c = this.collapsedEl, cm = this.cmargins;
36378         switch(this.position){
36379             case "west":
36380                 return [-(cm.right+c.getWidth()+cm.left), 0];
36381             break;
36382             case "east":
36383                 return [cm.right+c.getWidth()+cm.left, 0];
36384             break;
36385             case "north":
36386                 return [0, -(cm.top+cm.bottom+c.getHeight())];
36387             break;
36388             case "south":
36389                 return [0, cm.top+cm.bottom+c.getHeight()];
36390             break;
36391         }
36392     }
36393 });/*
36394  * Based on:
36395  * Ext JS Library 1.1.1
36396  * Copyright(c) 2006-2007, Ext JS, LLC.
36397  *
36398  * Originally Released Under LGPL - original licence link has changed is not relivant.
36399  *
36400  * Fork - LGPL
36401  * <script type="text/javascript">
36402  */
36403 /*
36404  * These classes are private internal classes
36405  */
36406 Roo.bootstrap.layout.Center = function(config){
36407     config.region = "center";
36408     Roo.bootstrap.layout.Region.call(this, config);
36409     this.visible = true;
36410     this.minWidth = config.minWidth || 20;
36411     this.minHeight = config.minHeight || 20;
36412 };
36413
36414 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36415     hide : function(){
36416         // center panel can't be hidden
36417     },
36418     
36419     show : function(){
36420         // center panel can't be hidden
36421     },
36422     
36423     getMinWidth: function(){
36424         return this.minWidth;
36425     },
36426     
36427     getMinHeight: function(){
36428         return this.minHeight;
36429     }
36430 });
36431
36432
36433
36434
36435  
36436
36437
36438
36439
36440
36441 Roo.bootstrap.layout.North = function(config)
36442 {
36443     config.region = 'north';
36444     config.cursor = 'n-resize';
36445     
36446     Roo.bootstrap.layout.Split.call(this, config);
36447     
36448     
36449     if(this.split){
36450         this.split.placement = Roo.bootstrap.SplitBar.TOP;
36451         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36452         this.split.el.addClass("roo-layout-split-v");
36453     }
36454     var size = config.initialSize || config.height;
36455     if(typeof size != "undefined"){
36456         this.el.setHeight(size);
36457     }
36458 };
36459 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36460 {
36461     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36462     
36463     
36464     
36465     getBox : function(){
36466         if(this.collapsed){
36467             return this.collapsedEl.getBox();
36468         }
36469         var box = this.el.getBox();
36470         if(this.split){
36471             box.height += this.split.el.getHeight();
36472         }
36473         return box;
36474     },
36475     
36476     updateBox : function(box){
36477         if(this.split && !this.collapsed){
36478             box.height -= this.split.el.getHeight();
36479             this.split.el.setLeft(box.x);
36480             this.split.el.setTop(box.y+box.height);
36481             this.split.el.setWidth(box.width);
36482         }
36483         if(this.collapsed){
36484             this.updateBody(box.width, null);
36485         }
36486         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36487     }
36488 });
36489
36490
36491
36492
36493
36494 Roo.bootstrap.layout.South = function(config){
36495     config.region = 'south';
36496     config.cursor = 's-resize';
36497     Roo.bootstrap.layout.Split.call(this, config);
36498     if(this.split){
36499         this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36500         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36501         this.split.el.addClass("roo-layout-split-v");
36502     }
36503     var size = config.initialSize || config.height;
36504     if(typeof size != "undefined"){
36505         this.el.setHeight(size);
36506     }
36507 };
36508
36509 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36510     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36511     getBox : function(){
36512         if(this.collapsed){
36513             return this.collapsedEl.getBox();
36514         }
36515         var box = this.el.getBox();
36516         if(this.split){
36517             var sh = this.split.el.getHeight();
36518             box.height += sh;
36519             box.y -= sh;
36520         }
36521         return box;
36522     },
36523     
36524     updateBox : function(box){
36525         if(this.split && !this.collapsed){
36526             var sh = this.split.el.getHeight();
36527             box.height -= sh;
36528             box.y += sh;
36529             this.split.el.setLeft(box.x);
36530             this.split.el.setTop(box.y-sh);
36531             this.split.el.setWidth(box.width);
36532         }
36533         if(this.collapsed){
36534             this.updateBody(box.width, null);
36535         }
36536         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36537     }
36538 });
36539
36540 Roo.bootstrap.layout.East = function(config){
36541     config.region = "east";
36542     config.cursor = "e-resize";
36543     Roo.bootstrap.layout.Split.call(this, config);
36544     if(this.split){
36545         this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36546         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36547         this.split.el.addClass("roo-layout-split-h");
36548     }
36549     var size = config.initialSize || config.width;
36550     if(typeof size != "undefined"){
36551         this.el.setWidth(size);
36552     }
36553 };
36554 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36555     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36556     getBox : function(){
36557         if(this.collapsed){
36558             return this.collapsedEl.getBox();
36559         }
36560         var box = this.el.getBox();
36561         if(this.split){
36562             var sw = this.split.el.getWidth();
36563             box.width += sw;
36564             box.x -= sw;
36565         }
36566         return box;
36567     },
36568
36569     updateBox : function(box){
36570         if(this.split && !this.collapsed){
36571             var sw = this.split.el.getWidth();
36572             box.width -= sw;
36573             this.split.el.setLeft(box.x);
36574             this.split.el.setTop(box.y);
36575             this.split.el.setHeight(box.height);
36576             box.x += sw;
36577         }
36578         if(this.collapsed){
36579             this.updateBody(null, box.height);
36580         }
36581         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36582     }
36583 });
36584
36585 Roo.bootstrap.layout.West = function(config){
36586     config.region = "west";
36587     config.cursor = "w-resize";
36588     
36589     Roo.bootstrap.layout.Split.call(this, config);
36590     if(this.split){
36591         this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36592         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36593         this.split.el.addClass("roo-layout-split-h");
36594     }
36595     
36596 };
36597 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36598     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36599     
36600     onRender: function(ctr, pos)
36601     {
36602         Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36603         var size = this.config.initialSize || this.config.width;
36604         if(typeof size != "undefined"){
36605             this.el.setWidth(size);
36606         }
36607     },
36608     
36609     getBox : function(){
36610         if(this.collapsed){
36611             return this.collapsedEl.getBox();
36612         }
36613         var box = this.el.getBox();
36614         if(this.split){
36615             box.width += this.split.el.getWidth();
36616         }
36617         return box;
36618     },
36619     
36620     updateBox : function(box){
36621         if(this.split && !this.collapsed){
36622             var sw = this.split.el.getWidth();
36623             box.width -= sw;
36624             this.split.el.setLeft(box.x+box.width);
36625             this.split.el.setTop(box.y);
36626             this.split.el.setHeight(box.height);
36627         }
36628         if(this.collapsed){
36629             this.updateBody(null, box.height);
36630         }
36631         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36632     }
36633 });
36634 Roo.namespace("Roo.bootstrap.panel");/*
36635  * Based on:
36636  * Ext JS Library 1.1.1
36637  * Copyright(c) 2006-2007, Ext JS, LLC.
36638  *
36639  * Originally Released Under LGPL - original licence link has changed is not relivant.
36640  *
36641  * Fork - LGPL
36642  * <script type="text/javascript">
36643  */
36644 /**
36645  * @class Roo.ContentPanel
36646  * @extends Roo.util.Observable
36647  * A basic ContentPanel element.
36648  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
36649  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
36650  * @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
36651  * @cfg {Boolean}   closable      True if the panel can be closed/removed
36652  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
36653  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36654  * @cfg {Toolbar}   toolbar       A toolbar for this panel
36655  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
36656  * @cfg {String} title          The title for this panel
36657  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36658  * @cfg {String} url            Calls {@link #setUrl} with this value
36659  * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36660  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
36661  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
36662  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
36663  * @cfg {Boolean} badges render the badges
36664
36665  * @constructor
36666  * Create a new ContentPanel.
36667  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36668  * @param {String/Object} config A string to set only the title or a config object
36669  * @param {String} content (optional) Set the HTML content for this panel
36670  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36671  */
36672 Roo.bootstrap.panel.Content = function( config){
36673     
36674     this.tpl = config.tpl || false;
36675     
36676     var el = config.el;
36677     var content = config.content;
36678
36679     if(config.autoCreate){ // xtype is available if this is called from factory
36680         el = Roo.id();
36681     }
36682     this.el = Roo.get(el);
36683     if(!this.el && config && config.autoCreate){
36684         if(typeof config.autoCreate == "object"){
36685             if(!config.autoCreate.id){
36686                 config.autoCreate.id = config.id||el;
36687             }
36688             this.el = Roo.DomHelper.append(document.body,
36689                         config.autoCreate, true);
36690         }else{
36691             var elcfg =  {   tag: "div",
36692                             cls: "roo-layout-inactive-content",
36693                             id: config.id||el
36694                             };
36695             if (config.html) {
36696                 elcfg.html = config.html;
36697                 
36698             }
36699                         
36700             this.el = Roo.DomHelper.append(document.body, elcfg , true);
36701         }
36702     } 
36703     this.closable = false;
36704     this.loaded = false;
36705     this.active = false;
36706    
36707       
36708     if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36709         
36710         this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36711         
36712         this.wrapEl = this.el; //this.el.wrap();
36713         var ti = [];
36714         if (config.toolbar.items) {
36715             ti = config.toolbar.items ;
36716             delete config.toolbar.items ;
36717         }
36718         
36719         var nitems = [];
36720         this.toolbar.render(this.wrapEl, 'before');
36721         for(var i =0;i < ti.length;i++) {
36722           //  Roo.log(['add child', items[i]]);
36723             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36724         }
36725         this.toolbar.items = nitems;
36726         this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36727         delete config.toolbar;
36728         
36729     }
36730     /*
36731     // xtype created footer. - not sure if will work as we normally have to render first..
36732     if (this.footer && !this.footer.el && this.footer.xtype) {
36733         if (!this.wrapEl) {
36734             this.wrapEl = this.el.wrap();
36735         }
36736     
36737         this.footer.container = this.wrapEl.createChild();
36738          
36739         this.footer = Roo.factory(this.footer, Roo);
36740         
36741     }
36742     */
36743     
36744      if(typeof config == "string"){
36745         this.title = config;
36746     }else{
36747         Roo.apply(this, config);
36748     }
36749     
36750     if(this.resizeEl){
36751         this.resizeEl = Roo.get(this.resizeEl, true);
36752     }else{
36753         this.resizeEl = this.el;
36754     }
36755     // handle view.xtype
36756     
36757  
36758     
36759     
36760     this.addEvents({
36761         /**
36762          * @event activate
36763          * Fires when this panel is activated. 
36764          * @param {Roo.ContentPanel} this
36765          */
36766         "activate" : true,
36767         /**
36768          * @event deactivate
36769          * Fires when this panel is activated. 
36770          * @param {Roo.ContentPanel} this
36771          */
36772         "deactivate" : true,
36773
36774         /**
36775          * @event resize
36776          * Fires when this panel is resized if fitToFrame is true.
36777          * @param {Roo.ContentPanel} this
36778          * @param {Number} width The width after any component adjustments
36779          * @param {Number} height The height after any component adjustments
36780          */
36781         "resize" : true,
36782         
36783          /**
36784          * @event render
36785          * Fires when this tab is created
36786          * @param {Roo.ContentPanel} this
36787          */
36788         "render" : true
36789         
36790         
36791         
36792     });
36793     
36794
36795     
36796     
36797     if(this.autoScroll){
36798         this.resizeEl.setStyle("overflow", "auto");
36799     } else {
36800         // fix randome scrolling
36801         //this.el.on('scroll', function() {
36802         //    Roo.log('fix random scolling');
36803         //    this.scrollTo('top',0); 
36804         //});
36805     }
36806     content = content || this.content;
36807     if(content){
36808         this.setContent(content);
36809     }
36810     if(config && config.url){
36811         this.setUrl(this.url, this.params, this.loadOnce);
36812     }
36813     
36814     
36815     
36816     Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36817     
36818     if (this.view && typeof(this.view.xtype) != 'undefined') {
36819         this.view.el = this.el.appendChild(document.createElement("div"));
36820         this.view = Roo.factory(this.view); 
36821         this.view.render  &&  this.view.render(false, '');  
36822     }
36823     
36824     
36825     this.fireEvent('render', this);
36826 };
36827
36828 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36829     
36830     tabTip : '',
36831     
36832     setRegion : function(region){
36833         this.region = region;
36834         this.setActiveClass(region && !this.background);
36835     },
36836     
36837     
36838     setActiveClass: function(state)
36839     {
36840         if(state){
36841            this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36842            this.el.setStyle('position','relative');
36843         }else{
36844            this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36845            this.el.setStyle('position', 'absolute');
36846         } 
36847     },
36848     
36849     /**
36850      * Returns the toolbar for this Panel if one was configured. 
36851      * @return {Roo.Toolbar} 
36852      */
36853     getToolbar : function(){
36854         return this.toolbar;
36855     },
36856     
36857     setActiveState : function(active)
36858     {
36859         this.active = active;
36860         this.setActiveClass(active);
36861         if(!active){
36862             if(this.fireEvent("deactivate", this) === false){
36863                 return false;
36864             }
36865             return true;
36866         }
36867         this.fireEvent("activate", this);
36868         return true;
36869     },
36870     /**
36871      * Updates this panel's element
36872      * @param {String} content The new content
36873      * @param {Boolean} loadScripts (optional) true to look for and process scripts
36874     */
36875     setContent : function(content, loadScripts){
36876         this.el.update(content, loadScripts);
36877     },
36878
36879     ignoreResize : function(w, h){
36880         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36881             return true;
36882         }else{
36883             this.lastSize = {width: w, height: h};
36884             return false;
36885         }
36886     },
36887     /**
36888      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36889      * @return {Roo.UpdateManager} The UpdateManager
36890      */
36891     getUpdateManager : function(){
36892         return this.el.getUpdateManager();
36893     },
36894      /**
36895      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36896      * @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:
36897 <pre><code>
36898 panel.load({
36899     url: "your-url.php",
36900     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36901     callback: yourFunction,
36902     scope: yourObject, //(optional scope)
36903     discardUrl: false,
36904     nocache: false,
36905     text: "Loading...",
36906     timeout: 30,
36907     scripts: false
36908 });
36909 </code></pre>
36910      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36911      * 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.
36912      * @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}
36913      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36914      * @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.
36915      * @return {Roo.ContentPanel} this
36916      */
36917     load : function(){
36918         var um = this.el.getUpdateManager();
36919         um.update.apply(um, arguments);
36920         return this;
36921     },
36922
36923
36924     /**
36925      * 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.
36926      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36927      * @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)
36928      * @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)
36929      * @return {Roo.UpdateManager} The UpdateManager
36930      */
36931     setUrl : function(url, params, loadOnce){
36932         if(this.refreshDelegate){
36933             this.removeListener("activate", this.refreshDelegate);
36934         }
36935         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36936         this.on("activate", this.refreshDelegate);
36937         return this.el.getUpdateManager();
36938     },
36939     
36940     _handleRefresh : function(url, params, loadOnce){
36941         if(!loadOnce || !this.loaded){
36942             var updater = this.el.getUpdateManager();
36943             updater.update(url, params, this._setLoaded.createDelegate(this));
36944         }
36945     },
36946     
36947     _setLoaded : function(){
36948         this.loaded = true;
36949     }, 
36950     
36951     /**
36952      * Returns this panel's id
36953      * @return {String} 
36954      */
36955     getId : function(){
36956         return this.el.id;
36957     },
36958     
36959     /** 
36960      * Returns this panel's element - used by regiosn to add.
36961      * @return {Roo.Element} 
36962      */
36963     getEl : function(){
36964         return this.wrapEl || this.el;
36965     },
36966     
36967    
36968     
36969     adjustForComponents : function(width, height)
36970     {
36971         //Roo.log('adjustForComponents ');
36972         if(this.resizeEl != this.el){
36973             width -= this.el.getFrameWidth('lr');
36974             height -= this.el.getFrameWidth('tb');
36975         }
36976         if(this.toolbar){
36977             var te = this.toolbar.getEl();
36978             te.setWidth(width);
36979             height -= te.getHeight();
36980         }
36981         if(this.footer){
36982             var te = this.footer.getEl();
36983             te.setWidth(width);
36984             height -= te.getHeight();
36985         }
36986         
36987         
36988         if(this.adjustments){
36989             width += this.adjustments[0];
36990             height += this.adjustments[1];
36991         }
36992         return {"width": width, "height": height};
36993     },
36994     
36995     setSize : function(width, height){
36996         if(this.fitToFrame && !this.ignoreResize(width, height)){
36997             if(this.fitContainer && this.resizeEl != this.el){
36998                 this.el.setSize(width, height);
36999             }
37000             var size = this.adjustForComponents(width, height);
37001             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37002             this.fireEvent('resize', this, size.width, size.height);
37003         }
37004     },
37005     
37006     /**
37007      * Returns this panel's title
37008      * @return {String} 
37009      */
37010     getTitle : function(){
37011         
37012         if (typeof(this.title) != 'object') {
37013             return this.title;
37014         }
37015         
37016         var t = '';
37017         for (var k in this.title) {
37018             if (!this.title.hasOwnProperty(k)) {
37019                 continue;
37020             }
37021             
37022             if (k.indexOf('-') >= 0) {
37023                 var s = k.split('-');
37024                 for (var i = 0; i<s.length; i++) {
37025                     t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37026                 }
37027             } else {
37028                 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37029             }
37030         }
37031         return t;
37032     },
37033     
37034     /**
37035      * Set this panel's title
37036      * @param {String} title
37037      */
37038     setTitle : function(title){
37039         this.title = title;
37040         if(this.region){
37041             this.region.updatePanelTitle(this, title);
37042         }
37043     },
37044     
37045     /**
37046      * Returns true is this panel was configured to be closable
37047      * @return {Boolean} 
37048      */
37049     isClosable : function(){
37050         return this.closable;
37051     },
37052     
37053     beforeSlide : function(){
37054         this.el.clip();
37055         this.resizeEl.clip();
37056     },
37057     
37058     afterSlide : function(){
37059         this.el.unclip();
37060         this.resizeEl.unclip();
37061     },
37062     
37063     /**
37064      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
37065      *   Will fail silently if the {@link #setUrl} method has not been called.
37066      *   This does not activate the panel, just updates its content.
37067      */
37068     refresh : function(){
37069         if(this.refreshDelegate){
37070            this.loaded = false;
37071            this.refreshDelegate();
37072         }
37073     },
37074     
37075     /**
37076      * Destroys this panel
37077      */
37078     destroy : function(){
37079         this.el.removeAllListeners();
37080         var tempEl = document.createElement("span");
37081         tempEl.appendChild(this.el.dom);
37082         tempEl.innerHTML = "";
37083         this.el.remove();
37084         this.el = null;
37085     },
37086     
37087     /**
37088      * form - if the content panel contains a form - this is a reference to it.
37089      * @type {Roo.form.Form}
37090      */
37091     form : false,
37092     /**
37093      * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37094      *    This contains a reference to it.
37095      * @type {Roo.View}
37096      */
37097     view : false,
37098     
37099       /**
37100      * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37101      * <pre><code>
37102
37103 layout.addxtype({
37104        xtype : 'Form',
37105        items: [ .... ]
37106    }
37107 );
37108
37109 </code></pre>
37110      * @param {Object} cfg Xtype definition of item to add.
37111      */
37112     
37113     
37114     getChildContainer: function () {
37115         return this.getEl();
37116     }
37117     
37118     
37119     /*
37120         var  ret = new Roo.factory(cfg);
37121         return ret;
37122         
37123         
37124         // add form..
37125         if (cfg.xtype.match(/^Form$/)) {
37126             
37127             var el;
37128             //if (this.footer) {
37129             //    el = this.footer.container.insertSibling(false, 'before');
37130             //} else {
37131                 el = this.el.createChild();
37132             //}
37133
37134             this.form = new  Roo.form.Form(cfg);
37135             
37136             
37137             if ( this.form.allItems.length) {
37138                 this.form.render(el.dom);
37139             }
37140             return this.form;
37141         }
37142         // should only have one of theses..
37143         if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37144             // views.. should not be just added - used named prop 'view''
37145             
37146             cfg.el = this.el.appendChild(document.createElement("div"));
37147             // factory?
37148             
37149             var ret = new Roo.factory(cfg);
37150              
37151              ret.render && ret.render(false, ''); // render blank..
37152             this.view = ret;
37153             return ret;
37154         }
37155         return false;
37156     }
37157     \*/
37158 });
37159  
37160 /**
37161  * @class Roo.bootstrap.panel.Grid
37162  * @extends Roo.bootstrap.panel.Content
37163  * @constructor
37164  * Create a new GridPanel.
37165  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37166  * @param {Object} config A the config object
37167   
37168  */
37169
37170
37171
37172 Roo.bootstrap.panel.Grid = function(config)
37173 {
37174     
37175       
37176     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37177         {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37178
37179     config.el = this.wrapper;
37180     //this.el = this.wrapper;
37181     
37182       if (config.container) {
37183         // ctor'ed from a Border/panel.grid
37184         
37185         
37186         this.wrapper.setStyle("overflow", "hidden");
37187         this.wrapper.addClass('roo-grid-container');
37188
37189     }
37190     
37191     
37192     if(config.toolbar){
37193         var tool_el = this.wrapper.createChild();    
37194         this.toolbar = Roo.factory(config.toolbar);
37195         var ti = [];
37196         if (config.toolbar.items) {
37197             ti = config.toolbar.items ;
37198             delete config.toolbar.items ;
37199         }
37200         
37201         var nitems = [];
37202         this.toolbar.render(tool_el);
37203         for(var i =0;i < ti.length;i++) {
37204           //  Roo.log(['add child', items[i]]);
37205             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37206         }
37207         this.toolbar.items = nitems;
37208         
37209         delete config.toolbar;
37210     }
37211     
37212     Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37213     config.grid.scrollBody = true;;
37214     config.grid.monitorWindowResize = false; // turn off autosizing
37215     config.grid.autoHeight = false;
37216     config.grid.autoWidth = false;
37217     
37218     this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37219     
37220     if (config.background) {
37221         // render grid on panel activation (if panel background)
37222         this.on('activate', function(gp) {
37223             if (!gp.grid.rendered) {
37224                 gp.grid.render(this.wrapper);
37225                 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");   
37226             }
37227         });
37228             
37229     } else {
37230         this.grid.render(this.wrapper);
37231         this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");               
37232
37233     }
37234     //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37235     // ??? needed ??? config.el = this.wrapper;
37236     
37237     
37238     
37239   
37240     // xtype created footer. - not sure if will work as we normally have to render first..
37241     if (this.footer && !this.footer.el && this.footer.xtype) {
37242         
37243         var ctr = this.grid.getView().getFooterPanel(true);
37244         this.footer.dataSource = this.grid.dataSource;
37245         this.footer = Roo.factory(this.footer, Roo);
37246         this.footer.render(ctr);
37247         
37248     }
37249     
37250     
37251     
37252     
37253      
37254 };
37255
37256 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37257     getId : function(){
37258         return this.grid.id;
37259     },
37260     
37261     /**
37262      * Returns the grid for this panel
37263      * @return {Roo.bootstrap.Table} 
37264      */
37265     getGrid : function(){
37266         return this.grid;    
37267     },
37268     
37269     setSize : function(width, height){
37270         if(!this.ignoreResize(width, height)){
37271             var grid = this.grid;
37272             var size = this.adjustForComponents(width, height);
37273             var gridel = grid.getGridEl();
37274             gridel.setSize(size.width, size.height);
37275             /*
37276             var thd = grid.getGridEl().select('thead',true).first();
37277             var tbd = grid.getGridEl().select('tbody', true).first();
37278             if (tbd) {
37279                 tbd.setSize(width, height - thd.getHeight());
37280             }
37281             */
37282             grid.autoSize();
37283         }
37284     },
37285      
37286     
37287     
37288     beforeSlide : function(){
37289         this.grid.getView().scroller.clip();
37290     },
37291     
37292     afterSlide : function(){
37293         this.grid.getView().scroller.unclip();
37294     },
37295     
37296     destroy : function(){
37297         this.grid.destroy();
37298         delete this.grid;
37299         Roo.bootstrap.panel.Grid.superclass.destroy.call(this); 
37300     }
37301 });
37302
37303 /**
37304  * @class Roo.bootstrap.panel.Nest
37305  * @extends Roo.bootstrap.panel.Content
37306  * @constructor
37307  * Create a new Panel, that can contain a layout.Border.
37308  * 
37309  * 
37310  * @param {Roo.BorderLayout} layout The layout for this panel
37311  * @param {String/Object} config A string to set only the title or a config object
37312  */
37313 Roo.bootstrap.panel.Nest = function(config)
37314 {
37315     // construct with only one argument..
37316     /* FIXME - implement nicer consturctors
37317     if (layout.layout) {
37318         config = layout;
37319         layout = config.layout;
37320         delete config.layout;
37321     }
37322     if (layout.xtype && !layout.getEl) {
37323         // then layout needs constructing..
37324         layout = Roo.factory(layout, Roo);
37325     }
37326     */
37327     
37328     config.el =  config.layout.getEl();
37329     
37330     Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37331     
37332     config.layout.monitorWindowResize = false; // turn off autosizing
37333     this.layout = config.layout;
37334     this.layout.getEl().addClass("roo-layout-nested-layout");
37335     
37336     
37337     
37338     
37339 };
37340
37341 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37342
37343     setSize : function(width, height){
37344         if(!this.ignoreResize(width, height)){
37345             var size = this.adjustForComponents(width, height);
37346             var el = this.layout.getEl();
37347             if (size.height < 1) {
37348                 el.setWidth(size.width);   
37349             } else {
37350                 el.setSize(size.width, size.height);
37351             }
37352             var touch = el.dom.offsetWidth;
37353             this.layout.layout();
37354             // ie requires a double layout on the first pass
37355             if(Roo.isIE && !this.initialized){
37356                 this.initialized = true;
37357                 this.layout.layout();
37358             }
37359         }
37360     },
37361     
37362     // activate all subpanels if not currently active..
37363     
37364     setActiveState : function(active){
37365         this.active = active;
37366         this.setActiveClass(active);
37367         
37368         if(!active){
37369             this.fireEvent("deactivate", this);
37370             return;
37371         }
37372         
37373         this.fireEvent("activate", this);
37374         // not sure if this should happen before or after..
37375         if (!this.layout) {
37376             return; // should not happen..
37377         }
37378         var reg = false;
37379         for (var r in this.layout.regions) {
37380             reg = this.layout.getRegion(r);
37381             if (reg.getActivePanel()) {
37382                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
37383                 reg.setActivePanel(reg.getActivePanel());
37384                 continue;
37385             }
37386             if (!reg.panels.length) {
37387                 continue;
37388             }
37389             reg.showPanel(reg.getPanel(0));
37390         }
37391         
37392         
37393         
37394         
37395     },
37396     
37397     /**
37398      * Returns the nested BorderLayout for this panel
37399      * @return {Roo.BorderLayout} 
37400      */
37401     getLayout : function(){
37402         return this.layout;
37403     },
37404     
37405      /**
37406      * Adds a xtype elements to the layout of the nested panel
37407      * <pre><code>
37408
37409 panel.addxtype({
37410        xtype : 'ContentPanel',
37411        region: 'west',
37412        items: [ .... ]
37413    }
37414 );
37415
37416 panel.addxtype({
37417         xtype : 'NestedLayoutPanel',
37418         region: 'west',
37419         layout: {
37420            center: { },
37421            west: { }   
37422         },
37423         items : [ ... list of content panels or nested layout panels.. ]
37424    }
37425 );
37426 </code></pre>
37427      * @param {Object} cfg Xtype definition of item to add.
37428      */
37429     addxtype : function(cfg) {
37430         return this.layout.addxtype(cfg);
37431     
37432     }
37433 });        /*
37434  * Based on:
37435  * Ext JS Library 1.1.1
37436  * Copyright(c) 2006-2007, Ext JS, LLC.
37437  *
37438  * Originally Released Under LGPL - original licence link has changed is not relivant.
37439  *
37440  * Fork - LGPL
37441  * <script type="text/javascript">
37442  */
37443 /**
37444  * @class Roo.TabPanel
37445  * @extends Roo.util.Observable
37446  * A lightweight tab container.
37447  * <br><br>
37448  * Usage:
37449  * <pre><code>
37450 // basic tabs 1, built from existing content
37451 var tabs = new Roo.TabPanel("tabs1");
37452 tabs.addTab("script", "View Script");
37453 tabs.addTab("markup", "View Markup");
37454 tabs.activate("script");
37455
37456 // more advanced tabs, built from javascript
37457 var jtabs = new Roo.TabPanel("jtabs");
37458 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37459
37460 // set up the UpdateManager
37461 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37462 var updater = tab2.getUpdateManager();
37463 updater.setDefaultUrl("ajax1.htm");
37464 tab2.on('activate', updater.refresh, updater, true);
37465
37466 // Use setUrl for Ajax loading
37467 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37468 tab3.setUrl("ajax2.htm", null, true);
37469
37470 // Disabled tab
37471 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37472 tab4.disable();
37473
37474 jtabs.activate("jtabs-1");
37475  * </code></pre>
37476  * @constructor
37477  * Create a new TabPanel.
37478  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37479  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37480  */
37481 Roo.bootstrap.panel.Tabs = function(config){
37482     /**
37483     * The container element for this TabPanel.
37484     * @type Roo.Element
37485     */
37486     this.el = Roo.get(config.el);
37487     delete config.el;
37488     if(config){
37489         if(typeof config == "boolean"){
37490             this.tabPosition = config ? "bottom" : "top";
37491         }else{
37492             Roo.apply(this, config);
37493         }
37494     }
37495     
37496     if(this.tabPosition == "bottom"){
37497         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37498         this.el.addClass("roo-tabs-bottom");
37499     }
37500     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37501     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37502     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37503     if(Roo.isIE){
37504         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37505     }
37506     if(this.tabPosition != "bottom"){
37507         /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37508          * @type Roo.Element
37509          */
37510         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37511         this.el.addClass("roo-tabs-top");
37512     }
37513     this.items = [];
37514
37515     this.bodyEl.setStyle("position", "relative");
37516
37517     this.active = null;
37518     this.activateDelegate = this.activate.createDelegate(this);
37519
37520     this.addEvents({
37521         /**
37522          * @event tabchange
37523          * Fires when the active tab changes
37524          * @param {Roo.TabPanel} this
37525          * @param {Roo.TabPanelItem} activePanel The new active tab
37526          */
37527         "tabchange": true,
37528         /**
37529          * @event beforetabchange
37530          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37531          * @param {Roo.TabPanel} this
37532          * @param {Object} e Set cancel to true on this object to cancel the tab change
37533          * @param {Roo.TabPanelItem} tab The tab being changed to
37534          */
37535         "beforetabchange" : true
37536     });
37537
37538     Roo.EventManager.onWindowResize(this.onResize, this);
37539     this.cpad = this.el.getPadding("lr");
37540     this.hiddenCount = 0;
37541
37542
37543     // toolbar on the tabbar support...
37544     if (this.toolbar) {
37545         alert("no toolbar support yet");
37546         this.toolbar  = false;
37547         /*
37548         var tcfg = this.toolbar;
37549         tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
37550         this.toolbar = new Roo.Toolbar(tcfg);
37551         if (Roo.isSafari) {
37552             var tbl = tcfg.container.child('table', true);
37553             tbl.setAttribute('width', '100%');
37554         }
37555         */
37556         
37557     }
37558    
37559
37560
37561     Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37562 };
37563
37564 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37565     /*
37566      *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37567      */
37568     tabPosition : "top",
37569     /*
37570      *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37571      */
37572     currentTabWidth : 0,
37573     /*
37574      *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37575      */
37576     minTabWidth : 40,
37577     /*
37578      *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37579      */
37580     maxTabWidth : 250,
37581     /*
37582      *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37583      */
37584     preferredTabWidth : 175,
37585     /*
37586      *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37587      */
37588     resizeTabs : false,
37589     /*
37590      *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37591      */
37592     monitorResize : true,
37593     /*
37594      *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
37595      */
37596     toolbar : false,
37597
37598     /**
37599      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37600      * @param {String} id The id of the div to use <b>or create</b>
37601      * @param {String} text The text for the tab
37602      * @param {String} content (optional) Content to put in the TabPanelItem body
37603      * @param {Boolean} closable (optional) True to create a close icon on the tab
37604      * @return {Roo.TabPanelItem} The created TabPanelItem
37605      */
37606     addTab : function(id, text, content, closable, tpl)
37607     {
37608         var item = new Roo.bootstrap.panel.TabItem({
37609             panel: this,
37610             id : id,
37611             text : text,
37612             closable : closable,
37613             tpl : tpl
37614         });
37615         this.addTabItem(item);
37616         if(content){
37617             item.setContent(content);
37618         }
37619         return item;
37620     },
37621
37622     /**
37623      * Returns the {@link Roo.TabPanelItem} with the specified id/index
37624      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37625      * @return {Roo.TabPanelItem}
37626      */
37627     getTab : function(id){
37628         return this.items[id];
37629     },
37630
37631     /**
37632      * Hides the {@link Roo.TabPanelItem} with the specified id/index
37633      * @param {String/Number} id The id or index of the TabPanelItem to hide.
37634      */
37635     hideTab : function(id){
37636         var t = this.items[id];
37637         if(!t.isHidden()){
37638            t.setHidden(true);
37639            this.hiddenCount++;
37640            this.autoSizeTabs();
37641         }
37642     },
37643
37644     /**
37645      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37646      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37647      */
37648     unhideTab : function(id){
37649         var t = this.items[id];
37650         if(t.isHidden()){
37651            t.setHidden(false);
37652            this.hiddenCount--;
37653            this.autoSizeTabs();
37654         }
37655     },
37656
37657     /**
37658      * Adds an existing {@link Roo.TabPanelItem}.
37659      * @param {Roo.TabPanelItem} item The TabPanelItem to add
37660      */
37661     addTabItem : function(item){
37662         this.items[item.id] = item;
37663         this.items.push(item);
37664       //  if(this.resizeTabs){
37665     //       item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37666   //         this.autoSizeTabs();
37667 //        }else{
37668 //            item.autoSize();
37669        // }
37670     },
37671
37672     /**
37673      * Removes a {@link Roo.TabPanelItem}.
37674      * @param {String/Number} id The id or index of the TabPanelItem to remove.
37675      */
37676     removeTab : function(id){
37677         var items = this.items;
37678         var tab = items[id];
37679         if(!tab) { return; }
37680         var index = items.indexOf(tab);
37681         if(this.active == tab && items.length > 1){
37682             var newTab = this.getNextAvailable(index);
37683             if(newTab) {
37684                 newTab.activate();
37685             }
37686         }
37687         this.stripEl.dom.removeChild(tab.pnode.dom);
37688         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37689             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37690         }
37691         items.splice(index, 1);
37692         delete this.items[tab.id];
37693         tab.fireEvent("close", tab);
37694         tab.purgeListeners();
37695         this.autoSizeTabs();
37696     },
37697
37698     getNextAvailable : function(start){
37699         var items = this.items;
37700         var index = start;
37701         // look for a next tab that will slide over to
37702         // replace the one being removed
37703         while(index < items.length){
37704             var item = items[++index];
37705             if(item && !item.isHidden()){
37706                 return item;
37707             }
37708         }
37709         // if one isn't found select the previous tab (on the left)
37710         index = start;
37711         while(index >= 0){
37712             var item = items[--index];
37713             if(item && !item.isHidden()){
37714                 return item;
37715             }
37716         }
37717         return null;
37718     },
37719
37720     /**
37721      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37722      * @param {String/Number} id The id or index of the TabPanelItem to disable.
37723      */
37724     disableTab : function(id){
37725         var tab = this.items[id];
37726         if(tab && this.active != tab){
37727             tab.disable();
37728         }
37729     },
37730
37731     /**
37732      * Enables a {@link Roo.TabPanelItem} that is disabled.
37733      * @param {String/Number} id The id or index of the TabPanelItem to enable.
37734      */
37735     enableTab : function(id){
37736         var tab = this.items[id];
37737         tab.enable();
37738     },
37739
37740     /**
37741      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37742      * @param {String/Number} id The id or index of the TabPanelItem to activate.
37743      * @return {Roo.TabPanelItem} The TabPanelItem.
37744      */
37745     activate : function(id){
37746         var tab = this.items[id];
37747         if(!tab){
37748             return null;
37749         }
37750         if(tab == this.active || tab.disabled){
37751             return tab;
37752         }
37753         var e = {};
37754         this.fireEvent("beforetabchange", this, e, tab);
37755         if(e.cancel !== true && !tab.disabled){
37756             if(this.active){
37757                 this.active.hide();
37758             }
37759             this.active = this.items[id];
37760             this.active.show();
37761             this.fireEvent("tabchange", this, this.active);
37762         }
37763         return tab;
37764     },
37765
37766     /**
37767      * Gets the active {@link Roo.TabPanelItem}.
37768      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37769      */
37770     getActiveTab : function(){
37771         return this.active;
37772     },
37773
37774     /**
37775      * Updates the tab body element to fit the height of the container element
37776      * for overflow scrolling
37777      * @param {Number} targetHeight (optional) Override the starting height from the elements height
37778      */
37779     syncHeight : function(targetHeight){
37780         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37781         var bm = this.bodyEl.getMargins();
37782         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37783         this.bodyEl.setHeight(newHeight);
37784         return newHeight;
37785     },
37786
37787     onResize : function(){
37788         if(this.monitorResize){
37789             this.autoSizeTabs();
37790         }
37791     },
37792
37793     /**
37794      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37795      */
37796     beginUpdate : function(){
37797         this.updating = true;
37798     },
37799
37800     /**
37801      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37802      */
37803     endUpdate : function(){
37804         this.updating = false;
37805         this.autoSizeTabs();
37806     },
37807
37808     /**
37809      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37810      */
37811     autoSizeTabs : function(){
37812         var count = this.items.length;
37813         var vcount = count - this.hiddenCount;
37814         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37815             return;
37816         }
37817         var w = Math.max(this.el.getWidth() - this.cpad, 10);
37818         var availWidth = Math.floor(w / vcount);
37819         var b = this.stripBody;
37820         if(b.getWidth() > w){
37821             var tabs = this.items;
37822             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37823             if(availWidth < this.minTabWidth){
37824                 /*if(!this.sleft){    // incomplete scrolling code
37825                     this.createScrollButtons();
37826                 }
37827                 this.showScroll();
37828                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37829             }
37830         }else{
37831             if(this.currentTabWidth < this.preferredTabWidth){
37832                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37833             }
37834         }
37835     },
37836
37837     /**
37838      * Returns the number of tabs in this TabPanel.
37839      * @return {Number}
37840      */
37841      getCount : function(){
37842          return this.items.length;
37843      },
37844
37845     /**
37846      * Resizes all the tabs to the passed width
37847      * @param {Number} The new width
37848      */
37849     setTabWidth : function(width){
37850         this.currentTabWidth = width;
37851         for(var i = 0, len = this.items.length; i < len; i++) {
37852                 if(!this.items[i].isHidden()) {
37853                 this.items[i].setWidth(width);
37854             }
37855         }
37856     },
37857
37858     /**
37859      * Destroys this TabPanel
37860      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37861      */
37862     destroy : function(removeEl){
37863         Roo.EventManager.removeResizeListener(this.onResize, this);
37864         for(var i = 0, len = this.items.length; i < len; i++){
37865             this.items[i].purgeListeners();
37866         }
37867         if(removeEl === true){
37868             this.el.update("");
37869             this.el.remove();
37870         }
37871     },
37872     
37873     createStrip : function(container)
37874     {
37875         var strip = document.createElement("nav");
37876         strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37877         container.appendChild(strip);
37878         return strip;
37879     },
37880     
37881     createStripList : function(strip)
37882     {
37883         // div wrapper for retard IE
37884         // returns the "tr" element.
37885         strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37886         //'<div class="x-tabs-strip-wrap">'+
37887           //  '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37888           //  '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37889         return strip.firstChild; //.firstChild.firstChild.firstChild;
37890     },
37891     createBody : function(container)
37892     {
37893         var body = document.createElement("div");
37894         Roo.id(body, "tab-body");
37895         //Roo.fly(body).addClass("x-tabs-body");
37896         Roo.fly(body).addClass("tab-content");
37897         container.appendChild(body);
37898         return body;
37899     },
37900     createItemBody :function(bodyEl, id){
37901         var body = Roo.getDom(id);
37902         if(!body){
37903             body = document.createElement("div");
37904             body.id = id;
37905         }
37906         //Roo.fly(body).addClass("x-tabs-item-body");
37907         Roo.fly(body).addClass("tab-pane");
37908          bodyEl.insertBefore(body, bodyEl.firstChild);
37909         return body;
37910     },
37911     /** @private */
37912     createStripElements :  function(stripEl, text, closable, tpl)
37913     {
37914         var td = document.createElement("li"); // was td..
37915         
37916         
37917         //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37918         
37919         
37920         stripEl.appendChild(td);
37921         /*if(closable){
37922             td.className = "x-tabs-closable";
37923             if(!this.closeTpl){
37924                 this.closeTpl = new Roo.Template(
37925                    '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37926                    '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37927                    '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
37928                 );
37929             }
37930             var el = this.closeTpl.overwrite(td, {"text": text});
37931             var close = el.getElementsByTagName("div")[0];
37932             var inner = el.getElementsByTagName("em")[0];
37933             return {"el": el, "close": close, "inner": inner};
37934         } else {
37935         */
37936         // not sure what this is..
37937 //            if(!this.tabTpl){
37938                 //this.tabTpl = new Roo.Template(
37939                 //   '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37940                 //   '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37941                 //);
37942 //                this.tabTpl = new Roo.Template(
37943 //                   '<a href="#">' +
37944 //                   '<span unselectable="on"' +
37945 //                            (this.disableTooltips ? '' : ' title="{text}"') +
37946 //                            ' >{text}</span></a>'
37947 //                );
37948 //                
37949 //            }
37950
37951
37952             var template = tpl || this.tabTpl || false;
37953             
37954             if(!template){
37955                 
37956                 template = new Roo.Template(
37957                    '<a href="#">' +
37958                    '<span unselectable="on"' +
37959                             (this.disableTooltips ? '' : ' title="{text}"') +
37960                             ' >{text}</span></a>'
37961                 );
37962             }
37963             
37964             switch (typeof(template)) {
37965                 case 'object' :
37966                     break;
37967                 case 'string' :
37968                     template = new Roo.Template(template);
37969                     break;
37970                 default :
37971                     break;
37972             }
37973             
37974             var el = template.overwrite(td, {"text": text});
37975             
37976             var inner = el.getElementsByTagName("span")[0];
37977             
37978             return {"el": el, "inner": inner};
37979             
37980     }
37981         
37982     
37983 });
37984
37985 /**
37986  * @class Roo.TabPanelItem
37987  * @extends Roo.util.Observable
37988  * Represents an individual item (tab plus body) in a TabPanel.
37989  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37990  * @param {String} id The id of this TabPanelItem
37991  * @param {String} text The text for the tab of this TabPanelItem
37992  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37993  */
37994 Roo.bootstrap.panel.TabItem = function(config){
37995     /**
37996      * The {@link Roo.TabPanel} this TabPanelItem belongs to
37997      * @type Roo.TabPanel
37998      */
37999     this.tabPanel = config.panel;
38000     /**
38001      * The id for this TabPanelItem
38002      * @type String
38003      */
38004     this.id = config.id;
38005     /** @private */
38006     this.disabled = false;
38007     /** @private */
38008     this.text = config.text;
38009     /** @private */
38010     this.loaded = false;
38011     this.closable = config.closable;
38012
38013     /**
38014      * The body element for this TabPanelItem.
38015      * @type Roo.Element
38016      */
38017     this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38018     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38019     this.bodyEl.setStyle("display", "block");
38020     this.bodyEl.setStyle("zoom", "1");
38021     //this.hideAction();
38022
38023     var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38024     /** @private */
38025     this.el = Roo.get(els.el);
38026     this.inner = Roo.get(els.inner, true);
38027     this.textEl = Roo.get(this.el.dom.firstChild, true);
38028     this.pnode = Roo.get(els.el.parentNode, true);
38029 //    this.el.on("mousedown", this.onTabMouseDown, this);
38030     this.el.on("click", this.onTabClick, this);
38031     /** @private */
38032     if(config.closable){
38033         var c = Roo.get(els.close, true);
38034         c.dom.title = this.closeText;
38035         c.addClassOnOver("close-over");
38036         c.on("click", this.closeClick, this);
38037      }
38038
38039     this.addEvents({
38040          /**
38041          * @event activate
38042          * Fires when this tab becomes the active tab.
38043          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38044          * @param {Roo.TabPanelItem} this
38045          */
38046         "activate": true,
38047         /**
38048          * @event beforeclose
38049          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38050          * @param {Roo.TabPanelItem} this
38051          * @param {Object} e Set cancel to true on this object to cancel the close.
38052          */
38053         "beforeclose": true,
38054         /**
38055          * @event close
38056          * Fires when this tab is closed.
38057          * @param {Roo.TabPanelItem} this
38058          */
38059          "close": true,
38060         /**
38061          * @event deactivate
38062          * Fires when this tab is no longer the active tab.
38063          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38064          * @param {Roo.TabPanelItem} this
38065          */
38066          "deactivate" : true
38067     });
38068     this.hidden = false;
38069
38070     Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38071 };
38072
38073 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38074            {
38075     purgeListeners : function(){
38076        Roo.util.Observable.prototype.purgeListeners.call(this);
38077        this.el.removeAllListeners();
38078     },
38079     /**
38080      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38081      */
38082     show : function(){
38083         this.pnode.addClass("active");
38084         this.showAction();
38085         if(Roo.isOpera){
38086             this.tabPanel.stripWrap.repaint();
38087         }
38088         this.fireEvent("activate", this.tabPanel, this);
38089     },
38090
38091     /**
38092      * Returns true if this tab is the active tab.
38093      * @return {Boolean}
38094      */
38095     isActive : function(){
38096         return this.tabPanel.getActiveTab() == this;
38097     },
38098
38099     /**
38100      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38101      */
38102     hide : function(){
38103         this.pnode.removeClass("active");
38104         this.hideAction();
38105         this.fireEvent("deactivate", this.tabPanel, this);
38106     },
38107
38108     hideAction : function(){
38109         this.bodyEl.hide();
38110         this.bodyEl.setStyle("position", "absolute");
38111         this.bodyEl.setLeft("-20000px");
38112         this.bodyEl.setTop("-20000px");
38113     },
38114
38115     showAction : function(){
38116         this.bodyEl.setStyle("position", "relative");
38117         this.bodyEl.setTop("");
38118         this.bodyEl.setLeft("");
38119         this.bodyEl.show();
38120     },
38121
38122     /**
38123      * Set the tooltip for the tab.
38124      * @param {String} tooltip The tab's tooltip
38125      */
38126     setTooltip : function(text){
38127         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38128             this.textEl.dom.qtip = text;
38129             this.textEl.dom.removeAttribute('title');
38130         }else{
38131             this.textEl.dom.title = text;
38132         }
38133     },
38134
38135     onTabClick : function(e){
38136         e.preventDefault();
38137         this.tabPanel.activate(this.id);
38138     },
38139
38140     onTabMouseDown : function(e){
38141         e.preventDefault();
38142         this.tabPanel.activate(this.id);
38143     },
38144 /*
38145     getWidth : function(){
38146         return this.inner.getWidth();
38147     },
38148
38149     setWidth : function(width){
38150         var iwidth = width - this.pnode.getPadding("lr");
38151         this.inner.setWidth(iwidth);
38152         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38153         this.pnode.setWidth(width);
38154     },
38155 */
38156     /**
38157      * Show or hide the tab
38158      * @param {Boolean} hidden True to hide or false to show.
38159      */
38160     setHidden : function(hidden){
38161         this.hidden = hidden;
38162         this.pnode.setStyle("display", hidden ? "none" : "");
38163     },
38164
38165     /**
38166      * Returns true if this tab is "hidden"
38167      * @return {Boolean}
38168      */
38169     isHidden : function(){
38170         return this.hidden;
38171     },
38172
38173     /**
38174      * Returns the text for this tab
38175      * @return {String}
38176      */
38177     getText : function(){
38178         return this.text;
38179     },
38180     /*
38181     autoSize : function(){
38182         //this.el.beginMeasure();
38183         this.textEl.setWidth(1);
38184         /*
38185          *  #2804 [new] Tabs in Roojs
38186          *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38187          */
38188         //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38189         //this.el.endMeasure();
38190     //},
38191
38192     /**
38193      * Sets the text for the tab (Note: this also sets the tooltip text)
38194      * @param {String} text The tab's text and tooltip
38195      */
38196     setText : function(text){
38197         this.text = text;
38198         this.textEl.update(text);
38199         this.setTooltip(text);
38200         //if(!this.tabPanel.resizeTabs){
38201         //    this.autoSize();
38202         //}
38203     },
38204     /**
38205      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38206      */
38207     activate : function(){
38208         this.tabPanel.activate(this.id);
38209     },
38210
38211     /**
38212      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38213      */
38214     disable : function(){
38215         if(this.tabPanel.active != this){
38216             this.disabled = true;
38217             this.pnode.addClass("disabled");
38218         }
38219     },
38220
38221     /**
38222      * Enables this TabPanelItem if it was previously disabled.
38223      */
38224     enable : function(){
38225         this.disabled = false;
38226         this.pnode.removeClass("disabled");
38227     },
38228
38229     /**
38230      * Sets the content for this TabPanelItem.
38231      * @param {String} content The content
38232      * @param {Boolean} loadScripts true to look for and load scripts
38233      */
38234     setContent : function(content, loadScripts){
38235         this.bodyEl.update(content, loadScripts);
38236     },
38237
38238     /**
38239      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38240      * @return {Roo.UpdateManager} The UpdateManager
38241      */
38242     getUpdateManager : function(){
38243         return this.bodyEl.getUpdateManager();
38244     },
38245
38246     /**
38247      * Set a URL to be used to load the content for this TabPanelItem.
38248      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38249      * @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)
38250      * @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)
38251      * @return {Roo.UpdateManager} The UpdateManager
38252      */
38253     setUrl : function(url, params, loadOnce){
38254         if(this.refreshDelegate){
38255             this.un('activate', this.refreshDelegate);
38256         }
38257         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38258         this.on("activate", this.refreshDelegate);
38259         return this.bodyEl.getUpdateManager();
38260     },
38261
38262     /** @private */
38263     _handleRefresh : function(url, params, loadOnce){
38264         if(!loadOnce || !this.loaded){
38265             var updater = this.bodyEl.getUpdateManager();
38266             updater.update(url, params, this._setLoaded.createDelegate(this));
38267         }
38268     },
38269
38270     /**
38271      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
38272      *   Will fail silently if the setUrl method has not been called.
38273      *   This does not activate the panel, just updates its content.
38274      */
38275     refresh : function(){
38276         if(this.refreshDelegate){
38277            this.loaded = false;
38278            this.refreshDelegate();
38279         }
38280     },
38281
38282     /** @private */
38283     _setLoaded : function(){
38284         this.loaded = true;
38285     },
38286
38287     /** @private */
38288     closeClick : function(e){
38289         var o = {};
38290         e.stopEvent();
38291         this.fireEvent("beforeclose", this, o);
38292         if(o.cancel !== true){
38293             this.tabPanel.removeTab(this.id);
38294         }
38295     },
38296     /**
38297      * The text displayed in the tooltip for the close icon.
38298      * @type String
38299      */
38300     closeText : "Close this tab"
38301 });
38302 /**
38303 *    This script refer to:
38304 *    Title: International Telephone Input
38305 *    Author: Jack O'Connor
38306 *    Code version:  v12.1.12
38307 *    Availability: https://github.com/jackocnr/intl-tel-input.git
38308 **/
38309
38310 Roo.bootstrap.PhoneInputData = function() {
38311     var d = [
38312       [
38313         "Afghanistan (‫افغانستان‬‎)",
38314         "af",
38315         "93"
38316       ],
38317       [
38318         "Albania (Shqipëri)",
38319         "al",
38320         "355"
38321       ],
38322       [
38323         "Algeria (‫الجزائر‬‎)",
38324         "dz",
38325         "213"
38326       ],
38327       [
38328         "American Samoa",
38329         "as",
38330         "1684"
38331       ],
38332       [
38333         "Andorra",
38334         "ad",
38335         "376"
38336       ],
38337       [
38338         "Angola",
38339         "ao",
38340         "244"
38341       ],
38342       [
38343         "Anguilla",
38344         "ai",
38345         "1264"
38346       ],
38347       [
38348         "Antigua and Barbuda",
38349         "ag",
38350         "1268"
38351       ],
38352       [
38353         "Argentina",
38354         "ar",
38355         "54"
38356       ],
38357       [
38358         "Armenia (Հայաստան)",
38359         "am",
38360         "374"
38361       ],
38362       [
38363         "Aruba",
38364         "aw",
38365         "297"
38366       ],
38367       [
38368         "Australia",
38369         "au",
38370         "61",
38371         0
38372       ],
38373       [
38374         "Austria (Österreich)",
38375         "at",
38376         "43"
38377       ],
38378       [
38379         "Azerbaijan (Azərbaycan)",
38380         "az",
38381         "994"
38382       ],
38383       [
38384         "Bahamas",
38385         "bs",
38386         "1242"
38387       ],
38388       [
38389         "Bahrain (‫البحرين‬‎)",
38390         "bh",
38391         "973"
38392       ],
38393       [
38394         "Bangladesh (বাংলাদেশ)",
38395         "bd",
38396         "880"
38397       ],
38398       [
38399         "Barbados",
38400         "bb",
38401         "1246"
38402       ],
38403       [
38404         "Belarus (Беларусь)",
38405         "by",
38406         "375"
38407       ],
38408       [
38409         "Belgium (België)",
38410         "be",
38411         "32"
38412       ],
38413       [
38414         "Belize",
38415         "bz",
38416         "501"
38417       ],
38418       [
38419         "Benin (Bénin)",
38420         "bj",
38421         "229"
38422       ],
38423       [
38424         "Bermuda",
38425         "bm",
38426         "1441"
38427       ],
38428       [
38429         "Bhutan (འབྲུག)",
38430         "bt",
38431         "975"
38432       ],
38433       [
38434         "Bolivia",
38435         "bo",
38436         "591"
38437       ],
38438       [
38439         "Bosnia and Herzegovina (Босна и Херцеговина)",
38440         "ba",
38441         "387"
38442       ],
38443       [
38444         "Botswana",
38445         "bw",
38446         "267"
38447       ],
38448       [
38449         "Brazil (Brasil)",
38450         "br",
38451         "55"
38452       ],
38453       [
38454         "British Indian Ocean Territory",
38455         "io",
38456         "246"
38457       ],
38458       [
38459         "British Virgin Islands",
38460         "vg",
38461         "1284"
38462       ],
38463       [
38464         "Brunei",
38465         "bn",
38466         "673"
38467       ],
38468       [
38469         "Bulgaria (България)",
38470         "bg",
38471         "359"
38472       ],
38473       [
38474         "Burkina Faso",
38475         "bf",
38476         "226"
38477       ],
38478       [
38479         "Burundi (Uburundi)",
38480         "bi",
38481         "257"
38482       ],
38483       [
38484         "Cambodia (កម្ពុជា)",
38485         "kh",
38486         "855"
38487       ],
38488       [
38489         "Cameroon (Cameroun)",
38490         "cm",
38491         "237"
38492       ],
38493       [
38494         "Canada",
38495         "ca",
38496         "1",
38497         1,
38498         ["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"]
38499       ],
38500       [
38501         "Cape Verde (Kabu Verdi)",
38502         "cv",
38503         "238"
38504       ],
38505       [
38506         "Caribbean Netherlands",
38507         "bq",
38508         "599",
38509         1
38510       ],
38511       [
38512         "Cayman Islands",
38513         "ky",
38514         "1345"
38515       ],
38516       [
38517         "Central African Republic (République centrafricaine)",
38518         "cf",
38519         "236"
38520       ],
38521       [
38522         "Chad (Tchad)",
38523         "td",
38524         "235"
38525       ],
38526       [
38527         "Chile",
38528         "cl",
38529         "56"
38530       ],
38531       [
38532         "China (中国)",
38533         "cn",
38534         "86"
38535       ],
38536       [
38537         "Christmas Island",
38538         "cx",
38539         "61",
38540         2
38541       ],
38542       [
38543         "Cocos (Keeling) Islands",
38544         "cc",
38545         "61",
38546         1
38547       ],
38548       [
38549         "Colombia",
38550         "co",
38551         "57"
38552       ],
38553       [
38554         "Comoros (‫جزر القمر‬‎)",
38555         "km",
38556         "269"
38557       ],
38558       [
38559         "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38560         "cd",
38561         "243"
38562       ],
38563       [
38564         "Congo (Republic) (Congo-Brazzaville)",
38565         "cg",
38566         "242"
38567       ],
38568       [
38569         "Cook Islands",
38570         "ck",
38571         "682"
38572       ],
38573       [
38574         "Costa Rica",
38575         "cr",
38576         "506"
38577       ],
38578       [
38579         "Côte d’Ivoire",
38580         "ci",
38581         "225"
38582       ],
38583       [
38584         "Croatia (Hrvatska)",
38585         "hr",
38586         "385"
38587       ],
38588       [
38589         "Cuba",
38590         "cu",
38591         "53"
38592       ],
38593       [
38594         "Curaçao",
38595         "cw",
38596         "599",
38597         0
38598       ],
38599       [
38600         "Cyprus (Κύπρος)",
38601         "cy",
38602         "357"
38603       ],
38604       [
38605         "Czech Republic (Česká republika)",
38606         "cz",
38607         "420"
38608       ],
38609       [
38610         "Denmark (Danmark)",
38611         "dk",
38612         "45"
38613       ],
38614       [
38615         "Djibouti",
38616         "dj",
38617         "253"
38618       ],
38619       [
38620         "Dominica",
38621         "dm",
38622         "1767"
38623       ],
38624       [
38625         "Dominican Republic (República Dominicana)",
38626         "do",
38627         "1",
38628         2,
38629         ["809", "829", "849"]
38630       ],
38631       [
38632         "Ecuador",
38633         "ec",
38634         "593"
38635       ],
38636       [
38637         "Egypt (‫مصر‬‎)",
38638         "eg",
38639         "20"
38640       ],
38641       [
38642         "El Salvador",
38643         "sv",
38644         "503"
38645       ],
38646       [
38647         "Equatorial Guinea (Guinea Ecuatorial)",
38648         "gq",
38649         "240"
38650       ],
38651       [
38652         "Eritrea",
38653         "er",
38654         "291"
38655       ],
38656       [
38657         "Estonia (Eesti)",
38658         "ee",
38659         "372"
38660       ],
38661       [
38662         "Ethiopia",
38663         "et",
38664         "251"
38665       ],
38666       [
38667         "Falkland Islands (Islas Malvinas)",
38668         "fk",
38669         "500"
38670       ],
38671       [
38672         "Faroe Islands (Føroyar)",
38673         "fo",
38674         "298"
38675       ],
38676       [
38677         "Fiji",
38678         "fj",
38679         "679"
38680       ],
38681       [
38682         "Finland (Suomi)",
38683         "fi",
38684         "358",
38685         0
38686       ],
38687       [
38688         "France",
38689         "fr",
38690         "33"
38691       ],
38692       [
38693         "French Guiana (Guyane française)",
38694         "gf",
38695         "594"
38696       ],
38697       [
38698         "French Polynesia (Polynésie française)",
38699         "pf",
38700         "689"
38701       ],
38702       [
38703         "Gabon",
38704         "ga",
38705         "241"
38706       ],
38707       [
38708         "Gambia",
38709         "gm",
38710         "220"
38711       ],
38712       [
38713         "Georgia (საქართველო)",
38714         "ge",
38715         "995"
38716       ],
38717       [
38718         "Germany (Deutschland)",
38719         "de",
38720         "49"
38721       ],
38722       [
38723         "Ghana (Gaana)",
38724         "gh",
38725         "233"
38726       ],
38727       [
38728         "Gibraltar",
38729         "gi",
38730         "350"
38731       ],
38732       [
38733         "Greece (Ελλάδα)",
38734         "gr",
38735         "30"
38736       ],
38737       [
38738         "Greenland (Kalaallit Nunaat)",
38739         "gl",
38740         "299"
38741       ],
38742       [
38743         "Grenada",
38744         "gd",
38745         "1473"
38746       ],
38747       [
38748         "Guadeloupe",
38749         "gp",
38750         "590",
38751         0
38752       ],
38753       [
38754         "Guam",
38755         "gu",
38756         "1671"
38757       ],
38758       [
38759         "Guatemala",
38760         "gt",
38761         "502"
38762       ],
38763       [
38764         "Guernsey",
38765         "gg",
38766         "44",
38767         1
38768       ],
38769       [
38770         "Guinea (Guinée)",
38771         "gn",
38772         "224"
38773       ],
38774       [
38775         "Guinea-Bissau (Guiné Bissau)",
38776         "gw",
38777         "245"
38778       ],
38779       [
38780         "Guyana",
38781         "gy",
38782         "592"
38783       ],
38784       [
38785         "Haiti",
38786         "ht",
38787         "509"
38788       ],
38789       [
38790         "Honduras",
38791         "hn",
38792         "504"
38793       ],
38794       [
38795         "Hong Kong (香港)",
38796         "hk",
38797         "852"
38798       ],
38799       [
38800         "Hungary (Magyarország)",
38801         "hu",
38802         "36"
38803       ],
38804       [
38805         "Iceland (Ísland)",
38806         "is",
38807         "354"
38808       ],
38809       [
38810         "India (भारत)",
38811         "in",
38812         "91"
38813       ],
38814       [
38815         "Indonesia",
38816         "id",
38817         "62"
38818       ],
38819       [
38820         "Iran (‫ایران‬‎)",
38821         "ir",
38822         "98"
38823       ],
38824       [
38825         "Iraq (‫العراق‬‎)",
38826         "iq",
38827         "964"
38828       ],
38829       [
38830         "Ireland",
38831         "ie",
38832         "353"
38833       ],
38834       [
38835         "Isle of Man",
38836         "im",
38837         "44",
38838         2
38839       ],
38840       [
38841         "Israel (‫ישראל‬‎)",
38842         "il",
38843         "972"
38844       ],
38845       [
38846         "Italy (Italia)",
38847         "it",
38848         "39",
38849         0
38850       ],
38851       [
38852         "Jamaica",
38853         "jm",
38854         "1876"
38855       ],
38856       [
38857         "Japan (日本)",
38858         "jp",
38859         "81"
38860       ],
38861       [
38862         "Jersey",
38863         "je",
38864         "44",
38865         3
38866       ],
38867       [
38868         "Jordan (‫الأردن‬‎)",
38869         "jo",
38870         "962"
38871       ],
38872       [
38873         "Kazakhstan (Казахстан)",
38874         "kz",
38875         "7",
38876         1
38877       ],
38878       [
38879         "Kenya",
38880         "ke",
38881         "254"
38882       ],
38883       [
38884         "Kiribati",
38885         "ki",
38886         "686"
38887       ],
38888       [
38889         "Kosovo",
38890         "xk",
38891         "383"
38892       ],
38893       [
38894         "Kuwait (‫الكويت‬‎)",
38895         "kw",
38896         "965"
38897       ],
38898       [
38899         "Kyrgyzstan (Кыргызстан)",
38900         "kg",
38901         "996"
38902       ],
38903       [
38904         "Laos (ລາວ)",
38905         "la",
38906         "856"
38907       ],
38908       [
38909         "Latvia (Latvija)",
38910         "lv",
38911         "371"
38912       ],
38913       [
38914         "Lebanon (‫لبنان‬‎)",
38915         "lb",
38916         "961"
38917       ],
38918       [
38919         "Lesotho",
38920         "ls",
38921         "266"
38922       ],
38923       [
38924         "Liberia",
38925         "lr",
38926         "231"
38927       ],
38928       [
38929         "Libya (‫ليبيا‬‎)",
38930         "ly",
38931         "218"
38932       ],
38933       [
38934         "Liechtenstein",
38935         "li",
38936         "423"
38937       ],
38938       [
38939         "Lithuania (Lietuva)",
38940         "lt",
38941         "370"
38942       ],
38943       [
38944         "Luxembourg",
38945         "lu",
38946         "352"
38947       ],
38948       [
38949         "Macau (澳門)",
38950         "mo",
38951         "853"
38952       ],
38953       [
38954         "Macedonia (FYROM) (Македонија)",
38955         "mk",
38956         "389"
38957       ],
38958       [
38959         "Madagascar (Madagasikara)",
38960         "mg",
38961         "261"
38962       ],
38963       [
38964         "Malawi",
38965         "mw",
38966         "265"
38967       ],
38968       [
38969         "Malaysia",
38970         "my",
38971         "60"
38972       ],
38973       [
38974         "Maldives",
38975         "mv",
38976         "960"
38977       ],
38978       [
38979         "Mali",
38980         "ml",
38981         "223"
38982       ],
38983       [
38984         "Malta",
38985         "mt",
38986         "356"
38987       ],
38988       [
38989         "Marshall Islands",
38990         "mh",
38991         "692"
38992       ],
38993       [
38994         "Martinique",
38995         "mq",
38996         "596"
38997       ],
38998       [
38999         "Mauritania (‫موريتانيا‬‎)",
39000         "mr",
39001         "222"
39002       ],
39003       [
39004         "Mauritius (Moris)",
39005         "mu",
39006         "230"
39007       ],
39008       [
39009         "Mayotte",
39010         "yt",
39011         "262",
39012         1
39013       ],
39014       [
39015         "Mexico (México)",
39016         "mx",
39017         "52"
39018       ],
39019       [
39020         "Micronesia",
39021         "fm",
39022         "691"
39023       ],
39024       [
39025         "Moldova (Republica Moldova)",
39026         "md",
39027         "373"
39028       ],
39029       [
39030         "Monaco",
39031         "mc",
39032         "377"
39033       ],
39034       [
39035         "Mongolia (Монгол)",
39036         "mn",
39037         "976"
39038       ],
39039       [
39040         "Montenegro (Crna Gora)",
39041         "me",
39042         "382"
39043       ],
39044       [
39045         "Montserrat",
39046         "ms",
39047         "1664"
39048       ],
39049       [
39050         "Morocco (‫المغرب‬‎)",
39051         "ma",
39052         "212",
39053         0
39054       ],
39055       [
39056         "Mozambique (Moçambique)",
39057         "mz",
39058         "258"
39059       ],
39060       [
39061         "Myanmar (Burma) (မြန်မာ)",
39062         "mm",
39063         "95"
39064       ],
39065       [
39066         "Namibia (Namibië)",
39067         "na",
39068         "264"
39069       ],
39070       [
39071         "Nauru",
39072         "nr",
39073         "674"
39074       ],
39075       [
39076         "Nepal (नेपाल)",
39077         "np",
39078         "977"
39079       ],
39080       [
39081         "Netherlands (Nederland)",
39082         "nl",
39083         "31"
39084       ],
39085       [
39086         "New Caledonia (Nouvelle-Calédonie)",
39087         "nc",
39088         "687"
39089       ],
39090       [
39091         "New Zealand",
39092         "nz",
39093         "64"
39094       ],
39095       [
39096         "Nicaragua",
39097         "ni",
39098         "505"
39099       ],
39100       [
39101         "Niger (Nijar)",
39102         "ne",
39103         "227"
39104       ],
39105       [
39106         "Nigeria",
39107         "ng",
39108         "234"
39109       ],
39110       [
39111         "Niue",
39112         "nu",
39113         "683"
39114       ],
39115       [
39116         "Norfolk Island",
39117         "nf",
39118         "672"
39119       ],
39120       [
39121         "North Korea (조선 민주주의 인민 공화국)",
39122         "kp",
39123         "850"
39124       ],
39125       [
39126         "Northern Mariana Islands",
39127         "mp",
39128         "1670"
39129       ],
39130       [
39131         "Norway (Norge)",
39132         "no",
39133         "47",
39134         0
39135       ],
39136       [
39137         "Oman (‫عُمان‬‎)",
39138         "om",
39139         "968"
39140       ],
39141       [
39142         "Pakistan (‫پاکستان‬‎)",
39143         "pk",
39144         "92"
39145       ],
39146       [
39147         "Palau",
39148         "pw",
39149         "680"
39150       ],
39151       [
39152         "Palestine (‫فلسطين‬‎)",
39153         "ps",
39154         "970"
39155       ],
39156       [
39157         "Panama (Panamá)",
39158         "pa",
39159         "507"
39160       ],
39161       [
39162         "Papua New Guinea",
39163         "pg",
39164         "675"
39165       ],
39166       [
39167         "Paraguay",
39168         "py",
39169         "595"
39170       ],
39171       [
39172         "Peru (Perú)",
39173         "pe",
39174         "51"
39175       ],
39176       [
39177         "Philippines",
39178         "ph",
39179         "63"
39180       ],
39181       [
39182         "Poland (Polska)",
39183         "pl",
39184         "48"
39185       ],
39186       [
39187         "Portugal",
39188         "pt",
39189         "351"
39190       ],
39191       [
39192         "Puerto Rico",
39193         "pr",
39194         "1",
39195         3,
39196         ["787", "939"]
39197       ],
39198       [
39199         "Qatar (‫قطر‬‎)",
39200         "qa",
39201         "974"
39202       ],
39203       [
39204         "Réunion (La Réunion)",
39205         "re",
39206         "262",
39207         0
39208       ],
39209       [
39210         "Romania (România)",
39211         "ro",
39212         "40"
39213       ],
39214       [
39215         "Russia (Россия)",
39216         "ru",
39217         "7",
39218         0
39219       ],
39220       [
39221         "Rwanda",
39222         "rw",
39223         "250"
39224       ],
39225       [
39226         "Saint Barthélemy",
39227         "bl",
39228         "590",
39229         1
39230       ],
39231       [
39232         "Saint Helena",
39233         "sh",
39234         "290"
39235       ],
39236       [
39237         "Saint Kitts and Nevis",
39238         "kn",
39239         "1869"
39240       ],
39241       [
39242         "Saint Lucia",
39243         "lc",
39244         "1758"
39245       ],
39246       [
39247         "Saint Martin (Saint-Martin (partie française))",
39248         "mf",
39249         "590",
39250         2
39251       ],
39252       [
39253         "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39254         "pm",
39255         "508"
39256       ],
39257       [
39258         "Saint Vincent and the Grenadines",
39259         "vc",
39260         "1784"
39261       ],
39262       [
39263         "Samoa",
39264         "ws",
39265         "685"
39266       ],
39267       [
39268         "San Marino",
39269         "sm",
39270         "378"
39271       ],
39272       [
39273         "São Tomé and Príncipe (São Tomé e Príncipe)",
39274         "st",
39275         "239"
39276       ],
39277       [
39278         "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
39279         "sa",
39280         "966"
39281       ],
39282       [
39283         "Senegal (Sénégal)",
39284         "sn",
39285         "221"
39286       ],
39287       [
39288         "Serbia (Србија)",
39289         "rs",
39290         "381"
39291       ],
39292       [
39293         "Seychelles",
39294         "sc",
39295         "248"
39296       ],
39297       [
39298         "Sierra Leone",
39299         "sl",
39300         "232"
39301       ],
39302       [
39303         "Singapore",
39304         "sg",
39305         "65"
39306       ],
39307       [
39308         "Sint Maarten",
39309         "sx",
39310         "1721"
39311       ],
39312       [
39313         "Slovakia (Slovensko)",
39314         "sk",
39315         "421"
39316       ],
39317       [
39318         "Slovenia (Slovenija)",
39319         "si",
39320         "386"
39321       ],
39322       [
39323         "Solomon Islands",
39324         "sb",
39325         "677"
39326       ],
39327       [
39328         "Somalia (Soomaaliya)",
39329         "so",
39330         "252"
39331       ],
39332       [
39333         "South Africa",
39334         "za",
39335         "27"
39336       ],
39337       [
39338         "South Korea (대한민국)",
39339         "kr",
39340         "82"
39341       ],
39342       [
39343         "South Sudan (‫جنوب السودان‬‎)",
39344         "ss",
39345         "211"
39346       ],
39347       [
39348         "Spain (España)",
39349         "es",
39350         "34"
39351       ],
39352       [
39353         "Sri Lanka (ශ්‍රී ලංකාව)",
39354         "lk",
39355         "94"
39356       ],
39357       [
39358         "Sudan (‫السودان‬‎)",
39359         "sd",
39360         "249"
39361       ],
39362       [
39363         "Suriname",
39364         "sr",
39365         "597"
39366       ],
39367       [
39368         "Svalbard and Jan Mayen",
39369         "sj",
39370         "47",
39371         1
39372       ],
39373       [
39374         "Swaziland",
39375         "sz",
39376         "268"
39377       ],
39378       [
39379         "Sweden (Sverige)",
39380         "se",
39381         "46"
39382       ],
39383       [
39384         "Switzerland (Schweiz)",
39385         "ch",
39386         "41"
39387       ],
39388       [
39389         "Syria (‫سوريا‬‎)",
39390         "sy",
39391         "963"
39392       ],
39393       [
39394         "Taiwan (台灣)",
39395         "tw",
39396         "886"
39397       ],
39398       [
39399         "Tajikistan",
39400         "tj",
39401         "992"
39402       ],
39403       [
39404         "Tanzania",
39405         "tz",
39406         "255"
39407       ],
39408       [
39409         "Thailand (ไทย)",
39410         "th",
39411         "66"
39412       ],
39413       [
39414         "Timor-Leste",
39415         "tl",
39416         "670"
39417       ],
39418       [
39419         "Togo",
39420         "tg",
39421         "228"
39422       ],
39423       [
39424         "Tokelau",
39425         "tk",
39426         "690"
39427       ],
39428       [
39429         "Tonga",
39430         "to",
39431         "676"
39432       ],
39433       [
39434         "Trinidad and Tobago",
39435         "tt",
39436         "1868"
39437       ],
39438       [
39439         "Tunisia (‫تونس‬‎)",
39440         "tn",
39441         "216"
39442       ],
39443       [
39444         "Turkey (Türkiye)",
39445         "tr",
39446         "90"
39447       ],
39448       [
39449         "Turkmenistan",
39450         "tm",
39451         "993"
39452       ],
39453       [
39454         "Turks and Caicos Islands",
39455         "tc",
39456         "1649"
39457       ],
39458       [
39459         "Tuvalu",
39460         "tv",
39461         "688"
39462       ],
39463       [
39464         "U.S. Virgin Islands",
39465         "vi",
39466         "1340"
39467       ],
39468       [
39469         "Uganda",
39470         "ug",
39471         "256"
39472       ],
39473       [
39474         "Ukraine (Україна)",
39475         "ua",
39476         "380"
39477       ],
39478       [
39479         "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
39480         "ae",
39481         "971"
39482       ],
39483       [
39484         "United Kingdom",
39485         "gb",
39486         "44",
39487         0
39488       ],
39489       [
39490         "United States",
39491         "us",
39492         "1",
39493         0
39494       ],
39495       [
39496         "Uruguay",
39497         "uy",
39498         "598"
39499       ],
39500       [
39501         "Uzbekistan (Oʻzbekiston)",
39502         "uz",
39503         "998"
39504       ],
39505       [
39506         "Vanuatu",
39507         "vu",
39508         "678"
39509       ],
39510       [
39511         "Vatican City (Città del Vaticano)",
39512         "va",
39513         "39",
39514         1
39515       ],
39516       [
39517         "Venezuela",
39518         "ve",
39519         "58"
39520       ],
39521       [
39522         "Vietnam (Việt Nam)",
39523         "vn",
39524         "84"
39525       ],
39526       [
39527         "Wallis and Futuna (Wallis-et-Futuna)",
39528         "wf",
39529         "681"
39530       ],
39531       [
39532         "Western Sahara (‫الصحراء الغربية‬‎)",
39533         "eh",
39534         "212",
39535         1
39536       ],
39537       [
39538         "Yemen (‫اليمن‬‎)",
39539         "ye",
39540         "967"
39541       ],
39542       [
39543         "Zambia",
39544         "zm",
39545         "260"
39546       ],
39547       [
39548         "Zimbabwe",
39549         "zw",
39550         "263"
39551       ],
39552       [
39553         "Åland Islands",
39554         "ax",
39555         "358",
39556         1
39557       ]
39558   ];
39559   
39560   return d;
39561 }/**
39562 *    This script refer to:
39563 *    Title: International Telephone Input
39564 *    Author: Jack O'Connor
39565 *    Code version:  v12.1.12
39566 *    Availability: https://github.com/jackocnr/intl-tel-input.git
39567 **/
39568
39569 /**
39570  * @class Roo.bootstrap.PhoneInput
39571  * @extends Roo.bootstrap.TriggerField
39572  * An input with International dial-code selection
39573  
39574  * @cfg {String} defaultDialCode default '+852'
39575  * @cfg {Array} preferedCountries default []
39576   
39577  * @constructor
39578  * Create a new PhoneInput.
39579  * @param {Object} config Configuration options
39580  */
39581
39582 Roo.bootstrap.PhoneInput = function(config) {
39583     Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39584 };
39585
39586 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39587         
39588         listWidth: undefined,
39589         
39590         selectedClass: 'active',
39591         
39592         invalidClass : "has-warning",
39593         
39594         validClass: 'has-success',
39595         
39596         allowed: '0123456789',
39597         
39598         /**
39599          * @cfg {String} defaultDialCode The default dial code when initializing the input
39600          */
39601         defaultDialCode: '+852',
39602         
39603         /**
39604          * @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
39605          */
39606         preferedCountries: false,
39607         
39608         getAutoCreate : function()
39609         {
39610             var data = Roo.bootstrap.PhoneInputData();
39611             var align = this.labelAlign || this.parentLabelAlign();
39612             var id = Roo.id();
39613             
39614             this.allCountries = [];
39615             this.dialCodeMapping = [];
39616             
39617             for (var i = 0; i < data.length; i++) {
39618               var c = data[i];
39619               this.allCountries[i] = {
39620                 name: c[0],
39621                 iso2: c[1],
39622                 dialCode: c[2],
39623                 priority: c[3] || 0,
39624                 areaCodes: c[4] || null
39625               };
39626               this.dialCodeMapping[c[2]] = {
39627                   name: c[0],
39628                   iso2: c[1],
39629                   priority: c[3] || 0,
39630                   areaCodes: c[4] || null
39631               };
39632             }
39633             
39634             var cfg = {
39635                 cls: 'form-group',
39636                 cn: []
39637             };
39638             
39639             var input =  {
39640                 tag: 'input',
39641                 id : id,
39642                 cls : 'form-control tel-input',
39643                 autocomplete: 'new-password'
39644             };
39645             
39646             var hiddenInput = {
39647                 tag: 'input',
39648                 type: 'hidden',
39649                 cls: 'hidden-tel-input'
39650             };
39651             
39652             if (this.name) {
39653                 hiddenInput.name = this.name;
39654             }
39655             
39656             if (this.disabled) {
39657                 input.disabled = true;
39658             }
39659             
39660             var flag_container = {
39661                 tag: 'div',
39662                 cls: 'flag-box',
39663                 cn: [
39664                     {
39665                         tag: 'div',
39666                         cls: 'flag'
39667                     },
39668                     {
39669                         tag: 'div',
39670                         cls: 'caret'
39671                     }
39672                 ]
39673             };
39674             
39675             var box = {
39676                 tag: 'div',
39677                 cls: this.hasFeedback ? 'has-feedback' : '',
39678                 cn: [
39679                     hiddenInput,
39680                     input,
39681                     {
39682                         tag: 'input',
39683                         cls: 'dial-code-holder',
39684                         disabled: true
39685                     }
39686                 ]
39687             };
39688             
39689             var container = {
39690                 cls: 'roo-select2-container input-group',
39691                 cn: [
39692                     flag_container,
39693                     box
39694                 ]
39695             };
39696             
39697             if (this.fieldLabel.length) {
39698                 var indicator = {
39699                     tag: 'i',
39700                     tooltip: 'This field is required'
39701                 };
39702                 
39703                 var label = {
39704                     tag: 'label',
39705                     'for':  id,
39706                     cls: 'control-label',
39707                     cn: []
39708                 };
39709                 
39710                 var label_text = {
39711                     tag: 'span',
39712                     html: this.fieldLabel
39713                 };
39714                 
39715                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39716                 label.cn = [
39717                     indicator,
39718                     label_text
39719                 ];
39720                 
39721                 if(this.indicatorpos == 'right') {
39722                     indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39723                     label.cn = [
39724                         label_text,
39725                         indicator
39726                     ];
39727                 }
39728                 
39729                 if(align == 'left') {
39730                     container = {
39731                         tag: 'div',
39732                         cn: [
39733                             container
39734                         ]
39735                     };
39736                     
39737                     if(this.labelWidth > 12){
39738                         label.style = "width: " + this.labelWidth + 'px';
39739                     }
39740                     if(this.labelWidth < 13 && this.labelmd == 0){
39741                         this.labelmd = this.labelWidth;
39742                     }
39743                     if(this.labellg > 0){
39744                         label.cls += ' col-lg-' + this.labellg;
39745                         input.cls += ' col-lg-' + (12 - this.labellg);
39746                     }
39747                     if(this.labelmd > 0){
39748                         label.cls += ' col-md-' + this.labelmd;
39749                         container.cls += ' col-md-' + (12 - this.labelmd);
39750                     }
39751                     if(this.labelsm > 0){
39752                         label.cls += ' col-sm-' + this.labelsm;
39753                         container.cls += ' col-sm-' + (12 - this.labelsm);
39754                     }
39755                     if(this.labelxs > 0){
39756                         label.cls += ' col-xs-' + this.labelxs;
39757                         container.cls += ' col-xs-' + (12 - this.labelxs);
39758                     }
39759                 }
39760             }
39761             
39762             cfg.cn = [
39763                 label,
39764                 container
39765             ];
39766             
39767             var settings = this;
39768             
39769             ['xs','sm','md','lg'].map(function(size){
39770                 if (settings[size]) {
39771                     cfg.cls += ' col-' + size + '-' + settings[size];
39772                 }
39773             });
39774             
39775             this.store = new Roo.data.Store({
39776                 proxy : new Roo.data.MemoryProxy({}),
39777                 reader : new Roo.data.JsonReader({
39778                     fields : [
39779                         {
39780                             'name' : 'name',
39781                             'type' : 'string'
39782                         },
39783                         {
39784                             'name' : 'iso2',
39785                             'type' : 'string'
39786                         },
39787                         {
39788                             'name' : 'dialCode',
39789                             'type' : 'string'
39790                         },
39791                         {
39792                             'name' : 'priority',
39793                             'type' : 'string'
39794                         },
39795                         {
39796                             'name' : 'areaCodes',
39797                             'type' : 'string'
39798                         }
39799                     ]
39800                 })
39801             });
39802             
39803             if(!this.preferedCountries) {
39804                 this.preferedCountries = [
39805                     'hk',
39806                     'gb',
39807                     'us'
39808                 ];
39809             }
39810             
39811             var p = this.preferedCountries.reverse();
39812             
39813             if(p) {
39814                 for (var i = 0; i < p.length; i++) {
39815                     for (var j = 0; j < this.allCountries.length; j++) {
39816                         if(this.allCountries[j].iso2 == p[i]) {
39817                             var t = this.allCountries[j];
39818                             this.allCountries.splice(j,1);
39819                             this.allCountries.unshift(t);
39820                         }
39821                     } 
39822                 }
39823             }
39824             
39825             this.store.proxy.data = {
39826                 success: true,
39827                 data: this.allCountries
39828             };
39829             
39830             return cfg;
39831         },
39832         
39833         initEvents : function()
39834         {
39835             this.createList();
39836             Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39837             
39838             this.indicator = this.indicatorEl();
39839             this.flag = this.flagEl();
39840             this.dialCodeHolder = this.dialCodeHolderEl();
39841             
39842             this.trigger = this.el.select('div.flag-box',true).first();
39843             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39844             
39845             var _this = this;
39846             
39847             (function(){
39848                 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39849                 _this.list.setWidth(lw);
39850             }).defer(100);
39851             
39852             this.list.on('mouseover', this.onViewOver, this);
39853             this.list.on('mousemove', this.onViewMove, this);
39854             this.inputEl().on("keyup", this.onKeyUp, this);
39855             
39856             this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39857
39858             this.view = new Roo.View(this.list, this.tpl, {
39859                 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39860             });
39861             
39862             this.view.on('click', this.onViewClick, this);
39863             this.setValue(this.defaultDialCode);
39864         },
39865         
39866         onTriggerClick : function(e)
39867         {
39868             Roo.log('trigger click');
39869             if(this.disabled){
39870                 return;
39871             }
39872             
39873             if(this.isExpanded()){
39874                 this.collapse();
39875                 this.hasFocus = false;
39876             }else {
39877                 this.store.load({});
39878                 this.hasFocus = true;
39879                 this.expand();
39880             }
39881         },
39882         
39883         isExpanded : function()
39884         {
39885             return this.list.isVisible();
39886         },
39887         
39888         collapse : function()
39889         {
39890             if(!this.isExpanded()){
39891                 return;
39892             }
39893             this.list.hide();
39894             Roo.get(document).un('mousedown', this.collapseIf, this);
39895             Roo.get(document).un('mousewheel', this.collapseIf, this);
39896             this.fireEvent('collapse', this);
39897             this.validate();
39898         },
39899         
39900         expand : function()
39901         {
39902             Roo.log('expand');
39903
39904             if(this.isExpanded() || !this.hasFocus){
39905                 return;
39906             }
39907             
39908             var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39909             this.list.setWidth(lw);
39910             
39911             this.list.show();
39912             this.restrictHeight();
39913             
39914             Roo.get(document).on('mousedown', this.collapseIf, this);
39915             Roo.get(document).on('mousewheel', this.collapseIf, this);
39916             
39917             this.fireEvent('expand', this);
39918         },
39919         
39920         restrictHeight : function()
39921         {
39922             this.list.alignTo(this.inputEl(), this.listAlign);
39923             this.list.alignTo(this.inputEl(), this.listAlign);
39924         },
39925         
39926         onViewOver : function(e, t)
39927         {
39928             if(this.inKeyMode){
39929                 return;
39930             }
39931             var item = this.view.findItemFromChild(t);
39932             
39933             if(item){
39934                 var index = this.view.indexOf(item);
39935                 this.select(index, false);
39936             }
39937         },
39938
39939         // private
39940         onViewClick : function(view, doFocus, el, e)
39941         {
39942             var index = this.view.getSelectedIndexes()[0];
39943             
39944             var r = this.store.getAt(index);
39945             
39946             if(r){
39947                 this.onSelect(r, index);
39948             }
39949             if(doFocus !== false && !this.blockFocus){
39950                 this.inputEl().focus();
39951             }
39952         },
39953         
39954         onViewMove : function(e, t)
39955         {
39956             this.inKeyMode = false;
39957         },
39958         
39959         select : function(index, scrollIntoView)
39960         {
39961             this.selectedIndex = index;
39962             this.view.select(index);
39963             if(scrollIntoView !== false){
39964                 var el = this.view.getNode(index);
39965                 if(el){
39966                     this.list.scrollChildIntoView(el, false);
39967                 }
39968             }
39969         },
39970         
39971         createList : function()
39972         {
39973             this.list = Roo.get(document.body).createChild({
39974                 tag: 'ul',
39975                 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39976                 style: 'display:none'
39977             });
39978             this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39979         },
39980         
39981         collapseIf : function(e)
39982         {
39983             var in_combo  = e.within(this.el);
39984             var in_list =  e.within(this.list);
39985             var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39986             
39987             if (in_combo || in_list || is_list) {
39988                 return;
39989             }
39990             this.collapse();
39991         },
39992         
39993         onSelect : function(record, index)
39994         {
39995             if(this.fireEvent('beforeselect', this, record, index) !== false){
39996                 
39997                 this.setFlagClass(record.data.iso2);
39998                 this.setDialCode(record.data.dialCode);
39999                 this.hasFocus = false;
40000                 this.collapse();
40001                 this.fireEvent('select', this, record, index);
40002             }
40003         },
40004         
40005         flagEl : function()
40006         {
40007             var flag = this.el.select('div.flag',true).first();
40008             if(!flag){
40009                 return false;
40010             }
40011             return flag;
40012         },
40013         
40014         dialCodeHolderEl : function()
40015         {
40016             var d = this.el.select('input.dial-code-holder',true).first();
40017             if(!d){
40018                 return false;
40019             }
40020             return d;
40021         },
40022         
40023         setDialCode : function(v)
40024         {
40025             this.dialCodeHolder.dom.value = '+'+v;
40026         },
40027         
40028         setFlagClass : function(n)
40029         {
40030             this.flag.dom.className = 'flag '+n;
40031         },
40032         
40033         getValue : function()
40034         {
40035             var v = this.inputEl().getValue();
40036             if(this.dialCodeHolder) {
40037                 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40038             }
40039             return v;
40040         },
40041         
40042         setValue : function(v)
40043         {
40044             var d = this.getDialCode(v);
40045             
40046             //invalid dial code
40047             if(v.length == 0 || !d || d.length == 0) {
40048                 if(this.rendered){
40049                     this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40050                     this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40051                 }
40052                 return;
40053             }
40054             
40055             //valid dial code
40056             this.setFlagClass(this.dialCodeMapping[d].iso2);
40057             this.setDialCode(d);
40058             this.inputEl().dom.value = v.replace('+'+d,'');
40059             this.hiddenEl().dom.value = this.getValue();
40060             
40061             this.validate();
40062         },
40063         
40064         getDialCode : function(v = '')
40065         {
40066             if (v.length == 0) {
40067                 return this.dialCodeHolder.dom.value;
40068             }
40069             
40070             var dialCode = "";
40071             if (v.charAt(0) != "+") {
40072                 return false;
40073             }
40074             var numericChars = "";
40075             for (var i = 1; i < v.length; i++) {
40076               var c = v.charAt(i);
40077               if (!isNaN(c)) {
40078                 numericChars += c;
40079                 if (this.dialCodeMapping[numericChars]) {
40080                   dialCode = v.substr(1, i);
40081                 }
40082                 if (numericChars.length == 4) {
40083                   break;
40084                 }
40085               }
40086             }
40087             return dialCode;
40088         },
40089         
40090         reset : function()
40091         {
40092             this.setValue(this.defaultDialCode);
40093             this.validate();
40094         },
40095         
40096         hiddenEl : function()
40097         {
40098             return this.el.select('input.hidden-tel-input',true).first();
40099         },
40100         
40101         onKeyUp : function(e){
40102             
40103             var k = e.getKey();
40104             var c = e.getCharCode();
40105             
40106             if(
40107                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40108                     this.allowed.indexOf(String.fromCharCode(c)) === -1
40109             ){
40110                 e.stopEvent();
40111             }
40112             
40113             // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40114             //     return;
40115             // }
40116             if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40117                 e.stopEvent();
40118             }
40119             
40120             this.setValue(this.getValue());
40121         }
40122         
40123 });
40124 /**
40125  * @class Roo.bootstrap.MoneyField
40126  * @extends Roo.bootstrap.ComboBox
40127  * Bootstrap MoneyField class
40128  * 
40129  * @constructor
40130  * Create a new MoneyField.
40131  * @param {Object} config Configuration options
40132  */
40133
40134 Roo.bootstrap.MoneyField = function(config) {
40135     
40136     Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40137     
40138 };
40139
40140 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40141     
40142     /**
40143      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40144      */
40145     allowDecimals : true,
40146     /**
40147      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40148      */
40149     decimalSeparator : ".",
40150     /**
40151      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40152      */
40153     decimalPrecision : 0,
40154     /**
40155      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40156      */
40157     allowNegative : true,
40158     /**
40159      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40160      */
40161     minValue : Number.NEGATIVE_INFINITY,
40162     /**
40163      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40164      */
40165     maxValue : Number.MAX_VALUE,
40166     /**
40167      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40168      */
40169     minText : "The minimum value for this field is {0}",
40170     /**
40171      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40172      */
40173     maxText : "The maximum value for this field is {0}",
40174     /**
40175      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
40176      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40177      */
40178     nanText : "{0} is not a valid number",
40179     /**
40180      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40181      */
40182     castInt : true,
40183     /**
40184      * @cfg {String} defaults currency of the MoneyField
40185      * value should be in lkey
40186      */
40187     defaultCurrency : false,
40188     /**
40189      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40190      */
40191     thousandsDelimiter : false,
40192     
40193     
40194     inputlg : 9,
40195     inputmd : 9,
40196     inputsm : 9,
40197     inputxs : 6,
40198     
40199     store : false,
40200     
40201     getAutoCreate : function()
40202     {
40203         var align = this.labelAlign || this.parentLabelAlign();
40204         
40205         var id = Roo.id();
40206
40207         var cfg = {
40208             cls: 'form-group',
40209             cn: []
40210         };
40211
40212         var input =  {
40213             tag: 'input',
40214             id : id,
40215             cls : 'form-control roo-money-amount-input',
40216             autocomplete: 'new-password'
40217         };
40218         
40219         var hiddenInput = {
40220             tag: 'input',
40221             type: 'hidden',
40222             id: Roo.id(),
40223             cls: 'hidden-number-input'
40224         };
40225         
40226         if (this.name) {
40227             hiddenInput.name = this.name;
40228         }
40229
40230         if (this.disabled) {
40231             input.disabled = true;
40232         }
40233
40234         var clg = 12 - this.inputlg;
40235         var cmd = 12 - this.inputmd;
40236         var csm = 12 - this.inputsm;
40237         var cxs = 12 - this.inputxs;
40238         
40239         var container = {
40240             tag : 'div',
40241             cls : 'row roo-money-field',
40242             cn : [
40243                 {
40244                     tag : 'div',
40245                     cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40246                     cn : [
40247                         {
40248                             tag : 'div',
40249                             cls: 'roo-select2-container input-group',
40250                             cn: [
40251                                 {
40252                                     tag : 'input',
40253                                     cls : 'form-control roo-money-currency-input',
40254                                     autocomplete: 'new-password',
40255                                     readOnly : 1,
40256                                     name : this.currencyName
40257                                 },
40258                                 {
40259                                     tag :'span',
40260                                     cls : 'input-group-addon',
40261                                     cn : [
40262                                         {
40263                                             tag: 'span',
40264                                             cls: 'caret'
40265                                         }
40266                                     ]
40267                                 }
40268                             ]
40269                         }
40270                     ]
40271                 },
40272                 {
40273                     tag : 'div',
40274                     cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40275                     cn : [
40276                         {
40277                             tag: 'div',
40278                             cls: this.hasFeedback ? 'has-feedback' : '',
40279                             cn: [
40280                                 input
40281                             ]
40282                         }
40283                     ]
40284                 }
40285             ]
40286             
40287         };
40288         
40289         if (this.fieldLabel.length) {
40290             var indicator = {
40291                 tag: 'i',
40292                 tooltip: 'This field is required'
40293             };
40294
40295             var label = {
40296                 tag: 'label',
40297                 'for':  id,
40298                 cls: 'control-label',
40299                 cn: []
40300             };
40301
40302             var label_text = {
40303                 tag: 'span',
40304                 html: this.fieldLabel
40305             };
40306
40307             indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40308             label.cn = [
40309                 indicator,
40310                 label_text
40311             ];
40312
40313             if(this.indicatorpos == 'right') {
40314                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40315                 label.cn = [
40316                     label_text,
40317                     indicator
40318                 ];
40319             }
40320
40321             if(align == 'left') {
40322                 container = {
40323                     tag: 'div',
40324                     cn: [
40325                         container
40326                     ]
40327                 };
40328
40329                 if(this.labelWidth > 12){
40330                     label.style = "width: " + this.labelWidth + 'px';
40331                 }
40332                 if(this.labelWidth < 13 && this.labelmd == 0){
40333                     this.labelmd = this.labelWidth;
40334                 }
40335                 if(this.labellg > 0){
40336                     label.cls += ' col-lg-' + this.labellg;
40337                     input.cls += ' col-lg-' + (12 - this.labellg);
40338                 }
40339                 if(this.labelmd > 0){
40340                     label.cls += ' col-md-' + this.labelmd;
40341                     container.cls += ' col-md-' + (12 - this.labelmd);
40342                 }
40343                 if(this.labelsm > 0){
40344                     label.cls += ' col-sm-' + this.labelsm;
40345                     container.cls += ' col-sm-' + (12 - this.labelsm);
40346                 }
40347                 if(this.labelxs > 0){
40348                     label.cls += ' col-xs-' + this.labelxs;
40349                     container.cls += ' col-xs-' + (12 - this.labelxs);
40350                 }
40351             }
40352         }
40353
40354         cfg.cn = [
40355             label,
40356             container,
40357             hiddenInput
40358         ];
40359         
40360         var settings = this;
40361
40362         ['xs','sm','md','lg'].map(function(size){
40363             if (settings[size]) {
40364                 cfg.cls += ' col-' + size + '-' + settings[size];
40365             }
40366         });
40367         
40368         return cfg;
40369     },
40370     
40371     initEvents : function()
40372     {
40373         this.indicator = this.indicatorEl();
40374         
40375         this.initCurrencyEvent();
40376         
40377         this.initNumberEvent();
40378     },
40379     
40380     initCurrencyEvent : function()
40381     {
40382         if (!this.store) {
40383             throw "can not find store for combo";
40384         }
40385         
40386         this.store = Roo.factory(this.store, Roo.data);
40387         this.store.parent = this;
40388         
40389         this.createList();
40390         
40391         this.triggerEl = this.el.select('.input-group-addon', true).first();
40392         
40393         this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40394         
40395         var _this = this;
40396         
40397         (function(){
40398             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40399             _this.list.setWidth(lw);
40400         }).defer(100);
40401         
40402         this.list.on('mouseover', this.onViewOver, this);
40403         this.list.on('mousemove', this.onViewMove, this);
40404         this.list.on('scroll', this.onViewScroll, this);
40405         
40406         if(!this.tpl){
40407             this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40408         }
40409         
40410         this.view = new Roo.View(this.list, this.tpl, {
40411             singleSelect:true, store: this.store, selectedClass: this.selectedClass
40412         });
40413         
40414         this.view.on('click', this.onViewClick, this);
40415         
40416         this.store.on('beforeload', this.onBeforeLoad, this);
40417         this.store.on('load', this.onLoad, this);
40418         this.store.on('loadexception', this.onLoadException, this);
40419         
40420         this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40421             "up" : function(e){
40422                 this.inKeyMode = true;
40423                 this.selectPrev();
40424             },
40425
40426             "down" : function(e){
40427                 if(!this.isExpanded()){
40428                     this.onTriggerClick();
40429                 }else{
40430                     this.inKeyMode = true;
40431                     this.selectNext();
40432                 }
40433             },
40434
40435             "enter" : function(e){
40436                 this.collapse();
40437                 
40438                 if(this.fireEvent("specialkey", this, e)){
40439                     this.onViewClick(false);
40440                 }
40441                 
40442                 return true;
40443             },
40444
40445             "esc" : function(e){
40446                 this.collapse();
40447             },
40448
40449             "tab" : function(e){
40450                 this.collapse();
40451                 
40452                 if(this.fireEvent("specialkey", this, e)){
40453                     this.onViewClick(false);
40454                 }
40455                 
40456                 return true;
40457             },
40458
40459             scope : this,
40460
40461             doRelay : function(foo, bar, hname){
40462                 if(hname == 'down' || this.scope.isExpanded()){
40463                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40464                 }
40465                 return true;
40466             },
40467
40468             forceKeyDown: true
40469         });
40470         
40471         this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40472         
40473     },
40474     
40475     initNumberEvent : function(e)
40476     {
40477         this.inputEl().on("keydown" , this.fireKey,  this);
40478         this.inputEl().on("focus", this.onFocus,  this);
40479         this.inputEl().on("blur", this.onBlur,  this);
40480         
40481         this.inputEl().relayEvent('keyup', this);
40482         
40483         if(this.indicator){
40484             this.indicator.addClass('invisible');
40485         }
40486  
40487         this.originalValue = this.getValue();
40488         
40489         if(this.validationEvent == 'keyup'){
40490             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40491             this.inputEl().on('keyup', this.filterValidation, this);
40492         }
40493         else if(this.validationEvent !== false){
40494             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40495         }
40496         
40497         if(this.selectOnFocus){
40498             this.on("focus", this.preFocus, this);
40499             
40500         }
40501         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40502             this.inputEl().on("keypress", this.filterKeys, this);
40503         } else {
40504             this.inputEl().relayEvent('keypress', this);
40505         }
40506         
40507         var allowed = "0123456789";
40508         
40509         if(this.allowDecimals){
40510             allowed += this.decimalSeparator;
40511         }
40512         
40513         if(this.allowNegative){
40514             allowed += "-";
40515         }
40516         
40517         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40518         
40519         var keyPress = function(e){
40520             
40521             var k = e.getKey();
40522             
40523             var c = e.getCharCode();
40524             
40525             if(
40526                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40527                     allowed.indexOf(String.fromCharCode(c)) === -1
40528             ){
40529                 e.stopEvent();
40530                 return;
40531             }
40532             
40533             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40534                 return;
40535             }
40536             
40537             if(allowed.indexOf(String.fromCharCode(c)) === -1){
40538                 e.stopEvent();
40539             }
40540         };
40541         
40542         this.inputEl().on("keypress", keyPress, this);
40543         
40544     },
40545     
40546     onTriggerClick : function(e)
40547     {   
40548         if(this.disabled){
40549             return;
40550         }
40551         
40552         this.page = 0;
40553         this.loadNext = false;
40554         
40555         if(this.isExpanded()){
40556             this.collapse();
40557             return;
40558         }
40559         
40560         this.hasFocus = true;
40561         
40562         if(this.triggerAction == 'all') {
40563             this.doQuery(this.allQuery, true);
40564             return;
40565         }
40566         
40567         this.doQuery(this.getRawValue());
40568     },
40569     
40570     getCurrency : function()
40571     {   
40572         var v = this.currencyEl().getValue();
40573         
40574         return v;
40575     },
40576     
40577     restrictHeight : function()
40578     {
40579         this.list.alignTo(this.currencyEl(), this.listAlign);
40580         this.list.alignTo(this.currencyEl(), this.listAlign);
40581     },
40582     
40583     onViewClick : function(view, doFocus, el, e)
40584     {
40585         var index = this.view.getSelectedIndexes()[0];
40586         
40587         var r = this.store.getAt(index);
40588         
40589         if(r){
40590             this.onSelect(r, index);
40591         }
40592     },
40593     
40594     onSelect : function(record, index){
40595         
40596         if(this.fireEvent('beforeselect', this, record, index) !== false){
40597         
40598             this.setFromCurrencyData(index > -1 ? record.data : false);
40599             
40600             this.collapse();
40601             
40602             this.fireEvent('select', this, record, index);
40603         }
40604     },
40605     
40606     setFromCurrencyData : function(o)
40607     {
40608         var currency = '';
40609         
40610         this.lastCurrency = o;
40611         
40612         if (this.currencyField) {
40613             currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40614         } else {
40615             Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
40616         }
40617         
40618         this.lastSelectionText = currency;
40619         
40620         //setting default currency
40621         if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40622             this.setCurrency(this.defaultCurrency);
40623             return;
40624         }
40625         
40626         this.setCurrency(currency);
40627     },
40628     
40629     setFromData : function(o)
40630     {
40631         var c = {};
40632         
40633         c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40634         
40635         this.setFromCurrencyData(c);
40636         
40637         var value = '';
40638         
40639         if (this.name) {
40640             value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40641         } else {
40642             Roo.log('no value set for '+ (this.name ? this.name : this.id));
40643         }
40644         
40645         this.setValue(value);
40646         
40647     },
40648     
40649     setCurrency : function(v)
40650     {   
40651         this.currencyValue = v;
40652         
40653         if(this.rendered){
40654             this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40655             this.validate();
40656         }
40657     },
40658     
40659     setValue : function(v)
40660     {
40661         v = this.fixPrecision(v);
40662         
40663         v = String(v).replace(".", this.decimalSeparator);
40664         
40665         this.value = v;
40666         
40667         if(this.rendered){
40668             
40669             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40670             
40671             this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision, 
40672                 this.thousandsDelimiter || ','
40673             );
40674             
40675             if(this.allowBlank && !v) {
40676                 this.inputEl().dom.value = '';
40677             }
40678             
40679             this.validate();
40680         }
40681     },
40682     
40683     getRawValue : function()
40684     {
40685         var v = this.inputEl().getValue();
40686         
40687         return v;
40688     },
40689     
40690     getValue : function()
40691     {
40692         return this.fixPrecision(this.parseValue(this.getRawValue()));
40693     },
40694     
40695     parseValue : function(value)
40696     {
40697         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40698         return isNaN(value) ? '' : value;
40699     },
40700     
40701     fixPrecision : function(value)
40702     {
40703         var nan = isNaN(value);
40704         
40705         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40706             return nan ? '' : value;
40707         }
40708         
40709         return parseFloat(value).toFixed(this.decimalPrecision);
40710     },
40711     
40712     decimalPrecisionFcn : function(v)
40713     {
40714         return Math.floor(v);
40715     },
40716     
40717     validateValue : function(value)
40718     {
40719         if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40720             return false;
40721         }
40722         
40723         var num = this.parseValue(value);
40724         
40725         if(isNaN(num)){
40726             this.markInvalid(String.format(this.nanText, value));
40727             return false;
40728         }
40729         
40730         if(num < this.minValue){
40731             this.markInvalid(String.format(this.minText, this.minValue));
40732             return false;
40733         }
40734         
40735         if(num > this.maxValue){
40736             this.markInvalid(String.format(this.maxText, this.maxValue));
40737             return false;
40738         }
40739         
40740         return true;
40741     },
40742     
40743     validate : function()
40744     {
40745         if(this.disabled || this.allowBlank){
40746             this.markValid();
40747             return true;
40748         }
40749         
40750         var currency = this.getCurrency();
40751         
40752         if(this.validateValue(this.getRawValue()) && currency.length){
40753             this.markValid();
40754             return true;
40755         }
40756         
40757         this.markInvalid();
40758         return false;
40759     },
40760     
40761     getName: function()
40762     {
40763         return this.name;
40764     },
40765     
40766     beforeBlur : function()
40767     {
40768         if(!this.castInt){
40769             return;
40770         }
40771         
40772         var v = this.parseValue(this.getRawValue());
40773         
40774         if(v || v == 0){
40775             this.setValue(v);
40776         }
40777     },
40778     
40779     onBlur : function()
40780     {
40781         this.beforeBlur();
40782         
40783         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40784             //this.el.removeClass(this.focusClass);
40785         }
40786         
40787         this.hasFocus = false;
40788         
40789         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40790             this.validate();
40791         }
40792         
40793         var v = this.getValue();
40794         
40795         if(String(v) !== String(this.startValue)){
40796             this.fireEvent('change', this, v, this.startValue);
40797         }
40798         
40799         this.fireEvent("blur", this);
40800     },
40801     
40802     inputEl : function()
40803     {
40804         return this.el.select('.roo-money-amount-input', true).first();
40805     },
40806     
40807     currencyEl : function()
40808     {
40809         return this.el.select('.roo-money-currency-input', true).first();
40810     },
40811     
40812     hiddenEl : function()
40813     {
40814         return this.el.select('input.hidden-number-input',true).first();
40815     }
40816     
40817 });