Roo/bootstrap/MoneyField.js
[roojs1] / roojs-bootstrap-debug.js
1 /*
2  * - LGPL
3  *
4  * base class for bootstrap elements.
5  * 
6  */
7
8 Roo.bootstrap = Roo.bootstrap || {};
9 /**
10  * @class Roo.bootstrap.Component
11  * @extends Roo.Component
12  * Bootstrap Component base class
13  * @cfg {String} cls css class
14  * @cfg {String} style any extra css
15  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16  * @cfg {Boolean} can_build_overlaid  True if element can be rebuild from a HTML page
17  * @cfg {string} dataId cutomer id
18  * @cfg {string} name Specifies name attribute
19  * @cfg {string} tooltip  Text for the tooltip
20  * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar -  getHeaderChildContainer)
21  * 
22  * @constructor
23  * Do not use directly - it does not do anything..
24  * @param {Object} config The config object
25  */
26
27
28
29 Roo.bootstrap.Component = function(config){
30     Roo.bootstrap.Component.superclass.constructor.call(this, config);
31        
32     this.addEvents({
33         /**
34          * @event childrenrendered
35          * Fires when the children have been rendered..
36          * @param {Roo.bootstrap.Component} this
37          */
38         "childrenrendered" : true
39         
40         
41         
42     });
43     
44     
45 };
46
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
48     
49     
50     allowDomMove : false, // to stop relocations in parent onRender...
51     
52     cls : false,
53     
54     style : false,
55     
56     autoCreate : false,
57     
58     tooltip : null,
59     /**
60      * Initialize Events for the element
61      */
62     initEvents : function() { },
63     
64     xattr : false,
65     
66     parentId : false,
67     
68     can_build_overlaid : true,
69     
70     container_method : false,
71     
72     dataId : false,
73     
74     name : false,
75     
76     parent: function() {
77         // returns the parent component..
78         return Roo.ComponentMgr.get(this.parentId)
79         
80         
81     },
82     
83     // private
84     onRender : function(ct, position)
85     {
86        // Roo.log("Call onRender: " + this.xtype);
87         
88         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
89         
90         if(this.el){
91             if (this.el.attr('xtype')) {
92                 this.el.attr('xtypex', this.el.attr('xtype'));
93                 this.el.dom.removeAttribute('xtype');
94                 
95                 this.initEvents();
96             }
97             
98             return;
99         }
100         
101          
102         
103         var cfg = Roo.apply({},  this.getAutoCreate());
104         
105         cfg.id = this.id || Roo.id();
106         
107         // fill in the extra attributes 
108         if (this.xattr && typeof(this.xattr) =='object') {
109             for (var i in this.xattr) {
110                 cfg[i] = this.xattr[i];
111             }
112         }
113         
114         if(this.dataId){
115             cfg.dataId = this.dataId;
116         }
117         
118         if (this.cls) {
119             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
120         }
121         
122         if (this.style) { // fixme needs to support more complex style data.
123             cfg.style = this.style;
124         }
125         
126         if(this.name){
127             cfg.name = this.name;
128         }
129         
130         this.el = ct.createChild(cfg, position);
131         
132         if (this.tooltip) {
133             this.tooltipEl().attr('tooltip', this.tooltip);
134         }
135         
136         if(this.tabIndex !== undefined){
137             this.el.dom.setAttribute('tabIndex', this.tabIndex);
138         }
139         
140         this.initEvents();
141         
142     },
143     /**
144      * Fetch the element to add children to
145      * @return {Roo.Element} defaults to this.el
146      */
147     getChildContainer : function()
148     {
149         return this.el;
150     },
151     /**
152      * Fetch the element to display the tooltip on.
153      * @return {Roo.Element} defaults to this.el
154      */
155     tooltipEl : function()
156     {
157         return this.el;
158     },
159         
160     addxtype  : function(tree,cntr)
161     {
162         var cn = this;
163         
164         cn = Roo.factory(tree);
165         //Roo.log(['addxtype', cn]);
166            
167         cn.parentType = this.xtype; //??
168         cn.parentId = this.id;
169         
170         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171         if (typeof(cn.container_method) == 'string') {
172             cntr = cn.container_method;
173         }
174         
175         
176         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
177         
178         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
179         
180         var build_from_html =  Roo.XComponent.build_from_html;
181           
182         var is_body  = (tree.xtype == 'Body') ;
183           
184         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
185           
186         var self_cntr_el = Roo.get(this[cntr](false));
187         
188         // do not try and build conditional elements 
189         if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
190             return false;
191         }
192         
193         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195                 return this.addxtypeChild(tree,cntr, is_body);
196             }
197             
198             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
199                 
200             if(echild){
201                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
202             }
203             
204             Roo.log('skipping render');
205             return cn;
206             
207         }
208         
209         var ret = false;
210         if (!build_from_html) {
211             return false;
212         }
213         
214         // this i think handles overlaying multiple children of the same type
215         // with the sam eelement.. - which might be buggy..
216         while (true) {
217             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
218             
219             if (!echild) {
220                 break;
221             }
222             
223             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
224                 break;
225             }
226             
227             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
228         }
229        
230         return ret;
231     },
232     
233     
234     addxtypeChild : function (tree, cntr, is_body)
235     {
236         Roo.debug && Roo.log('addxtypeChild:' + cntr);
237         var cn = this;
238         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
239         
240         
241         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242                     (typeof(tree['flexy:foreach']) != 'undefined');
243           
244         
245         
246          skip_children = false;
247         // render the element if it's not BODY.
248         if (!is_body) {
249            
250             cn = Roo.factory(tree);
251            
252             cn.parentType = this.xtype; //??
253             cn.parentId = this.id;
254             
255             var build_from_html =  Roo.XComponent.build_from_html;
256             
257             
258             // does the container contain child eleemnts with 'xtype' attributes.
259             // that match this xtype..
260             // note - when we render we create these as well..
261             // so we should check to see if body has xtype set.
262             if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
263                
264                 var self_cntr_el = Roo.get(this[cntr](false));
265                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
266                 if (echild) { 
267                     //Roo.log(Roo.XComponent.build_from_html);
268                     //Roo.log("got echild:");
269                     //Roo.log(echild);
270                 }
271                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272                 // and are not displayed -this causes this to use up the wrong element when matching.
273                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
274                 
275                 
276                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
278                   
279                   
280                   
281                     cn.el = echild;
282                   //  Roo.log("GOT");
283                     //echild.dom.removeAttribute('xtype');
284                 } else {
285                     Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286                     Roo.debug && Roo.log(self_cntr_el);
287                     Roo.debug && Roo.log(echild);
288                     Roo.debug && Roo.log(cn);
289                 }
290             }
291            
292             
293            
294             // if object has flexy:if - then it may or may not be rendered.
295             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
296                 // skip a flexy if element.
297                 Roo.debug && Roo.log('skipping render');
298                 Roo.debug && Roo.log(tree);
299                 if (!cn.el) {
300                     Roo.debug && Roo.log('skipping all children');
301                     skip_children = true;
302                 }
303                 
304              } else {
305                  
306                 // actually if flexy:foreach is found, we really want to create 
307                 // multiple copies here...
308                 //Roo.log('render');
309                 //Roo.log(this[cntr]());
310                 // some elements do not have render methods.. like the layouts...
311                 
312                 if(this[cntr](true) === false){
313                     cn.items = [];
314                     return cn;
315                 }
316                 
317                 cn.render && cn.render(this[cntr](true));
318                 
319              }
320             // then add the element..
321         }
322         
323         
324         // handle the kids..
325         
326         var nitems = [];
327         /*
328         if (typeof (tree.menu) != 'undefined') {
329             tree.menu.parentType = cn.xtype;
330             tree.menu.triggerEl = cn.el;
331             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
332             
333         }
334         */
335         if (!tree.items || !tree.items.length) {
336             cn.items = nitems;
337             //Roo.log(["no children", this]);
338             
339             return cn;
340         }
341          
342         var items = tree.items;
343         delete tree.items;
344         
345         //Roo.log(items.length);
346             // add the items..
347         if (!skip_children) {    
348             for(var i =0;i < items.length;i++) {
349               //  Roo.log(['add child', items[i]]);
350                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
351             }
352         }
353         
354         cn.items = nitems;
355         
356         //Roo.log("fire childrenrendered");
357         
358         cn.fireEvent('childrenrendered', this);
359         
360         return cn;
361     },
362     /**
363      * Show a component - removes 'hidden' class
364      */
365     show : function()
366     {
367         if (this.el) {
368             this.el.removeClass('hidden');
369         }
370     },
371     /**
372      * Hide a component - adds 'hidden' class
373      */
374     hide: function()
375     {
376         if (this.el && !this.el.hasClass('hidden')) {
377             this.el.addClass('hidden');
378         }
379     }
380 });
381
382  /*
383  * - LGPL
384  *
385  * Body
386  *
387  */
388
389 /**
390  * @class Roo.bootstrap.Body
391  * @extends Roo.bootstrap.Component
392  * Bootstrap Body class
393  *
394  * @constructor
395  * Create a new body
396  * @param {Object} config The config object
397  */
398
399 Roo.bootstrap.Body = function(config){
400
401     config = config || {};
402
403     Roo.bootstrap.Body.superclass.constructor.call(this, config);
404     this.el = Roo.get(config.el ? config.el : document.body );
405     if (this.cls && this.cls.length) {
406         Roo.get(document.body).addClass(this.cls);
407     }
408 };
409
410 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
411
412     is_body : true,// just to make sure it's constructed?
413
414         autoCreate : {
415         cls: 'container'
416     },
417     onRender : function(ct, position)
418     {
419        /* Roo.log("Roo.bootstrap.Body - onRender");
420         if (this.cls && this.cls.length) {
421             Roo.get(document.body).addClass(this.cls);
422         }
423         // style??? xttr???
424         */
425     }
426
427
428
429
430 });
431 /*
432  * - LGPL
433  *
434  * button group
435  * 
436  */
437
438
439 /**
440  * @class Roo.bootstrap.ButtonGroup
441  * @extends Roo.bootstrap.Component
442  * Bootstrap ButtonGroup class
443  * @cfg {String} size lg | sm | xs (default empty normal)
444  * @cfg {String} align vertical | justified  (default none)
445  * @cfg {String} direction up | down (default down)
446  * @cfg {Boolean} toolbar false | true
447  * @cfg {Boolean} btn true | false
448  * 
449  * 
450  * @constructor
451  * Create a new Input
452  * @param {Object} config The config object
453  */
454
455 Roo.bootstrap.ButtonGroup = function(config){
456     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
457 };
458
459 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
460     
461     size: '',
462     align: '',
463     direction: '',
464     toolbar: false,
465     btn: true,
466
467     getAutoCreate : function(){
468         var cfg = {
469             cls: 'btn-group',
470             html : null
471         };
472         
473         cfg.html = this.html || cfg.html;
474         
475         if (this.toolbar) {
476             cfg = {
477                 cls: 'btn-toolbar',
478                 html: null
479             };
480             
481             return cfg;
482         }
483         
484         if (['vertical','justified'].indexOf(this.align)!==-1) {
485             cfg.cls = 'btn-group-' + this.align;
486             
487             if (this.align == 'justified') {
488                 console.log(this.items);
489             }
490         }
491         
492         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
493             cfg.cls += ' btn-group-' + this.size;
494         }
495         
496         if (this.direction == 'up') {
497             cfg.cls += ' dropup' ;
498         }
499         
500         return cfg;
501     }
502    
503 });
504
505  /*
506  * - LGPL
507  *
508  * button
509  * 
510  */
511
512 /**
513  * @class Roo.bootstrap.Button
514  * @extends Roo.bootstrap.Component
515  * Bootstrap Button class
516  * @cfg {String} html The button content
517  * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default 
518  * @cfg {String} size ( lg | sm | xs)
519  * @cfg {String} tag ( a | input | submit)
520  * @cfg {String} href empty or href
521  * @cfg {Boolean} disabled default false;
522  * @cfg {Boolean} isClose default false;
523  * @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)
524  * @cfg {String} badge text for badge
525  * @cfg {String} theme default 
526  * @cfg {Boolean} inverse 
527  * @cfg {Boolean} toggle 
528  * @cfg {String} ontext text for on toggle state
529  * @cfg {String} offtext text for off toggle state
530  * @cfg {Boolean} defaulton 
531  * @cfg {Boolean} preventDefault  default true
532  * @cfg {Boolean} removeClass remove the standard class..
533  * @cfg {String} target  target for a href. (_self|_blank|_parent|_top| other)
534  * 
535  * @constructor
536  * Create a new button
537  * @param {Object} config The config object
538  */
539
540
541 Roo.bootstrap.Button = function(config){
542     Roo.bootstrap.Button.superclass.constructor.call(this, config);
543     this.weightClass = ["btn-default", 
544                        "btn-primary", 
545                        "btn-success", 
546                        "btn-info", 
547                        "btn-warning",
548                        "btn-danger",
549                        "btn-link"
550                       ],  
551     this.addEvents({
552         // raw events
553         /**
554          * @event click
555          * When a butotn is pressed
556          * @param {Roo.bootstrap.Button} this
557          * @param {Roo.EventObject} e
558          */
559         "click" : true,
560          /**
561          * @event toggle
562          * After the button has been toggles
563          * @param {Roo.EventObject} e
564          * @param {boolean} pressed (also available as button.pressed)
565          */
566         "toggle" : true
567     });
568 };
569
570 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
571     html: false,
572     active: false,
573     weight: '',
574     size: '',
575     tag: 'button',
576     href: '',
577     disabled: false,
578     isClose: false,
579     glyphicon: '',
580     badge: '',
581     theme: 'default',
582     inverse: false,
583     
584     toggle: false,
585     ontext: 'ON',
586     offtext: 'OFF',
587     defaulton: true,
588     preventDefault: true,
589     removeClass: false,
590     name: false,
591     target: false,
592     
593     
594     pressed : null,
595      
596     
597     getAutoCreate : function(){
598         
599         var cfg = {
600             tag : 'button',
601             cls : 'roo-button',
602             html: ''
603         };
604         
605         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
606             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
607             this.tag = 'button';
608         } else {
609             cfg.tag = this.tag;
610         }
611         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
612         
613         if (this.toggle == true) {
614             cfg={
615                 tag: 'div',
616                 cls: 'slider-frame roo-button',
617                 cn: [
618                     {
619                         tag: 'span',
620                         'data-on-text':'ON',
621                         'data-off-text':'OFF',
622                         cls: 'slider-button',
623                         html: this.offtext
624                     }
625                 ]
626             };
627             
628             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
629                 cfg.cls += ' '+this.weight;
630             }
631             
632             return cfg;
633         }
634         
635         if (this.isClose) {
636             cfg.cls += ' close';
637             
638             cfg["aria-hidden"] = true;
639             
640             cfg.html = "&times;";
641             
642             return cfg;
643         }
644         
645          
646         if (this.theme==='default') {
647             cfg.cls = 'btn roo-button';
648             
649             //if (this.parentType != 'Navbar') {
650             this.weight = this.weight.length ?  this.weight : 'default';
651             //}
652             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
653                 
654                 cfg.cls += ' btn-' + this.weight;
655             }
656         } else if (this.theme==='glow') {
657             
658             cfg.tag = 'a';
659             cfg.cls = 'btn-glow roo-button';
660             
661             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
662                 
663                 cfg.cls += ' ' + this.weight;
664             }
665         }
666    
667         
668         if (this.inverse) {
669             this.cls += ' inverse';
670         }
671         
672         
673         if (this.active) {
674             cfg.cls += ' active';
675         }
676         
677         if (this.disabled) {
678             cfg.disabled = 'disabled';
679         }
680         
681         if (this.items) {
682             Roo.log('changing to ul' );
683             cfg.tag = 'ul';
684             this.glyphicon = 'caret';
685         }
686         
687         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
688          
689         //gsRoo.log(this.parentType);
690         if (this.parentType === 'Navbar' && !this.parent().bar) {
691             Roo.log('changing to li?');
692             
693             cfg.tag = 'li';
694             
695             cfg.cls = '';
696             cfg.cn =  [{
697                 tag : 'a',
698                 cls : 'roo-button',
699                 html : this.html,
700                 href : this.href || '#'
701             }];
702             if (this.menu) {
703                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
704                 cfg.cls += ' dropdown';
705             }   
706             
707             delete cfg.html;
708             
709         }
710         
711        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
712         
713         if (this.glyphicon) {
714             cfg.html = ' ' + cfg.html;
715             
716             cfg.cn = [
717                 {
718                     tag: 'span',
719                     cls: 'glyphicon glyphicon-' + this.glyphicon
720                 }
721             ];
722         }
723         
724         if (this.badge) {
725             cfg.html += ' ';
726             
727             cfg.tag = 'a';
728             
729 //            cfg.cls='btn roo-button';
730             
731             cfg.href=this.href;
732             
733             var value = cfg.html;
734             
735             if(this.glyphicon){
736                 value = {
737                             tag: 'span',
738                             cls: 'glyphicon glyphicon-' + this.glyphicon,
739                             html: this.html
740                         };
741                 
742             }
743             
744             cfg.cn = [
745                 value,
746                 {
747                     tag: 'span',
748                     cls: 'badge',
749                     html: this.badge
750                 }
751             ];
752             
753             cfg.html='';
754         }
755         
756         if (this.menu) {
757             cfg.cls += ' dropdown';
758             cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
759         }
760         
761         if (cfg.tag !== 'a' && this.href !== '') {
762             throw "Tag must be a to set href.";
763         } else if (this.href.length > 0) {
764             cfg.href = this.href;
765         }
766         
767         if(this.removeClass){
768             cfg.cls = '';
769         }
770         
771         if(this.target){
772             cfg.target = this.target;
773         }
774         
775         return cfg;
776     },
777     initEvents: function() {
778        // Roo.log('init events?');
779 //        Roo.log(this.el.dom);
780         // add the menu...
781         
782         if (typeof (this.menu) != 'undefined') {
783             this.menu.parentType = this.xtype;
784             this.menu.triggerEl = this.el;
785             this.addxtype(Roo.apply({}, this.menu));
786         }
787
788
789        if (this.el.hasClass('roo-button')) {
790             this.el.on('click', this.onClick, this);
791        } else {
792             this.el.select('.roo-button').on('click', this.onClick, this);
793        }
794        
795        if(this.removeClass){
796            this.el.on('click', this.onClick, this);
797        }
798        
799        this.el.enableDisplayMode();
800         
801     },
802     onClick : function(e)
803     {
804         if (this.disabled) {
805             return;
806         }
807         
808         
809         Roo.log('button on click ');
810         if(this.preventDefault){
811             e.preventDefault();
812         }
813         if (this.pressed === true || this.pressed === false) {
814             this.pressed = !this.pressed;
815             this.el[this.pressed ? 'addClass' : 'removeClass']('active');
816             this.fireEvent('toggle', this, e, this.pressed);
817         }
818         
819         
820         this.fireEvent('click', this, e);
821     },
822     
823     /**
824      * Enables this button
825      */
826     enable : function()
827     {
828         this.disabled = false;
829         this.el.removeClass('disabled');
830     },
831     
832     /**
833      * Disable this button
834      */
835     disable : function()
836     {
837         this.disabled = true;
838         this.el.addClass('disabled');
839     },
840      /**
841      * sets the active state on/off, 
842      * @param {Boolean} state (optional) Force a particular state
843      */
844     setActive : function(v) {
845         
846         this.el[v ? 'addClass' : 'removeClass']('active');
847     },
848      /**
849      * toggles the current active state 
850      */
851     toggleActive : function()
852     {
853        var active = this.el.hasClass('active');
854        this.setActive(!active);
855        
856         
857     },
858     setText : function(str)
859     {
860         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
861     },
862     getText : function()
863     {
864         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
865     },
866     hide: function() {
867        
868      
869         this.el.hide();   
870     },
871     show: function() {
872        
873         this.el.show();   
874     },
875     setWeight : function(str)
876     {
877           this.el.removeClass(this.weightClass);
878         this.el.addClass('btn-' + str);        
879     }
880     
881     
882 });
883
884  /*
885  * - LGPL
886  *
887  * column
888  * 
889  */
890
891 /**
892  * @class Roo.bootstrap.Column
893  * @extends Roo.bootstrap.Component
894  * Bootstrap Column class
895  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
896  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
897  * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
898  * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
899  * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
900  * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
901  * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
902  * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
903  *
904  * 
905  * @cfg {Boolean} hidden (true|false) hide the element
906  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
907  * @cfg {String} fa (ban|check|...) font awesome icon
908  * @cfg {Number} fasize (1|2|....) font awsome size
909
910  * @cfg {String} icon (info-sign|check|...) glyphicon name
911
912  * @cfg {String} html content of column.
913  * 
914  * @constructor
915  * Create a new Column
916  * @param {Object} config The config object
917  */
918
919 Roo.bootstrap.Column = function(config){
920     Roo.bootstrap.Column.superclass.constructor.call(this, config);
921 };
922
923 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
924     
925     xs: false,
926     sm: false,
927     md: false,
928     lg: false,
929     xsoff: false,
930     smoff: false,
931     mdoff: false,
932     lgoff: false,
933     html: '',
934     offset: 0,
935     alert: false,
936     fa: false,
937     icon : false,
938     hidden : false,
939     fasize : 1,
940     
941     getAutoCreate : function(){
942         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
943         
944         cfg = {
945             tag: 'div',
946             cls: 'column'
947         };
948         
949         var settings=this;
950         ['xs','sm','md','lg'].map(function(size){
951             //Roo.log( size + ':' + settings[size]);
952             
953             if (settings[size+'off'] !== false) {
954                 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
955             }
956             
957             if (settings[size] === false) {
958                 return;
959             }
960             
961             if (!settings[size]) { // 0 = hidden
962                 cfg.cls += ' hidden-' + size;
963                 return;
964             }
965             cfg.cls += ' col-' + size + '-' + settings[size];
966             
967         });
968         
969         if (this.hidden) {
970             cfg.cls += ' hidden';
971         }
972         
973         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
974             cfg.cls +=' alert alert-' + this.alert;
975         }
976         
977         
978         if (this.html.length) {
979             cfg.html = this.html;
980         }
981         if (this.fa) {
982             var fasize = '';
983             if (this.fasize > 1) {
984                 fasize = ' fa-' + this.fasize + 'x';
985             }
986             cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
987             
988             
989         }
990         if (this.icon) {
991             cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' +  (cfg.html || '');
992         }
993         
994         return cfg;
995     }
996    
997 });
998
999  
1000
1001  /*
1002  * - LGPL
1003  *
1004  * page container.
1005  * 
1006  */
1007
1008
1009 /**
1010  * @class Roo.bootstrap.Container
1011  * @extends Roo.bootstrap.Component
1012  * Bootstrap Container class
1013  * @cfg {Boolean} jumbotron is it a jumbotron element
1014  * @cfg {String} html content of element
1015  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1016  * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel  - type - primary/success.....
1017  * @cfg {String} header content of header (for panel)
1018  * @cfg {String} footer content of footer (for panel)
1019  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1020  * @cfg {String} tag (header|aside|section) type of HTML tag.
1021  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1022  * @cfg {String} fa font awesome icon
1023  * @cfg {String} icon (info-sign|check|...) glyphicon name
1024  * @cfg {Boolean} hidden (true|false) hide the element
1025  * @cfg {Boolean} expandable (true|false) default false
1026  * @cfg {Boolean} expanded (true|false) default true
1027  * @cfg {String} rheader contet on the right of header
1028  * @cfg {Boolean} clickable (true|false) default false
1029
1030  *     
1031  * @constructor
1032  * Create a new Container
1033  * @param {Object} config The config object
1034  */
1035
1036 Roo.bootstrap.Container = function(config){
1037     Roo.bootstrap.Container.superclass.constructor.call(this, config);
1038     
1039     this.addEvents({
1040         // raw events
1041          /**
1042          * @event expand
1043          * After the panel has been expand
1044          * 
1045          * @param {Roo.bootstrap.Container} this
1046          */
1047         "expand" : true,
1048         /**
1049          * @event collapse
1050          * After the panel has been collapsed
1051          * 
1052          * @param {Roo.bootstrap.Container} this
1053          */
1054         "collapse" : true,
1055         /**
1056          * @event click
1057          * When a element is chick
1058          * @param {Roo.bootstrap.Container} this
1059          * @param {Roo.EventObject} e
1060          */
1061         "click" : true
1062     });
1063 };
1064
1065 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
1066     
1067     jumbotron : false,
1068     well: '',
1069     panel : '',
1070     header: '',
1071     footer : '',
1072     sticky: '',
1073     tag : false,
1074     alert : false,
1075     fa: false,
1076     icon : false,
1077     expandable : false,
1078     rheader : '',
1079     expanded : true,
1080     clickable: false,
1081   
1082      
1083     getChildContainer : function() {
1084         
1085         if(!this.el){
1086             return false;
1087         }
1088         
1089         if (this.panel.length) {
1090             return this.el.select('.panel-body',true).first();
1091         }
1092         
1093         return this.el;
1094     },
1095     
1096     
1097     getAutoCreate : function(){
1098         
1099         var cfg = {
1100             tag : this.tag || 'div',
1101             html : '',
1102             cls : ''
1103         };
1104         if (this.jumbotron) {
1105             cfg.cls = 'jumbotron';
1106         }
1107         
1108         
1109         
1110         // - this is applied by the parent..
1111         //if (this.cls) {
1112         //    cfg.cls = this.cls + '';
1113         //}
1114         
1115         if (this.sticky.length) {
1116             
1117             var bd = Roo.get(document.body);
1118             if (!bd.hasClass('bootstrap-sticky')) {
1119                 bd.addClass('bootstrap-sticky');
1120                 Roo.select('html',true).setStyle('height', '100%');
1121             }
1122              
1123             cfg.cls += 'bootstrap-sticky-' + this.sticky;
1124         }
1125         
1126         
1127         if (this.well.length) {
1128             switch (this.well) {
1129                 case 'lg':
1130                 case 'sm':
1131                     cfg.cls +=' well well-' +this.well;
1132                     break;
1133                 default:
1134                     cfg.cls +=' well';
1135                     break;
1136             }
1137         }
1138         
1139         if (this.hidden) {
1140             cfg.cls += ' hidden';
1141         }
1142         
1143         
1144         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1145             cfg.cls +=' alert alert-' + this.alert;
1146         }
1147         
1148         var body = cfg;
1149         
1150         if (this.panel.length) {
1151             cfg.cls += ' panel panel-' + this.panel;
1152             cfg.cn = [];
1153             if (this.header.length) {
1154                 
1155                 var h = [];
1156                 
1157                 if(this.expandable){
1158                     
1159                     cfg.cls = cfg.cls + ' expandable';
1160                     
1161                     h.push({
1162                         tag: 'i',
1163                         cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus') 
1164                     });
1165                     
1166                 }
1167                 
1168                 h.push(
1169                     {
1170                         tag: 'span',
1171                         cls : 'panel-title',
1172                         html : (this.expandable ? '&nbsp;' : '') + this.header
1173                     },
1174                     {
1175                         tag: 'span',
1176                         cls: 'panel-header-right',
1177                         html: this.rheader
1178                     }
1179                 );
1180                 
1181                 cfg.cn.push({
1182                     cls : 'panel-heading',
1183                     style : this.expandable ? 'cursor: pointer' : '',
1184                     cn : h
1185                 });
1186                 
1187             }
1188             
1189             body = false;
1190             cfg.cn.push({
1191                 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1192                 html : this.html
1193             });
1194             
1195             
1196             if (this.footer.length) {
1197                 cfg.cn.push({
1198                     cls : 'panel-footer',
1199                     html : this.footer
1200                     
1201                 });
1202             }
1203             
1204         }
1205         
1206         if (body) {
1207             body.html = this.html || cfg.html;
1208             // prefix with the icons..
1209             if (this.fa) {
1210                 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1211             }
1212             if (this.icon) {
1213                 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1214             }
1215             
1216             
1217         }
1218         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1219             cfg.cls =  'container';
1220         }
1221         
1222         return cfg;
1223     },
1224     
1225     initEvents: function() 
1226     {
1227         if(this.expandable){
1228             var headerEl = this.headerEl();
1229         
1230             if(headerEl){
1231                 headerEl.on('click', this.onToggleClick, this);
1232             }
1233         }
1234         
1235         if(this.clickable){
1236             this.el.on('click', this.onClick, this);
1237         }
1238         
1239     },
1240     
1241     onToggleClick : function()
1242     {
1243         var headerEl = this.headerEl();
1244         
1245         if(!headerEl){
1246             return;
1247         }
1248         
1249         if(this.expanded){
1250             this.collapse();
1251             return;
1252         }
1253         
1254         this.expand();
1255     },
1256     
1257     expand : function()
1258     {
1259         if(this.fireEvent('expand', this)) {
1260             
1261             this.expanded = true;
1262             
1263             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1264             
1265             this.el.select('.panel-body',true).first().removeClass('hide');
1266             
1267             var toggleEl = this.toggleEl();
1268
1269             if(!toggleEl){
1270                 return;
1271             }
1272
1273             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1274         }
1275         
1276     },
1277     
1278     collapse : function()
1279     {
1280         if(this.fireEvent('collapse', this)) {
1281             
1282             this.expanded = false;
1283             
1284             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1285             this.el.select('.panel-body',true).first().addClass('hide');
1286         
1287             var toggleEl = this.toggleEl();
1288
1289             if(!toggleEl){
1290                 return;
1291             }
1292
1293             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1294         }
1295     },
1296     
1297     toggleEl : function()
1298     {
1299         if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1300             return;
1301         }
1302         
1303         return this.el.select('.panel-heading .fa',true).first();
1304     },
1305     
1306     headerEl : function()
1307     {
1308         if(!this.el || !this.panel.length || !this.header.length){
1309             return;
1310         }
1311         
1312         return this.el.select('.panel-heading',true).first()
1313     },
1314     
1315     bodyEl : function()
1316     {
1317         if(!this.el || !this.panel.length){
1318             return;
1319         }
1320         
1321         return this.el.select('.panel-body',true).first()
1322     },
1323     
1324     titleEl : function()
1325     {
1326         if(!this.el || !this.panel.length || !this.header.length){
1327             return;
1328         }
1329         
1330         return this.el.select('.panel-title',true).first();
1331     },
1332     
1333     setTitle : function(v)
1334     {
1335         var titleEl = this.titleEl();
1336         
1337         if(!titleEl){
1338             return;
1339         }
1340         
1341         titleEl.dom.innerHTML = v;
1342     },
1343     
1344     getTitle : function()
1345     {
1346         
1347         var titleEl = this.titleEl();
1348         
1349         if(!titleEl){
1350             return '';
1351         }
1352         
1353         return titleEl.dom.innerHTML;
1354     },
1355     
1356     setRightTitle : function(v)
1357     {
1358         var t = this.el.select('.panel-header-right',true).first();
1359         
1360         if(!t){
1361             return;
1362         }
1363         
1364         t.dom.innerHTML = v;
1365     },
1366     
1367     onClick : function(e)
1368     {
1369         e.preventDefault();
1370         
1371         this.fireEvent('click', this, e);
1372     }
1373    
1374 });
1375
1376  /*
1377  * - LGPL
1378  *
1379  * image
1380  * 
1381  */
1382
1383
1384 /**
1385  * @class Roo.bootstrap.Img
1386  * @extends Roo.bootstrap.Component
1387  * Bootstrap Img class
1388  * @cfg {Boolean} imgResponsive false | true
1389  * @cfg {String} border rounded | circle | thumbnail
1390  * @cfg {String} src image source
1391  * @cfg {String} alt image alternative text
1392  * @cfg {String} href a tag href
1393  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1394  * @cfg {String} xsUrl xs image source
1395  * @cfg {String} smUrl sm image source
1396  * @cfg {String} mdUrl md image source
1397  * @cfg {String} lgUrl lg image source
1398  * 
1399  * @constructor
1400  * Create a new Input
1401  * @param {Object} config The config object
1402  */
1403
1404 Roo.bootstrap.Img = function(config){
1405     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1406     
1407     this.addEvents({
1408         // img events
1409         /**
1410          * @event click
1411          * The img click event for the img.
1412          * @param {Roo.EventObject} e
1413          */
1414         "click" : true
1415     });
1416 };
1417
1418 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1419     
1420     imgResponsive: true,
1421     border: '',
1422     src: 'about:blank',
1423     href: false,
1424     target: false,
1425     xsUrl: '',
1426     smUrl: '',
1427     mdUrl: '',
1428     lgUrl: '',
1429
1430     getAutoCreate : function()
1431     {   
1432         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1433             return this.createSingleImg();
1434         }
1435         
1436         var cfg = {
1437             tag: 'div',
1438             cls: 'roo-image-responsive-group',
1439             cn: []
1440         };
1441         var _this = this;
1442         
1443         Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1444             
1445             if(!_this[size + 'Url']){
1446                 return;
1447             }
1448             
1449             var img = {
1450                 tag: 'img',
1451                 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1452                 html: _this.html || cfg.html,
1453                 src: _this[size + 'Url']
1454             };
1455             
1456             img.cls += ' roo-image-responsive-' + size;
1457             
1458             var s = ['xs', 'sm', 'md', 'lg'];
1459             
1460             s.splice(s.indexOf(size), 1);
1461             
1462             Roo.each(s, function(ss){
1463                 img.cls += ' hidden-' + ss;
1464             });
1465             
1466             if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1467                 cfg.cls += ' img-' + _this.border;
1468             }
1469             
1470             if(_this.alt){
1471                 cfg.alt = _this.alt;
1472             }
1473             
1474             if(_this.href){
1475                 var a = {
1476                     tag: 'a',
1477                     href: _this.href,
1478                     cn: [
1479                         img
1480                     ]
1481                 };
1482
1483                 if(this.target){
1484                     a.target = _this.target;
1485                 }
1486             }
1487             
1488             cfg.cn.push((_this.href) ? a : img);
1489             
1490         });
1491         
1492         return cfg;
1493     },
1494     
1495     createSingleImg : function()
1496     {
1497         var cfg = {
1498             tag: 'img',
1499             cls: (this.imgResponsive) ? 'img-responsive' : '',
1500             html : null,
1501             src : 'about:blank'  // just incase src get's set to undefined?!?
1502         };
1503         
1504         cfg.html = this.html || cfg.html;
1505         
1506         cfg.src = this.src || cfg.src;
1507         
1508         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1509             cfg.cls += ' img-' + this.border;
1510         }
1511         
1512         if(this.alt){
1513             cfg.alt = this.alt;
1514         }
1515         
1516         if(this.href){
1517             var a = {
1518                 tag: 'a',
1519                 href: this.href,
1520                 cn: [
1521                     cfg
1522                 ]
1523             };
1524             
1525             if(this.target){
1526                 a.target = this.target;
1527             }
1528             
1529         }
1530         
1531         return (this.href) ? a : cfg;
1532     },
1533     
1534     initEvents: function() 
1535     {
1536         if(!this.href){
1537             this.el.on('click', this.onClick, this);
1538         }
1539         
1540     },
1541     
1542     onClick : function(e)
1543     {
1544         Roo.log('img onclick');
1545         this.fireEvent('click', this, e);
1546     },
1547     /**
1548      * Sets the url of the image - used to update it
1549      * @param {String} url the url of the image
1550      */
1551     
1552     setSrc : function(url)
1553     {
1554         this.src =  url;
1555         
1556         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1557             this.el.dom.src =  url;
1558             return;
1559         }
1560         
1561         this.el.select('img', true).first().dom.src =  url;
1562     }
1563     
1564     
1565    
1566 });
1567
1568  /*
1569  * - LGPL
1570  *
1571  * image
1572  * 
1573  */
1574
1575
1576 /**
1577  * @class Roo.bootstrap.Link
1578  * @extends Roo.bootstrap.Component
1579  * Bootstrap Link Class
1580  * @cfg {String} alt image alternative text
1581  * @cfg {String} href a tag href
1582  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1583  * @cfg {String} html the content of the link.
1584  * @cfg {String} anchor name for the anchor link
1585  * @cfg {String} fa - favicon
1586
1587  * @cfg {Boolean} preventDefault (true | false) default false
1588
1589  * 
1590  * @constructor
1591  * Create a new Input
1592  * @param {Object} config The config object
1593  */
1594
1595 Roo.bootstrap.Link = function(config){
1596     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1597     
1598     this.addEvents({
1599         // img events
1600         /**
1601          * @event click
1602          * The img click event for the img.
1603          * @param {Roo.EventObject} e
1604          */
1605         "click" : true
1606     });
1607 };
1608
1609 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1610     
1611     href: false,
1612     target: false,
1613     preventDefault: false,
1614     anchor : false,
1615     alt : false,
1616     fa: false,
1617
1618
1619     getAutoCreate : function()
1620     {
1621         var html = this.html || '';
1622         
1623         if (this.fa !== false) {
1624             html = '<i class="fa fa-' + this.fa + '"></i>';
1625         }
1626         var cfg = {
1627             tag: 'a'
1628         };
1629         // anchor's do not require html/href...
1630         if (this.anchor === false) {
1631             cfg.html = html;
1632             cfg.href = this.href || '#';
1633         } else {
1634             cfg.name = this.anchor;
1635             if (this.html !== false || this.fa !== false) {
1636                 cfg.html = html;
1637             }
1638             if (this.href !== false) {
1639                 cfg.href = this.href;
1640             }
1641         }
1642         
1643         if(this.alt !== false){
1644             cfg.alt = this.alt;
1645         }
1646         
1647         
1648         if(this.target !== false) {
1649             cfg.target = this.target;
1650         }
1651         
1652         return cfg;
1653     },
1654     
1655     initEvents: function() {
1656         
1657         if(!this.href || this.preventDefault){
1658             this.el.on('click', this.onClick, this);
1659         }
1660     },
1661     
1662     onClick : function(e)
1663     {
1664         if(this.preventDefault){
1665             e.preventDefault();
1666         }
1667         //Roo.log('img onclick');
1668         this.fireEvent('click', this, e);
1669     }
1670    
1671 });
1672
1673  /*
1674  * - LGPL
1675  *
1676  * header
1677  * 
1678  */
1679
1680 /**
1681  * @class Roo.bootstrap.Header
1682  * @extends Roo.bootstrap.Component
1683  * Bootstrap Header class
1684  * @cfg {String} html content of header
1685  * @cfg {Number} level (1|2|3|4|5|6) default 1
1686  * 
1687  * @constructor
1688  * Create a new Header
1689  * @param {Object} config The config object
1690  */
1691
1692
1693 Roo.bootstrap.Header  = function(config){
1694     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1695 };
1696
1697 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1698     
1699     //href : false,
1700     html : false,
1701     level : 1,
1702     
1703     
1704     
1705     getAutoCreate : function(){
1706         
1707         
1708         
1709         var cfg = {
1710             tag: 'h' + (1 *this.level),
1711             html: this.html || ''
1712         } ;
1713         
1714         return cfg;
1715     }
1716    
1717 });
1718
1719  
1720
1721  /*
1722  * Based on:
1723  * Ext JS Library 1.1.1
1724  * Copyright(c) 2006-2007, Ext JS, LLC.
1725  *
1726  * Originally Released Under LGPL - original licence link has changed is not relivant.
1727  *
1728  * Fork - LGPL
1729  * <script type="text/javascript">
1730  */
1731  
1732 /**
1733  * @class Roo.bootstrap.MenuMgr
1734  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1735  * @singleton
1736  */
1737 Roo.bootstrap.MenuMgr = function(){
1738    var menus, active, groups = {}, attached = false, lastShow = new Date();
1739
1740    // private - called when first menu is created
1741    function init(){
1742        menus = {};
1743        active = new Roo.util.MixedCollection();
1744        Roo.get(document).addKeyListener(27, function(){
1745            if(active.length > 0){
1746                hideAll();
1747            }
1748        });
1749    }
1750
1751    // private
1752    function hideAll(){
1753        if(active && active.length > 0){
1754            var c = active.clone();
1755            c.each(function(m){
1756                m.hide();
1757            });
1758        }
1759    }
1760
1761    // private
1762    function onHide(m){
1763        active.remove(m);
1764        if(active.length < 1){
1765            Roo.get(document).un("mouseup", onMouseDown);
1766             
1767            attached = false;
1768        }
1769    }
1770
1771    // private
1772    function onShow(m){
1773        var last = active.last();
1774        lastShow = new Date();
1775        active.add(m);
1776        if(!attached){
1777           Roo.get(document).on("mouseup", onMouseDown);
1778            
1779            attached = true;
1780        }
1781        if(m.parentMenu){
1782           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1783           m.parentMenu.activeChild = m;
1784        }else if(last && last.isVisible()){
1785           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1786        }
1787    }
1788
1789    // private
1790    function onBeforeHide(m){
1791        if(m.activeChild){
1792            m.activeChild.hide();
1793        }
1794        if(m.autoHideTimer){
1795            clearTimeout(m.autoHideTimer);
1796            delete m.autoHideTimer;
1797        }
1798    }
1799
1800    // private
1801    function onBeforeShow(m){
1802        var pm = m.parentMenu;
1803        if(!pm && !m.allowOtherMenus){
1804            hideAll();
1805        }else if(pm && pm.activeChild && active != m){
1806            pm.activeChild.hide();
1807        }
1808    }
1809
1810    // private this should really trigger on mouseup..
1811    function onMouseDown(e){
1812         Roo.log("on Mouse Up");
1813         
1814         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1815             Roo.log("MenuManager hideAll");
1816             hideAll();
1817             e.stopEvent();
1818         }
1819         
1820         
1821    }
1822
1823    // private
1824    function onBeforeCheck(mi, state){
1825        if(state){
1826            var g = groups[mi.group];
1827            for(var i = 0, l = g.length; i < l; i++){
1828                if(g[i] != mi){
1829                    g[i].setChecked(false);
1830                }
1831            }
1832        }
1833    }
1834
1835    return {
1836
1837        /**
1838         * Hides all menus that are currently visible
1839         */
1840        hideAll : function(){
1841             hideAll();  
1842        },
1843
1844        // private
1845        register : function(menu){
1846            if(!menus){
1847                init();
1848            }
1849            menus[menu.id] = menu;
1850            menu.on("beforehide", onBeforeHide);
1851            menu.on("hide", onHide);
1852            menu.on("beforeshow", onBeforeShow);
1853            menu.on("show", onShow);
1854            var g = menu.group;
1855            if(g && menu.events["checkchange"]){
1856                if(!groups[g]){
1857                    groups[g] = [];
1858                }
1859                groups[g].push(menu);
1860                menu.on("checkchange", onCheck);
1861            }
1862        },
1863
1864         /**
1865          * Returns a {@link Roo.menu.Menu} object
1866          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1867          * be used to generate and return a new Menu instance.
1868          */
1869        get : function(menu){
1870            if(typeof menu == "string"){ // menu id
1871                return menus[menu];
1872            }else if(menu.events){  // menu instance
1873                return menu;
1874            }
1875            /*else if(typeof menu.length == 'number'){ // array of menu items?
1876                return new Roo.bootstrap.Menu({items:menu});
1877            }else{ // otherwise, must be a config
1878                return new Roo.bootstrap.Menu(menu);
1879            }
1880            */
1881            return false;
1882        },
1883
1884        // private
1885        unregister : function(menu){
1886            delete menus[menu.id];
1887            menu.un("beforehide", onBeforeHide);
1888            menu.un("hide", onHide);
1889            menu.un("beforeshow", onBeforeShow);
1890            menu.un("show", onShow);
1891            var g = menu.group;
1892            if(g && menu.events["checkchange"]){
1893                groups[g].remove(menu);
1894                menu.un("checkchange", onCheck);
1895            }
1896        },
1897
1898        // private
1899        registerCheckable : function(menuItem){
1900            var g = menuItem.group;
1901            if(g){
1902                if(!groups[g]){
1903                    groups[g] = [];
1904                }
1905                groups[g].push(menuItem);
1906                menuItem.on("beforecheckchange", onBeforeCheck);
1907            }
1908        },
1909
1910        // private
1911        unregisterCheckable : function(menuItem){
1912            var g = menuItem.group;
1913            if(g){
1914                groups[g].remove(menuItem);
1915                menuItem.un("beforecheckchange", onBeforeCheck);
1916            }
1917        }
1918    };
1919 }();/*
1920  * - LGPL
1921  *
1922  * menu
1923  * 
1924  */
1925
1926 /**
1927  * @class Roo.bootstrap.Menu
1928  * @extends Roo.bootstrap.Component
1929  * Bootstrap Menu class - container for MenuItems
1930  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1931  * @cfg {bool} hidden  if the menu should be hidden when rendered.
1932  * @cfg {bool} stopEvent (true|false)  Stop event after trigger press (default true)
1933  * @cfg {bool} isLink (true|false)  the menu has link disable auto expand and collaspe (default false)
1934  * 
1935  * @constructor
1936  * Create a new Menu
1937  * @param {Object} config The config object
1938  */
1939
1940
1941 Roo.bootstrap.Menu = function(config){
1942     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1943     if (this.registerMenu && this.type != 'treeview')  {
1944         Roo.bootstrap.MenuMgr.register(this);
1945     }
1946     this.addEvents({
1947         /**
1948          * @event beforeshow
1949          * Fires before this menu is displayed
1950          * @param {Roo.menu.Menu} this
1951          */
1952         beforeshow : true,
1953         /**
1954          * @event beforehide
1955          * Fires before this menu is hidden
1956          * @param {Roo.menu.Menu} this
1957          */
1958         beforehide : true,
1959         /**
1960          * @event show
1961          * Fires after this menu is displayed
1962          * @param {Roo.menu.Menu} this
1963          */
1964         show : true,
1965         /**
1966          * @event hide
1967          * Fires after this menu is hidden
1968          * @param {Roo.menu.Menu} this
1969          */
1970         hide : true,
1971         /**
1972          * @event click
1973          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1974          * @param {Roo.menu.Menu} this
1975          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1976          * @param {Roo.EventObject} e
1977          */
1978         click : true,
1979         /**
1980          * @event mouseover
1981          * Fires when the mouse is hovering over this menu
1982          * @param {Roo.menu.Menu} this
1983          * @param {Roo.EventObject} e
1984          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1985          */
1986         mouseover : true,
1987         /**
1988          * @event mouseout
1989          * Fires when the mouse exits this menu
1990          * @param {Roo.menu.Menu} this
1991          * @param {Roo.EventObject} e
1992          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1993          */
1994         mouseout : true,
1995         /**
1996          * @event itemclick
1997          * Fires when a menu item contained in this menu is clicked
1998          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1999          * @param {Roo.EventObject} e
2000          */
2001         itemclick: true
2002     });
2003     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2004 };
2005
2006 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
2007     
2008    /// html : false,
2009     //align : '',
2010     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
2011     type: false,
2012     /**
2013      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2014      */
2015     registerMenu : true,
2016     
2017     menuItems :false, // stores the menu items..
2018     
2019     hidden:true,
2020         
2021     parentMenu : false,
2022     
2023     stopEvent : true,
2024     
2025     isLink : false,
2026     
2027     getChildContainer : function() {
2028         return this.el;  
2029     },
2030     
2031     getAutoCreate : function(){
2032          
2033         //if (['right'].indexOf(this.align)!==-1) {
2034         //    cfg.cn[1].cls += ' pull-right'
2035         //}
2036         
2037         
2038         var cfg = {
2039             tag : 'ul',
2040             cls : 'dropdown-menu' ,
2041             style : 'z-index:1000'
2042             
2043         };
2044         
2045         if (this.type === 'submenu') {
2046             cfg.cls = 'submenu active';
2047         }
2048         if (this.type === 'treeview') {
2049             cfg.cls = 'treeview-menu';
2050         }
2051         
2052         return cfg;
2053     },
2054     initEvents : function() {
2055         
2056        // Roo.log("ADD event");
2057        // Roo.log(this.triggerEl.dom);
2058         
2059         this.triggerEl.on('click', this.onTriggerClick, this);
2060         
2061         this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2062         
2063         this.triggerEl.addClass('dropdown-toggle');
2064         
2065         if (Roo.isTouch) {
2066             this.el.on('touchstart'  , this.onTouch, this);
2067         }
2068         this.el.on('click' , this.onClick, this);
2069
2070         this.el.on("mouseover", this.onMouseOver, this);
2071         this.el.on("mouseout", this.onMouseOut, this);
2072         
2073     },
2074     
2075     findTargetItem : function(e)
2076     {
2077         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
2078         if(!t){
2079             return false;
2080         }
2081         //Roo.log(t);         Roo.log(t.id);
2082         if(t && t.id){
2083             //Roo.log(this.menuitems);
2084             return this.menuitems.get(t.id);
2085             
2086             //return this.items.get(t.menuItemId);
2087         }
2088         
2089         return false;
2090     },
2091     
2092     onTouch : function(e) 
2093     {
2094         Roo.log("menu.onTouch");
2095         //e.stopEvent(); this make the user popdown broken
2096         this.onClick(e);
2097     },
2098     
2099     onClick : function(e)
2100     {
2101         Roo.log("menu.onClick");
2102         
2103         var t = this.findTargetItem(e);
2104         if(!t || t.isContainer){
2105             return;
2106         }
2107         Roo.log(e);
2108         /*
2109         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
2110             if(t == this.activeItem && t.shouldDeactivate(e)){
2111                 this.activeItem.deactivate();
2112                 delete this.activeItem;
2113                 return;
2114             }
2115             if(t.canActivate){
2116                 this.setActiveItem(t, true);
2117             }
2118             return;
2119             
2120             
2121         }
2122         */
2123        
2124         Roo.log('pass click event');
2125         
2126         t.onClick(e);
2127         
2128         this.fireEvent("click", this, t, e);
2129         
2130         var _this = this;
2131         
2132         if(!t.href.length || t.href == '#'){
2133             (function() { _this.hide(); }).defer(100);
2134         }
2135         
2136     },
2137     
2138     onMouseOver : function(e){
2139         var t  = this.findTargetItem(e);
2140         //Roo.log(t);
2141         //if(t){
2142         //    if(t.canActivate && !t.disabled){
2143         //        this.setActiveItem(t, true);
2144         //    }
2145         //}
2146         
2147         this.fireEvent("mouseover", this, e, t);
2148     },
2149     isVisible : function(){
2150         return !this.hidden;
2151     },
2152      onMouseOut : function(e){
2153         var t  = this.findTargetItem(e);
2154         
2155         //if(t ){
2156         //    if(t == this.activeItem && t.shouldDeactivate(e)){
2157         //        this.activeItem.deactivate();
2158         //        delete this.activeItem;
2159         //    }
2160         //}
2161         this.fireEvent("mouseout", this, e, t);
2162     },
2163     
2164     
2165     /**
2166      * Displays this menu relative to another element
2167      * @param {String/HTMLElement/Roo.Element} element The element to align to
2168      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2169      * the element (defaults to this.defaultAlign)
2170      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2171      */
2172     show : function(el, pos, parentMenu){
2173         this.parentMenu = parentMenu;
2174         if(!this.el){
2175             this.render();
2176         }
2177         this.fireEvent("beforeshow", this);
2178         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2179     },
2180      /**
2181      * Displays this menu at a specific xy position
2182      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2183      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2184      */
2185     showAt : function(xy, parentMenu, /* private: */_e){
2186         this.parentMenu = parentMenu;
2187         if(!this.el){
2188             this.render();
2189         }
2190         if(_e !== false){
2191             this.fireEvent("beforeshow", this);
2192             //xy = this.el.adjustForConstraints(xy);
2193         }
2194         
2195         //this.el.show();
2196         this.hideMenuItems();
2197         this.hidden = false;
2198         this.triggerEl.addClass('open');
2199         
2200         if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2201             xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2202         }
2203         
2204         if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2205             this.el.setXY(xy);
2206         }
2207         
2208         this.focus();
2209         this.fireEvent("show", this);
2210     },
2211     
2212     focus : function(){
2213         return;
2214         if(!this.hidden){
2215             this.doFocus.defer(50, this);
2216         }
2217     },
2218
2219     doFocus : function(){
2220         if(!this.hidden){
2221             this.focusEl.focus();
2222         }
2223     },
2224
2225     /**
2226      * Hides this menu and optionally all parent menus
2227      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2228      */
2229     hide : function(deep)
2230     {
2231         
2232         this.hideMenuItems();
2233         if(this.el && this.isVisible()){
2234             this.fireEvent("beforehide", this);
2235             if(this.activeItem){
2236                 this.activeItem.deactivate();
2237                 this.activeItem = null;
2238             }
2239             this.triggerEl.removeClass('open');;
2240             this.hidden = true;
2241             this.fireEvent("hide", this);
2242         }
2243         if(deep === true && this.parentMenu){
2244             this.parentMenu.hide(true);
2245         }
2246     },
2247     
2248     onTriggerClick : function(e)
2249     {
2250         Roo.log('trigger click');
2251         
2252         var target = e.getTarget();
2253         
2254         Roo.log(target.nodeName.toLowerCase());
2255         
2256         if(target.nodeName.toLowerCase() === 'i'){
2257             e.preventDefault();
2258         }
2259         
2260     },
2261     
2262     onTriggerPress  : function(e)
2263     {
2264         Roo.log('trigger press');
2265         //Roo.log(e.getTarget());
2266        // Roo.log(this.triggerEl.dom);
2267        
2268         // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2269         var pel = Roo.get(e.getTarget());
2270         if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2271             Roo.log('is treeview or dropdown?');
2272             return;
2273         }
2274         
2275         if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2276             return;
2277         }
2278         
2279         if (this.isVisible()) {
2280             Roo.log('hide');
2281             this.hide();
2282         } else {
2283             Roo.log('show');
2284             this.show(this.triggerEl, false, false);
2285         }
2286         
2287         if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2288             e.stopEvent();
2289         }
2290         
2291     },
2292        
2293     
2294     hideMenuItems : function()
2295     {
2296         Roo.log("hide Menu Items");
2297         if (!this.el) { 
2298             return;
2299         }
2300         //$(backdrop).remove()
2301         this.el.select('.open',true).each(function(aa) {
2302             
2303             aa.removeClass('open');
2304           //var parent = getParent($(this))
2305           //var relatedTarget = { relatedTarget: this }
2306           
2307            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2308           //if (e.isDefaultPrevented()) return
2309            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2310         });
2311     },
2312     addxtypeChild : function (tree, cntr) {
2313         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2314           
2315         this.menuitems.add(comp);
2316         return comp;
2317
2318     },
2319     getEl : function()
2320     {
2321         Roo.log(this.el);
2322         return this.el;
2323     }
2324 });
2325
2326  
2327  /*
2328  * - LGPL
2329  *
2330  * menu item
2331  * 
2332  */
2333
2334
2335 /**
2336  * @class Roo.bootstrap.MenuItem
2337  * @extends Roo.bootstrap.Component
2338  * Bootstrap MenuItem class
2339  * @cfg {String} html the menu label
2340  * @cfg {String} href the link
2341  * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2342  * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2343  * @cfg {Boolean} active  used on sidebars to highlight active itesm
2344  * @cfg {String} fa favicon to show on left of menu item.
2345  * @cfg {Roo.bootsrap.Menu} menu the child menu.
2346  * 
2347  * 
2348  * @constructor
2349  * Create a new MenuItem
2350  * @param {Object} config The config object
2351  */
2352
2353
2354 Roo.bootstrap.MenuItem = function(config){
2355     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2356     this.addEvents({
2357         // raw events
2358         /**
2359          * @event click
2360          * The raw click event for the entire grid.
2361          * @param {Roo.bootstrap.MenuItem} this
2362          * @param {Roo.EventObject} e
2363          */
2364         "click" : true
2365     });
2366 };
2367
2368 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
2369     
2370     href : false,
2371     html : false,
2372     preventDefault: false,
2373     isContainer : false,
2374     active : false,
2375     fa: false,
2376     
2377     getAutoCreate : function(){
2378         
2379         if(this.isContainer){
2380             return {
2381                 tag: 'li',
2382                 cls: 'dropdown-menu-item'
2383             };
2384         }
2385         var ctag = {
2386             tag: 'span',
2387             html: 'Link'
2388         };
2389         
2390         var anc = {
2391             tag : 'a',
2392             href : '#',
2393             cn : [  ]
2394         };
2395         
2396         if (this.fa !== false) {
2397             anc.cn.push({
2398                 tag : 'i',
2399                 cls : 'fa fa-' + this.fa
2400             });
2401         }
2402         
2403         anc.cn.push(ctag);
2404         
2405         
2406         var cfg= {
2407             tag: 'li',
2408             cls: 'dropdown-menu-item',
2409             cn: [ anc ]
2410         };
2411         if (this.parent().type == 'treeview') {
2412             cfg.cls = 'treeview-menu';
2413         }
2414         if (this.active) {
2415             cfg.cls += ' active';
2416         }
2417         
2418         
2419         
2420         anc.href = this.href || cfg.cn[0].href ;
2421         ctag.html = this.html || cfg.cn[0].html ;
2422         return cfg;
2423     },
2424     
2425     initEvents: function()
2426     {
2427         if (this.parent().type == 'treeview') {
2428             this.el.select('a').on('click', this.onClick, this);
2429         }
2430         
2431         if (this.menu) {
2432             this.menu.parentType = this.xtype;
2433             this.menu.triggerEl = this.el;
2434             this.menu = this.addxtype(Roo.apply({}, this.menu));
2435         }
2436         
2437     },
2438     onClick : function(e)
2439     {
2440         Roo.log('item on click ');
2441         
2442         if(this.preventDefault){
2443             e.preventDefault();
2444         }
2445         //this.parent().hideMenuItems();
2446         
2447         this.fireEvent('click', this, e);
2448     },
2449     getEl : function()
2450     {
2451         return this.el;
2452     } 
2453 });
2454
2455  
2456
2457  /*
2458  * - LGPL
2459  *
2460  * menu separator
2461  * 
2462  */
2463
2464
2465 /**
2466  * @class Roo.bootstrap.MenuSeparator
2467  * @extends Roo.bootstrap.Component
2468  * Bootstrap MenuSeparator class
2469  * 
2470  * @constructor
2471  * Create a new MenuItem
2472  * @param {Object} config The config object
2473  */
2474
2475
2476 Roo.bootstrap.MenuSeparator = function(config){
2477     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2478 };
2479
2480 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2481     
2482     getAutoCreate : function(){
2483         var cfg = {
2484             cls: 'divider',
2485             tag : 'li'
2486         };
2487         
2488         return cfg;
2489     }
2490    
2491 });
2492
2493  
2494
2495  
2496 /*
2497 * Licence: LGPL
2498 */
2499
2500 /**
2501  * @class Roo.bootstrap.Modal
2502  * @extends Roo.bootstrap.Component
2503  * Bootstrap Modal class
2504  * @cfg {String} title Title of dialog
2505  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2506  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn
2507  * @cfg {Boolean} specificTitle default false
2508  * @cfg {Array} buttons Array of buttons or standard button set..
2509  * @cfg {String} buttonPosition (left|right|center) default right
2510  * @cfg {Boolean} animate default true
2511  * @cfg {Boolean} allow_close default true
2512  * @cfg {Boolean} fitwindow default false
2513  * @cfg {String} size (sm|lg) default empty
2514  *
2515  *
2516  * @constructor
2517  * Create a new Modal Dialog
2518  * @param {Object} config The config object
2519  */
2520
2521 Roo.bootstrap.Modal = function(config){
2522     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2523     this.addEvents({
2524         // raw events
2525         /**
2526          * @event btnclick
2527          * The raw btnclick event for the button
2528          * @param {Roo.EventObject} e
2529          */
2530         "btnclick" : true,
2531         /**
2532          * @event resize
2533          * Fire when dialog resize
2534          * @param {Roo.bootstrap.Modal} this
2535          * @param {Roo.EventObject} e
2536          */
2537         "resize" : true
2538     });
2539     this.buttons = this.buttons || [];
2540
2541     if (this.tmpl) {
2542         this.tmpl = Roo.factory(this.tmpl);
2543     }
2544
2545 };
2546
2547 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2548
2549     title : 'test dialog',
2550
2551     buttons : false,
2552
2553     // set on load...
2554
2555     html: false,
2556
2557     tmp: false,
2558
2559     specificTitle: false,
2560
2561     buttonPosition: 'right',
2562
2563     allow_close : true,
2564
2565     animate : true,
2566
2567     fitwindow: false,
2568
2569
2570      // private
2571     dialogEl: false,
2572     bodyEl:  false,
2573     footerEl:  false,
2574     titleEl:  false,
2575     closeEl:  false,
2576
2577     size: '',
2578
2579
2580     onRender : function(ct, position)
2581     {
2582         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2583
2584         if(!this.el){
2585             var cfg = Roo.apply({},  this.getAutoCreate());
2586             cfg.id = Roo.id();
2587             //if(!cfg.name){
2588             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2589             //}
2590             //if (!cfg.name.length) {
2591             //    delete cfg.name;
2592            // }
2593             if (this.cls) {
2594                 cfg.cls += ' ' + this.cls;
2595             }
2596             if (this.style) {
2597                 cfg.style = this.style;
2598             }
2599             this.el = Roo.get(document.body).createChild(cfg, position);
2600         }
2601         //var type = this.el.dom.type;
2602
2603
2604         if(this.tabIndex !== undefined){
2605             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2606         }
2607
2608         this.dialogEl = this.el.select('.modal-dialog',true).first();
2609         this.bodyEl = this.el.select('.modal-body',true).first();
2610         this.closeEl = this.el.select('.modal-header .close', true).first();
2611         this.headerEl = this.el.select('.modal-header',true).first();
2612         this.titleEl = this.el.select('.modal-title',true).first();
2613         this.footerEl = this.el.select('.modal-footer',true).first();
2614
2615         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2616         this.maskEl.enableDisplayMode("block");
2617         this.maskEl.hide();
2618         //this.el.addClass("x-dlg-modal");
2619
2620         if (this.buttons.length) {
2621             Roo.each(this.buttons, function(bb) {
2622                 var b = Roo.apply({}, bb);
2623                 b.xns = b.xns || Roo.bootstrap;
2624                 b.xtype = b.xtype || 'Button';
2625                 if (typeof(b.listeners) == 'undefined') {
2626                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2627                 }
2628
2629                 var btn = Roo.factory(b);
2630
2631                 btn.render(this.el.select('.modal-footer div').first());
2632
2633             },this);
2634         }
2635         // render the children.
2636         var nitems = [];
2637
2638         if(typeof(this.items) != 'undefined'){
2639             var items = this.items;
2640             delete this.items;
2641
2642             for(var i =0;i < items.length;i++) {
2643                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2644             }
2645         }
2646
2647         this.items = nitems;
2648
2649         // where are these used - they used to be body/close/footer
2650
2651
2652         this.initEvents();
2653         //this.el.addClass([this.fieldClass, this.cls]);
2654
2655     },
2656
2657     getAutoCreate : function(){
2658
2659
2660         var bdy = {
2661                 cls : 'modal-body',
2662                 html : this.html || ''
2663         };
2664
2665         var title = {
2666             tag: 'h4',
2667             cls : 'modal-title',
2668             html : this.title
2669         };
2670
2671         if(this.specificTitle){
2672             title = this.title;
2673
2674         };
2675
2676         var header = [];
2677         if (this.allow_close) {
2678             header.push({
2679                 tag: 'button',
2680                 cls : 'close',
2681                 html : '&times'
2682             });
2683         }
2684
2685         header.push(title);
2686
2687         var size = '';
2688
2689         if(this.size.length){
2690             size = 'modal-' + this.size;
2691         }
2692
2693         var modal = {
2694             cls: "modal",
2695             style : 'display: none',
2696             cn : [
2697                 {
2698                     cls: "modal-dialog " + size,
2699                     cn : [
2700                         {
2701                             cls : "modal-content",
2702                             cn : [
2703                                 {
2704                                     cls : 'modal-header',
2705                                     cn : header
2706                                 },
2707                                 bdy,
2708                                 {
2709                                     cls : 'modal-footer',
2710                                     cn : [
2711                                         {
2712                                             tag: 'div',
2713                                             cls: 'btn-' + this.buttonPosition
2714                                         }
2715                                     ]
2716
2717                                 }
2718
2719
2720                             ]
2721
2722                         }
2723                     ]
2724
2725                 }
2726             ]
2727         };
2728
2729         if(this.animate){
2730             modal.cls += ' fade';
2731         }
2732
2733         return modal;
2734
2735     },
2736     getChildContainer : function() {
2737
2738          return this.bodyEl;
2739
2740     },
2741     getButtonContainer : function() {
2742          return this.el.select('.modal-footer div',true).first();
2743
2744     },
2745     initEvents : function()
2746     {
2747         if (this.allow_close) {
2748             this.closeEl.on('click', this.hide, this);
2749         }
2750         Roo.EventManager.onWindowResize(this.resize, this, true);
2751
2752
2753     },
2754
2755     resize : function()
2756     {
2757         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),  Roo.lib.Dom.getViewHeight(true));
2758         if (this.fitwindow) {
2759             var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2760             var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2761             this.setSize(w,h);
2762         }
2763     },
2764
2765     setSize : function(w,h)
2766     {
2767         if (!w && !h) {
2768             return;
2769         }
2770         this.resizeTo(w,h);
2771     },
2772
2773     show : function() {
2774
2775         if (!this.rendered) {
2776             this.render();
2777         }
2778
2779         this.el.setStyle('display', 'block');
2780
2781         if(this.animate){  // element has 'fade'  - so stuff happens after .3s ?- not sure why the delay?
2782             var _this = this;
2783             (function(){
2784                 this.el.addClass('in');
2785             }).defer(50, this);
2786         }else{
2787             this.el.addClass('in');
2788
2789         }
2790
2791         // not sure how we can show data in here..
2792         //if (this.tmpl) {
2793         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2794         //}
2795
2796         Roo.get(document.body).addClass("x-body-masked");
2797         
2798         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),   Roo.lib.Dom.getViewHeight(true));
2799         this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2800         this.maskEl.show();
2801         
2802         this.resize();
2803         
2804         this.fireEvent('show', this);
2805
2806         // set zindex here - otherwise it appears to be ignored...
2807         this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2808
2809         (function () {
2810             this.items.forEach( function(e) {
2811                 e.layout ? e.layout() : false;
2812
2813             });
2814         }).defer(100,this);
2815
2816     },
2817     hide : function()
2818     {
2819         if(this.fireEvent("beforehide", this) !== false){
2820             this.maskEl.hide();
2821             Roo.get(document.body).removeClass("x-body-masked");
2822             this.el.removeClass('in');
2823             this.el.select('.modal-dialog', true).first().setStyle('transform','');
2824
2825             if(this.animate){ // why
2826                 var _this = this;
2827                 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2828             }else{
2829                 this.el.setStyle('display', 'none');
2830             }
2831             this.fireEvent('hide', this);
2832         }
2833     },
2834
2835     addButton : function(str, cb)
2836     {
2837
2838
2839         var b = Roo.apply({}, { html : str } );
2840         b.xns = b.xns || Roo.bootstrap;
2841         b.xtype = b.xtype || 'Button';
2842         if (typeof(b.listeners) == 'undefined') {
2843             b.listeners = { click : cb.createDelegate(this)  };
2844         }
2845
2846         var btn = Roo.factory(b);
2847
2848         btn.render(this.el.select('.modal-footer div').first());
2849
2850         return btn;
2851
2852     },
2853
2854     setDefaultButton : function(btn)
2855     {
2856         //this.el.select('.modal-footer').()
2857     },
2858     diff : false,
2859
2860     resizeTo: function(w,h)
2861     {
2862         // skip.. ?? why??
2863
2864         this.dialogEl.setWidth(w);
2865         if (this.diff === false) {
2866             this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2867         }
2868
2869         this.bodyEl.setHeight(h-this.diff);
2870
2871         this.fireEvent('resize', this);
2872
2873     },
2874     setContentSize  : function(w, h)
2875     {
2876
2877     },
2878     onButtonClick: function(btn,e)
2879     {
2880         //Roo.log([a,b,c]);
2881         this.fireEvent('btnclick', btn.name, e);
2882     },
2883      /**
2884      * Set the title of the Dialog
2885      * @param {String} str new Title
2886      */
2887     setTitle: function(str) {
2888         this.titleEl.dom.innerHTML = str;
2889     },
2890     /**
2891      * Set the body of the Dialog
2892      * @param {String} str new Title
2893      */
2894     setBody: function(str) {
2895         this.bodyEl.dom.innerHTML = str;
2896     },
2897     /**
2898      * Set the body of the Dialog using the template
2899      * @param {Obj} data - apply this data to the template and replace the body contents.
2900      */
2901     applyBody: function(obj)
2902     {
2903         if (!this.tmpl) {
2904             Roo.log("Error - using apply Body without a template");
2905             //code
2906         }
2907         this.tmpl.overwrite(this.bodyEl, obj);
2908     }
2909
2910 });
2911
2912
2913 Roo.apply(Roo.bootstrap.Modal,  {
2914     /**
2915          * Button config that displays a single OK button
2916          * @type Object
2917          */
2918         OK :  [{
2919             name : 'ok',
2920             weight : 'primary',
2921             html : 'OK'
2922         }],
2923         /**
2924          * Button config that displays Yes and No buttons
2925          * @type Object
2926          */
2927         YESNO : [
2928             {
2929                 name  : 'no',
2930                 html : 'No'
2931             },
2932             {
2933                 name  :'yes',
2934                 weight : 'primary',
2935                 html : 'Yes'
2936             }
2937         ],
2938
2939         /**
2940          * Button config that displays OK and Cancel buttons
2941          * @type Object
2942          */
2943         OKCANCEL : [
2944             {
2945                name : 'cancel',
2946                 html : 'Cancel'
2947             },
2948             {
2949                 name : 'ok',
2950                 weight : 'primary',
2951                 html : 'OK'
2952             }
2953         ],
2954         /**
2955          * Button config that displays Yes, No and Cancel buttons
2956          * @type Object
2957          */
2958         YESNOCANCEL : [
2959             {
2960                 name : 'yes',
2961                 weight : 'primary',
2962                 html : 'Yes'
2963             },
2964             {
2965                 name : 'no',
2966                 html : 'No'
2967             },
2968             {
2969                 name : 'cancel',
2970                 html : 'Cancel'
2971             }
2972         ],
2973         
2974         zIndex : 10001
2975 });
2976 /*
2977  * - LGPL
2978  *
2979  * messagebox - can be used as a replace
2980  * 
2981  */
2982 /**
2983  * @class Roo.MessageBox
2984  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
2985  * Example usage:
2986  *<pre><code>
2987 // Basic alert:
2988 Roo.Msg.alert('Status', 'Changes saved successfully.');
2989
2990 // Prompt for user data:
2991 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2992     if (btn == 'ok'){
2993         // process text value...
2994     }
2995 });
2996
2997 // Show a dialog using config options:
2998 Roo.Msg.show({
2999    title:'Save Changes?',
3000    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3001    buttons: Roo.Msg.YESNOCANCEL,
3002    fn: processResult,
3003    animEl: 'elId'
3004 });
3005 </code></pre>
3006  * @singleton
3007  */
3008 Roo.bootstrap.MessageBox = function(){
3009     var dlg, opt, mask, waitTimer;
3010     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3011     var buttons, activeTextEl, bwidth;
3012
3013     
3014     // private
3015     var handleButton = function(button){
3016         dlg.hide();
3017         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3018     };
3019
3020     // private
3021     var handleHide = function(){
3022         if(opt && opt.cls){
3023             dlg.el.removeClass(opt.cls);
3024         }
3025         //if(waitTimer){
3026         //    Roo.TaskMgr.stop(waitTimer);
3027         //    waitTimer = null;
3028         //}
3029     };
3030
3031     // private
3032     var updateButtons = function(b){
3033         var width = 0;
3034         if(!b){
3035             buttons["ok"].hide();
3036             buttons["cancel"].hide();
3037             buttons["yes"].hide();
3038             buttons["no"].hide();
3039             //dlg.footer.dom.style.display = 'none';
3040             return width;
3041         }
3042         dlg.footerEl.dom.style.display = '';
3043         for(var k in buttons){
3044             if(typeof buttons[k] != "function"){
3045                 if(b[k]){
3046                     buttons[k].show();
3047                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3048                     width += buttons[k].el.getWidth()+15;
3049                 }else{
3050                     buttons[k].hide();
3051                 }
3052             }
3053         }
3054         return width;
3055     };
3056
3057     // private
3058     var handleEsc = function(d, k, e){
3059         if(opt && opt.closable !== false){
3060             dlg.hide();
3061         }
3062         if(e){
3063             e.stopEvent();
3064         }
3065     };
3066
3067     return {
3068         /**
3069          * Returns a reference to the underlying {@link Roo.BasicDialog} element
3070          * @return {Roo.BasicDialog} The BasicDialog element
3071          */
3072         getDialog : function(){
3073            if(!dlg){
3074                 dlg = new Roo.bootstrap.Modal( {
3075                     //draggable: true,
3076                     //resizable:false,
3077                     //constraintoviewport:false,
3078                     //fixedcenter:true,
3079                     //collapsible : false,
3080                     //shim:true,
3081                     //modal: true,
3082                 //    width: 'auto',
3083                   //  height:100,
3084                     //buttonAlign:"center",
3085                     closeClick : function(){
3086                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3087                             handleButton("no");
3088                         }else{
3089                             handleButton("cancel");
3090                         }
3091                     }
3092                 });
3093                 dlg.render();
3094                 dlg.on("hide", handleHide);
3095                 mask = dlg.mask;
3096                 //dlg.addKeyListener(27, handleEsc);
3097                 buttons = {};
3098                 this.buttons = buttons;
3099                 var bt = this.buttonText;
3100                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3101                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3102                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3103                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3104                 //Roo.log(buttons);
3105                 bodyEl = dlg.bodyEl.createChild({
3106
3107                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3108                         '<textarea class="roo-mb-textarea"></textarea>' +
3109                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
3110                 });
3111                 msgEl = bodyEl.dom.firstChild;
3112                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3113                 textboxEl.enableDisplayMode();
3114                 textboxEl.addKeyListener([10,13], function(){
3115                     if(dlg.isVisible() && opt && opt.buttons){
3116                         if(opt.buttons.ok){
3117                             handleButton("ok");
3118                         }else if(opt.buttons.yes){
3119                             handleButton("yes");
3120                         }
3121                     }
3122                 });
3123                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3124                 textareaEl.enableDisplayMode();
3125                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3126                 progressEl.enableDisplayMode();
3127                 
3128                 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3129                 var pf = progressEl.dom.firstChild;
3130                 if (pf) {
3131                     pp = Roo.get(pf.firstChild);
3132                     pp.setHeight(pf.offsetHeight);
3133                 }
3134                 
3135             }
3136             return dlg;
3137         },
3138
3139         /**
3140          * Updates the message box body text
3141          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3142          * the XHTML-compliant non-breaking space character '&amp;#160;')
3143          * @return {Roo.MessageBox} This message box
3144          */
3145         updateText : function(text)
3146         {
3147             if(!dlg.isVisible() && !opt.width){
3148                 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3149                 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3150             }
3151             msgEl.innerHTML = text || '&#160;';
3152       
3153             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3154             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3155             var w = Math.max(
3156                     Math.min(opt.width || cw , this.maxWidth), 
3157                     Math.max(opt.minWidth || this.minWidth, bwidth)
3158             );
3159             if(opt.prompt){
3160                 activeTextEl.setWidth(w);
3161             }
3162             if(dlg.isVisible()){
3163                 dlg.fixedcenter = false;
3164             }
3165             // to big, make it scroll. = But as usual stupid IE does not support
3166             // !important..
3167             
3168             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3169                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3170                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3171             } else {
3172                 bodyEl.dom.style.height = '';
3173                 bodyEl.dom.style.overflowY = '';
3174             }
3175             if (cw > w) {
3176                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3177             } else {
3178                 bodyEl.dom.style.overflowX = '';
3179             }
3180             
3181             dlg.setContentSize(w, bodyEl.getHeight());
3182             if(dlg.isVisible()){
3183                 dlg.fixedcenter = true;
3184             }
3185             return this;
3186         },
3187
3188         /**
3189          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
3190          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3191          * @param {Number} value Any number between 0 and 1 (e.g., .5)
3192          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3193          * @return {Roo.MessageBox} This message box
3194          */
3195         updateProgress : function(value, text){
3196             if(text){
3197                 this.updateText(text);
3198             }
3199             
3200             if (pp) { // weird bug on my firefox - for some reason this is not defined
3201                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3202                 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3203             }
3204             return this;
3205         },        
3206
3207         /**
3208          * Returns true if the message box is currently displayed
3209          * @return {Boolean} True if the message box is visible, else false
3210          */
3211         isVisible : function(){
3212             return dlg && dlg.isVisible();  
3213         },
3214
3215         /**
3216          * Hides the message box if it is displayed
3217          */
3218         hide : function(){
3219             if(this.isVisible()){
3220                 dlg.hide();
3221             }  
3222         },
3223
3224         /**
3225          * Displays a new message box, or reinitializes an existing message box, based on the config options
3226          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3227          * The following config object properties are supported:
3228          * <pre>
3229 Property    Type             Description
3230 ----------  ---------------  ------------------------------------------------------------------------------------
3231 animEl            String/Element   An id or Element from which the message box should animate as it opens and
3232                                    closes (defaults to undefined)
3233 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3234                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
3235 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
3236                                    progress and wait dialogs will ignore this property and always hide the
3237                                    close button as they can only be closed programmatically.
3238 cls               String           A custom CSS class to apply to the message box element
3239 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
3240                                    displayed (defaults to 75)
3241 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
3242                                    function will be btn (the name of the button that was clicked, if applicable,
3243                                    e.g. "ok"), and text (the value of the active text field, if applicable).
3244                                    Progress and wait dialogs will ignore this option since they do not respond to
3245                                    user actions and can only be closed programmatically, so any required function
3246                                    should be called by the same code after it closes the dialog.
3247 icon              String           A CSS class that provides a background image to be used as an icon for
3248                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3249 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
3250 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
3251 modal             Boolean          False to allow user interaction with the page while the message box is
3252                                    displayed (defaults to true)
3253 msg               String           A string that will replace the existing message box body text (defaults
3254                                    to the XHTML-compliant non-breaking space character '&#160;')
3255 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
3256 progress          Boolean          True to display a progress bar (defaults to false)
3257 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
3258 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
3259 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
3260 title             String           The title text
3261 value             String           The string value to set into the active textbox element if displayed
3262 wait              Boolean          True to display a progress bar (defaults to false)
3263 width             Number           The width of the dialog in pixels
3264 </pre>
3265          *
3266          * Example usage:
3267          * <pre><code>
3268 Roo.Msg.show({
3269    title: 'Address',
3270    msg: 'Please enter your address:',
3271    width: 300,
3272    buttons: Roo.MessageBox.OKCANCEL,
3273    multiline: true,
3274    fn: saveAddress,
3275    animEl: 'addAddressBtn'
3276 });
3277 </code></pre>
3278          * @param {Object} config Configuration options
3279          * @return {Roo.MessageBox} This message box
3280          */
3281         show : function(options)
3282         {
3283             
3284             // this causes nightmares if you show one dialog after another
3285             // especially on callbacks..
3286              
3287             if(this.isVisible()){
3288                 
3289                 this.hide();
3290                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3291                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
3292                 Roo.log("New Dialog Message:" +  options.msg )
3293                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3294                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3295                 
3296             }
3297             var d = this.getDialog();
3298             opt = options;
3299             d.setTitle(opt.title || "&#160;");
3300             d.closeEl.setDisplayed(opt.closable !== false);
3301             activeTextEl = textboxEl;
3302             opt.prompt = opt.prompt || (opt.multiline ? true : false);
3303             if(opt.prompt){
3304                 if(opt.multiline){
3305                     textboxEl.hide();
3306                     textareaEl.show();
3307                     textareaEl.setHeight(typeof opt.multiline == "number" ?
3308                         opt.multiline : this.defaultTextHeight);
3309                     activeTextEl = textareaEl;
3310                 }else{
3311                     textboxEl.show();
3312                     textareaEl.hide();
3313                 }
3314             }else{
3315                 textboxEl.hide();
3316                 textareaEl.hide();
3317             }
3318             progressEl.setDisplayed(opt.progress === true);
3319             this.updateProgress(0);
3320             activeTextEl.dom.value = opt.value || "";
3321             if(opt.prompt){
3322                 dlg.setDefaultButton(activeTextEl);
3323             }else{
3324                 var bs = opt.buttons;
3325                 var db = null;
3326                 if(bs && bs.ok){
3327                     db = buttons["ok"];
3328                 }else if(bs && bs.yes){
3329                     db = buttons["yes"];
3330                 }
3331                 dlg.setDefaultButton(db);
3332             }
3333             bwidth = updateButtons(opt.buttons);
3334             this.updateText(opt.msg);
3335             if(opt.cls){
3336                 d.el.addClass(opt.cls);
3337             }
3338             d.proxyDrag = opt.proxyDrag === true;
3339             d.modal = opt.modal !== false;
3340             d.mask = opt.modal !== false ? mask : false;
3341             if(!d.isVisible()){
3342                 // force it to the end of the z-index stack so it gets a cursor in FF
3343                 document.body.appendChild(dlg.el.dom);
3344                 d.animateTarget = null;
3345                 d.show(options.animEl);
3346             }
3347             return this;
3348         },
3349
3350         /**
3351          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
3352          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3353          * and closing the message box when the process is complete.
3354          * @param {String} title The title bar text
3355          * @param {String} msg The message box body text
3356          * @return {Roo.MessageBox} This message box
3357          */
3358         progress : function(title, msg){
3359             this.show({
3360                 title : title,
3361                 msg : msg,
3362                 buttons: false,
3363                 progress:true,
3364                 closable:false,
3365                 minWidth: this.minProgressWidth,
3366                 modal : true
3367             });
3368             return this;
3369         },
3370
3371         /**
3372          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3373          * If a callback function is passed it will be called after the user clicks the button, and the
3374          * id of the button that was clicked will be passed as the only parameter to the callback
3375          * (could also be the top-right close button).
3376          * @param {String} title The title bar text
3377          * @param {String} msg The message box body text
3378          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3379          * @param {Object} scope (optional) The scope of the callback function
3380          * @return {Roo.MessageBox} This message box
3381          */
3382         alert : function(title, msg, fn, scope)
3383         {
3384             this.show({
3385                 title : title,
3386                 msg : msg,
3387                 buttons: this.OK,
3388                 fn: fn,
3389                 closable : false,
3390                 scope : scope,
3391                 modal : true
3392             });
3393             return this;
3394         },
3395
3396         /**
3397          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
3398          * interaction while waiting for a long-running process to complete that does not have defined intervals.
3399          * You are responsible for closing the message box when the process is complete.
3400          * @param {String} msg The message box body text
3401          * @param {String} title (optional) The title bar text
3402          * @return {Roo.MessageBox} This message box
3403          */
3404         wait : function(msg, title){
3405             this.show({
3406                 title : title,
3407                 msg : msg,
3408                 buttons: false,
3409                 closable:false,
3410                 progress:true,
3411                 modal:true,
3412                 width:300,
3413                 wait:true
3414             });
3415             waitTimer = Roo.TaskMgr.start({
3416                 run: function(i){
3417                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3418                 },
3419                 interval: 1000
3420             });
3421             return this;
3422         },
3423
3424         /**
3425          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3426          * If a callback function is passed it will be called after the user clicks either button, and the id of the
3427          * button that was clicked will be passed as the only parameter to the callback (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         confirm : function(title, msg, fn, scope){
3435             this.show({
3436                 title : title,
3437                 msg : msg,
3438                 buttons: this.YESNO,
3439                 fn: fn,
3440                 scope : scope,
3441                 modal : true
3442             });
3443             return this;
3444         },
3445
3446         /**
3447          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3448          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
3449          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3450          * (could also be the top-right close button) and the text that was entered will be passed as the two
3451          * parameters to the callback.
3452          * @param {String} title The title bar text
3453          * @param {String} msg The message box body text
3454          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3455          * @param {Object} scope (optional) The scope of the callback function
3456          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3457          * property, or the height in pixels to create the textbox (defaults to false / single-line)
3458          * @return {Roo.MessageBox} This message box
3459          */
3460         prompt : function(title, msg, fn, scope, multiline){
3461             this.show({
3462                 title : title,
3463                 msg : msg,
3464                 buttons: this.OKCANCEL,
3465                 fn: fn,
3466                 minWidth:250,
3467                 scope : scope,
3468                 prompt:true,
3469                 multiline: multiline,
3470                 modal : true
3471             });
3472             return this;
3473         },
3474
3475         /**
3476          * Button config that displays a single OK button
3477          * @type Object
3478          */
3479         OK : {ok:true},
3480         /**
3481          * Button config that displays Yes and No buttons
3482          * @type Object
3483          */
3484         YESNO : {yes:true, no:true},
3485         /**
3486          * Button config that displays OK and Cancel buttons
3487          * @type Object
3488          */
3489         OKCANCEL : {ok:true, cancel:true},
3490         /**
3491          * Button config that displays Yes, No and Cancel buttons
3492          * @type Object
3493          */
3494         YESNOCANCEL : {yes:true, no:true, cancel:true},
3495
3496         /**
3497          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3498          * @type Number
3499          */
3500         defaultTextHeight : 75,
3501         /**
3502          * The maximum width in pixels of the message box (defaults to 600)
3503          * @type Number
3504          */
3505         maxWidth : 600,
3506         /**
3507          * The minimum width in pixels of the message box (defaults to 100)
3508          * @type Number
3509          */
3510         minWidth : 100,
3511         /**
3512          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
3513          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3514          * @type Number
3515          */
3516         minProgressWidth : 250,
3517         /**
3518          * An object containing the default button text strings that can be overriden for localized language support.
3519          * Supported properties are: ok, cancel, yes and no.
3520          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3521          * @type Object
3522          */
3523         buttonText : {
3524             ok : "OK",
3525             cancel : "Cancel",
3526             yes : "Yes",
3527             no : "No"
3528         }
3529     };
3530 }();
3531
3532 /**
3533  * Shorthand for {@link Roo.MessageBox}
3534  */
3535 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3536 Roo.Msg = Roo.Msg || Roo.MessageBox;
3537 /*
3538  * - LGPL
3539  *
3540  * navbar
3541  * 
3542  */
3543
3544 /**
3545  * @class Roo.bootstrap.Navbar
3546  * @extends Roo.bootstrap.Component
3547  * Bootstrap Navbar class
3548
3549  * @constructor
3550  * Create a new Navbar
3551  * @param {Object} config The config object
3552  */
3553
3554
3555 Roo.bootstrap.Navbar = function(config){
3556     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3557     this.addEvents({
3558         // raw events
3559         /**
3560          * @event beforetoggle
3561          * Fire before toggle the menu
3562          * @param {Roo.EventObject} e
3563          */
3564         "beforetoggle" : true
3565     });
3566 };
3567
3568 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3569     
3570     
3571    
3572     // private
3573     navItems : false,
3574     loadMask : false,
3575     
3576     
3577     getAutoCreate : function(){
3578         
3579         
3580         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3581         
3582     },
3583     
3584     initEvents :function ()
3585     {
3586         //Roo.log(this.el.select('.navbar-toggle',true));
3587         this.el.select('.navbar-toggle',true).on('click', function() {
3588             if(this.fireEvent('beforetoggle', this) !== false){
3589                this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3590             }
3591             
3592         }, this);
3593         
3594         var mark = {
3595             tag: "div",
3596             cls:"x-dlg-mask"
3597         };
3598         
3599         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3600         
3601         var size = this.el.getSize();
3602         this.maskEl.setSize(size.width, size.height);
3603         this.maskEl.enableDisplayMode("block");
3604         this.maskEl.hide();
3605         
3606         if(this.loadMask){
3607             this.maskEl.show();
3608         }
3609     },
3610     
3611     
3612     getChildContainer : function()
3613     {
3614         if (this.el.select('.collapse').getCount()) {
3615             return this.el.select('.collapse',true).first();
3616         }
3617         
3618         return this.el;
3619     },
3620     
3621     mask : function()
3622     {
3623         this.maskEl.show();
3624     },
3625     
3626     unmask : function()
3627     {
3628         this.maskEl.hide();
3629     } 
3630     
3631     
3632     
3633     
3634 });
3635
3636
3637
3638  
3639
3640  /*
3641  * - LGPL
3642  *
3643  * navbar
3644  * 
3645  */
3646
3647 /**
3648  * @class Roo.bootstrap.NavSimplebar
3649  * @extends Roo.bootstrap.Navbar
3650  * Bootstrap Sidebar class
3651  *
3652  * @cfg {Boolean} inverse is inverted color
3653  * 
3654  * @cfg {String} type (nav | pills | tabs)
3655  * @cfg {Boolean} arrangement stacked | justified
3656  * @cfg {String} align (left | right) alignment
3657  * 
3658  * @cfg {Boolean} main (true|false) main nav bar? default false
3659  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3660  * 
3661  * @cfg {String} tag (header|footer|nav|div) default is nav 
3662
3663  * 
3664  * 
3665  * 
3666  * @constructor
3667  * Create a new Sidebar
3668  * @param {Object} config The config object
3669  */
3670
3671
3672 Roo.bootstrap.NavSimplebar = function(config){
3673     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3674 };
3675
3676 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3677     
3678     inverse: false,
3679     
3680     type: false,
3681     arrangement: '',
3682     align : false,
3683     
3684     
3685     
3686     main : false,
3687     
3688     
3689     tag : false,
3690     
3691     
3692     getAutoCreate : function(){
3693         
3694         
3695         var cfg = {
3696             tag : this.tag || 'div',
3697             cls : 'navbar'
3698         };
3699           
3700         
3701         cfg.cn = [
3702             {
3703                 cls: 'nav',
3704                 tag : 'ul'
3705             }
3706         ];
3707         
3708          
3709         this.type = this.type || 'nav';
3710         if (['tabs','pills'].indexOf(this.type)!==-1) {
3711             cfg.cn[0].cls += ' nav-' + this.type
3712         
3713         
3714         } else {
3715             if (this.type!=='nav') {
3716                 Roo.log('nav type must be nav/tabs/pills')
3717             }
3718             cfg.cn[0].cls += ' navbar-nav'
3719         }
3720         
3721         
3722         
3723         
3724         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3725             cfg.cn[0].cls += ' nav-' + this.arrangement;
3726         }
3727         
3728         
3729         if (this.align === 'right') {
3730             cfg.cn[0].cls += ' navbar-right';
3731         }
3732         
3733         if (this.inverse) {
3734             cfg.cls += ' navbar-inverse';
3735             
3736         }
3737         
3738         
3739         return cfg;
3740     
3741         
3742     }
3743     
3744     
3745     
3746 });
3747
3748
3749
3750  
3751
3752  
3753        /*
3754  * - LGPL
3755  *
3756  * navbar
3757  * 
3758  */
3759
3760 /**
3761  * @class Roo.bootstrap.NavHeaderbar
3762  * @extends Roo.bootstrap.NavSimplebar
3763  * Bootstrap Sidebar class
3764  *
3765  * @cfg {String} brand what is brand
3766  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3767  * @cfg {String} brand_href href of the brand
3768  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3769  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3770  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3771  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3772  * 
3773  * @constructor
3774  * Create a new Sidebar
3775  * @param {Object} config The config object
3776  */
3777
3778
3779 Roo.bootstrap.NavHeaderbar = function(config){
3780     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3781       
3782 };
3783
3784 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3785     
3786     position: '',
3787     brand: '',
3788     brand_href: false,
3789     srButton : true,
3790     autohide : false,
3791     desktopCenter : false,
3792    
3793     
3794     getAutoCreate : function(){
3795         
3796         var   cfg = {
3797             tag: this.nav || 'nav',
3798             cls: 'navbar',
3799             role: 'navigation',
3800             cn: []
3801         };
3802         
3803         var cn = cfg.cn;
3804         if (this.desktopCenter) {
3805             cn.push({cls : 'container', cn : []});
3806             cn = cn[0].cn;
3807         }
3808         
3809         if(this.srButton){
3810             cn.push({
3811                 tag: 'div',
3812                 cls: 'navbar-header',
3813                 cn: [
3814                     {
3815                         tag: 'button',
3816                         type: 'button',
3817                         cls: 'navbar-toggle',
3818                         'data-toggle': 'collapse',
3819                         cn: [
3820                             {
3821                                 tag: 'span',
3822                                 cls: 'sr-only',
3823                                 html: 'Toggle navigation'
3824                             },
3825                             {
3826                                 tag: 'span',
3827                                 cls: 'icon-bar'
3828                             },
3829                             {
3830                                 tag: 'span',
3831                                 cls: 'icon-bar'
3832                             },
3833                             {
3834                                 tag: 'span',
3835                                 cls: 'icon-bar'
3836                             }
3837                         ]
3838                     }
3839                 ]
3840             });
3841         }
3842         
3843         cn.push({
3844             tag: 'div',
3845             cls: 'collapse navbar-collapse',
3846             cn : []
3847         });
3848         
3849         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3850         
3851         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3852             cfg.cls += ' navbar-' + this.position;
3853             
3854             // tag can override this..
3855             
3856             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3857         }
3858         
3859         if (this.brand !== '') {
3860             cn[0].cn.push({
3861                 tag: 'a',
3862                 href: this.brand_href ? this.brand_href : '#',
3863                 cls: 'navbar-brand',
3864                 cn: [
3865                 this.brand
3866                 ]
3867             });
3868         }
3869         
3870         if(this.main){
3871             cfg.cls += ' main-nav';
3872         }
3873         
3874         
3875         return cfg;
3876
3877         
3878     },
3879     getHeaderChildContainer : function()
3880     {
3881         if (this.srButton && this.el.select('.navbar-header').getCount()) {
3882             return this.el.select('.navbar-header',true).first();
3883         }
3884         
3885         return this.getChildContainer();
3886     },
3887     
3888     
3889     initEvents : function()
3890     {
3891         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3892         
3893         if (this.autohide) {
3894             
3895             var prevScroll = 0;
3896             var ft = this.el;
3897             
3898             Roo.get(document).on('scroll',function(e) {
3899                 var ns = Roo.get(document).getScroll().top;
3900                 var os = prevScroll;
3901                 prevScroll = ns;
3902                 
3903                 if(ns > os){
3904                     ft.removeClass('slideDown');
3905                     ft.addClass('slideUp');
3906                     return;
3907                 }
3908                 ft.removeClass('slideUp');
3909                 ft.addClass('slideDown');
3910                  
3911               
3912           },this);
3913         }
3914     }    
3915     
3916 });
3917
3918
3919
3920  
3921
3922  /*
3923  * - LGPL
3924  *
3925  * navbar
3926  * 
3927  */
3928
3929 /**
3930  * @class Roo.bootstrap.NavSidebar
3931  * @extends Roo.bootstrap.Navbar
3932  * Bootstrap Sidebar class
3933  * 
3934  * @constructor
3935  * Create a new Sidebar
3936  * @param {Object} config The config object
3937  */
3938
3939
3940 Roo.bootstrap.NavSidebar = function(config){
3941     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3942 };
3943
3944 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
3945     
3946     sidebar : true, // used by Navbar Item and NavbarGroup at present...
3947     
3948     getAutoCreate : function(){
3949         
3950         
3951         return  {
3952             tag: 'div',
3953             cls: 'sidebar sidebar-nav'
3954         };
3955     
3956         
3957     }
3958     
3959     
3960     
3961 });
3962
3963
3964
3965  
3966
3967  /*
3968  * - LGPL
3969  *
3970  * nav group
3971  * 
3972  */
3973
3974 /**
3975  * @class Roo.bootstrap.NavGroup
3976  * @extends Roo.bootstrap.Component
3977  * Bootstrap NavGroup class
3978  * @cfg {String} align (left|right)
3979  * @cfg {Boolean} inverse
3980  * @cfg {String} type (nav|pills|tab) default nav
3981  * @cfg {String} navId - reference Id for navbar.
3982
3983  * 
3984  * @constructor
3985  * Create a new nav group
3986  * @param {Object} config The config object
3987  */
3988
3989 Roo.bootstrap.NavGroup = function(config){
3990     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3991     this.navItems = [];
3992    
3993     Roo.bootstrap.NavGroup.register(this);
3994      this.addEvents({
3995         /**
3996              * @event changed
3997              * Fires when the active item changes
3998              * @param {Roo.bootstrap.NavGroup} this
3999              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4000              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
4001          */
4002         'changed': true
4003      });
4004     
4005 };
4006
4007 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
4008     
4009     align: '',
4010     inverse: false,
4011     form: false,
4012     type: 'nav',
4013     navId : '',
4014     // private
4015     
4016     navItems : false, 
4017     
4018     getAutoCreate : function()
4019     {
4020         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4021         
4022         cfg = {
4023             tag : 'ul',
4024             cls: 'nav' 
4025         };
4026         
4027         if (['tabs','pills'].indexOf(this.type)!==-1) {
4028             cfg.cls += ' nav-' + this.type
4029         } else {
4030             if (this.type!=='nav') {
4031                 Roo.log('nav type must be nav/tabs/pills')
4032             }
4033             cfg.cls += ' navbar-nav'
4034         }
4035         
4036         if (this.parent() && this.parent().sidebar) {
4037             cfg = {
4038                 tag: 'ul',
4039                 cls: 'dashboard-menu sidebar-menu'
4040             };
4041             
4042             return cfg;
4043         }
4044         
4045         if (this.form === true) {
4046             cfg = {
4047                 tag: 'form',
4048                 cls: 'navbar-form'
4049             };
4050             
4051             if (this.align === 'right') {
4052                 cfg.cls += ' navbar-right';
4053             } else {
4054                 cfg.cls += ' navbar-left';
4055             }
4056         }
4057         
4058         if (this.align === 'right') {
4059             cfg.cls += ' navbar-right';
4060         }
4061         
4062         if (this.inverse) {
4063             cfg.cls += ' navbar-inverse';
4064             
4065         }
4066         
4067         
4068         return cfg;
4069     },
4070     /**
4071     * sets the active Navigation item
4072     * @param {Roo.bootstrap.NavItem} the new current navitem
4073     */
4074     setActiveItem : function(item)
4075     {
4076         var prev = false;
4077         Roo.each(this.navItems, function(v){
4078             if (v == item) {
4079                 return ;
4080             }
4081             if (v.isActive()) {
4082                 v.setActive(false, true);
4083                 prev = v;
4084                 
4085             }
4086             
4087         });
4088
4089         item.setActive(true, true);
4090         this.fireEvent('changed', this, item, prev);
4091         
4092         
4093     },
4094     /**
4095     * gets the active Navigation item
4096     * @return {Roo.bootstrap.NavItem} the current navitem
4097     */
4098     getActive : function()
4099     {
4100         
4101         var prev = false;
4102         Roo.each(this.navItems, function(v){
4103             
4104             if (v.isActive()) {
4105                 prev = v;
4106                 
4107             }
4108             
4109         });
4110         return prev;
4111     },
4112     
4113     indexOfNav : function()
4114     {
4115         
4116         var prev = false;
4117         Roo.each(this.navItems, function(v,i){
4118             
4119             if (v.isActive()) {
4120                 prev = i;
4121                 
4122             }
4123             
4124         });
4125         return prev;
4126     },
4127     /**
4128     * adds a Navigation item
4129     * @param {Roo.bootstrap.NavItem} the navitem to add
4130     */
4131     addItem : function(cfg)
4132     {
4133         var cn = new Roo.bootstrap.NavItem(cfg);
4134         this.register(cn);
4135         cn.parentId = this.id;
4136         cn.onRender(this.el, null);
4137         return cn;
4138     },
4139     /**
4140     * register a Navigation item
4141     * @param {Roo.bootstrap.NavItem} the navitem to add
4142     */
4143     register : function(item)
4144     {
4145         this.navItems.push( item);
4146         item.navId = this.navId;
4147     
4148     },
4149     
4150     /**
4151     * clear all the Navigation item
4152     */
4153    
4154     clearAll : function()
4155     {
4156         this.navItems = [];
4157         this.el.dom.innerHTML = '';
4158     },
4159     
4160     getNavItem: function(tabId)
4161     {
4162         var ret = false;
4163         Roo.each(this.navItems, function(e) {
4164             if (e.tabId == tabId) {
4165                ret =  e;
4166                return false;
4167             }
4168             return true;
4169             
4170         });
4171         return ret;
4172     },
4173     
4174     setActiveNext : function()
4175     {
4176         var i = this.indexOfNav(this.getActive());
4177         if (i > this.navItems.length) {
4178             return;
4179         }
4180         this.setActiveItem(this.navItems[i+1]);
4181     },
4182     setActivePrev : function()
4183     {
4184         var i = this.indexOfNav(this.getActive());
4185         if (i  < 1) {
4186             return;
4187         }
4188         this.setActiveItem(this.navItems[i-1]);
4189     },
4190     clearWasActive : function(except) {
4191         Roo.each(this.navItems, function(e) {
4192             if (e.tabId != except.tabId && e.was_active) {
4193                e.was_active = false;
4194                return false;
4195             }
4196             return true;
4197             
4198         });
4199     },
4200     getWasActive : function ()
4201     {
4202         var r = false;
4203         Roo.each(this.navItems, function(e) {
4204             if (e.was_active) {
4205                r = e;
4206                return false;
4207             }
4208             return true;
4209             
4210         });
4211         return r;
4212     }
4213     
4214     
4215 });
4216
4217  
4218 Roo.apply(Roo.bootstrap.NavGroup, {
4219     
4220     groups: {},
4221      /**
4222     * register a Navigation Group
4223     * @param {Roo.bootstrap.NavGroup} the navgroup to add
4224     */
4225     register : function(navgrp)
4226     {
4227         this.groups[navgrp.navId] = navgrp;
4228         
4229     },
4230     /**
4231     * fetch a Navigation Group based on the navigation ID
4232     * @param {string} the navgroup to add
4233     * @returns {Roo.bootstrap.NavGroup} the navgroup 
4234     */
4235     get: function(navId) {
4236         if (typeof(this.groups[navId]) == 'undefined') {
4237             return false;
4238             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4239         }
4240         return this.groups[navId] ;
4241     }
4242     
4243     
4244     
4245 });
4246
4247  /*
4248  * - LGPL
4249  *
4250  * row
4251  * 
4252  */
4253
4254 /**
4255  * @class Roo.bootstrap.NavItem
4256  * @extends Roo.bootstrap.Component
4257  * Bootstrap Navbar.NavItem class
4258  * @cfg {String} href  link to
4259  * @cfg {String} html content of button
4260  * @cfg {String} badge text inside badge
4261  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4262  * @cfg {String} glyphicon name of glyphicon
4263  * @cfg {String} icon name of font awesome icon
4264  * @cfg {Boolean} active Is item active
4265  * @cfg {Boolean} disabled Is item disabled
4266  
4267  * @cfg {Boolean} preventDefault (true | false) default false
4268  * @cfg {String} tabId the tab that this item activates.
4269  * @cfg {String} tagtype (a|span) render as a href or span?
4270  * @cfg {Boolean} animateRef (true|false) link to element default false  
4271   
4272  * @constructor
4273  * Create a new Navbar Item
4274  * @param {Object} config The config object
4275  */
4276 Roo.bootstrap.NavItem = function(config){
4277     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4278     this.addEvents({
4279         // raw events
4280         /**
4281          * @event click
4282          * The raw click event for the entire grid.
4283          * @param {Roo.EventObject} e
4284          */
4285         "click" : true,
4286          /**
4287             * @event changed
4288             * Fires when the active item active state changes
4289             * @param {Roo.bootstrap.NavItem} this
4290             * @param {boolean} state the new state
4291              
4292          */
4293         'changed': true,
4294         /**
4295             * @event scrollto
4296             * Fires when scroll to element
4297             * @param {Roo.bootstrap.NavItem} this
4298             * @param {Object} options
4299             * @param {Roo.EventObject} e
4300              
4301          */
4302         'scrollto': true
4303     });
4304    
4305 };
4306
4307 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
4308     
4309     href: false,
4310     html: '',
4311     badge: '',
4312     icon: false,
4313     glyphicon: false,
4314     active: false,
4315     preventDefault : false,
4316     tabId : false,
4317     tagtype : 'a',
4318     disabled : false,
4319     animateRef : false,
4320     was_active : false,
4321     
4322     getAutoCreate : function(){
4323          
4324         var cfg = {
4325             tag: 'li',
4326             cls: 'nav-item'
4327             
4328         };
4329         
4330         if (this.active) {
4331             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4332         }
4333         if (this.disabled) {
4334             cfg.cls += ' disabled';
4335         }
4336         
4337         if (this.href || this.html || this.glyphicon || this.icon) {
4338             cfg.cn = [
4339                 {
4340                     tag: this.tagtype,
4341                     href : this.href || "#",
4342                     html: this.html || ''
4343                 }
4344             ];
4345             
4346             if (this.icon) {
4347                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4348             }
4349
4350             if(this.glyphicon) {
4351                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
4352             }
4353             
4354             if (this.menu) {
4355                 
4356                 cfg.cn[0].html += " <span class='caret'></span>";
4357              
4358             }
4359             
4360             if (this.badge !== '') {
4361                  
4362                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4363             }
4364         }
4365         
4366         
4367         
4368         return cfg;
4369     },
4370     initEvents: function() 
4371     {
4372         if (typeof (this.menu) != 'undefined') {
4373             this.menu.parentType = this.xtype;
4374             this.menu.triggerEl = this.el;
4375             this.menu = this.addxtype(Roo.apply({}, this.menu));
4376         }
4377         
4378         this.el.select('a',true).on('click', this.onClick, this);
4379         
4380         if(this.tagtype == 'span'){
4381             this.el.select('span',true).on('click', this.onClick, this);
4382         }
4383        
4384         // at this point parent should be available..
4385         this.parent().register(this);
4386     },
4387     
4388     onClick : function(e)
4389     {
4390         if (e.getTarget('.dropdown-menu-item')) {
4391             // did you click on a menu itemm.... - then don't trigger onclick..
4392             return;
4393         }
4394         
4395         if(
4396                 this.preventDefault || 
4397                 this.href == '#' 
4398         ){
4399             Roo.log("NavItem - prevent Default?");
4400             e.preventDefault();
4401         }
4402         
4403         if (this.disabled) {
4404             return;
4405         }
4406         
4407         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4408         if (tg && tg.transition) {
4409             Roo.log("waiting for the transitionend");
4410             return;
4411         }
4412         
4413         
4414         
4415         //Roo.log("fire event clicked");
4416         if(this.fireEvent('click', this, e) === false){
4417             return;
4418         };
4419         
4420         if(this.tagtype == 'span'){
4421             return;
4422         }
4423         
4424         //Roo.log(this.href);
4425         var ael = this.el.select('a',true).first();
4426         //Roo.log(ael);
4427         
4428         if(ael && this.animateRef && this.href.indexOf('#') > -1){
4429             //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4430             if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4431                 return; // ignore... - it's a 'hash' to another page.
4432             }
4433             Roo.log("NavItem - prevent Default?");
4434             e.preventDefault();
4435             this.scrollToElement(e);
4436         }
4437         
4438         
4439         var p =  this.parent();
4440    
4441         if (['tabs','pills'].indexOf(p.type)!==-1) {
4442             if (typeof(p.setActiveItem) !== 'undefined') {
4443                 p.setActiveItem(this);
4444             }
4445         }
4446         
4447         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4448         if (p.parentType == 'NavHeaderbar' && !this.menu) {
4449             // remove the collapsed menu expand...
4450             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
4451         }
4452     },
4453     
4454     isActive: function () {
4455         return this.active
4456     },
4457     setActive : function(state, fire, is_was_active)
4458     {
4459         if (this.active && !state && this.navId) {
4460             this.was_active = true;
4461             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4462             if (nv) {
4463                 nv.clearWasActive(this);
4464             }
4465             
4466         }
4467         this.active = state;
4468         
4469         if (!state ) {
4470             this.el.removeClass('active');
4471         } else if (!this.el.hasClass('active')) {
4472             this.el.addClass('active');
4473         }
4474         if (fire) {
4475             this.fireEvent('changed', this, state);
4476         }
4477         
4478         // show a panel if it's registered and related..
4479         
4480         if (!this.navId || !this.tabId || !state || is_was_active) {
4481             return;
4482         }
4483         
4484         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4485         if (!tg) {
4486             return;
4487         }
4488         var pan = tg.getPanelByName(this.tabId);
4489         if (!pan) {
4490             return;
4491         }
4492         // if we can not flip to new panel - go back to old nav highlight..
4493         if (false == tg.showPanel(pan)) {
4494             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4495             if (nv) {
4496                 var onav = nv.getWasActive();
4497                 if (onav) {
4498                     onav.setActive(true, false, true);
4499                 }
4500             }
4501             
4502         }
4503         
4504         
4505         
4506     },
4507      // this should not be here...
4508     setDisabled : function(state)
4509     {
4510         this.disabled = state;
4511         if (!state ) {
4512             this.el.removeClass('disabled');
4513         } else if (!this.el.hasClass('disabled')) {
4514             this.el.addClass('disabled');
4515         }
4516         
4517     },
4518     
4519     /**
4520      * Fetch the element to display the tooltip on.
4521      * @return {Roo.Element} defaults to this.el
4522      */
4523     tooltipEl : function()
4524     {
4525         return this.el.select('' + this.tagtype + '', true).first();
4526     },
4527     
4528     scrollToElement : function(e)
4529     {
4530         var c = document.body;
4531         
4532         /*
4533          * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4534          */
4535         if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4536             c = document.documentElement;
4537         }
4538         
4539         var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4540         
4541         if(!target){
4542             return;
4543         }
4544
4545         var o = target.calcOffsetsTo(c);
4546         
4547         var options = {
4548             target : target,
4549             value : o[1]
4550         };
4551         
4552         this.fireEvent('scrollto', this, options, e);
4553         
4554         Roo.get(c).scrollTo('top', options.value, true);
4555         
4556         return;
4557     }
4558 });
4559  
4560
4561  /*
4562  * - LGPL
4563  *
4564  * sidebar item
4565  *
4566  *  li
4567  *    <span> icon </span>
4568  *    <span> text </span>
4569  *    <span>badge </span>
4570  */
4571
4572 /**
4573  * @class Roo.bootstrap.NavSidebarItem
4574  * @extends Roo.bootstrap.NavItem
4575  * Bootstrap Navbar.NavSidebarItem class
4576  * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4577  * {Boolean} open is the menu open
4578  * {Boolean} buttonView use button as the tigger el rather that a (default false)
4579  * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4580  * {String} buttonSize (sm|md|lg)the extra classes for the button
4581  * {Boolean} showArrow show arrow next to the text (default true)
4582  * @constructor
4583  * Create a new Navbar Button
4584  * @param {Object} config The config object
4585  */
4586 Roo.bootstrap.NavSidebarItem = function(config){
4587     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4588     this.addEvents({
4589         // raw events
4590         /**
4591          * @event click
4592          * The raw click event for the entire grid.
4593          * @param {Roo.EventObject} e
4594          */
4595         "click" : true,
4596          /**
4597             * @event changed
4598             * Fires when the active item active state changes
4599             * @param {Roo.bootstrap.NavSidebarItem} this
4600             * @param {boolean} state the new state
4601              
4602          */
4603         'changed': true
4604     });
4605    
4606 };
4607
4608 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4609     
4610     badgeWeight : 'default',
4611     
4612     open: false,
4613     
4614     buttonView : false,
4615     
4616     buttonWeight : 'default',
4617     
4618     buttonSize : 'md',
4619     
4620     showArrow : true,
4621     
4622     getAutoCreate : function(){
4623         
4624         
4625         var a = {
4626                 tag: 'a',
4627                 href : this.href || '#',
4628                 cls: '',
4629                 html : '',
4630                 cn : []
4631         };
4632         
4633         if(this.buttonView){
4634             a = {
4635                 tag: 'button',
4636                 href : this.href || '#',
4637                 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4638                 html : this.html,
4639                 cn : []
4640             };
4641         }
4642         
4643         var cfg = {
4644             tag: 'li',
4645             cls: '',
4646             cn: [ a ]
4647         };
4648         
4649         if (this.active) {
4650             cfg.cls += ' active';
4651         }
4652         
4653         if (this.disabled) {
4654             cfg.cls += ' disabled';
4655         }
4656         if (this.open) {
4657             cfg.cls += ' open x-open';
4658         }
4659         // left icon..
4660         if (this.glyphicon || this.icon) {
4661             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4662             a.cn.push({ tag : 'i', cls : c }) ;
4663         }
4664         
4665         if(!this.buttonView){
4666             var span = {
4667                 tag: 'span',
4668                 html : this.html || ''
4669             };
4670
4671             a.cn.push(span);
4672             
4673         }
4674         
4675         if (this.badge !== '') {
4676             a.cn.push({ tag: 'span',  cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge }); 
4677         }
4678         
4679         if (this.menu) {
4680             
4681             if(this.showArrow){
4682                 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4683             }
4684             
4685             a.cls += ' dropdown-toggle treeview' ;
4686         }
4687         
4688         return cfg;
4689     },
4690     
4691     initEvents : function()
4692     { 
4693         if (typeof (this.menu) != 'undefined') {
4694             this.menu.parentType = this.xtype;
4695             this.menu.triggerEl = this.el;
4696             this.menu = this.addxtype(Roo.apply({}, this.menu));
4697         }
4698         
4699         this.el.on('click', this.onClick, this);
4700         
4701         if(this.badge !== ''){
4702             this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4703         }
4704         
4705     },
4706     
4707     onClick : function(e)
4708     {
4709         if(this.disabled){
4710             e.preventDefault();
4711             return;
4712         }
4713         
4714         if(this.preventDefault){
4715             e.preventDefault();
4716         }
4717         
4718         this.fireEvent('click', this);
4719     },
4720     
4721     disable : function()
4722     {
4723         this.setDisabled(true);
4724     },
4725     
4726     enable : function()
4727     {
4728         this.setDisabled(false);
4729     },
4730     
4731     setDisabled : function(state)
4732     {
4733         if(this.disabled == state){
4734             return;
4735         }
4736         
4737         this.disabled = state;
4738         
4739         if (state) {
4740             this.el.addClass('disabled');
4741             return;
4742         }
4743         
4744         this.el.removeClass('disabled');
4745         
4746         return;
4747     },
4748     
4749     setActive : function(state)
4750     {
4751         if(this.active == state){
4752             return;
4753         }
4754         
4755         this.active = state;
4756         
4757         if (state) {
4758             this.el.addClass('active');
4759             return;
4760         }
4761         
4762         this.el.removeClass('active');
4763         
4764         return;
4765     },
4766     
4767     isActive: function () 
4768     {
4769         return this.active;
4770     },
4771     
4772     setBadge : function(str)
4773     {
4774         if(!this.badgeEl){
4775             return;
4776         }
4777         
4778         this.badgeEl.dom.innerHTML = str;
4779     }
4780     
4781    
4782      
4783  
4784 });
4785  
4786
4787  /*
4788  * - LGPL
4789  *
4790  * row
4791  * 
4792  */
4793
4794 /**
4795  * @class Roo.bootstrap.Row
4796  * @extends Roo.bootstrap.Component
4797  * Bootstrap Row class (contains columns...)
4798  * 
4799  * @constructor
4800  * Create a new Row
4801  * @param {Object} config The config object
4802  */
4803
4804 Roo.bootstrap.Row = function(config){
4805     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4806 };
4807
4808 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4809     
4810     getAutoCreate : function(){
4811        return {
4812             cls: 'row clearfix'
4813        };
4814     }
4815     
4816     
4817 });
4818
4819  
4820
4821  /*
4822  * - LGPL
4823  *
4824  * element
4825  * 
4826  */
4827
4828 /**
4829  * @class Roo.bootstrap.Element
4830  * @extends Roo.bootstrap.Component
4831  * Bootstrap Element class
4832  * @cfg {String} html contents of the element
4833  * @cfg {String} tag tag of the element
4834  * @cfg {String} cls class of the element
4835  * @cfg {Boolean} preventDefault (true|false) default false
4836  * @cfg {Boolean} clickable (true|false) default false
4837  * 
4838  * @constructor
4839  * Create a new Element
4840  * @param {Object} config The config object
4841  */
4842
4843 Roo.bootstrap.Element = function(config){
4844     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4845     
4846     this.addEvents({
4847         // raw events
4848         /**
4849          * @event click
4850          * When a element is chick
4851          * @param {Roo.bootstrap.Element} this
4852          * @param {Roo.EventObject} e
4853          */
4854         "click" : true
4855     });
4856 };
4857
4858 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4859     
4860     tag: 'div',
4861     cls: '',
4862     html: '',
4863     preventDefault: false, 
4864     clickable: false,
4865     
4866     getAutoCreate : function(){
4867         
4868         var cfg = {
4869             tag: this.tag,
4870             cls: this.cls,
4871             html: this.html
4872         };
4873         
4874         return cfg;
4875     },
4876     
4877     initEvents: function() 
4878     {
4879         Roo.bootstrap.Element.superclass.initEvents.call(this);
4880         
4881         if(this.clickable){
4882             this.el.on('click', this.onClick, this);
4883         }
4884         
4885     },
4886     
4887     onClick : function(e)
4888     {
4889         if(this.preventDefault){
4890             e.preventDefault();
4891         }
4892         
4893         this.fireEvent('click', this, e);
4894     },
4895     
4896     getValue : function()
4897     {
4898         return this.el.dom.innerHTML;
4899     },
4900     
4901     setValue : function(value)
4902     {
4903         this.el.dom.innerHTML = value;
4904     }
4905    
4906 });
4907
4908  
4909
4910  /*
4911  * - LGPL
4912  *
4913  * pagination
4914  * 
4915  */
4916
4917 /**
4918  * @class Roo.bootstrap.Pagination
4919  * @extends Roo.bootstrap.Component
4920  * Bootstrap Pagination class
4921  * @cfg {String} size xs | sm | md | lg
4922  * @cfg {Boolean} inverse false | true
4923  * 
4924  * @constructor
4925  * Create a new Pagination
4926  * @param {Object} config The config object
4927  */
4928
4929 Roo.bootstrap.Pagination = function(config){
4930     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4931 };
4932
4933 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
4934     
4935     cls: false,
4936     size: false,
4937     inverse: false,
4938     
4939     getAutoCreate : function(){
4940         var cfg = {
4941             tag: 'ul',
4942                 cls: 'pagination'
4943         };
4944         if (this.inverse) {
4945             cfg.cls += ' inverse';
4946         }
4947         if (this.html) {
4948             cfg.html=this.html;
4949         }
4950         if (this.cls) {
4951             cfg.cls += " " + this.cls;
4952         }
4953         return cfg;
4954     }
4955    
4956 });
4957
4958  
4959
4960  /*
4961  * - LGPL
4962  *
4963  * Pagination item
4964  * 
4965  */
4966
4967
4968 /**
4969  * @class Roo.bootstrap.PaginationItem
4970  * @extends Roo.bootstrap.Component
4971  * Bootstrap PaginationItem class
4972  * @cfg {String} html text
4973  * @cfg {String} href the link
4974  * @cfg {Boolean} preventDefault (true | false) default true
4975  * @cfg {Boolean} active (true | false) default false
4976  * @cfg {Boolean} disabled default false
4977  * 
4978  * 
4979  * @constructor
4980  * Create a new PaginationItem
4981  * @param {Object} config The config object
4982  */
4983
4984
4985 Roo.bootstrap.PaginationItem = function(config){
4986     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4987     this.addEvents({
4988         // raw events
4989         /**
4990          * @event click
4991          * The raw click event for the entire grid.
4992          * @param {Roo.EventObject} e
4993          */
4994         "click" : true
4995     });
4996 };
4997
4998 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
4999     
5000     href : false,
5001     html : false,
5002     preventDefault: true,
5003     active : false,
5004     cls : false,
5005     disabled: false,
5006     
5007     getAutoCreate : function(){
5008         var cfg= {
5009             tag: 'li',
5010             cn: [
5011                 {
5012                     tag : 'a',
5013                     href : this.href ? this.href : '#',
5014                     html : this.html ? this.html : ''
5015                 }
5016             ]
5017         };
5018         
5019         if(this.cls){
5020             cfg.cls = this.cls;
5021         }
5022         
5023         if(this.disabled){
5024             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5025         }
5026         
5027         if(this.active){
5028             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5029         }
5030         
5031         return cfg;
5032     },
5033     
5034     initEvents: function() {
5035         
5036         this.el.on('click', this.onClick, this);
5037         
5038     },
5039     onClick : function(e)
5040     {
5041         Roo.log('PaginationItem on click ');
5042         if(this.preventDefault){
5043             e.preventDefault();
5044         }
5045         
5046         if(this.disabled){
5047             return;
5048         }
5049         
5050         this.fireEvent('click', this, e);
5051     }
5052    
5053 });
5054
5055  
5056
5057  /*
5058  * - LGPL
5059  *
5060  * slider
5061  * 
5062  */
5063
5064
5065 /**
5066  * @class Roo.bootstrap.Slider
5067  * @extends Roo.bootstrap.Component
5068  * Bootstrap Slider class
5069  *    
5070  * @constructor
5071  * Create a new Slider
5072  * @param {Object} config The config object
5073  */
5074
5075 Roo.bootstrap.Slider = function(config){
5076     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5077 };
5078
5079 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
5080     
5081     getAutoCreate : function(){
5082         
5083         var cfg = {
5084             tag: 'div',
5085             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5086             cn: [
5087                 {
5088                     tag: 'a',
5089                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
5090                 }
5091             ]
5092         };
5093         
5094         return cfg;
5095     }
5096    
5097 });
5098
5099  /*
5100  * Based on:
5101  * Ext JS Library 1.1.1
5102  * Copyright(c) 2006-2007, Ext JS, LLC.
5103  *
5104  * Originally Released Under LGPL - original licence link has changed is not relivant.
5105  *
5106  * Fork - LGPL
5107  * <script type="text/javascript">
5108  */
5109  
5110
5111 /**
5112  * @class Roo.grid.ColumnModel
5113  * @extends Roo.util.Observable
5114  * This is the default implementation of a ColumnModel used by the Grid. It defines
5115  * the columns in the grid.
5116  * <br>Usage:<br>
5117  <pre><code>
5118  var colModel = new Roo.grid.ColumnModel([
5119         {header: "Ticker", width: 60, sortable: true, locked: true},
5120         {header: "Company Name", width: 150, sortable: true},
5121         {header: "Market Cap.", width: 100, sortable: true},
5122         {header: "$ Sales", width: 100, sortable: true, renderer: money},
5123         {header: "Employees", width: 100, sortable: true, resizable: false}
5124  ]);
5125  </code></pre>
5126  * <p>
5127  
5128  * The config options listed for this class are options which may appear in each
5129  * individual column definition.
5130  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5131  * @constructor
5132  * @param {Object} config An Array of column config objects. See this class's
5133  * config objects for details.
5134 */
5135 Roo.grid.ColumnModel = function(config){
5136         /**
5137      * The config passed into the constructor
5138      */
5139     this.config = config;
5140     this.lookup = {};
5141
5142     // if no id, create one
5143     // if the column does not have a dataIndex mapping,
5144     // map it to the order it is in the config
5145     for(var i = 0, len = config.length; i < len; i++){
5146         var c = config[i];
5147         if(typeof c.dataIndex == "undefined"){
5148             c.dataIndex = i;
5149         }
5150         if(typeof c.renderer == "string"){
5151             c.renderer = Roo.util.Format[c.renderer];
5152         }
5153         if(typeof c.id == "undefined"){
5154             c.id = Roo.id();
5155         }
5156         if(c.editor && c.editor.xtype){
5157             c.editor  = Roo.factory(c.editor, Roo.grid);
5158         }
5159         if(c.editor && c.editor.isFormField){
5160             c.editor = new Roo.grid.GridEditor(c.editor);
5161         }
5162         this.lookup[c.id] = c;
5163     }
5164
5165     /**
5166      * The width of columns which have no width specified (defaults to 100)
5167      * @type Number
5168      */
5169     this.defaultWidth = 100;
5170
5171     /**
5172      * Default sortable of columns which have no sortable specified (defaults to false)
5173      * @type Boolean
5174      */
5175     this.defaultSortable = false;
5176
5177     this.addEvents({
5178         /**
5179              * @event widthchange
5180              * Fires when the width of a column changes.
5181              * @param {ColumnModel} this
5182              * @param {Number} columnIndex The column index
5183              * @param {Number} newWidth The new width
5184              */
5185             "widthchange": true,
5186         /**
5187              * @event headerchange
5188              * Fires when the text of a header changes.
5189              * @param {ColumnModel} this
5190              * @param {Number} columnIndex The column index
5191              * @param {Number} newText The new header text
5192              */
5193             "headerchange": true,
5194         /**
5195              * @event hiddenchange
5196              * Fires when a column is hidden or "unhidden".
5197              * @param {ColumnModel} this
5198              * @param {Number} columnIndex The column index
5199              * @param {Boolean} hidden true if hidden, false otherwise
5200              */
5201             "hiddenchange": true,
5202             /**
5203          * @event columnmoved
5204          * Fires when a column is moved.
5205          * @param {ColumnModel} this
5206          * @param {Number} oldIndex
5207          * @param {Number} newIndex
5208          */
5209         "columnmoved" : true,
5210         /**
5211          * @event columlockchange
5212          * Fires when a column's locked state is changed
5213          * @param {ColumnModel} this
5214          * @param {Number} colIndex
5215          * @param {Boolean} locked true if locked
5216          */
5217         "columnlockchange" : true
5218     });
5219     Roo.grid.ColumnModel.superclass.constructor.call(this);
5220 };
5221 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5222     /**
5223      * @cfg {String} header The header text to display in the Grid view.
5224      */
5225     /**
5226      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5227      * {@link Roo.data.Record} definition from which to draw the column's value. If not
5228      * specified, the column's index is used as an index into the Record's data Array.
5229      */
5230     /**
5231      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5232      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5233      */
5234     /**
5235      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5236      * Defaults to the value of the {@link #defaultSortable} property.
5237      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5238      */
5239     /**
5240      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
5241      */
5242     /**
5243      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
5244      */
5245     /**
5246      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5247      */
5248     /**
5249      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5250      */
5251     /**
5252      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5253      * given the cell's data value. See {@link #setRenderer}. If not specified, the
5254      * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5255      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5256      */
5257        /**
5258      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
5259      */
5260     /**
5261      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
5262      */
5263     /**
5264      * @cfg {String} cursor (Optional)
5265      */
5266     /**
5267      * @cfg {String} tooltip (Optional)
5268      */
5269     /**
5270      * @cfg {Number} xs (Optional)
5271      */
5272     /**
5273      * @cfg {Number} sm (Optional)
5274      */
5275     /**
5276      * @cfg {Number} md (Optional)
5277      */
5278     /**
5279      * @cfg {Number} lg (Optional)
5280      */
5281     /**
5282      * Returns the id of the column at the specified index.
5283      * @param {Number} index The column index
5284      * @return {String} the id
5285      */
5286     getColumnId : function(index){
5287         return this.config[index].id;
5288     },
5289
5290     /**
5291      * Returns the column for a specified id.
5292      * @param {String} id The column id
5293      * @return {Object} the column
5294      */
5295     getColumnById : function(id){
5296         return this.lookup[id];
5297     },
5298
5299     
5300     /**
5301      * Returns the column for a specified dataIndex.
5302      * @param {String} dataIndex The column dataIndex
5303      * @return {Object|Boolean} the column or false if not found
5304      */
5305     getColumnByDataIndex: function(dataIndex){
5306         var index = this.findColumnIndex(dataIndex);
5307         return index > -1 ? this.config[index] : false;
5308     },
5309     
5310     /**
5311      * Returns the index for a specified column id.
5312      * @param {String} id The column id
5313      * @return {Number} the index, or -1 if not found
5314      */
5315     getIndexById : function(id){
5316         for(var i = 0, len = this.config.length; i < len; i++){
5317             if(this.config[i].id == id){
5318                 return i;
5319             }
5320         }
5321         return -1;
5322     },
5323     
5324     /**
5325      * Returns the index for a specified column dataIndex.
5326      * @param {String} dataIndex The column dataIndex
5327      * @return {Number} the index, or -1 if not found
5328      */
5329     
5330     findColumnIndex : function(dataIndex){
5331         for(var i = 0, len = this.config.length; i < len; i++){
5332             if(this.config[i].dataIndex == dataIndex){
5333                 return i;
5334             }
5335         }
5336         return -1;
5337     },
5338     
5339     
5340     moveColumn : function(oldIndex, newIndex){
5341         var c = this.config[oldIndex];
5342         this.config.splice(oldIndex, 1);
5343         this.config.splice(newIndex, 0, c);
5344         this.dataMap = null;
5345         this.fireEvent("columnmoved", this, oldIndex, newIndex);
5346     },
5347
5348     isLocked : function(colIndex){
5349         return this.config[colIndex].locked === true;
5350     },
5351
5352     setLocked : function(colIndex, value, suppressEvent){
5353         if(this.isLocked(colIndex) == value){
5354             return;
5355         }
5356         this.config[colIndex].locked = value;
5357         if(!suppressEvent){
5358             this.fireEvent("columnlockchange", this, colIndex, value);
5359         }
5360     },
5361
5362     getTotalLockedWidth : function(){
5363         var totalWidth = 0;
5364         for(var i = 0; i < this.config.length; i++){
5365             if(this.isLocked(i) && !this.isHidden(i)){
5366                 this.totalWidth += this.getColumnWidth(i);
5367             }
5368         }
5369         return totalWidth;
5370     },
5371
5372     getLockedCount : function(){
5373         for(var i = 0, len = this.config.length; i < len; i++){
5374             if(!this.isLocked(i)){
5375                 return i;
5376             }
5377         }
5378         
5379         return this.config.length;
5380     },
5381
5382     /**
5383      * Returns the number of columns.
5384      * @return {Number}
5385      */
5386     getColumnCount : function(visibleOnly){
5387         if(visibleOnly === true){
5388             var c = 0;
5389             for(var i = 0, len = this.config.length; i < len; i++){
5390                 if(!this.isHidden(i)){
5391                     c++;
5392                 }
5393             }
5394             return c;
5395         }
5396         return this.config.length;
5397     },
5398
5399     /**
5400      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5401      * @param {Function} fn
5402      * @param {Object} scope (optional)
5403      * @return {Array} result
5404      */
5405     getColumnsBy : function(fn, scope){
5406         var r = [];
5407         for(var i = 0, len = this.config.length; i < len; i++){
5408             var c = this.config[i];
5409             if(fn.call(scope||this, c, i) === true){
5410                 r[r.length] = c;
5411             }
5412         }
5413         return r;
5414     },
5415
5416     /**
5417      * Returns true if the specified column is sortable.
5418      * @param {Number} col The column index
5419      * @return {Boolean}
5420      */
5421     isSortable : function(col){
5422         if(typeof this.config[col].sortable == "undefined"){
5423             return this.defaultSortable;
5424         }
5425         return this.config[col].sortable;
5426     },
5427
5428     /**
5429      * Returns the rendering (formatting) function defined for the column.
5430      * @param {Number} col The column index.
5431      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5432      */
5433     getRenderer : function(col){
5434         if(!this.config[col].renderer){
5435             return Roo.grid.ColumnModel.defaultRenderer;
5436         }
5437         return this.config[col].renderer;
5438     },
5439
5440     /**
5441      * Sets the rendering (formatting) function for a column.
5442      * @param {Number} col The column index
5443      * @param {Function} fn The function to use to process the cell's raw data
5444      * to return HTML markup for the grid view. The render function is called with
5445      * the following parameters:<ul>
5446      * <li>Data value.</li>
5447      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5448      * <li>css A CSS style string to apply to the table cell.</li>
5449      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5450      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5451      * <li>Row index</li>
5452      * <li>Column index</li>
5453      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5454      */
5455     setRenderer : function(col, fn){
5456         this.config[col].renderer = fn;
5457     },
5458
5459     /**
5460      * Returns the width for the specified column.
5461      * @param {Number} col The column index
5462      * @return {Number}
5463      */
5464     getColumnWidth : function(col){
5465         return this.config[col].width * 1 || this.defaultWidth;
5466     },
5467
5468     /**
5469      * Sets the width for a column.
5470      * @param {Number} col The column index
5471      * @param {Number} width The new width
5472      */
5473     setColumnWidth : function(col, width, suppressEvent){
5474         this.config[col].width = width;
5475         this.totalWidth = null;
5476         if(!suppressEvent){
5477              this.fireEvent("widthchange", this, col, width);
5478         }
5479     },
5480
5481     /**
5482      * Returns the total width of all columns.
5483      * @param {Boolean} includeHidden True to include hidden column widths
5484      * @return {Number}
5485      */
5486     getTotalWidth : function(includeHidden){
5487         if(!this.totalWidth){
5488             this.totalWidth = 0;
5489             for(var i = 0, len = this.config.length; i < len; i++){
5490                 if(includeHidden || !this.isHidden(i)){
5491                     this.totalWidth += this.getColumnWidth(i);
5492                 }
5493             }
5494         }
5495         return this.totalWidth;
5496     },
5497
5498     /**
5499      * Returns the header for the specified column.
5500      * @param {Number} col The column index
5501      * @return {String}
5502      */
5503     getColumnHeader : function(col){
5504         return this.config[col].header;
5505     },
5506
5507     /**
5508      * Sets the header for a column.
5509      * @param {Number} col The column index
5510      * @param {String} header The new header
5511      */
5512     setColumnHeader : function(col, header){
5513         this.config[col].header = header;
5514         this.fireEvent("headerchange", this, col, header);
5515     },
5516
5517     /**
5518      * Returns the tooltip for the specified column.
5519      * @param {Number} col The column index
5520      * @return {String}
5521      */
5522     getColumnTooltip : function(col){
5523             return this.config[col].tooltip;
5524     },
5525     /**
5526      * Sets the tooltip for a column.
5527      * @param {Number} col The column index
5528      * @param {String} tooltip The new tooltip
5529      */
5530     setColumnTooltip : function(col, tooltip){
5531             this.config[col].tooltip = tooltip;
5532     },
5533
5534     /**
5535      * Returns the dataIndex for the specified column.
5536      * @param {Number} col The column index
5537      * @return {Number}
5538      */
5539     getDataIndex : function(col){
5540         return this.config[col].dataIndex;
5541     },
5542
5543     /**
5544      * Sets the dataIndex for a column.
5545      * @param {Number} col The column index
5546      * @param {Number} dataIndex The new dataIndex
5547      */
5548     setDataIndex : function(col, dataIndex){
5549         this.config[col].dataIndex = dataIndex;
5550     },
5551
5552     
5553     
5554     /**
5555      * Returns true if the cell is editable.
5556      * @param {Number} colIndex The column index
5557      * @param {Number} rowIndex The row index - this is nto actually used..?
5558      * @return {Boolean}
5559      */
5560     isCellEditable : function(colIndex, rowIndex){
5561         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5562     },
5563
5564     /**
5565      * Returns the editor defined for the cell/column.
5566      * return false or null to disable editing.
5567      * @param {Number} colIndex The column index
5568      * @param {Number} rowIndex The row index
5569      * @return {Object}
5570      */
5571     getCellEditor : function(colIndex, rowIndex){
5572         return this.config[colIndex].editor;
5573     },
5574
5575     /**
5576      * Sets if a column is editable.
5577      * @param {Number} col The column index
5578      * @param {Boolean} editable True if the column is editable
5579      */
5580     setEditable : function(col, editable){
5581         this.config[col].editable = editable;
5582     },
5583
5584
5585     /**
5586      * Returns true if the column is hidden.
5587      * @param {Number} colIndex The column index
5588      * @return {Boolean}
5589      */
5590     isHidden : function(colIndex){
5591         return this.config[colIndex].hidden;
5592     },
5593
5594
5595     /**
5596      * Returns true if the column width cannot be changed
5597      */
5598     isFixed : function(colIndex){
5599         return this.config[colIndex].fixed;
5600     },
5601
5602     /**
5603      * Returns true if the column can be resized
5604      * @return {Boolean}
5605      */
5606     isResizable : function(colIndex){
5607         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5608     },
5609     /**
5610      * Sets if a column is hidden.
5611      * @param {Number} colIndex The column index
5612      * @param {Boolean} hidden True if the column is hidden
5613      */
5614     setHidden : function(colIndex, hidden){
5615         this.config[colIndex].hidden = hidden;
5616         this.totalWidth = null;
5617         this.fireEvent("hiddenchange", this, colIndex, hidden);
5618     },
5619
5620     /**
5621      * Sets the editor for a column.
5622      * @param {Number} col The column index
5623      * @param {Object} editor The editor object
5624      */
5625     setEditor : function(col, editor){
5626         this.config[col].editor = editor;
5627     }
5628 });
5629
5630 Roo.grid.ColumnModel.defaultRenderer = function(value)
5631 {
5632     if(typeof value == "object") {
5633         return value;
5634     }
5635         if(typeof value == "string" && value.length < 1){
5636             return "&#160;";
5637         }
5638     
5639         return String.format("{0}", value);
5640 };
5641
5642 // Alias for backwards compatibility
5643 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5644 /*
5645  * Based on:
5646  * Ext JS Library 1.1.1
5647  * Copyright(c) 2006-2007, Ext JS, LLC.
5648  *
5649  * Originally Released Under LGPL - original licence link has changed is not relivant.
5650  *
5651  * Fork - LGPL
5652  * <script type="text/javascript">
5653  */
5654  
5655 /**
5656  * @class Roo.LoadMask
5657  * A simple utility class for generically masking elements while loading data.  If the element being masked has
5658  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5659  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
5660  * element's UpdateManager load indicator and will be destroyed after the initial load.
5661  * @constructor
5662  * Create a new LoadMask
5663  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5664  * @param {Object} config The config object
5665  */
5666 Roo.LoadMask = function(el, config){
5667     this.el = Roo.get(el);
5668     Roo.apply(this, config);
5669     if(this.store){
5670         this.store.on('beforeload', this.onBeforeLoad, this);
5671         this.store.on('load', this.onLoad, this);
5672         this.store.on('loadexception', this.onLoadException, this);
5673         this.removeMask = false;
5674     }else{
5675         var um = this.el.getUpdateManager();
5676         um.showLoadIndicator = false; // disable the default indicator
5677         um.on('beforeupdate', this.onBeforeLoad, this);
5678         um.on('update', this.onLoad, this);
5679         um.on('failure', this.onLoad, this);
5680         this.removeMask = true;
5681     }
5682 };
5683
5684 Roo.LoadMask.prototype = {
5685     /**
5686      * @cfg {Boolean} removeMask
5687      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5688      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
5689      */
5690     /**
5691      * @cfg {String} msg
5692      * The text to display in a centered loading message box (defaults to 'Loading...')
5693      */
5694     msg : 'Loading...',
5695     /**
5696      * @cfg {String} msgCls
5697      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5698      */
5699     msgCls : 'x-mask-loading',
5700
5701     /**
5702      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5703      * @type Boolean
5704      */
5705     disabled: false,
5706
5707     /**
5708      * Disables the mask to prevent it from being displayed
5709      */
5710     disable : function(){
5711        this.disabled = true;
5712     },
5713
5714     /**
5715      * Enables the mask so that it can be displayed
5716      */
5717     enable : function(){
5718         this.disabled = false;
5719     },
5720     
5721     onLoadException : function()
5722     {
5723         Roo.log(arguments);
5724         
5725         if (typeof(arguments[3]) != 'undefined') {
5726             Roo.MessageBox.alert("Error loading",arguments[3]);
5727         } 
5728         /*
5729         try {
5730             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5731                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5732             }   
5733         } catch(e) {
5734             
5735         }
5736         */
5737     
5738         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5739     },
5740     // private
5741     onLoad : function()
5742     {
5743         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5744     },
5745
5746     // private
5747     onBeforeLoad : function(){
5748         if(!this.disabled){
5749             (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5750         }
5751     },
5752
5753     // private
5754     destroy : function(){
5755         if(this.store){
5756             this.store.un('beforeload', this.onBeforeLoad, this);
5757             this.store.un('load', this.onLoad, this);
5758             this.store.un('loadexception', this.onLoadException, this);
5759         }else{
5760             var um = this.el.getUpdateManager();
5761             um.un('beforeupdate', this.onBeforeLoad, this);
5762             um.un('update', this.onLoad, this);
5763             um.un('failure', this.onLoad, this);
5764         }
5765     }
5766 };/*
5767  * - LGPL
5768  *
5769  * table
5770  * 
5771  */
5772
5773 /**
5774  * @class Roo.bootstrap.Table
5775  * @extends Roo.bootstrap.Component
5776  * Bootstrap Table class
5777  * @cfg {String} cls table class
5778  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5779  * @cfg {String} bgcolor Specifies the background color for a table
5780  * @cfg {Number} border Specifies whether the table cells should have borders or not
5781  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5782  * @cfg {Number} cellspacing Specifies the space between cells
5783  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5784  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5785  * @cfg {String} sortable Specifies that the table should be sortable
5786  * @cfg {String} summary Specifies a summary of the content of a table
5787  * @cfg {Number} width Specifies the width of a table
5788  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5789  * 
5790  * @cfg {boolean} striped Should the rows be alternative striped
5791  * @cfg {boolean} bordered Add borders to the table
5792  * @cfg {boolean} hover Add hover highlighting
5793  * @cfg {boolean} condensed Format condensed
5794  * @cfg {boolean} responsive Format condensed
5795  * @cfg {Boolean} loadMask (true|false) default false
5796  * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5797  * @cfg {Boolean} headerShow (true|false) generate thead, default true
5798  * @cfg {Boolean} rowSelection (true|false) default false
5799  * @cfg {Boolean} cellSelection (true|false) default false
5800  * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5801  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5802  * @cfg {Boolean} lazyLoad  auto load data while scrolling to the end (default false)
5803  
5804  * 
5805  * @constructor
5806  * Create a new Table
5807  * @param {Object} config The config object
5808  */
5809
5810 Roo.bootstrap.Table = function(config){
5811     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5812     
5813   
5814     
5815     // BC...
5816     this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5817     this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5818     this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5819     this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5820     
5821     this.sm = this.sm || {xtype: 'RowSelectionModel'};
5822     if (this.sm) {
5823         this.sm.grid = this;
5824         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5825         this.sm = this.selModel;
5826         this.sm.xmodule = this.xmodule || false;
5827     }
5828     
5829     if (this.cm && typeof(this.cm.config) == 'undefined') {
5830         this.colModel = new Roo.grid.ColumnModel(this.cm);
5831         this.cm = this.colModel;
5832         this.cm.xmodule = this.xmodule || false;
5833     }
5834     if (this.store) {
5835         this.store= Roo.factory(this.store, Roo.data);
5836         this.ds = this.store;
5837         this.ds.xmodule = this.xmodule || false;
5838          
5839     }
5840     if (this.footer && this.store) {
5841         this.footer.dataSource = this.ds;
5842         this.footer = Roo.factory(this.footer);
5843     }
5844     
5845     /** @private */
5846     this.addEvents({
5847         /**
5848          * @event cellclick
5849          * Fires when a cell is clicked
5850          * @param {Roo.bootstrap.Table} this
5851          * @param {Roo.Element} el
5852          * @param {Number} rowIndex
5853          * @param {Number} columnIndex
5854          * @param {Roo.EventObject} e
5855          */
5856         "cellclick" : true,
5857         /**
5858          * @event celldblclick
5859          * Fires when a cell is double clicked
5860          * @param {Roo.bootstrap.Table} this
5861          * @param {Roo.Element} el
5862          * @param {Number} rowIndex
5863          * @param {Number} columnIndex
5864          * @param {Roo.EventObject} e
5865          */
5866         "celldblclick" : true,
5867         /**
5868          * @event rowclick
5869          * Fires when a row is clicked
5870          * @param {Roo.bootstrap.Table} this
5871          * @param {Roo.Element} el
5872          * @param {Number} rowIndex
5873          * @param {Roo.EventObject} e
5874          */
5875         "rowclick" : true,
5876         /**
5877          * @event rowdblclick
5878          * Fires when a row is double clicked
5879          * @param {Roo.bootstrap.Table} this
5880          * @param {Roo.Element} el
5881          * @param {Number} rowIndex
5882          * @param {Roo.EventObject} e
5883          */
5884         "rowdblclick" : true,
5885         /**
5886          * @event mouseover
5887          * Fires when a mouseover occur
5888          * @param {Roo.bootstrap.Table} this
5889          * @param {Roo.Element} el
5890          * @param {Number} rowIndex
5891          * @param {Number} columnIndex
5892          * @param {Roo.EventObject} e
5893          */
5894         "mouseover" : true,
5895         /**
5896          * @event mouseout
5897          * Fires when a mouseout occur
5898          * @param {Roo.bootstrap.Table} this
5899          * @param {Roo.Element} el
5900          * @param {Number} rowIndex
5901          * @param {Number} columnIndex
5902          * @param {Roo.EventObject} e
5903          */
5904         "mouseout" : true,
5905         /**
5906          * @event rowclass
5907          * Fires when a row is rendered, so you can change add a style to it.
5908          * @param {Roo.bootstrap.Table} this
5909          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5910          */
5911         'rowclass' : true,
5912           /**
5913          * @event rowsrendered
5914          * Fires when all the  rows have been rendered
5915          * @param {Roo.bootstrap.Table} this
5916          */
5917         'rowsrendered' : true,
5918         /**
5919          * @event contextmenu
5920          * The raw contextmenu event for the entire grid.
5921          * @param {Roo.EventObject} e
5922          */
5923         "contextmenu" : true,
5924         /**
5925          * @event rowcontextmenu
5926          * Fires when a row is right clicked
5927          * @param {Roo.bootstrap.Table} this
5928          * @param {Number} rowIndex
5929          * @param {Roo.EventObject} e
5930          */
5931         "rowcontextmenu" : true,
5932         /**
5933          * @event cellcontextmenu
5934          * Fires when a cell is right clicked
5935          * @param {Roo.bootstrap.Table} this
5936          * @param {Number} rowIndex
5937          * @param {Number} cellIndex
5938          * @param {Roo.EventObject} e
5939          */
5940          "cellcontextmenu" : true,
5941          /**
5942          * @event headercontextmenu
5943          * Fires when a header is right clicked
5944          * @param {Roo.bootstrap.Table} this
5945          * @param {Number} columnIndex
5946          * @param {Roo.EventObject} e
5947          */
5948         "headercontextmenu" : true
5949     });
5950 };
5951
5952 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
5953     
5954     cls: false,
5955     align: false,
5956     bgcolor: false,
5957     border: false,
5958     cellpadding: false,
5959     cellspacing: false,
5960     frame: false,
5961     rules: false,
5962     sortable: false,
5963     summary: false,
5964     width: false,
5965     striped : false,
5966     scrollBody : false,
5967     bordered: false,
5968     hover:  false,
5969     condensed : false,
5970     responsive : false,
5971     sm : false,
5972     cm : false,
5973     store : false,
5974     loadMask : false,
5975     footerShow : true,
5976     headerShow : true,
5977   
5978     rowSelection : false,
5979     cellSelection : false,
5980     layout : false,
5981     
5982     // Roo.Element - the tbody
5983     mainBody: false,
5984     // Roo.Element - thead element
5985     mainHead: false,
5986     
5987     container: false, // used by gridpanel...
5988     
5989     lazyLoad : false,
5990     
5991     getAutoCreate : function()
5992     {
5993         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5994         
5995         cfg = {
5996             tag: 'table',
5997             cls : 'table',
5998             cn : []
5999         };
6000         if (this.scrollBody) {
6001             cfg.cls += ' table-body-fixed';
6002         }    
6003         if (this.striped) {
6004             cfg.cls += ' table-striped';
6005         }
6006         
6007         if (this.hover) {
6008             cfg.cls += ' table-hover';
6009         }
6010         if (this.bordered) {
6011             cfg.cls += ' table-bordered';
6012         }
6013         if (this.condensed) {
6014             cfg.cls += ' table-condensed';
6015         }
6016         if (this.responsive) {
6017             cfg.cls += ' table-responsive';
6018         }
6019         
6020         if (this.cls) {
6021             cfg.cls+=  ' ' +this.cls;
6022         }
6023         
6024         // this lot should be simplifed...
6025         
6026         if (this.align) {
6027             cfg.align=this.align;
6028         }
6029         if (this.bgcolor) {
6030             cfg.bgcolor=this.bgcolor;
6031         }
6032         if (this.border) {
6033             cfg.border=this.border;
6034         }
6035         if (this.cellpadding) {
6036             cfg.cellpadding=this.cellpadding;
6037         }
6038         if (this.cellspacing) {
6039             cfg.cellspacing=this.cellspacing;
6040         }
6041         if (this.frame) {
6042             cfg.frame=this.frame;
6043         }
6044         if (this.rules) {
6045             cfg.rules=this.rules;
6046         }
6047         if (this.sortable) {
6048             cfg.sortable=this.sortable;
6049         }
6050         if (this.summary) {
6051             cfg.summary=this.summary;
6052         }
6053         if (this.width) {
6054             cfg.width=this.width;
6055         }
6056         if (this.layout) {
6057             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6058         }
6059         
6060         if(this.store || this.cm){
6061             if(this.headerShow){
6062                 cfg.cn.push(this.renderHeader());
6063             }
6064             
6065             cfg.cn.push(this.renderBody());
6066             
6067             if(this.footerShow){
6068                 cfg.cn.push(this.renderFooter());
6069             }
6070             // where does this come from?
6071             //cfg.cls+=  ' TableGrid';
6072         }
6073         
6074         return { cn : [ cfg ] };
6075     },
6076     
6077     initEvents : function()
6078     {   
6079         if(!this.store || !this.cm){
6080             return;
6081         }
6082         if (this.selModel) {
6083             this.selModel.initEvents();
6084         }
6085         
6086         
6087         //Roo.log('initEvents with ds!!!!');
6088         
6089         this.mainBody = this.el.select('tbody', true).first();
6090         this.mainHead = this.el.select('thead', true).first();
6091         
6092         
6093         
6094         
6095         var _this = this;
6096         
6097         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6098             e.on('click', _this.sort, _this);
6099         });
6100         
6101         this.mainBody.on("click", this.onClick, this);
6102         this.mainBody.on("dblclick", this.onDblClick, this);
6103         
6104         // why is this done????? = it breaks dialogs??
6105         //this.parent().el.setStyle('position', 'relative');
6106         
6107         
6108         if (this.footer) {
6109             this.footer.parentId = this.id;
6110             this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6111             
6112             if(this.lazyLoad){
6113                 this.el.select('tfoot tr td').first().addClass('hide');
6114             }
6115         } 
6116         
6117         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6118         
6119         this.store.on('load', this.onLoad, this);
6120         this.store.on('beforeload', this.onBeforeLoad, this);
6121         this.store.on('update', this.onUpdate, this);
6122         this.store.on('add', this.onAdd, this);
6123         this.store.on("clear", this.clear, this);
6124         
6125         this.el.on("contextmenu", this.onContextMenu, this);
6126         
6127         this.mainBody.on('scroll', this.onBodyScroll, this);
6128         
6129         
6130     },
6131     
6132     onContextMenu : function(e, t)
6133     {
6134         this.processEvent("contextmenu", e);
6135     },
6136     
6137     processEvent : function(name, e)
6138     {
6139         if (name != 'touchstart' ) {
6140             this.fireEvent(name, e);    
6141         }
6142         
6143         var t = e.getTarget();
6144         
6145         var cell = Roo.get(t);
6146         
6147         if(!cell){
6148             return;
6149         }
6150         
6151         if(cell.findParent('tfoot', false, true)){
6152             return;
6153         }
6154         
6155         if(cell.findParent('thead', false, true)){
6156             
6157             if(e.getTarget().nodeName.toLowerCase() != 'th'){
6158                 cell = Roo.get(t).findParent('th', false, true);
6159                 if (!cell) {
6160                     Roo.log("failed to find th in thead?");
6161                     Roo.log(e.getTarget());
6162                     return;
6163                 }
6164             }
6165             
6166             var cellIndex = cell.dom.cellIndex;
6167             
6168             var ename = name == 'touchstart' ? 'click' : name;
6169             this.fireEvent("header" + ename, this, cellIndex, e);
6170             
6171             return;
6172         }
6173         
6174         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6175             cell = Roo.get(t).findParent('td', false, true);
6176             if (!cell) {
6177                 Roo.log("failed to find th in tbody?");
6178                 Roo.log(e.getTarget());
6179                 return;
6180             }
6181         }
6182         
6183         var row = cell.findParent('tr', false, true);
6184         var cellIndex = cell.dom.cellIndex;
6185         var rowIndex = row.dom.rowIndex - 1;
6186         
6187         if(row !== false){
6188             
6189             this.fireEvent("row" + name, this, rowIndex, e);
6190             
6191             if(cell !== false){
6192             
6193                 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6194             }
6195         }
6196         
6197     },
6198     
6199     onMouseover : function(e, el)
6200     {
6201         var cell = Roo.get(el);
6202         
6203         if(!cell){
6204             return;
6205         }
6206         
6207         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6208             cell = cell.findParent('td', false, true);
6209         }
6210         
6211         var row = cell.findParent('tr', false, true);
6212         var cellIndex = cell.dom.cellIndex;
6213         var rowIndex = row.dom.rowIndex - 1; // start from 0
6214         
6215         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6216         
6217     },
6218     
6219     onMouseout : function(e, el)
6220     {
6221         var cell = Roo.get(el);
6222         
6223         if(!cell){
6224             return;
6225         }
6226         
6227         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6228             cell = cell.findParent('td', false, true);
6229         }
6230         
6231         var row = cell.findParent('tr', false, true);
6232         var cellIndex = cell.dom.cellIndex;
6233         var rowIndex = row.dom.rowIndex - 1; // start from 0
6234         
6235         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6236         
6237     },
6238     
6239     onClick : function(e, el)
6240     {
6241         var cell = Roo.get(el);
6242         
6243         if(!cell || (!this.cellSelection && !this.rowSelection)){
6244             return;
6245         }
6246         
6247         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6248             cell = cell.findParent('td', false, true);
6249         }
6250         
6251         if(!cell || typeof(cell) == 'undefined'){
6252             return;
6253         }
6254         
6255         var row = cell.findParent('tr', false, true);
6256         
6257         if(!row || typeof(row) == 'undefined'){
6258             return;
6259         }
6260         
6261         var cellIndex = cell.dom.cellIndex;
6262         var rowIndex = this.getRowIndex(row);
6263         
6264         // why??? - should these not be based on SelectionModel?
6265         if(this.cellSelection){
6266             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6267         }
6268         
6269         if(this.rowSelection){
6270             this.fireEvent('rowclick', this, row, rowIndex, e);
6271         }
6272         
6273         
6274     },
6275         
6276     onDblClick : function(e,el)
6277     {
6278         var cell = Roo.get(el);
6279         
6280         if(!cell || (!this.cellSelection && !this.rowSelection)){
6281             return;
6282         }
6283         
6284         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6285             cell = cell.findParent('td', false, true);
6286         }
6287         
6288         if(!cell || typeof(cell) == 'undefined'){
6289             return;
6290         }
6291         
6292         var row = cell.findParent('tr', false, true);
6293         
6294         if(!row || typeof(row) == 'undefined'){
6295             return;
6296         }
6297         
6298         var cellIndex = cell.dom.cellIndex;
6299         var rowIndex = this.getRowIndex(row);
6300         
6301         if(this.cellSelection){
6302             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6303         }
6304         
6305         if(this.rowSelection){
6306             this.fireEvent('rowdblclick', this, row, rowIndex, e);
6307         }
6308     },
6309     
6310     sort : function(e,el)
6311     {
6312         var col = Roo.get(el);
6313         
6314         if(!col.hasClass('sortable')){
6315             return;
6316         }
6317         
6318         var sort = col.attr('sort');
6319         var dir = 'ASC';
6320         
6321         if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6322             dir = 'DESC';
6323         }
6324         
6325         this.store.sortInfo = {field : sort, direction : dir};
6326         
6327         if (this.footer) {
6328             Roo.log("calling footer first");
6329             this.footer.onClick('first');
6330         } else {
6331         
6332             this.store.load({ params : { start : 0 } });
6333         }
6334     },
6335     
6336     renderHeader : function()
6337     {
6338         var header = {
6339             tag: 'thead',
6340             cn : []
6341         };
6342         
6343         var cm = this.cm;
6344         this.totalWidth = 0;
6345         
6346         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6347             
6348             var config = cm.config[i];
6349             
6350             var c = {
6351                 tag: 'th',
6352                 style : '',
6353                 html: cm.getColumnHeader(i)
6354             };
6355             
6356             var hh = '';
6357             
6358             if(typeof(config.sortable) != 'undefined' && config.sortable){
6359                 c.cls = 'sortable';
6360                 c.html = '<i class="glyphicon"></i>' + c.html;
6361             }
6362             
6363             if(typeof(config.lgHeader) != 'undefined'){
6364                 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6365             }
6366             
6367             if(typeof(config.mdHeader) != 'undefined'){
6368                 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6369             }
6370             
6371             if(typeof(config.smHeader) != 'undefined'){
6372                 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6373             }
6374             
6375             if(typeof(config.xsHeader) != 'undefined'){
6376                 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6377             }
6378             
6379             if(hh.length){
6380                 c.html = hh;
6381             }
6382             
6383             if(typeof(config.tooltip) != 'undefined'){
6384                 c.tooltip = config.tooltip;
6385             }
6386             
6387             if(typeof(config.colspan) != 'undefined'){
6388                 c.colspan = config.colspan;
6389             }
6390             
6391             if(typeof(config.hidden) != 'undefined' && config.hidden){
6392                 c.style += ' display:none;';
6393             }
6394             
6395             if(typeof(config.dataIndex) != 'undefined'){
6396                 c.sort = config.dataIndex;
6397             }
6398             
6399            
6400             
6401             if(typeof(config.align) != 'undefined' && config.align.length){
6402                 c.style += ' text-align:' + config.align + ';';
6403             }
6404             
6405             if(typeof(config.width) != 'undefined'){
6406                 c.style += ' width:' + config.width + 'px;';
6407                 this.totalWidth += config.width;
6408             } else {
6409                 this.totalWidth += 100; // assume minimum of 100 per column?
6410             }
6411             
6412             if(typeof(config.cls) != 'undefined'){
6413                 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6414             }
6415             
6416             ['xs','sm','md','lg'].map(function(size){
6417                 
6418                 if(typeof(config[size]) == 'undefined'){
6419                     return;
6420                 }
6421                 
6422                 if (!config[size]) { // 0 = hidden
6423                     c.cls += ' hidden-' + size;
6424                     return;
6425                 }
6426                 
6427                 c.cls += ' col-' + size + '-' + config[size];
6428
6429             });
6430             
6431             header.cn.push(c)
6432         }
6433         
6434         return header;
6435     },
6436     
6437     renderBody : function()
6438     {
6439         var body = {
6440             tag: 'tbody',
6441             cn : [
6442                 {
6443                     tag: 'tr',
6444                     cn : [
6445                         {
6446                             tag : 'td',
6447                             colspan :  this.cm.getColumnCount()
6448                         }
6449                     ]
6450                 }
6451             ]
6452         };
6453         
6454         return body;
6455     },
6456     
6457     renderFooter : function()
6458     {
6459         var footer = {
6460             tag: 'tfoot',
6461             cn : [
6462                 {
6463                     tag: 'tr',
6464                     cn : [
6465                         {
6466                             tag : 'td',
6467                             colspan :  this.cm.getColumnCount()
6468                         }
6469                     ]
6470                 }
6471             ]
6472         };
6473         
6474         return footer;
6475     },
6476     
6477     
6478     
6479     onLoad : function()
6480     {
6481 //        Roo.log('ds onload');
6482         this.clear();
6483         
6484         var _this = this;
6485         var cm = this.cm;
6486         var ds = this.store;
6487         
6488         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6489             e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6490             if (_this.store.sortInfo) {
6491                     
6492                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6493                     e.select('i', true).addClass(['glyphicon-arrow-up']);
6494                 }
6495                 
6496                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6497                     e.select('i', true).addClass(['glyphicon-arrow-down']);
6498                 }
6499             }
6500         });
6501         
6502         var tbody =  this.mainBody;
6503               
6504         if(ds.getCount() > 0){
6505             ds.data.each(function(d,rowIndex){
6506                 var row =  this.renderRow(cm, ds, rowIndex);
6507                 
6508                 tbody.createChild(row);
6509                 
6510                 var _this = this;
6511                 
6512                 if(row.cellObjects.length){
6513                     Roo.each(row.cellObjects, function(r){
6514                         _this.renderCellObject(r);
6515                     })
6516                 }
6517                 
6518             }, this);
6519         }
6520         
6521         Roo.each(this.el.select('tbody td', true).elements, function(e){
6522             e.on('mouseover', _this.onMouseover, _this);
6523         });
6524         
6525         Roo.each(this.el.select('tbody td', true).elements, function(e){
6526             e.on('mouseout', _this.onMouseout, _this);
6527         });
6528         this.fireEvent('rowsrendered', this);
6529         //if(this.loadMask){
6530         //    this.maskEl.hide();
6531         //}
6532         
6533         this.autoSize();
6534     },
6535     
6536     
6537     onUpdate : function(ds,record)
6538     {
6539         this.refreshRow(record);
6540         this.autoSize();
6541     },
6542     
6543     onRemove : function(ds, record, index, isUpdate){
6544         if(isUpdate !== true){
6545             this.fireEvent("beforerowremoved", this, index, record);
6546         }
6547         var bt = this.mainBody.dom;
6548         
6549         var rows = this.el.select('tbody > tr', true).elements;
6550         
6551         if(typeof(rows[index]) != 'undefined'){
6552             bt.removeChild(rows[index].dom);
6553         }
6554         
6555 //        if(bt.rows[index]){
6556 //            bt.removeChild(bt.rows[index]);
6557 //        }
6558         
6559         if(isUpdate !== true){
6560             //this.stripeRows(index);
6561             //this.syncRowHeights(index, index);
6562             //this.layout();
6563             this.fireEvent("rowremoved", this, index, record);
6564         }
6565     },
6566     
6567     onAdd : function(ds, records, rowIndex)
6568     {
6569         //Roo.log('on Add called');
6570         // - note this does not handle multiple adding very well..
6571         var bt = this.mainBody.dom;
6572         for (var i =0 ; i < records.length;i++) {
6573             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6574             //Roo.log(records[i]);
6575             //Roo.log(this.store.getAt(rowIndex+i));
6576             this.insertRow(this.store, rowIndex + i, false);
6577             return;
6578         }
6579         
6580     },
6581     
6582     
6583     refreshRow : function(record){
6584         var ds = this.store, index;
6585         if(typeof record == 'number'){
6586             index = record;
6587             record = ds.getAt(index);
6588         }else{
6589             index = ds.indexOf(record);
6590         }
6591         this.insertRow(ds, index, true);
6592         this.autoSize();
6593         this.onRemove(ds, record, index+1, true);
6594         this.autoSize();
6595         //this.syncRowHeights(index, index);
6596         //this.layout();
6597         this.fireEvent("rowupdated", this, index, record);
6598     },
6599     
6600     insertRow : function(dm, rowIndex, isUpdate){
6601         
6602         if(!isUpdate){
6603             this.fireEvent("beforerowsinserted", this, rowIndex);
6604         }
6605             //var s = this.getScrollState();
6606         var row = this.renderRow(this.cm, this.store, rowIndex);
6607         // insert before rowIndex..
6608         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6609         
6610         var _this = this;
6611                 
6612         if(row.cellObjects.length){
6613             Roo.each(row.cellObjects, function(r){
6614                 _this.renderCellObject(r);
6615             })
6616         }
6617             
6618         if(!isUpdate){
6619             this.fireEvent("rowsinserted", this, rowIndex);
6620             //this.syncRowHeights(firstRow, lastRow);
6621             //this.stripeRows(firstRow);
6622             //this.layout();
6623         }
6624         
6625     },
6626     
6627     
6628     getRowDom : function(rowIndex)
6629     {
6630         var rows = this.el.select('tbody > tr', true).elements;
6631         
6632         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6633         
6634     },
6635     // returns the object tree for a tr..
6636   
6637     
6638     renderRow : function(cm, ds, rowIndex) 
6639     {
6640         
6641         var d = ds.getAt(rowIndex);
6642         
6643         var row = {
6644             tag : 'tr',
6645             cn : []
6646         };
6647             
6648         var cellObjects = [];
6649         
6650         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6651             var config = cm.config[i];
6652             
6653             var renderer = cm.getRenderer(i);
6654             var value = '';
6655             var id = false;
6656             
6657             if(typeof(renderer) !== 'undefined'){
6658                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6659             }
6660             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6661             // and are rendered into the cells after the row is rendered - using the id for the element.
6662             
6663             if(typeof(value) === 'object'){
6664                 id = Roo.id();
6665                 cellObjects.push({
6666                     container : id,
6667                     cfg : value 
6668                 })
6669             }
6670             
6671             var rowcfg = {
6672                 record: d,
6673                 rowIndex : rowIndex,
6674                 colIndex : i,
6675                 rowClass : ''
6676             };
6677
6678             this.fireEvent('rowclass', this, rowcfg);
6679             
6680             var td = {
6681                 tag: 'td',
6682                 cls : rowcfg.rowClass,
6683                 style: '',
6684                 html: (typeof(value) === 'object') ? '' : value
6685             };
6686             
6687             if (id) {
6688                 td.id = id;
6689             }
6690             
6691             if(typeof(config.colspan) != 'undefined'){
6692                 td.colspan = config.colspan;
6693             }
6694             
6695             if(typeof(config.hidden) != 'undefined' && config.hidden){
6696                 td.style += ' display:none;';
6697             }
6698             
6699             if(typeof(config.align) != 'undefined' && config.align.length){
6700                 td.style += ' text-align:' + config.align + ';';
6701             }
6702             
6703             if(typeof(config.width) != 'undefined'){
6704                 td.style += ' width:' +  config.width + 'px;';
6705             }
6706             
6707             if(typeof(config.cursor) != 'undefined'){
6708                 td.style += ' cursor:' +  config.cursor + ';';
6709             }
6710             
6711             if(typeof(config.cls) != 'undefined'){
6712                 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6713             }
6714             
6715             ['xs','sm','md','lg'].map(function(size){
6716                 
6717                 if(typeof(config[size]) == 'undefined'){
6718                     return;
6719                 }
6720                 
6721                 if (!config[size]) { // 0 = hidden
6722                     td.cls += ' hidden-' + size;
6723                     return;
6724                 }
6725                 
6726                 td.cls += ' col-' + size + '-' + config[size];
6727
6728             });
6729              
6730             row.cn.push(td);
6731            
6732         }
6733         
6734         row.cellObjects = cellObjects;
6735         
6736         return row;
6737           
6738     },
6739     
6740     
6741     
6742     onBeforeLoad : function()
6743     {
6744         //Roo.log('ds onBeforeLoad');
6745         
6746         //this.clear();
6747         
6748         //if(this.loadMask){
6749         //    this.maskEl.show();
6750         //}
6751     },
6752      /**
6753      * Remove all rows
6754      */
6755     clear : function()
6756     {
6757         this.el.select('tbody', true).first().dom.innerHTML = '';
6758     },
6759     /**
6760      * Show or hide a row.
6761      * @param {Number} rowIndex to show or hide
6762      * @param {Boolean} state hide
6763      */
6764     setRowVisibility : function(rowIndex, state)
6765     {
6766         var bt = this.mainBody.dom;
6767         
6768         var rows = this.el.select('tbody > tr', true).elements;
6769         
6770         if(typeof(rows[rowIndex]) == 'undefined'){
6771             return;
6772         }
6773         rows[rowIndex].dom.style.display = state ? '' : 'none';
6774     },
6775     
6776     
6777     getSelectionModel : function(){
6778         if(!this.selModel){
6779             this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6780         }
6781         return this.selModel;
6782     },
6783     /*
6784      * Render the Roo.bootstrap object from renderder
6785      */
6786     renderCellObject : function(r)
6787     {
6788         var _this = this;
6789         
6790         r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6791         
6792         var t = r.cfg.render(r.container);
6793         
6794         if(r.cfg.cn){
6795             Roo.each(r.cfg.cn, function(c){
6796                 var child = {
6797                     container: t.getChildContainer(),
6798                     cfg: c
6799                 };
6800                 _this.renderCellObject(child);
6801             })
6802         }
6803     },
6804     
6805     getRowIndex : function(row)
6806     {
6807         var rowIndex = -1;
6808         
6809         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6810             if(el != row){
6811                 return;
6812             }
6813             
6814             rowIndex = index;
6815         });
6816         
6817         return rowIndex;
6818     },
6819      /**
6820      * Returns the grid's underlying element = used by panel.Grid
6821      * @return {Element} The element
6822      */
6823     getGridEl : function(){
6824         return this.el;
6825     },
6826      /**
6827      * Forces a resize - used by panel.Grid
6828      * @return {Element} The element
6829      */
6830     autoSize : function()
6831     {
6832         //var ctr = Roo.get(this.container.dom.parentElement);
6833         var ctr = Roo.get(this.el.dom);
6834         
6835         var thd = this.getGridEl().select('thead',true).first();
6836         var tbd = this.getGridEl().select('tbody', true).first();
6837         var tfd = this.getGridEl().select('tfoot', true).first();
6838         
6839         var cw = ctr.getWidth();
6840         
6841         if (tbd) {
6842             
6843             tbd.setSize(ctr.getWidth(),
6844                         ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6845             );
6846             var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6847             cw -= barsize;
6848         }
6849         cw = Math.max(cw, this.totalWidth);
6850         this.getGridEl().select('tr',true).setWidth(cw);
6851         // resize 'expandable coloumn?
6852         
6853         return; // we doe not have a view in this design..
6854         
6855     },
6856     onBodyScroll: function()
6857     {
6858         //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6859         this.mainHead.setStyle({
6860             'position' : 'relative',
6861             'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6862         });
6863         
6864         if(this.lazyLoad){
6865             
6866             var scrollHeight = this.mainBody.dom.scrollHeight;
6867             
6868             var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6869             
6870             var height = this.mainBody.getHeight();
6871             
6872             if(scrollHeight - height == scrollTop) {
6873                 
6874                 var total = this.ds.getTotalCount();
6875                 
6876                 if(this.footer.cursor + this.footer.pageSize < total){
6877                     
6878                     this.footer.ds.load({
6879                         params : {
6880                             start : this.footer.cursor + this.footer.pageSize,
6881                             limit : this.footer.pageSize
6882                         },
6883                         add : true
6884                     });
6885                 }
6886             }
6887             
6888         }
6889     }
6890 });
6891
6892  
6893
6894  /*
6895  * - LGPL
6896  *
6897  * table cell
6898  * 
6899  */
6900
6901 /**
6902  * @class Roo.bootstrap.TableCell
6903  * @extends Roo.bootstrap.Component
6904  * Bootstrap TableCell class
6905  * @cfg {String} html cell contain text
6906  * @cfg {String} cls cell class
6907  * @cfg {String} tag cell tag (td|th) default td
6908  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6909  * @cfg {String} align Aligns the content in a cell
6910  * @cfg {String} axis Categorizes cells
6911  * @cfg {String} bgcolor Specifies the background color of a cell
6912  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6913  * @cfg {Number} colspan Specifies the number of columns a cell should span
6914  * @cfg {String} headers Specifies one or more header cells a cell is related to
6915  * @cfg {Number} height Sets the height of a cell
6916  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6917  * @cfg {Number} rowspan Sets the number of rows a cell should span
6918  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6919  * @cfg {String} valign Vertical aligns the content in a cell
6920  * @cfg {Number} width Specifies the width of a cell
6921  * 
6922  * @constructor
6923  * Create a new TableCell
6924  * @param {Object} config The config object
6925  */
6926
6927 Roo.bootstrap.TableCell = function(config){
6928     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6929 };
6930
6931 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
6932     
6933     html: false,
6934     cls: false,
6935     tag: false,
6936     abbr: false,
6937     align: false,
6938     axis: false,
6939     bgcolor: false,
6940     charoff: false,
6941     colspan: false,
6942     headers: false,
6943     height: false,
6944     nowrap: false,
6945     rowspan: false,
6946     scope: false,
6947     valign: false,
6948     width: false,
6949     
6950     
6951     getAutoCreate : function(){
6952         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6953         
6954         cfg = {
6955             tag: 'td'
6956         };
6957         
6958         if(this.tag){
6959             cfg.tag = this.tag;
6960         }
6961         
6962         if (this.html) {
6963             cfg.html=this.html
6964         }
6965         if (this.cls) {
6966             cfg.cls=this.cls
6967         }
6968         if (this.abbr) {
6969             cfg.abbr=this.abbr
6970         }
6971         if (this.align) {
6972             cfg.align=this.align
6973         }
6974         if (this.axis) {
6975             cfg.axis=this.axis
6976         }
6977         if (this.bgcolor) {
6978             cfg.bgcolor=this.bgcolor
6979         }
6980         if (this.charoff) {
6981             cfg.charoff=this.charoff
6982         }
6983         if (this.colspan) {
6984             cfg.colspan=this.colspan
6985         }
6986         if (this.headers) {
6987             cfg.headers=this.headers
6988         }
6989         if (this.height) {
6990             cfg.height=this.height
6991         }
6992         if (this.nowrap) {
6993             cfg.nowrap=this.nowrap
6994         }
6995         if (this.rowspan) {
6996             cfg.rowspan=this.rowspan
6997         }
6998         if (this.scope) {
6999             cfg.scope=this.scope
7000         }
7001         if (this.valign) {
7002             cfg.valign=this.valign
7003         }
7004         if (this.width) {
7005             cfg.width=this.width
7006         }
7007         
7008         
7009         return cfg;
7010     }
7011    
7012 });
7013
7014  
7015
7016  /*
7017  * - LGPL
7018  *
7019  * table row
7020  * 
7021  */
7022
7023 /**
7024  * @class Roo.bootstrap.TableRow
7025  * @extends Roo.bootstrap.Component
7026  * Bootstrap TableRow class
7027  * @cfg {String} cls row class
7028  * @cfg {String} align Aligns the content in a table row
7029  * @cfg {String} bgcolor Specifies a background color for a table row
7030  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7031  * @cfg {String} valign Vertical aligns the content in a table row
7032  * 
7033  * @constructor
7034  * Create a new TableRow
7035  * @param {Object} config The config object
7036  */
7037
7038 Roo.bootstrap.TableRow = function(config){
7039     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7040 };
7041
7042 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
7043     
7044     cls: false,
7045     align: false,
7046     bgcolor: false,
7047     charoff: false,
7048     valign: false,
7049     
7050     getAutoCreate : function(){
7051         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7052         
7053         cfg = {
7054             tag: 'tr'
7055         };
7056             
7057         if(this.cls){
7058             cfg.cls = this.cls;
7059         }
7060         if(this.align){
7061             cfg.align = this.align;
7062         }
7063         if(this.bgcolor){
7064             cfg.bgcolor = this.bgcolor;
7065         }
7066         if(this.charoff){
7067             cfg.charoff = this.charoff;
7068         }
7069         if(this.valign){
7070             cfg.valign = this.valign;
7071         }
7072         
7073         return cfg;
7074     }
7075    
7076 });
7077
7078  
7079
7080  /*
7081  * - LGPL
7082  *
7083  * table body
7084  * 
7085  */
7086
7087 /**
7088  * @class Roo.bootstrap.TableBody
7089  * @extends Roo.bootstrap.Component
7090  * Bootstrap TableBody class
7091  * @cfg {String} cls element class
7092  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7093  * @cfg {String} align Aligns the content inside the element
7094  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7095  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7096  * 
7097  * @constructor
7098  * Create a new TableBody
7099  * @param {Object} config The config object
7100  */
7101
7102 Roo.bootstrap.TableBody = function(config){
7103     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7104 };
7105
7106 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
7107     
7108     cls: false,
7109     tag: false,
7110     align: false,
7111     charoff: false,
7112     valign: false,
7113     
7114     getAutoCreate : function(){
7115         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7116         
7117         cfg = {
7118             tag: 'tbody'
7119         };
7120             
7121         if (this.cls) {
7122             cfg.cls=this.cls
7123         }
7124         if(this.tag){
7125             cfg.tag = this.tag;
7126         }
7127         
7128         if(this.align){
7129             cfg.align = this.align;
7130         }
7131         if(this.charoff){
7132             cfg.charoff = this.charoff;
7133         }
7134         if(this.valign){
7135             cfg.valign = this.valign;
7136         }
7137         
7138         return cfg;
7139     }
7140     
7141     
7142 //    initEvents : function()
7143 //    {
7144 //        
7145 //        if(!this.store){
7146 //            return;
7147 //        }
7148 //        
7149 //        this.store = Roo.factory(this.store, Roo.data);
7150 //        this.store.on('load', this.onLoad, this);
7151 //        
7152 //        this.store.load();
7153 //        
7154 //    },
7155 //    
7156 //    onLoad: function () 
7157 //    {   
7158 //        this.fireEvent('load', this);
7159 //    }
7160 //    
7161 //   
7162 });
7163
7164  
7165
7166  /*
7167  * Based on:
7168  * Ext JS Library 1.1.1
7169  * Copyright(c) 2006-2007, Ext JS, LLC.
7170  *
7171  * Originally Released Under LGPL - original licence link has changed is not relivant.
7172  *
7173  * Fork - LGPL
7174  * <script type="text/javascript">
7175  */
7176
7177 // as we use this in bootstrap.
7178 Roo.namespace('Roo.form');
7179  /**
7180  * @class Roo.form.Action
7181  * Internal Class used to handle form actions
7182  * @constructor
7183  * @param {Roo.form.BasicForm} el The form element or its id
7184  * @param {Object} config Configuration options
7185  */
7186
7187  
7188  
7189 // define the action interface
7190 Roo.form.Action = function(form, options){
7191     this.form = form;
7192     this.options = options || {};
7193 };
7194 /**
7195  * Client Validation Failed
7196  * @const 
7197  */
7198 Roo.form.Action.CLIENT_INVALID = 'client';
7199 /**
7200  * Server Validation Failed
7201  * @const 
7202  */
7203 Roo.form.Action.SERVER_INVALID = 'server';
7204  /**
7205  * Connect to Server Failed
7206  * @const 
7207  */
7208 Roo.form.Action.CONNECT_FAILURE = 'connect';
7209 /**
7210  * Reading Data from Server Failed
7211  * @const 
7212  */
7213 Roo.form.Action.LOAD_FAILURE = 'load';
7214
7215 Roo.form.Action.prototype = {
7216     type : 'default',
7217     failureType : undefined,
7218     response : undefined,
7219     result : undefined,
7220
7221     // interface method
7222     run : function(options){
7223
7224     },
7225
7226     // interface method
7227     success : function(response){
7228
7229     },
7230
7231     // interface method
7232     handleResponse : function(response){
7233
7234     },
7235
7236     // default connection failure
7237     failure : function(response){
7238         
7239         this.response = response;
7240         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7241         this.form.afterAction(this, false);
7242     },
7243
7244     processResponse : function(response){
7245         this.response = response;
7246         if(!response.responseText){
7247             return true;
7248         }
7249         this.result = this.handleResponse(response);
7250         return this.result;
7251     },
7252
7253     // utility functions used internally
7254     getUrl : function(appendParams){
7255         var url = this.options.url || this.form.url || this.form.el.dom.action;
7256         if(appendParams){
7257             var p = this.getParams();
7258             if(p){
7259                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7260             }
7261         }
7262         return url;
7263     },
7264
7265     getMethod : function(){
7266         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7267     },
7268
7269     getParams : function(){
7270         var bp = this.form.baseParams;
7271         var p = this.options.params;
7272         if(p){
7273             if(typeof p == "object"){
7274                 p = Roo.urlEncode(Roo.applyIf(p, bp));
7275             }else if(typeof p == 'string' && bp){
7276                 p += '&' + Roo.urlEncode(bp);
7277             }
7278         }else if(bp){
7279             p = Roo.urlEncode(bp);
7280         }
7281         return p;
7282     },
7283
7284     createCallback : function(){
7285         return {
7286             success: this.success,
7287             failure: this.failure,
7288             scope: this,
7289             timeout: (this.form.timeout*1000),
7290             upload: this.form.fileUpload ? this.success : undefined
7291         };
7292     }
7293 };
7294
7295 Roo.form.Action.Submit = function(form, options){
7296     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7297 };
7298
7299 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7300     type : 'submit',
7301
7302     haveProgress : false,
7303     uploadComplete : false,
7304     
7305     // uploadProgress indicator.
7306     uploadProgress : function()
7307     {
7308         if (!this.form.progressUrl) {
7309             return;
7310         }
7311         
7312         if (!this.haveProgress) {
7313             Roo.MessageBox.progress("Uploading", "Uploading");
7314         }
7315         if (this.uploadComplete) {
7316            Roo.MessageBox.hide();
7317            return;
7318         }
7319         
7320         this.haveProgress = true;
7321    
7322         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7323         
7324         var c = new Roo.data.Connection();
7325         c.request({
7326             url : this.form.progressUrl,
7327             params: {
7328                 id : uid
7329             },
7330             method: 'GET',
7331             success : function(req){
7332                //console.log(data);
7333                 var rdata = false;
7334                 var edata;
7335                 try  {
7336                    rdata = Roo.decode(req.responseText)
7337                 } catch (e) {
7338                     Roo.log("Invalid data from server..");
7339                     Roo.log(edata);
7340                     return;
7341                 }
7342                 if (!rdata || !rdata.success) {
7343                     Roo.log(rdata);
7344                     Roo.MessageBox.alert(Roo.encode(rdata));
7345                     return;
7346                 }
7347                 var data = rdata.data;
7348                 
7349                 if (this.uploadComplete) {
7350                    Roo.MessageBox.hide();
7351                    return;
7352                 }
7353                    
7354                 if (data){
7355                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7356                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7357                     );
7358                 }
7359                 this.uploadProgress.defer(2000,this);
7360             },
7361        
7362             failure: function(data) {
7363                 Roo.log('progress url failed ');
7364                 Roo.log(data);
7365             },
7366             scope : this
7367         });
7368            
7369     },
7370     
7371     
7372     run : function()
7373     {
7374         // run get Values on the form, so it syncs any secondary forms.
7375         this.form.getValues();
7376         
7377         var o = this.options;
7378         var method = this.getMethod();
7379         var isPost = method == 'POST';
7380         if(o.clientValidation === false || this.form.isValid()){
7381             
7382             if (this.form.progressUrl) {
7383                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7384                     (new Date() * 1) + '' + Math.random());
7385                     
7386             } 
7387             
7388             
7389             Roo.Ajax.request(Roo.apply(this.createCallback(), {
7390                 form:this.form.el.dom,
7391                 url:this.getUrl(!isPost),
7392                 method: method,
7393                 params:isPost ? this.getParams() : null,
7394                 isUpload: this.form.fileUpload
7395             }));
7396             
7397             this.uploadProgress();
7398
7399         }else if (o.clientValidation !== false){ // client validation failed
7400             this.failureType = Roo.form.Action.CLIENT_INVALID;
7401             this.form.afterAction(this, false);
7402         }
7403     },
7404
7405     success : function(response)
7406     {
7407         this.uploadComplete= true;
7408         if (this.haveProgress) {
7409             Roo.MessageBox.hide();
7410         }
7411         
7412         
7413         var result = this.processResponse(response);
7414         if(result === true || result.success){
7415             this.form.afterAction(this, true);
7416             return;
7417         }
7418         if(result.errors){
7419             this.form.markInvalid(result.errors);
7420             this.failureType = Roo.form.Action.SERVER_INVALID;
7421         }
7422         this.form.afterAction(this, false);
7423     },
7424     failure : function(response)
7425     {
7426         this.uploadComplete= true;
7427         if (this.haveProgress) {
7428             Roo.MessageBox.hide();
7429         }
7430         
7431         this.response = response;
7432         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7433         this.form.afterAction(this, false);
7434     },
7435     
7436     handleResponse : function(response){
7437         if(this.form.errorReader){
7438             var rs = this.form.errorReader.read(response);
7439             var errors = [];
7440             if(rs.records){
7441                 for(var i = 0, len = rs.records.length; i < len; i++) {
7442                     var r = rs.records[i];
7443                     errors[i] = r.data;
7444                 }
7445             }
7446             if(errors.length < 1){
7447                 errors = null;
7448             }
7449             return {
7450                 success : rs.success,
7451                 errors : errors
7452             };
7453         }
7454         var ret = false;
7455         try {
7456             ret = Roo.decode(response.responseText);
7457         } catch (e) {
7458             ret = {
7459                 success: false,
7460                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7461                 errors : []
7462             };
7463         }
7464         return ret;
7465         
7466     }
7467 });
7468
7469
7470 Roo.form.Action.Load = function(form, options){
7471     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7472     this.reader = this.form.reader;
7473 };
7474
7475 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7476     type : 'load',
7477
7478     run : function(){
7479         
7480         Roo.Ajax.request(Roo.apply(
7481                 this.createCallback(), {
7482                     method:this.getMethod(),
7483                     url:this.getUrl(false),
7484                     params:this.getParams()
7485         }));
7486     },
7487
7488     success : function(response){
7489         
7490         var result = this.processResponse(response);
7491         if(result === true || !result.success || !result.data){
7492             this.failureType = Roo.form.Action.LOAD_FAILURE;
7493             this.form.afterAction(this, false);
7494             return;
7495         }
7496         this.form.clearInvalid();
7497         this.form.setValues(result.data);
7498         this.form.afterAction(this, true);
7499     },
7500
7501     handleResponse : function(response){
7502         if(this.form.reader){
7503             var rs = this.form.reader.read(response);
7504             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7505             return {
7506                 success : rs.success,
7507                 data : data
7508             };
7509         }
7510         return Roo.decode(response.responseText);
7511     }
7512 });
7513
7514 Roo.form.Action.ACTION_TYPES = {
7515     'load' : Roo.form.Action.Load,
7516     'submit' : Roo.form.Action.Submit
7517 };/*
7518  * - LGPL
7519  *
7520  * form
7521  *
7522  */
7523
7524 /**
7525  * @class Roo.bootstrap.Form
7526  * @extends Roo.bootstrap.Component
7527  * Bootstrap Form class
7528  * @cfg {String} method  GET | POST (default POST)
7529  * @cfg {String} labelAlign top | left (default top)
7530  * @cfg {String} align left  | right - for navbars
7531  * @cfg {Boolean} loadMask load mask when submit (default true)
7532
7533  *
7534  * @constructor
7535  * Create a new Form
7536  * @param {Object} config The config object
7537  */
7538
7539
7540 Roo.bootstrap.Form = function(config){
7541     Roo.bootstrap.Form.superclass.constructor.call(this, config);
7542     
7543     Roo.bootstrap.Form.popover.apply();
7544     
7545     this.addEvents({
7546         /**
7547          * @event clientvalidation
7548          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7549          * @param {Form} this
7550          * @param {Boolean} valid true if the form has passed client-side validation
7551          */
7552         clientvalidation: true,
7553         /**
7554          * @event beforeaction
7555          * Fires before any action is performed. Return false to cancel the action.
7556          * @param {Form} this
7557          * @param {Action} action The action to be performed
7558          */
7559         beforeaction: true,
7560         /**
7561          * @event actionfailed
7562          * Fires when an action fails.
7563          * @param {Form} this
7564          * @param {Action} action The action that failed
7565          */
7566         actionfailed : true,
7567         /**
7568          * @event actioncomplete
7569          * Fires when an action is completed.
7570          * @param {Form} this
7571          * @param {Action} action The action that completed
7572          */
7573         actioncomplete : true
7574     });
7575
7576 };
7577
7578 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
7579
7580      /**
7581      * @cfg {String} method
7582      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7583      */
7584     method : 'POST',
7585     /**
7586      * @cfg {String} url
7587      * The URL to use for form actions if one isn't supplied in the action options.
7588      */
7589     /**
7590      * @cfg {Boolean} fileUpload
7591      * Set to true if this form is a file upload.
7592      */
7593
7594     /**
7595      * @cfg {Object} baseParams
7596      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7597      */
7598
7599     /**
7600      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7601      */
7602     timeout: 30,
7603     /**
7604      * @cfg {Sting} align (left|right) for navbar forms
7605      */
7606     align : 'left',
7607
7608     // private
7609     activeAction : null,
7610
7611     /**
7612      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7613      * element by passing it or its id or mask the form itself by passing in true.
7614      * @type Mixed
7615      */
7616     waitMsgTarget : false,
7617
7618     loadMask : true,
7619     
7620     /**
7621      * @cfg {Boolean} errorMask (true|false) default false
7622      */
7623     errorMask : false,
7624     
7625     /**
7626      * @cfg {Number} maskOffset Default 100
7627      */
7628     maskOffset : 100,
7629     
7630     /**
7631      * @cfg {Boolean} maskBody
7632      */
7633     maskBody : false,
7634
7635     getAutoCreate : function(){
7636
7637         var cfg = {
7638             tag: 'form',
7639             method : this.method || 'POST',
7640             id : this.id || Roo.id(),
7641             cls : ''
7642         };
7643         if (this.parent().xtype.match(/^Nav/)) {
7644             cfg.cls = 'navbar-form navbar-' + this.align;
7645
7646         }
7647
7648         if (this.labelAlign == 'left' ) {
7649             cfg.cls += ' form-horizontal';
7650         }
7651
7652
7653         return cfg;
7654     },
7655     initEvents : function()
7656     {
7657         this.el.on('submit', this.onSubmit, this);
7658         // this was added as random key presses on the form where triggering form submit.
7659         this.el.on('keypress', function(e) {
7660             if (e.getCharCode() != 13) {
7661                 return true;
7662             }
7663             // we might need to allow it for textareas.. and some other items.
7664             // check e.getTarget().
7665
7666             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7667                 return true;
7668             }
7669
7670             Roo.log("keypress blocked");
7671
7672             e.preventDefault();
7673             return false;
7674         });
7675         
7676     },
7677     // private
7678     onSubmit : function(e){
7679         e.stopEvent();
7680     },
7681
7682      /**
7683      * Returns true if client-side validation on the form is successful.
7684      * @return Boolean
7685      */
7686     isValid : function(){
7687         var items = this.getItems();
7688         var valid = true;
7689         var target = false;
7690         
7691         items.each(function(f){
7692             if(f.validate()){
7693                 return;
7694             }
7695             valid = false;
7696
7697             if(!target && f.el.isVisible(true)){
7698                 target = f;
7699             }
7700            
7701         });
7702         
7703         if(this.errorMask && !valid){
7704             Roo.bootstrap.Form.popover.mask(this, target);
7705         }
7706         
7707         return valid;
7708     },
7709     
7710     /**
7711      * Returns true if any fields in this form have changed since their original load.
7712      * @return Boolean
7713      */
7714     isDirty : function(){
7715         var dirty = false;
7716         var items = this.getItems();
7717         items.each(function(f){
7718            if(f.isDirty()){
7719                dirty = true;
7720                return false;
7721            }
7722            return true;
7723         });
7724         return dirty;
7725     },
7726      /**
7727      * Performs a predefined action (submit or load) or custom actions you define on this form.
7728      * @param {String} actionName The name of the action type
7729      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
7730      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7731      * accept other config options):
7732      * <pre>
7733 Property          Type             Description
7734 ----------------  ---------------  ----------------------------------------------------------------------------------
7735 url               String           The url for the action (defaults to the form's url)
7736 method            String           The form method to use (defaults to the form's method, or POST if not defined)
7737 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
7738 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
7739                                    validate the form on the client (defaults to false)
7740      * </pre>
7741      * @return {BasicForm} this
7742      */
7743     doAction : function(action, options){
7744         if(typeof action == 'string'){
7745             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7746         }
7747         if(this.fireEvent('beforeaction', this, action) !== false){
7748             this.beforeAction(action);
7749             action.run.defer(100, action);
7750         }
7751         return this;
7752     },
7753
7754     // private
7755     beforeAction : function(action){
7756         var o = action.options;
7757         
7758         if(this.loadMask){
7759             
7760             if(this.maskBody){
7761                 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7762             } else {
7763                 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7764             }
7765         }
7766         // not really supported yet.. ??
7767
7768         //if(this.waitMsgTarget === true){
7769         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7770         //}else if(this.waitMsgTarget){
7771         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7772         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7773         //}else {
7774         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7775        // }
7776
7777     },
7778
7779     // private
7780     afterAction : function(action, success){
7781         this.activeAction = null;
7782         var o = action.options;
7783
7784         if(this.loadMask){
7785             
7786             if(this.maskBody){
7787                 Roo.get(document.body).unmask();
7788             } else {
7789                 this.el.unmask();
7790             }
7791         }
7792         
7793         //if(this.waitMsgTarget === true){
7794 //            this.el.unmask();
7795         //}else if(this.waitMsgTarget){
7796         //    this.waitMsgTarget.unmask();
7797         //}else{
7798         //    Roo.MessageBox.updateProgress(1);
7799         //    Roo.MessageBox.hide();
7800        // }
7801         //
7802         if(success){
7803             if(o.reset){
7804                 this.reset();
7805             }
7806             Roo.callback(o.success, o.scope, [this, action]);
7807             this.fireEvent('actioncomplete', this, action);
7808
7809         }else{
7810
7811             // failure condition..
7812             // we have a scenario where updates need confirming.
7813             // eg. if a locking scenario exists..
7814             // we look for { errors : { needs_confirm : true }} in the response.
7815             if (
7816                 (typeof(action.result) != 'undefined')  &&
7817                 (typeof(action.result.errors) != 'undefined')  &&
7818                 (typeof(action.result.errors.needs_confirm) != 'undefined')
7819            ){
7820                 var _t = this;
7821                 Roo.log("not supported yet");
7822                  /*
7823
7824                 Roo.MessageBox.confirm(
7825                     "Change requires confirmation",
7826                     action.result.errorMsg,
7827                     function(r) {
7828                         if (r != 'yes') {
7829                             return;
7830                         }
7831                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
7832                     }
7833
7834                 );
7835                 */
7836
7837
7838                 return;
7839             }
7840
7841             Roo.callback(o.failure, o.scope, [this, action]);
7842             // show an error message if no failed handler is set..
7843             if (!this.hasListener('actionfailed')) {
7844                 Roo.log("need to add dialog support");
7845                 /*
7846                 Roo.MessageBox.alert("Error",
7847                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7848                         action.result.errorMsg :
7849                         "Saving Failed, please check your entries or try again"
7850                 );
7851                 */
7852             }
7853
7854             this.fireEvent('actionfailed', this, action);
7855         }
7856
7857     },
7858     /**
7859      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7860      * @param {String} id The value to search for
7861      * @return Field
7862      */
7863     findField : function(id){
7864         var items = this.getItems();
7865         var field = items.get(id);
7866         if(!field){
7867              items.each(function(f){
7868                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7869                     field = f;
7870                     return false;
7871                 }
7872                 return true;
7873             });
7874         }
7875         return field || null;
7876     },
7877      /**
7878      * Mark fields in this form invalid in bulk.
7879      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7880      * @return {BasicForm} this
7881      */
7882     markInvalid : function(errors){
7883         if(errors instanceof Array){
7884             for(var i = 0, len = errors.length; i < len; i++){
7885                 var fieldError = errors[i];
7886                 var f = this.findField(fieldError.id);
7887                 if(f){
7888                     f.markInvalid(fieldError.msg);
7889                 }
7890             }
7891         }else{
7892             var field, id;
7893             for(id in errors){
7894                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7895                     field.markInvalid(errors[id]);
7896                 }
7897             }
7898         }
7899         //Roo.each(this.childForms || [], function (f) {
7900         //    f.markInvalid(errors);
7901         //});
7902
7903         return this;
7904     },
7905
7906     /**
7907      * Set values for fields in this form in bulk.
7908      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7909      * @return {BasicForm} this
7910      */
7911     setValues : function(values){
7912         if(values instanceof Array){ // array of objects
7913             for(var i = 0, len = values.length; i < len; i++){
7914                 var v = values[i];
7915                 var f = this.findField(v.id);
7916                 if(f){
7917                     f.setValue(v.value);
7918                     if(this.trackResetOnLoad){
7919                         f.originalValue = f.getValue();
7920                     }
7921                 }
7922             }
7923         }else{ // object hash
7924             var field, id;
7925             for(id in values){
7926                 if(typeof values[id] != 'function' && (field = this.findField(id))){
7927
7928                     if (field.setFromData &&
7929                         field.valueField &&
7930                         field.displayField &&
7931                         // combos' with local stores can
7932                         // be queried via setValue()
7933                         // to set their value..
7934                         (field.store && !field.store.isLocal)
7935                         ) {
7936                         // it's a combo
7937                         var sd = { };
7938                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7939                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7940                         field.setFromData(sd);
7941
7942                     } else if(field.setFromData && (field.store && !field.store.isLocal)) {
7943                         
7944                         field.setFromData(values);
7945                         
7946                     } else {
7947                         field.setValue(values[id]);
7948                     }
7949
7950
7951                     if(this.trackResetOnLoad){
7952                         field.originalValue = field.getValue();
7953                     }
7954                 }
7955             }
7956         }
7957
7958         //Roo.each(this.childForms || [], function (f) {
7959         //    f.setValues(values);
7960         //});
7961
7962         return this;
7963     },
7964
7965     /**
7966      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7967      * they are returned as an array.
7968      * @param {Boolean} asString
7969      * @return {Object}
7970      */
7971     getValues : function(asString){
7972         //if (this.childForms) {
7973             // copy values from the child forms
7974         //    Roo.each(this.childForms, function (f) {
7975         //        this.setValues(f.getValues());
7976         //    }, this);
7977         //}
7978
7979
7980
7981         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7982         if(asString === true){
7983             return fs;
7984         }
7985         return Roo.urlDecode(fs);
7986     },
7987
7988     /**
7989      * Returns the fields in this form as an object with key/value pairs.
7990      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7991      * @return {Object}
7992      */
7993     getFieldValues : function(with_hidden)
7994     {
7995         var items = this.getItems();
7996         var ret = {};
7997         items.each(function(f){
7998             
7999             if (!f.getName()) {
8000                 return;
8001             }
8002             
8003             var v = f.getValue();
8004             
8005             if (f.inputType =='radio') {
8006                 if (typeof(ret[f.getName()]) == 'undefined') {
8007                     ret[f.getName()] = ''; // empty..
8008                 }
8009
8010                 if (!f.el.dom.checked) {
8011                     return;
8012
8013                 }
8014                 v = f.el.dom.value;
8015
8016             }
8017             
8018             if(f.xtype == 'MoneyField'){
8019                 ret[f.currencyName] = f.getCurrency();
8020             }
8021
8022             // not sure if this supported any more..
8023             if ((typeof(v) == 'object') && f.getRawValue) {
8024                 v = f.getRawValue() ; // dates..
8025             }
8026             // combo boxes where name != hiddenName...
8027             if (f.name !== false && f.name != '' && f.name != f.getName()) {
8028                 ret[f.name] = f.getRawValue();
8029             }
8030             ret[f.getName()] = v;
8031         });
8032
8033         return ret;
8034     },
8035
8036     /**
8037      * Clears all invalid messages in this form.
8038      * @return {BasicForm} this
8039      */
8040     clearInvalid : function(){
8041         var items = this.getItems();
8042
8043         items.each(function(f){
8044            f.clearInvalid();
8045         });
8046
8047
8048
8049         return this;
8050     },
8051
8052     /**
8053      * Resets this form.
8054      * @return {BasicForm} this
8055      */
8056     reset : function(){
8057         var items = this.getItems();
8058         items.each(function(f){
8059             f.reset();
8060         });
8061
8062         Roo.each(this.childForms || [], function (f) {
8063             f.reset();
8064         });
8065
8066
8067         return this;
8068     },
8069     
8070     getItems : function()
8071     {
8072         var r=new Roo.util.MixedCollection(false, function(o){
8073             return o.id || (o.id = Roo.id());
8074         });
8075         var iter = function(el) {
8076             if (el.inputEl) {
8077                 r.add(el);
8078             }
8079             if (!el.items) {
8080                 return;
8081             }
8082             Roo.each(el.items,function(e) {
8083                 iter(e);
8084             });
8085
8086
8087         };
8088
8089         iter(this);
8090         return r;
8091         
8092     }
8093
8094 });
8095
8096 Roo.apply(Roo.bootstrap.Form, {
8097     
8098     popover : {
8099         
8100         padding : 5,
8101         
8102         isApplied : false,
8103         
8104         isMasked : false,
8105         
8106         form : false,
8107         
8108         target : false,
8109         
8110         toolTip : false,
8111         
8112         intervalID : false,
8113         
8114         maskEl : false,
8115         
8116         apply : function()
8117         {
8118             if(this.isApplied){
8119                 return;
8120             }
8121             
8122             this.maskEl = {
8123                 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8124                 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8125                 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8126                 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8127             };
8128             
8129             this.maskEl.top.enableDisplayMode("block");
8130             this.maskEl.left.enableDisplayMode("block");
8131             this.maskEl.bottom.enableDisplayMode("block");
8132             this.maskEl.right.enableDisplayMode("block");
8133             
8134             this.toolTip = new Roo.bootstrap.Tooltip({
8135                 cls : 'roo-form-error-popover',
8136                 alignment : {
8137                     'left' : ['r-l', [-2,0], 'right'],
8138                     'right' : ['l-r', [2,0], 'left'],
8139                     'bottom' : ['tl-bl', [0,2], 'top'],
8140                     'top' : [ 'bl-tl', [0,-2], 'bottom']
8141                 }
8142             });
8143             
8144             this.toolTip.render(Roo.get(document.body));
8145
8146             this.toolTip.el.enableDisplayMode("block");
8147             
8148             Roo.get(document.body).on('click', function(){
8149                 this.unmask();
8150             }, this);
8151             
8152             Roo.get(document.body).on('touchstart', function(){
8153                 this.unmask();
8154             }, this);
8155             
8156             this.isApplied = true
8157         },
8158         
8159         mask : function(form, target)
8160         {
8161             this.form = form;
8162             
8163             this.target = target;
8164             
8165             if(!this.form.errorMask || !target.el){
8166                 return;
8167             }
8168             
8169             var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8170             
8171             Roo.log(scrollable);
8172             
8173             var ot = this.target.el.calcOffsetsTo(scrollable);
8174             
8175             var scrollTo = ot[1] - this.form.maskOffset;
8176             
8177             scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8178             
8179             scrollable.scrollTo('top', scrollTo);
8180             
8181             var box = this.target.el.getBox();
8182             Roo.log(box);
8183             var zIndex = Roo.bootstrap.Modal.zIndex++;
8184
8185             
8186             this.maskEl.top.setStyle('position', 'absolute');
8187             this.maskEl.top.setStyle('z-index', zIndex);
8188             this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8189             this.maskEl.top.setLeft(0);
8190             this.maskEl.top.setTop(0);
8191             this.maskEl.top.show();
8192             
8193             this.maskEl.left.setStyle('position', 'absolute');
8194             this.maskEl.left.setStyle('z-index', zIndex);
8195             this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8196             this.maskEl.left.setLeft(0);
8197             this.maskEl.left.setTop(box.y - this.padding);
8198             this.maskEl.left.show();
8199
8200             this.maskEl.bottom.setStyle('position', 'absolute');
8201             this.maskEl.bottom.setStyle('z-index', zIndex);
8202             this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8203             this.maskEl.bottom.setLeft(0);
8204             this.maskEl.bottom.setTop(box.bottom + this.padding);
8205             this.maskEl.bottom.show();
8206
8207             this.maskEl.right.setStyle('position', 'absolute');
8208             this.maskEl.right.setStyle('z-index', zIndex);
8209             this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8210             this.maskEl.right.setLeft(box.right + this.padding);
8211             this.maskEl.right.setTop(box.y - this.padding);
8212             this.maskEl.right.show();
8213
8214             this.toolTip.bindEl = this.target.el;
8215
8216             this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8217
8218             var tip = this.target.blankText;
8219
8220             if(this.target.getValue() !== '' ) {
8221                 
8222                 if (this.target.invalidText.length) {
8223                     tip = this.target.invalidText;
8224                 } else if (this.target.regexText.length){
8225                     tip = this.target.regexText;
8226                 }
8227             }
8228
8229             this.toolTip.show(tip);
8230
8231             this.intervalID = window.setInterval(function() {
8232                 Roo.bootstrap.Form.popover.unmask();
8233             }, 10000);
8234
8235             window.onwheel = function(){ return false;};
8236             
8237             (function(){ this.isMasked = true; }).defer(500, this);
8238             
8239         },
8240         
8241         unmask : function()
8242         {
8243             if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8244                 return;
8245             }
8246             
8247             this.maskEl.top.setStyle('position', 'absolute');
8248             this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8249             this.maskEl.top.hide();
8250
8251             this.maskEl.left.setStyle('position', 'absolute');
8252             this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8253             this.maskEl.left.hide();
8254
8255             this.maskEl.bottom.setStyle('position', 'absolute');
8256             this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8257             this.maskEl.bottom.hide();
8258
8259             this.maskEl.right.setStyle('position', 'absolute');
8260             this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8261             this.maskEl.right.hide();
8262             
8263             this.toolTip.hide();
8264             
8265             this.toolTip.el.hide();
8266             
8267             window.onwheel = function(){ return true;};
8268             
8269             if(this.intervalID){
8270                 window.clearInterval(this.intervalID);
8271                 this.intervalID = false;
8272             }
8273             
8274             this.isMasked = false;
8275             
8276         }
8277         
8278     }
8279     
8280 });
8281
8282 /*
8283  * Based on:
8284  * Ext JS Library 1.1.1
8285  * Copyright(c) 2006-2007, Ext JS, LLC.
8286  *
8287  * Originally Released Under LGPL - original licence link has changed is not relivant.
8288  *
8289  * Fork - LGPL
8290  * <script type="text/javascript">
8291  */
8292 /**
8293  * @class Roo.form.VTypes
8294  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8295  * @singleton
8296  */
8297 Roo.form.VTypes = function(){
8298     // closure these in so they are only created once.
8299     var alpha = /^[a-zA-Z_]+$/;
8300     var alphanum = /^[a-zA-Z0-9_]+$/;
8301     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8302     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8303
8304     // All these messages and functions are configurable
8305     return {
8306         /**
8307          * The function used to validate email addresses
8308          * @param {String} value The email address
8309          */
8310         'email' : function(v){
8311             return email.test(v);
8312         },
8313         /**
8314          * The error text to display when the email validation function returns false
8315          * @type String
8316          */
8317         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8318         /**
8319          * The keystroke filter mask to be applied on email input
8320          * @type RegExp
8321          */
8322         'emailMask' : /[a-z0-9_\.\-@]/i,
8323
8324         /**
8325          * The function used to validate URLs
8326          * @param {String} value The URL
8327          */
8328         'url' : function(v){
8329             return url.test(v);
8330         },
8331         /**
8332          * The error text to display when the url validation function returns false
8333          * @type String
8334          */
8335         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8336         
8337         /**
8338          * The function used to validate alpha values
8339          * @param {String} value The value
8340          */
8341         'alpha' : function(v){
8342             return alpha.test(v);
8343         },
8344         /**
8345          * The error text to display when the alpha validation function returns false
8346          * @type String
8347          */
8348         'alphaText' : 'This field should only contain letters and _',
8349         /**
8350          * The keystroke filter mask to be applied on alpha input
8351          * @type RegExp
8352          */
8353         'alphaMask' : /[a-z_]/i,
8354
8355         /**
8356          * The function used to validate alphanumeric values
8357          * @param {String} value The value
8358          */
8359         'alphanum' : function(v){
8360             return alphanum.test(v);
8361         },
8362         /**
8363          * The error text to display when the alphanumeric validation function returns false
8364          * @type String
8365          */
8366         'alphanumText' : 'This field should only contain letters, numbers and _',
8367         /**
8368          * The keystroke filter mask to be applied on alphanumeric input
8369          * @type RegExp
8370          */
8371         'alphanumMask' : /[a-z0-9_]/i
8372     };
8373 }();/*
8374  * - LGPL
8375  *
8376  * Input
8377  * 
8378  */
8379
8380 /**
8381  * @class Roo.bootstrap.Input
8382  * @extends Roo.bootstrap.Component
8383  * Bootstrap Input class
8384  * @cfg {Boolean} disabled is it disabled
8385  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8386  * @cfg {String} name name of the input
8387  * @cfg {string} fieldLabel - the label associated
8388  * @cfg {string} placeholder - placeholder to put in text.
8389  * @cfg {string}  before - input group add on before
8390  * @cfg {string} after - input group add on after
8391  * @cfg {string} size - (lg|sm) or leave empty..
8392  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8393  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8394  * @cfg {Number} md colspan out of 12 for computer-sized screens
8395  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8396  * @cfg {string} value default value of the input
8397  * @cfg {Number} labelWidth set the width of label 
8398  * @cfg {Number} labellg set the width of label (1-12)
8399  * @cfg {Number} labelmd set the width of label (1-12)
8400  * @cfg {Number} labelsm set the width of label (1-12)
8401  * @cfg {Number} labelxs set the width of label (1-12)
8402  * @cfg {String} labelAlign (top|left)
8403  * @cfg {Boolean} readOnly Specifies that the field should be read-only
8404  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8405  * @cfg {String} indicatorpos (left|right) default left
8406
8407  * @cfg {String} align (left|center|right) Default left
8408  * @cfg {Boolean} forceFeedback (true|false) Default false
8409  * 
8410  * 
8411  * 
8412  * 
8413  * @constructor
8414  * Create a new Input
8415  * @param {Object} config The config object
8416  */
8417
8418 Roo.bootstrap.Input = function(config){
8419     
8420     Roo.bootstrap.Input.superclass.constructor.call(this, config);
8421     
8422     this.addEvents({
8423         /**
8424          * @event focus
8425          * Fires when this field receives input focus.
8426          * @param {Roo.form.Field} this
8427          */
8428         focus : true,
8429         /**
8430          * @event blur
8431          * Fires when this field loses input focus.
8432          * @param {Roo.form.Field} this
8433          */
8434         blur : true,
8435         /**
8436          * @event specialkey
8437          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
8438          * {@link Roo.EventObject#getKey} to determine which key was pressed.
8439          * @param {Roo.form.Field} this
8440          * @param {Roo.EventObject} e The event object
8441          */
8442         specialkey : true,
8443         /**
8444          * @event change
8445          * Fires just before the field blurs if the field value has changed.
8446          * @param {Roo.form.Field} this
8447          * @param {Mixed} newValue The new value
8448          * @param {Mixed} oldValue The original value
8449          */
8450         change : true,
8451         /**
8452          * @event invalid
8453          * Fires after the field has been marked as invalid.
8454          * @param {Roo.form.Field} this
8455          * @param {String} msg The validation message
8456          */
8457         invalid : true,
8458         /**
8459          * @event valid
8460          * Fires after the field has been validated with no errors.
8461          * @param {Roo.form.Field} this
8462          */
8463         valid : true,
8464          /**
8465          * @event keyup
8466          * Fires after the key up
8467          * @param {Roo.form.Field} this
8468          * @param {Roo.EventObject}  e The event Object
8469          */
8470         keyup : true
8471     });
8472 };
8473
8474 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
8475      /**
8476      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8477       automatic validation (defaults to "keyup").
8478      */
8479     validationEvent : "keyup",
8480      /**
8481      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8482      */
8483     validateOnBlur : true,
8484     /**
8485      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8486      */
8487     validationDelay : 250,
8488      /**
8489      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8490      */
8491     focusClass : "x-form-focus",  // not needed???
8492     
8493        
8494     /**
8495      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8496      */
8497     invalidClass : "has-warning",
8498     
8499     /**
8500      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8501      */
8502     validClass : "has-success",
8503     
8504     /**
8505      * @cfg {Boolean} hasFeedback (true|false) default true
8506      */
8507     hasFeedback : true,
8508     
8509     /**
8510      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8511      */
8512     invalidFeedbackClass : "glyphicon-warning-sign",
8513     
8514     /**
8515      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8516      */
8517     validFeedbackClass : "glyphicon-ok",
8518     
8519     /**
8520      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8521      */
8522     selectOnFocus : false,
8523     
8524      /**
8525      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8526      */
8527     maskRe : null,
8528        /**
8529      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8530      */
8531     vtype : null,
8532     
8533       /**
8534      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8535      */
8536     disableKeyFilter : false,
8537     
8538        /**
8539      * @cfg {Boolean} disabled True to disable the field (defaults to false).
8540      */
8541     disabled : false,
8542      /**
8543      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8544      */
8545     allowBlank : true,
8546     /**
8547      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8548      */
8549     blankText : "Please complete this mandatory field",
8550     
8551      /**
8552      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8553      */
8554     minLength : 0,
8555     /**
8556      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8557      */
8558     maxLength : Number.MAX_VALUE,
8559     /**
8560      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8561      */
8562     minLengthText : "The minimum length for this field is {0}",
8563     /**
8564      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8565      */
8566     maxLengthText : "The maximum length for this field is {0}",
8567   
8568     
8569     /**
8570      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8571      * If available, this function will be called only after the basic validators all return true, and will be passed the
8572      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8573      */
8574     validator : null,
8575     /**
8576      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8577      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8578      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
8579      */
8580     regex : null,
8581     /**
8582      * @cfg {String} regexText -- Depricated - use Invalid Text
8583      */
8584     regexText : "",
8585     
8586     /**
8587      * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8588      */
8589     invalidText : "",
8590     
8591     
8592     
8593     autocomplete: false,
8594     
8595     
8596     fieldLabel : '',
8597     inputType : 'text',
8598     
8599     name : false,
8600     placeholder: false,
8601     before : false,
8602     after : false,
8603     size : false,
8604     hasFocus : false,
8605     preventMark: false,
8606     isFormField : true,
8607     value : '',
8608     labelWidth : 2,
8609     labelAlign : false,
8610     readOnly : false,
8611     align : false,
8612     formatedValue : false,
8613     forceFeedback : false,
8614     
8615     indicatorpos : 'left',
8616     
8617     labellg : 0,
8618     labelmd : 0,
8619     labelsm : 0,
8620     labelxs : 0,
8621     
8622     parentLabelAlign : function()
8623     {
8624         var parent = this;
8625         while (parent.parent()) {
8626             parent = parent.parent();
8627             if (typeof(parent.labelAlign) !='undefined') {
8628                 return parent.labelAlign;
8629             }
8630         }
8631         return 'left';
8632         
8633     },
8634     
8635     getAutoCreate : function()
8636     {
8637         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8638         
8639         var id = Roo.id();
8640         
8641         var cfg = {};
8642         
8643         if(this.inputType != 'hidden'){
8644             cfg.cls = 'form-group' //input-group
8645         }
8646         
8647         var input =  {
8648             tag: 'input',
8649             id : id,
8650             type : this.inputType,
8651             value : this.value,
8652             cls : 'form-control',
8653             placeholder : this.placeholder || '',
8654             autocomplete : this.autocomplete || 'new-password'
8655         };
8656         
8657         if(this.align){
8658             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8659         }
8660         
8661         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8662             input.maxLength = this.maxLength;
8663         }
8664         
8665         if (this.disabled) {
8666             input.disabled=true;
8667         }
8668         
8669         if (this.readOnly) {
8670             input.readonly=true;
8671         }
8672         
8673         if (this.name) {
8674             input.name = this.name;
8675         }
8676         
8677         if (this.size) {
8678             input.cls += ' input-' + this.size;
8679         }
8680         
8681         var settings=this;
8682         ['xs','sm','md','lg'].map(function(size){
8683             if (settings[size]) {
8684                 cfg.cls += ' col-' + size + '-' + settings[size];
8685             }
8686         });
8687         
8688         var inputblock = input;
8689         
8690         var feedback = {
8691             tag: 'span',
8692             cls: 'glyphicon form-control-feedback'
8693         };
8694             
8695         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8696             
8697             inputblock = {
8698                 cls : 'has-feedback',
8699                 cn :  [
8700                     input,
8701                     feedback
8702                 ] 
8703             };  
8704         }
8705         
8706         if (this.before || this.after) {
8707             
8708             inputblock = {
8709                 cls : 'input-group',
8710                 cn :  [] 
8711             };
8712             
8713             if (this.before && typeof(this.before) == 'string') {
8714                 
8715                 inputblock.cn.push({
8716                     tag :'span',
8717                     cls : 'roo-input-before input-group-addon',
8718                     html : this.before
8719                 });
8720             }
8721             if (this.before && typeof(this.before) == 'object') {
8722                 this.before = Roo.factory(this.before);
8723                 
8724                 inputblock.cn.push({
8725                     tag :'span',
8726                     cls : 'roo-input-before input-group-' +
8727                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8728                 });
8729             }
8730             
8731             inputblock.cn.push(input);
8732             
8733             if (this.after && typeof(this.after) == 'string') {
8734                 inputblock.cn.push({
8735                     tag :'span',
8736                     cls : 'roo-input-after input-group-addon',
8737                     html : this.after
8738                 });
8739             }
8740             if (this.after && typeof(this.after) == 'object') {
8741                 this.after = Roo.factory(this.after);
8742                 
8743                 inputblock.cn.push({
8744                     tag :'span',
8745                     cls : 'roo-input-after input-group-' +
8746                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8747                 });
8748             }
8749             
8750             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8751                 inputblock.cls += ' has-feedback';
8752                 inputblock.cn.push(feedback);
8753             }
8754         };
8755         
8756         if (align ==='left' && this.fieldLabel.length) {
8757             
8758             cfg.cls += ' roo-form-group-label-left';
8759             
8760             cfg.cn = [
8761                 {
8762                     tag : 'i',
8763                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8764                     tooltip : 'This field is required'
8765                 },
8766                 {
8767                     tag: 'label',
8768                     'for' :  id,
8769                     cls : 'control-label',
8770                     html : this.fieldLabel
8771
8772                 },
8773                 {
8774                     cls : "", 
8775                     cn: [
8776                         inputblock
8777                     ]
8778                 }
8779             ];
8780             
8781             var labelCfg = cfg.cn[1];
8782             var contentCfg = cfg.cn[2];
8783             
8784             if(this.indicatorpos == 'right'){
8785                 cfg.cn = [
8786                     {
8787                         tag: 'label',
8788                         'for' :  id,
8789                         cls : 'control-label',
8790                         cn : [
8791                             {
8792                                 tag : 'span',
8793                                 html : this.fieldLabel
8794                             },
8795                             {
8796                                 tag : 'i',
8797                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8798                                 tooltip : 'This field is required'
8799                             }
8800                         ]
8801                     },
8802                     {
8803                         cls : "",
8804                         cn: [
8805                             inputblock
8806                         ]
8807                     }
8808
8809                 ];
8810                 
8811                 labelCfg = cfg.cn[0];
8812                 contentCfg = cfg.cn[1];
8813             
8814             }
8815             
8816             if(this.labelWidth > 12){
8817                 labelCfg.style = "width: " + this.labelWidth + 'px';
8818             }
8819             
8820             if(this.labelWidth < 13 && this.labelmd == 0){
8821                 this.labelmd = this.labelWidth;
8822             }
8823             
8824             if(this.labellg > 0){
8825                 labelCfg.cls += ' col-lg-' + this.labellg;
8826                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8827             }
8828             
8829             if(this.labelmd > 0){
8830                 labelCfg.cls += ' col-md-' + this.labelmd;
8831                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8832             }
8833             
8834             if(this.labelsm > 0){
8835                 labelCfg.cls += ' col-sm-' + this.labelsm;
8836                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8837             }
8838             
8839             if(this.labelxs > 0){
8840                 labelCfg.cls += ' col-xs-' + this.labelxs;
8841                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8842             }
8843             
8844             
8845         } else if ( this.fieldLabel.length) {
8846                 
8847             cfg.cn = [
8848                 {
8849                     tag : 'i',
8850                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8851                     tooltip : 'This field is required'
8852                 },
8853                 {
8854                     tag: 'label',
8855                    //cls : 'input-group-addon',
8856                     html : this.fieldLabel
8857
8858                 },
8859
8860                inputblock
8861
8862            ];
8863            
8864            if(this.indicatorpos == 'right'){
8865                 
8866                 cfg.cn = [
8867                     {
8868                         tag: 'label',
8869                        //cls : 'input-group-addon',
8870                         html : this.fieldLabel
8871
8872                     },
8873                     {
8874                         tag : 'i',
8875                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8876                         tooltip : 'This field is required'
8877                     },
8878
8879                    inputblock
8880
8881                ];
8882
8883             }
8884
8885         } else {
8886             
8887             cfg.cn = [
8888
8889                     inputblock
8890
8891             ];
8892                 
8893                 
8894         };
8895         
8896         if (this.parentType === 'Navbar' &&  this.parent().bar) {
8897            cfg.cls += ' navbar-form';
8898         }
8899         
8900         if (this.parentType === 'NavGroup') {
8901            cfg.cls += ' navbar-form';
8902            cfg.tag = 'li';
8903         }
8904         
8905         return cfg;
8906         
8907     },
8908     /**
8909      * return the real input element.
8910      */
8911     inputEl: function ()
8912     {
8913         return this.el.select('input.form-control',true).first();
8914     },
8915     
8916     tooltipEl : function()
8917     {
8918         return this.inputEl();
8919     },
8920     
8921     indicatorEl : function()
8922     {
8923         var indicator = this.el.select('i.roo-required-indicator',true).first();
8924         
8925         if(!indicator){
8926             return false;
8927         }
8928         
8929         return indicator;
8930         
8931     },
8932     
8933     setDisabled : function(v)
8934     {
8935         var i  = this.inputEl().dom;
8936         if (!v) {
8937             i.removeAttribute('disabled');
8938             return;
8939             
8940         }
8941         i.setAttribute('disabled','true');
8942     },
8943     initEvents : function()
8944     {
8945           
8946         this.inputEl().on("keydown" , this.fireKey,  this);
8947         this.inputEl().on("focus", this.onFocus,  this);
8948         this.inputEl().on("blur", this.onBlur,  this);
8949         
8950         this.inputEl().relayEvent('keyup', this);
8951         
8952         this.indicator = this.indicatorEl();
8953         
8954         if(this.indicator){
8955             this.indicator.addClass('invisible');
8956             
8957         }
8958  
8959         // reference to original value for reset
8960         this.originalValue = this.getValue();
8961         //Roo.form.TextField.superclass.initEvents.call(this);
8962         if(this.validationEvent == 'keyup'){
8963             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8964             this.inputEl().on('keyup', this.filterValidation, this);
8965         }
8966         else if(this.validationEvent !== false){
8967             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8968         }
8969         
8970         if(this.selectOnFocus){
8971             this.on("focus", this.preFocus, this);
8972             
8973         }
8974         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8975             this.inputEl().on("keypress", this.filterKeys, this);
8976         } else {
8977             this.inputEl().relayEvent('keypress', this);
8978         }
8979        /* if(this.grow){
8980             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
8981             this.el.on("click", this.autoSize,  this);
8982         }
8983         */
8984         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8985             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8986         }
8987         
8988         if (typeof(this.before) == 'object') {
8989             this.before.render(this.el.select('.roo-input-before',true).first());
8990         }
8991         if (typeof(this.after) == 'object') {
8992             this.after.render(this.el.select('.roo-input-after',true).first());
8993         }
8994         
8995         
8996     },
8997     filterValidation : function(e){
8998         if(!e.isNavKeyPress()){
8999             this.validationTask.delay(this.validationDelay);
9000         }
9001     },
9002      /**
9003      * Validates the field value
9004      * @return {Boolean} True if the value is valid, else false
9005      */
9006     validate : function(){
9007         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9008         if(this.disabled || this.validateValue(this.getRawValue())){
9009             this.markValid();
9010             return true;
9011         }
9012         
9013         this.markInvalid();
9014         return false;
9015     },
9016     
9017     
9018     /**
9019      * Validates a value according to the field's validation rules and marks the field as invalid
9020      * if the validation fails
9021      * @param {Mixed} value The value to validate
9022      * @return {Boolean} True if the value is valid, else false
9023      */
9024     validateValue : function(value){
9025         if(value.length < 1)  { // if it's blank
9026             if(this.allowBlank){
9027                 return true;
9028             }            
9029             return this.inputEl().hasClass('hide') ? true : false;
9030         }
9031         
9032         if(value.length < this.minLength){
9033             return false;
9034         }
9035         if(value.length > this.maxLength){
9036             return false;
9037         }
9038         if(this.vtype){
9039             var vt = Roo.form.VTypes;
9040             if(!vt[this.vtype](value, this)){
9041                 return false;
9042             }
9043         }
9044         if(typeof this.validator == "function"){
9045             var msg = this.validator(value);
9046             if(msg !== true){
9047                 return false;
9048             }
9049             if (typeof(msg) == 'string') {
9050                 this.invalidText = msg;
9051             }
9052         }
9053         
9054         if(this.regex && !this.regex.test(value)){
9055             return false;
9056         }
9057         
9058         return true;
9059     },
9060
9061     
9062     
9063      // private
9064     fireKey : function(e){
9065         //Roo.log('field ' + e.getKey());
9066         if(e.isNavKeyPress()){
9067             this.fireEvent("specialkey", this, e);
9068         }
9069     },
9070     focus : function (selectText){
9071         if(this.rendered){
9072             this.inputEl().focus();
9073             if(selectText === true){
9074                 this.inputEl().dom.select();
9075             }
9076         }
9077         return this;
9078     } ,
9079     
9080     onFocus : function(){
9081         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9082            // this.el.addClass(this.focusClass);
9083         }
9084         if(!this.hasFocus){
9085             this.hasFocus = true;
9086             this.startValue = this.getValue();
9087             this.fireEvent("focus", this);
9088         }
9089     },
9090     
9091     beforeBlur : Roo.emptyFn,
9092
9093     
9094     // private
9095     onBlur : function(){
9096         this.beforeBlur();
9097         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9098             //this.el.removeClass(this.focusClass);
9099         }
9100         this.hasFocus = false;
9101         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9102             this.validate();
9103         }
9104         var v = this.getValue();
9105         if(String(v) !== String(this.startValue)){
9106             this.fireEvent('change', this, v, this.startValue);
9107         }
9108         this.fireEvent("blur", this);
9109     },
9110     
9111     /**
9112      * Resets the current field value to the originally loaded value and clears any validation messages
9113      */
9114     reset : function(){
9115         this.setValue(this.originalValue);
9116         this.validate();
9117     },
9118      /**
9119      * Returns the name of the field
9120      * @return {Mixed} name The name field
9121      */
9122     getName: function(){
9123         return this.name;
9124     },
9125      /**
9126      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
9127      * @return {Mixed} value The field value
9128      */
9129     getValue : function(){
9130         
9131         var v = this.inputEl().getValue();
9132         
9133         return v;
9134     },
9135     /**
9136      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
9137      * @return {Mixed} value The field value
9138      */
9139     getRawValue : function(){
9140         var v = this.inputEl().getValue();
9141         
9142         return v;
9143     },
9144     
9145     /**
9146      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
9147      * @param {Mixed} value The value to set
9148      */
9149     setRawValue : function(v){
9150         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9151     },
9152     
9153     selectText : function(start, end){
9154         var v = this.getRawValue();
9155         if(v.length > 0){
9156             start = start === undefined ? 0 : start;
9157             end = end === undefined ? v.length : end;
9158             var d = this.inputEl().dom;
9159             if(d.setSelectionRange){
9160                 d.setSelectionRange(start, end);
9161             }else if(d.createTextRange){
9162                 var range = d.createTextRange();
9163                 range.moveStart("character", start);
9164                 range.moveEnd("character", v.length-end);
9165                 range.select();
9166             }
9167         }
9168     },
9169     
9170     /**
9171      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
9172      * @param {Mixed} value The value to set
9173      */
9174     setValue : function(v){
9175         this.value = v;
9176         if(this.rendered){
9177             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9178             this.validate();
9179         }
9180     },
9181     
9182     /*
9183     processValue : function(value){
9184         if(this.stripCharsRe){
9185             var newValue = value.replace(this.stripCharsRe, '');
9186             if(newValue !== value){
9187                 this.setRawValue(newValue);
9188                 return newValue;
9189             }
9190         }
9191         return value;
9192     },
9193   */
9194     preFocus : function(){
9195         
9196         if(this.selectOnFocus){
9197             this.inputEl().dom.select();
9198         }
9199     },
9200     filterKeys : function(e){
9201         var k = e.getKey();
9202         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9203             return;
9204         }
9205         var c = e.getCharCode(), cc = String.fromCharCode(c);
9206         if(Roo.isIE && (e.isSpecialKey() || !cc)){
9207             return;
9208         }
9209         if(!this.maskRe.test(cc)){
9210             e.stopEvent();
9211         }
9212     },
9213      /**
9214      * Clear any invalid styles/messages for this field
9215      */
9216     clearInvalid : function(){
9217         
9218         if(!this.el || this.preventMark){ // not rendered
9219             return;
9220         }
9221         
9222      
9223         this.el.removeClass(this.invalidClass);
9224         
9225         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9226             
9227             var feedback = this.el.select('.form-control-feedback', true).first();
9228             
9229             if(feedback){
9230                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9231             }
9232             
9233         }
9234         
9235         this.fireEvent('valid', this);
9236     },
9237     
9238      /**
9239      * Mark this field as valid
9240      */
9241     markValid : function()
9242     {
9243         if(!this.el  || this.preventMark){ // not rendered...
9244             return;
9245         }
9246         
9247         this.el.removeClass([this.invalidClass, this.validClass]);
9248         
9249         var feedback = this.el.select('.form-control-feedback', true).first();
9250             
9251         if(feedback){
9252             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9253         }
9254
9255         if(this.disabled){
9256             return;
9257         }
9258         
9259         if(this.allowBlank && !this.getRawValue().length){
9260             return;
9261         }
9262         
9263         if(this.indicator){
9264             this.indicator.removeClass('visible');
9265             this.indicator.addClass('invisible');
9266         }
9267         
9268         this.el.addClass(this.validClass);
9269         
9270         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9271             
9272             var feedback = this.el.select('.form-control-feedback', true).first();
9273             
9274             if(feedback){
9275                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9276                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9277             }
9278             
9279         }
9280         
9281         this.fireEvent('valid', this);
9282     },
9283     
9284      /**
9285      * Mark this field as invalid
9286      * @param {String} msg The validation message
9287      */
9288     markInvalid : function(msg)
9289     {
9290         if(!this.el  || this.preventMark){ // not rendered
9291             return;
9292         }
9293         
9294         this.el.removeClass([this.invalidClass, this.validClass]);
9295         
9296         var feedback = this.el.select('.form-control-feedback', true).first();
9297             
9298         if(feedback){
9299             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9300         }
9301
9302         if(this.disabled){
9303             return;
9304         }
9305         
9306         if(this.allowBlank && !this.getRawValue().length){
9307             return;
9308         }
9309         
9310         if(this.indicator){
9311             this.indicator.removeClass('invisible');
9312             this.indicator.addClass('visible');
9313         }
9314         
9315         this.el.addClass(this.invalidClass);
9316         
9317         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9318             
9319             var feedback = this.el.select('.form-control-feedback', true).first();
9320             
9321             if(feedback){
9322                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9323                 
9324                 if(this.getValue().length || this.forceFeedback){
9325                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9326                 }
9327                 
9328             }
9329             
9330         }
9331         
9332         this.fireEvent('invalid', this, msg);
9333     },
9334     // private
9335     SafariOnKeyDown : function(event)
9336     {
9337         // this is a workaround for a password hang bug on chrome/ webkit.
9338         if (this.inputEl().dom.type != 'password') {
9339             return;
9340         }
9341         
9342         var isSelectAll = false;
9343         
9344         if(this.inputEl().dom.selectionEnd > 0){
9345             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9346         }
9347         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9348             event.preventDefault();
9349             this.setValue('');
9350             return;
9351         }
9352         
9353         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9354             
9355             event.preventDefault();
9356             // this is very hacky as keydown always get's upper case.
9357             //
9358             var cc = String.fromCharCode(event.getCharCode());
9359             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
9360             
9361         }
9362     },
9363     adjustWidth : function(tag, w){
9364         tag = tag.toLowerCase();
9365         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9366             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9367                 if(tag == 'input'){
9368                     return w + 2;
9369                 }
9370                 if(tag == 'textarea'){
9371                     return w-2;
9372                 }
9373             }else if(Roo.isOpera){
9374                 if(tag == 'input'){
9375                     return w + 2;
9376                 }
9377                 if(tag == 'textarea'){
9378                     return w-2;
9379                 }
9380             }
9381         }
9382         return w;
9383     },
9384     
9385     setFieldLabel : function(v)
9386     {
9387         if(!this.rendered){
9388             return;
9389         }
9390         
9391         if(this.indicator){
9392             var ar = this.el.select('label > span',true);
9393             
9394             if (ar.elements.length) {
9395                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9396                 this.fieldLabel = v;
9397                 return;
9398             }
9399             
9400             var br = this.el.select('label',true);
9401             
9402             if(br.elements.length) {
9403                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9404                 this.fieldLabel = v;
9405                 return;
9406             }
9407             
9408             Roo.log('Cannot Found any of label > span || label in input');
9409             return;
9410         }
9411         
9412         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9413         this.fieldLabel = v;
9414         
9415         
9416     }
9417 });
9418
9419  
9420 /*
9421  * - LGPL
9422  *
9423  * Input
9424  * 
9425  */
9426
9427 /**
9428  * @class Roo.bootstrap.TextArea
9429  * @extends Roo.bootstrap.Input
9430  * Bootstrap TextArea class
9431  * @cfg {Number} cols Specifies the visible width of a text area
9432  * @cfg {Number} rows Specifies the visible number of lines in a text area
9433  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9434  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9435  * @cfg {string} html text
9436  * 
9437  * @constructor
9438  * Create a new TextArea
9439  * @param {Object} config The config object
9440  */
9441
9442 Roo.bootstrap.TextArea = function(config){
9443     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9444    
9445 };
9446
9447 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
9448      
9449     cols : false,
9450     rows : 5,
9451     readOnly : false,
9452     warp : 'soft',
9453     resize : false,
9454     value: false,
9455     html: false,
9456     
9457     getAutoCreate : function(){
9458         
9459         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9460         
9461         var id = Roo.id();
9462         
9463         var cfg = {};
9464         
9465         if(this.inputType != 'hidden'){
9466             cfg.cls = 'form-group' //input-group
9467         }
9468         
9469         var input =  {
9470             tag: 'textarea',
9471             id : id,
9472             warp : this.warp,
9473             rows : this.rows,
9474             value : this.value || '',
9475             html: this.html || '',
9476             cls : 'form-control',
9477             placeholder : this.placeholder || '' 
9478             
9479         };
9480         
9481         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9482             input.maxLength = this.maxLength;
9483         }
9484         
9485         if(this.resize){
9486             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9487         }
9488         
9489         if(this.cols){
9490             input.cols = this.cols;
9491         }
9492         
9493         if (this.readOnly) {
9494             input.readonly = true;
9495         }
9496         
9497         if (this.name) {
9498             input.name = this.name;
9499         }
9500         
9501         if (this.size) {
9502             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9503         }
9504         
9505         var settings=this;
9506         ['xs','sm','md','lg'].map(function(size){
9507             if (settings[size]) {
9508                 cfg.cls += ' col-' + size + '-' + settings[size];
9509             }
9510         });
9511         
9512         var inputblock = input;
9513         
9514         if(this.hasFeedback && !this.allowBlank){
9515             
9516             var feedback = {
9517                 tag: 'span',
9518                 cls: 'glyphicon form-control-feedback'
9519             };
9520
9521             inputblock = {
9522                 cls : 'has-feedback',
9523                 cn :  [
9524                     input,
9525                     feedback
9526                 ] 
9527             };  
9528         }
9529         
9530         
9531         if (this.before || this.after) {
9532             
9533             inputblock = {
9534                 cls : 'input-group',
9535                 cn :  [] 
9536             };
9537             if (this.before) {
9538                 inputblock.cn.push({
9539                     tag :'span',
9540                     cls : 'input-group-addon',
9541                     html : this.before
9542                 });
9543             }
9544             
9545             inputblock.cn.push(input);
9546             
9547             if(this.hasFeedback && !this.allowBlank){
9548                 inputblock.cls += ' has-feedback';
9549                 inputblock.cn.push(feedback);
9550             }
9551             
9552             if (this.after) {
9553                 inputblock.cn.push({
9554                     tag :'span',
9555                     cls : 'input-group-addon',
9556                     html : this.after
9557                 });
9558             }
9559             
9560         }
9561         
9562         if (align ==='left' && this.fieldLabel.length) {
9563             cfg.cn = [
9564                 {
9565                     tag: 'label',
9566                     'for' :  id,
9567                     cls : 'control-label',
9568                     html : this.fieldLabel
9569                 },
9570                 {
9571                     cls : "",
9572                     cn: [
9573                         inputblock
9574                     ]
9575                 }
9576
9577             ];
9578             
9579             if(this.labelWidth > 12){
9580                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9581             }
9582
9583             if(this.labelWidth < 13 && this.labelmd == 0){
9584                 this.labelmd = this.labelWidth;
9585             }
9586
9587             if(this.labellg > 0){
9588                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9589                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9590             }
9591
9592             if(this.labelmd > 0){
9593                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9594                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9595             }
9596
9597             if(this.labelsm > 0){
9598                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9599                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9600             }
9601
9602             if(this.labelxs > 0){
9603                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9604                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9605             }
9606             
9607         } else if ( this.fieldLabel.length) {
9608             cfg.cn = [
9609
9610                {
9611                    tag: 'label',
9612                    //cls : 'input-group-addon',
9613                    html : this.fieldLabel
9614
9615                },
9616
9617                inputblock
9618
9619            ];
9620
9621         } else {
9622
9623             cfg.cn = [
9624
9625                 inputblock
9626
9627             ];
9628                 
9629         }
9630         
9631         if (this.disabled) {
9632             input.disabled=true;
9633         }
9634         
9635         return cfg;
9636         
9637     },
9638     /**
9639      * return the real textarea element.
9640      */
9641     inputEl: function ()
9642     {
9643         return this.el.select('textarea.form-control',true).first();
9644     },
9645     
9646     /**
9647      * Clear any invalid styles/messages for this field
9648      */
9649     clearInvalid : function()
9650     {
9651         
9652         if(!this.el || this.preventMark){ // not rendered
9653             return;
9654         }
9655         
9656         var label = this.el.select('label', true).first();
9657         var icon = this.el.select('i.fa-star', true).first();
9658         
9659         if(label && icon){
9660             icon.remove();
9661         }
9662         
9663         this.el.removeClass(this.invalidClass);
9664         
9665         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9666             
9667             var feedback = this.el.select('.form-control-feedback', true).first();
9668             
9669             if(feedback){
9670                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9671             }
9672             
9673         }
9674         
9675         this.fireEvent('valid', this);
9676     },
9677     
9678      /**
9679      * Mark this field as valid
9680      */
9681     markValid : function()
9682     {
9683         if(!this.el  || this.preventMark){ // not rendered
9684             return;
9685         }
9686         
9687         this.el.removeClass([this.invalidClass, this.validClass]);
9688         
9689         var feedback = this.el.select('.form-control-feedback', true).first();
9690             
9691         if(feedback){
9692             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9693         }
9694
9695         if(this.disabled || this.allowBlank){
9696             return;
9697         }
9698         
9699         var label = this.el.select('label', true).first();
9700         var icon = this.el.select('i.fa-star', true).first();
9701         
9702         if(label && icon){
9703             icon.remove();
9704         }
9705         
9706         this.el.addClass(this.validClass);
9707         
9708         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9709             
9710             var feedback = this.el.select('.form-control-feedback', true).first();
9711             
9712             if(feedback){
9713                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9714                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9715             }
9716             
9717         }
9718         
9719         this.fireEvent('valid', this);
9720     },
9721     
9722      /**
9723      * Mark this field as invalid
9724      * @param {String} msg The validation message
9725      */
9726     markInvalid : function(msg)
9727     {
9728         if(!this.el  || this.preventMark){ // not rendered
9729             return;
9730         }
9731         
9732         this.el.removeClass([this.invalidClass, this.validClass]);
9733         
9734         var feedback = this.el.select('.form-control-feedback', true).first();
9735             
9736         if(feedback){
9737             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9738         }
9739
9740         if(this.disabled || this.allowBlank){
9741             return;
9742         }
9743         
9744         var label = this.el.select('label', true).first();
9745         var icon = this.el.select('i.fa-star', true).first();
9746         
9747         if(!this.getValue().length && label && !icon){
9748             this.el.createChild({
9749                 tag : 'i',
9750                 cls : 'text-danger fa fa-lg fa-star',
9751                 tooltip : 'This field is required',
9752                 style : 'margin-right:5px;'
9753             }, label, true);
9754         }
9755
9756         this.el.addClass(this.invalidClass);
9757         
9758         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9759             
9760             var feedback = this.el.select('.form-control-feedback', true).first();
9761             
9762             if(feedback){
9763                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9764                 
9765                 if(this.getValue().length || this.forceFeedback){
9766                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9767                 }
9768                 
9769             }
9770             
9771         }
9772         
9773         this.fireEvent('invalid', this, msg);
9774     }
9775 });
9776
9777  
9778 /*
9779  * - LGPL
9780  *
9781  * trigger field - base class for combo..
9782  * 
9783  */
9784  
9785 /**
9786  * @class Roo.bootstrap.TriggerField
9787  * @extends Roo.bootstrap.Input
9788  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9789  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9790  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9791  * for which you can provide a custom implementation.  For example:
9792  * <pre><code>
9793 var trigger = new Roo.bootstrap.TriggerField();
9794 trigger.onTriggerClick = myTriggerFn;
9795 trigger.applyTo('my-field');
9796 </code></pre>
9797  *
9798  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9799  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9800  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
9801  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9802  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9803
9804  * @constructor
9805  * Create a new TriggerField.
9806  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9807  * to the base TextField)
9808  */
9809 Roo.bootstrap.TriggerField = function(config){
9810     this.mimicing = false;
9811     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9812 };
9813
9814 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
9815     /**
9816      * @cfg {String} triggerClass A CSS class to apply to the trigger
9817      */
9818      /**
9819      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9820      */
9821     hideTrigger:false,
9822
9823     /**
9824      * @cfg {Boolean} removable (true|false) special filter default false
9825      */
9826     removable : false,
9827     
9828     /** @cfg {Boolean} grow @hide */
9829     /** @cfg {Number} growMin @hide */
9830     /** @cfg {Number} growMax @hide */
9831
9832     /**
9833      * @hide 
9834      * @method
9835      */
9836     autoSize: Roo.emptyFn,
9837     // private
9838     monitorTab : true,
9839     // private
9840     deferHeight : true,
9841
9842     
9843     actionMode : 'wrap',
9844     
9845     caret : false,
9846     
9847     
9848     getAutoCreate : function(){
9849        
9850         var align = this.labelAlign || this.parentLabelAlign();
9851         
9852         var id = Roo.id();
9853         
9854         var cfg = {
9855             cls: 'form-group' //input-group
9856         };
9857         
9858         
9859         var input =  {
9860             tag: 'input',
9861             id : id,
9862             type : this.inputType,
9863             cls : 'form-control',
9864             autocomplete: 'new-password',
9865             placeholder : this.placeholder || '' 
9866             
9867         };
9868         if (this.name) {
9869             input.name = this.name;
9870         }
9871         if (this.size) {
9872             input.cls += ' input-' + this.size;
9873         }
9874         
9875         if (this.disabled) {
9876             input.disabled=true;
9877         }
9878         
9879         var inputblock = input;
9880         
9881         if(this.hasFeedback && !this.allowBlank){
9882             
9883             var feedback = {
9884                 tag: 'span',
9885                 cls: 'glyphicon form-control-feedback'
9886             };
9887             
9888             if(this.removable && !this.editable && !this.tickable){
9889                 inputblock = {
9890                     cls : 'has-feedback',
9891                     cn :  [
9892                         inputblock,
9893                         {
9894                             tag: 'button',
9895                             html : 'x',
9896                             cls : 'roo-combo-removable-btn close'
9897                         },
9898                         feedback
9899                     ] 
9900                 };
9901             } else {
9902                 inputblock = {
9903                     cls : 'has-feedback',
9904                     cn :  [
9905                         inputblock,
9906                         feedback
9907                     ] 
9908                 };
9909             }
9910
9911         } else {
9912             if(this.removable && !this.editable && !this.tickable){
9913                 inputblock = {
9914                     cls : 'roo-removable',
9915                     cn :  [
9916                         inputblock,
9917                         {
9918                             tag: 'button',
9919                             html : 'x',
9920                             cls : 'roo-combo-removable-btn close'
9921                         }
9922                     ] 
9923                 };
9924             }
9925         }
9926         
9927         if (this.before || this.after) {
9928             
9929             inputblock = {
9930                 cls : 'input-group',
9931                 cn :  [] 
9932             };
9933             if (this.before) {
9934                 inputblock.cn.push({
9935                     tag :'span',
9936                     cls : 'input-group-addon',
9937                     html : this.before
9938                 });
9939             }
9940             
9941             inputblock.cn.push(input);
9942             
9943             if(this.hasFeedback && !this.allowBlank){
9944                 inputblock.cls += ' has-feedback';
9945                 inputblock.cn.push(feedback);
9946             }
9947             
9948             if (this.after) {
9949                 inputblock.cn.push({
9950                     tag :'span',
9951                     cls : 'input-group-addon',
9952                     html : this.after
9953                 });
9954             }
9955             
9956         };
9957         
9958         var box = {
9959             tag: 'div',
9960             cn: [
9961                 {
9962                     tag: 'input',
9963                     type : 'hidden',
9964                     cls: 'form-hidden-field'
9965                 },
9966                 inputblock
9967             ]
9968             
9969         };
9970         
9971         if(this.multiple){
9972             box = {
9973                 tag: 'div',
9974                 cn: [
9975                     {
9976                         tag: 'input',
9977                         type : 'hidden',
9978                         cls: 'form-hidden-field'
9979                     },
9980                     {
9981                         tag: 'ul',
9982                         cls: 'roo-select2-choices',
9983                         cn:[
9984                             {
9985                                 tag: 'li',
9986                                 cls: 'roo-select2-search-field',
9987                                 cn: [
9988
9989                                     inputblock
9990                                 ]
9991                             }
9992                         ]
9993                     }
9994                 ]
9995             }
9996         };
9997         
9998         var combobox = {
9999             cls: 'roo-select2-container input-group',
10000             cn: [
10001                 box
10002 //                {
10003 //                    tag: 'ul',
10004 //                    cls: 'typeahead typeahead-long dropdown-menu',
10005 //                    style: 'display:none'
10006 //                }
10007             ]
10008         };
10009         
10010         if(!this.multiple && this.showToggleBtn){
10011             
10012             var caret = {
10013                         tag: 'span',
10014                         cls: 'caret'
10015              };
10016             if (this.caret != false) {
10017                 caret = {
10018                      tag: 'i',
10019                      cls: 'fa fa-' + this.caret
10020                 };
10021                 
10022             }
10023             
10024             combobox.cn.push({
10025                 tag :'span',
10026                 cls : 'input-group-addon btn dropdown-toggle',
10027                 cn : [
10028                     caret,
10029                     {
10030                         tag: 'span',
10031                         cls: 'combobox-clear',
10032                         cn  : [
10033                             {
10034                                 tag : 'i',
10035                                 cls: 'icon-remove'
10036                             }
10037                         ]
10038                     }
10039                 ]
10040
10041             })
10042         }
10043         
10044         if(this.multiple){
10045             combobox.cls += ' roo-select2-container-multi';
10046         }
10047         
10048         if (align ==='left' && this.fieldLabel.length) {
10049             
10050             cfg.cls += ' roo-form-group-label-left';
10051
10052             cfg.cn = [
10053                 {
10054                     tag : 'i',
10055                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10056                     tooltip : 'This field is required'
10057                 },
10058                 {
10059                     tag: 'label',
10060                     'for' :  id,
10061                     cls : 'control-label',
10062                     html : this.fieldLabel
10063
10064                 },
10065                 {
10066                     cls : "", 
10067                     cn: [
10068                         combobox
10069                     ]
10070                 }
10071
10072             ];
10073             
10074             var labelCfg = cfg.cn[1];
10075             var contentCfg = cfg.cn[2];
10076             
10077             if(this.indicatorpos == 'right'){
10078                 cfg.cn = [
10079                     {
10080                         tag: 'label',
10081                         'for' :  id,
10082                         cls : 'control-label',
10083                         cn : [
10084                             {
10085                                 tag : 'span',
10086                                 html : this.fieldLabel
10087                             },
10088                             {
10089                                 tag : 'i',
10090                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10091                                 tooltip : 'This field is required'
10092                             }
10093                         ]
10094                     },
10095                     {
10096                         cls : "", 
10097                         cn: [
10098                             combobox
10099                         ]
10100                     }
10101
10102                 ];
10103                 
10104                 labelCfg = cfg.cn[0];
10105                 contentCfg = cfg.cn[1];
10106             }
10107             
10108             if(this.labelWidth > 12){
10109                 labelCfg.style = "width: " + this.labelWidth + 'px';
10110             }
10111             
10112             if(this.labelWidth < 13 && this.labelmd == 0){
10113                 this.labelmd = this.labelWidth;
10114             }
10115             
10116             if(this.labellg > 0){
10117                 labelCfg.cls += ' col-lg-' + this.labellg;
10118                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10119             }
10120             
10121             if(this.labelmd > 0){
10122                 labelCfg.cls += ' col-md-' + this.labelmd;
10123                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10124             }
10125             
10126             if(this.labelsm > 0){
10127                 labelCfg.cls += ' col-sm-' + this.labelsm;
10128                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10129             }
10130             
10131             if(this.labelxs > 0){
10132                 labelCfg.cls += ' col-xs-' + this.labelxs;
10133                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10134             }
10135             
10136         } else if ( this.fieldLabel.length) {
10137 //                Roo.log(" label");
10138             cfg.cn = [
10139                 {
10140                    tag : 'i',
10141                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10142                    tooltip : 'This field is required'
10143                },
10144                {
10145                    tag: 'label',
10146                    //cls : 'input-group-addon',
10147                    html : this.fieldLabel
10148
10149                },
10150
10151                combobox
10152
10153             ];
10154             
10155             if(this.indicatorpos == 'right'){
10156                 
10157                 cfg.cn = [
10158                     {
10159                        tag: 'label',
10160                        cn : [
10161                            {
10162                                tag : 'span',
10163                                html : this.fieldLabel
10164                            },
10165                            {
10166                               tag : 'i',
10167                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10168                               tooltip : 'This field is required'
10169                            }
10170                        ]
10171
10172                     },
10173                     combobox
10174
10175                 ];
10176
10177             }
10178
10179         } else {
10180             
10181 //                Roo.log(" no label && no align");
10182                 cfg = combobox
10183                      
10184                 
10185         }
10186         
10187         var settings=this;
10188         ['xs','sm','md','lg'].map(function(size){
10189             if (settings[size]) {
10190                 cfg.cls += ' col-' + size + '-' + settings[size];
10191             }
10192         });
10193         
10194         return cfg;
10195         
10196     },
10197     
10198     
10199     
10200     // private
10201     onResize : function(w, h){
10202 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10203 //        if(typeof w == 'number'){
10204 //            var x = w - this.trigger.getWidth();
10205 //            this.inputEl().setWidth(this.adjustWidth('input', x));
10206 //            this.trigger.setStyle('left', x+'px');
10207 //        }
10208     },
10209
10210     // private
10211     adjustSize : Roo.BoxComponent.prototype.adjustSize,
10212
10213     // private
10214     getResizeEl : function(){
10215         return this.inputEl();
10216     },
10217
10218     // private
10219     getPositionEl : function(){
10220         return this.inputEl();
10221     },
10222
10223     // private
10224     alignErrorIcon : function(){
10225         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10226     },
10227
10228     // private
10229     initEvents : function(){
10230         
10231         this.createList();
10232         
10233         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10234         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10235         if(!this.multiple && this.showToggleBtn){
10236             this.trigger = this.el.select('span.dropdown-toggle',true).first();
10237             if(this.hideTrigger){
10238                 this.trigger.setDisplayed(false);
10239             }
10240             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10241         }
10242         
10243         if(this.multiple){
10244             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10245         }
10246         
10247         if(this.removable && !this.editable && !this.tickable){
10248             var close = this.closeTriggerEl();
10249             
10250             if(close){
10251                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10252                 close.on('click', this.removeBtnClick, this, close);
10253             }
10254         }
10255         
10256         //this.trigger.addClassOnOver('x-form-trigger-over');
10257         //this.trigger.addClassOnClick('x-form-trigger-click');
10258         
10259         //if(!this.width){
10260         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10261         //}
10262     },
10263     
10264     closeTriggerEl : function()
10265     {
10266         var close = this.el.select('.roo-combo-removable-btn', true).first();
10267         return close ? close : false;
10268     },
10269     
10270     removeBtnClick : function(e, h, el)
10271     {
10272         e.preventDefault();
10273         
10274         if(this.fireEvent("remove", this) !== false){
10275             this.reset();
10276             this.fireEvent("afterremove", this)
10277         }
10278     },
10279     
10280     createList : function()
10281     {
10282         this.list = Roo.get(document.body).createChild({
10283             tag: 'ul',
10284             cls: 'typeahead typeahead-long dropdown-menu',
10285             style: 'display:none'
10286         });
10287         
10288         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10289         
10290     },
10291
10292     // private
10293     initTrigger : function(){
10294        
10295     },
10296
10297     // private
10298     onDestroy : function(){
10299         if(this.trigger){
10300             this.trigger.removeAllListeners();
10301           //  this.trigger.remove();
10302         }
10303         //if(this.wrap){
10304         //    this.wrap.remove();
10305         //}
10306         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10307     },
10308
10309     // private
10310     onFocus : function(){
10311         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10312         /*
10313         if(!this.mimicing){
10314             this.wrap.addClass('x-trigger-wrap-focus');
10315             this.mimicing = true;
10316             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10317             if(this.monitorTab){
10318                 this.el.on("keydown", this.checkTab, this);
10319             }
10320         }
10321         */
10322     },
10323
10324     // private
10325     checkTab : function(e){
10326         if(e.getKey() == e.TAB){
10327             this.triggerBlur();
10328         }
10329     },
10330
10331     // private
10332     onBlur : function(){
10333         // do nothing
10334     },
10335
10336     // private
10337     mimicBlur : function(e, t){
10338         /*
10339         if(!this.wrap.contains(t) && this.validateBlur()){
10340             this.triggerBlur();
10341         }
10342         */
10343     },
10344
10345     // private
10346     triggerBlur : function(){
10347         this.mimicing = false;
10348         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10349         if(this.monitorTab){
10350             this.el.un("keydown", this.checkTab, this);
10351         }
10352         //this.wrap.removeClass('x-trigger-wrap-focus');
10353         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10354     },
10355
10356     // private
10357     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10358     validateBlur : function(e, t){
10359         return true;
10360     },
10361
10362     // private
10363     onDisable : function(){
10364         this.inputEl().dom.disabled = true;
10365         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10366         //if(this.wrap){
10367         //    this.wrap.addClass('x-item-disabled');
10368         //}
10369     },
10370
10371     // private
10372     onEnable : function(){
10373         this.inputEl().dom.disabled = false;
10374         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10375         //if(this.wrap){
10376         //    this.el.removeClass('x-item-disabled');
10377         //}
10378     },
10379
10380     // private
10381     onShow : function(){
10382         var ae = this.getActionEl();
10383         
10384         if(ae){
10385             ae.dom.style.display = '';
10386             ae.dom.style.visibility = 'visible';
10387         }
10388     },
10389
10390     // private
10391     
10392     onHide : function(){
10393         var ae = this.getActionEl();
10394         ae.dom.style.display = 'none';
10395     },
10396
10397     /**
10398      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
10399      * by an implementing function.
10400      * @method
10401      * @param {EventObject} e
10402      */
10403     onTriggerClick : Roo.emptyFn
10404 });
10405  /*
10406  * Based on:
10407  * Ext JS Library 1.1.1
10408  * Copyright(c) 2006-2007, Ext JS, LLC.
10409  *
10410  * Originally Released Under LGPL - original licence link has changed is not relivant.
10411  *
10412  * Fork - LGPL
10413  * <script type="text/javascript">
10414  */
10415
10416
10417 /**
10418  * @class Roo.data.SortTypes
10419  * @singleton
10420  * Defines the default sorting (casting?) comparison functions used when sorting data.
10421  */
10422 Roo.data.SortTypes = {
10423     /**
10424      * Default sort that does nothing
10425      * @param {Mixed} s The value being converted
10426      * @return {Mixed} The comparison value
10427      */
10428     none : function(s){
10429         return s;
10430     },
10431     
10432     /**
10433      * The regular expression used to strip tags
10434      * @type {RegExp}
10435      * @property
10436      */
10437     stripTagsRE : /<\/?[^>]+>/gi,
10438     
10439     /**
10440      * Strips all HTML tags to sort on text only
10441      * @param {Mixed} s The value being converted
10442      * @return {String} The comparison value
10443      */
10444     asText : function(s){
10445         return String(s).replace(this.stripTagsRE, "");
10446     },
10447     
10448     /**
10449      * Strips all HTML tags to sort on text only - Case insensitive
10450      * @param {Mixed} s The value being converted
10451      * @return {String} The comparison value
10452      */
10453     asUCText : function(s){
10454         return String(s).toUpperCase().replace(this.stripTagsRE, "");
10455     },
10456     
10457     /**
10458      * Case insensitive string
10459      * @param {Mixed} s The value being converted
10460      * @return {String} The comparison value
10461      */
10462     asUCString : function(s) {
10463         return String(s).toUpperCase();
10464     },
10465     
10466     /**
10467      * Date sorting
10468      * @param {Mixed} s The value being converted
10469      * @return {Number} The comparison value
10470      */
10471     asDate : function(s) {
10472         if(!s){
10473             return 0;
10474         }
10475         if(s instanceof Date){
10476             return s.getTime();
10477         }
10478         return Date.parse(String(s));
10479     },
10480     
10481     /**
10482      * Float sorting
10483      * @param {Mixed} s The value being converted
10484      * @return {Float} The comparison value
10485      */
10486     asFloat : function(s) {
10487         var val = parseFloat(String(s).replace(/,/g, ""));
10488         if(isNaN(val)) {
10489             val = 0;
10490         }
10491         return val;
10492     },
10493     
10494     /**
10495      * Integer sorting
10496      * @param {Mixed} s The value being converted
10497      * @return {Number} The comparison value
10498      */
10499     asInt : function(s) {
10500         var val = parseInt(String(s).replace(/,/g, ""));
10501         if(isNaN(val)) {
10502             val = 0;
10503         }
10504         return val;
10505     }
10506 };/*
10507  * Based on:
10508  * Ext JS Library 1.1.1
10509  * Copyright(c) 2006-2007, Ext JS, LLC.
10510  *
10511  * Originally Released Under LGPL - original licence link has changed is not relivant.
10512  *
10513  * Fork - LGPL
10514  * <script type="text/javascript">
10515  */
10516
10517 /**
10518 * @class Roo.data.Record
10519  * Instances of this class encapsulate both record <em>definition</em> information, and record
10520  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10521  * to access Records cached in an {@link Roo.data.Store} object.<br>
10522  * <p>
10523  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10524  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10525  * objects.<br>
10526  * <p>
10527  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10528  * @constructor
10529  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10530  * {@link #create}. The parameters are the same.
10531  * @param {Array} data An associative Array of data values keyed by the field name.
10532  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10533  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10534  * not specified an integer id is generated.
10535  */
10536 Roo.data.Record = function(data, id){
10537     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10538     this.data = data;
10539 };
10540
10541 /**
10542  * Generate a constructor for a specific record layout.
10543  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10544  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10545  * Each field definition object may contain the following properties: <ul>
10546  * <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,
10547  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10548  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10549  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10550  * is being used, then this is a string containing the javascript expression to reference the data relative to 
10551  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10552  * to the data item relative to the record element. If the mapping expression is the same as the field name,
10553  * this may be omitted.</p></li>
10554  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10555  * <ul><li>auto (Default, implies no conversion)</li>
10556  * <li>string</li>
10557  * <li>int</li>
10558  * <li>float</li>
10559  * <li>boolean</li>
10560  * <li>date</li></ul></p></li>
10561  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10562  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10563  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10564  * by the Reader into an object that will be stored in the Record. It is passed the
10565  * following parameters:<ul>
10566  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10567  * </ul></p></li>
10568  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10569  * </ul>
10570  * <br>usage:<br><pre><code>
10571 var TopicRecord = Roo.data.Record.create(
10572     {name: 'title', mapping: 'topic_title'},
10573     {name: 'author', mapping: 'username'},
10574     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10575     {name: 'lastPost', mapping: 'post_time', type: 'date'},
10576     {name: 'lastPoster', mapping: 'user2'},
10577     {name: 'excerpt', mapping: 'post_text'}
10578 );
10579
10580 var myNewRecord = new TopicRecord({
10581     title: 'Do my job please',
10582     author: 'noobie',
10583     totalPosts: 1,
10584     lastPost: new Date(),
10585     lastPoster: 'Animal',
10586     excerpt: 'No way dude!'
10587 });
10588 myStore.add(myNewRecord);
10589 </code></pre>
10590  * @method create
10591  * @static
10592  */
10593 Roo.data.Record.create = function(o){
10594     var f = function(){
10595         f.superclass.constructor.apply(this, arguments);
10596     };
10597     Roo.extend(f, Roo.data.Record);
10598     var p = f.prototype;
10599     p.fields = new Roo.util.MixedCollection(false, function(field){
10600         return field.name;
10601     });
10602     for(var i = 0, len = o.length; i < len; i++){
10603         p.fields.add(new Roo.data.Field(o[i]));
10604     }
10605     f.getField = function(name){
10606         return p.fields.get(name);  
10607     };
10608     return f;
10609 };
10610
10611 Roo.data.Record.AUTO_ID = 1000;
10612 Roo.data.Record.EDIT = 'edit';
10613 Roo.data.Record.REJECT = 'reject';
10614 Roo.data.Record.COMMIT = 'commit';
10615
10616 Roo.data.Record.prototype = {
10617     /**
10618      * Readonly flag - true if this record has been modified.
10619      * @type Boolean
10620      */
10621     dirty : false,
10622     editing : false,
10623     error: null,
10624     modified: null,
10625
10626     // private
10627     join : function(store){
10628         this.store = store;
10629     },
10630
10631     /**
10632      * Set the named field to the specified value.
10633      * @param {String} name The name of the field to set.
10634      * @param {Object} value The value to set the field to.
10635      */
10636     set : function(name, value){
10637         if(this.data[name] == value){
10638             return;
10639         }
10640         this.dirty = true;
10641         if(!this.modified){
10642             this.modified = {};
10643         }
10644         if(typeof this.modified[name] == 'undefined'){
10645             this.modified[name] = this.data[name];
10646         }
10647         this.data[name] = value;
10648         if(!this.editing && this.store){
10649             this.store.afterEdit(this);
10650         }       
10651     },
10652
10653     /**
10654      * Get the value of the named field.
10655      * @param {String} name The name of the field to get the value of.
10656      * @return {Object} The value of the field.
10657      */
10658     get : function(name){
10659         return this.data[name]; 
10660     },
10661
10662     // private
10663     beginEdit : function(){
10664         this.editing = true;
10665         this.modified = {}; 
10666     },
10667
10668     // private
10669     cancelEdit : function(){
10670         this.editing = false;
10671         delete this.modified;
10672     },
10673
10674     // private
10675     endEdit : function(){
10676         this.editing = false;
10677         if(this.dirty && this.store){
10678             this.store.afterEdit(this);
10679         }
10680     },
10681
10682     /**
10683      * Usually called by the {@link Roo.data.Store} which owns the Record.
10684      * Rejects all changes made to the Record since either creation, or the last commit operation.
10685      * Modified fields are reverted to their original values.
10686      * <p>
10687      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10688      * of reject operations.
10689      */
10690     reject : function(){
10691         var m = this.modified;
10692         for(var n in m){
10693             if(typeof m[n] != "function"){
10694                 this.data[n] = m[n];
10695             }
10696         }
10697         this.dirty = false;
10698         delete this.modified;
10699         this.editing = false;
10700         if(this.store){
10701             this.store.afterReject(this);
10702         }
10703     },
10704
10705     /**
10706      * Usually called by the {@link Roo.data.Store} which owns the Record.
10707      * Commits all changes made to the Record since either creation, or the last commit operation.
10708      * <p>
10709      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10710      * of commit operations.
10711      */
10712     commit : function(){
10713         this.dirty = false;
10714         delete this.modified;
10715         this.editing = false;
10716         if(this.store){
10717             this.store.afterCommit(this);
10718         }
10719     },
10720
10721     // private
10722     hasError : function(){
10723         return this.error != null;
10724     },
10725
10726     // private
10727     clearError : function(){
10728         this.error = null;
10729     },
10730
10731     /**
10732      * Creates a copy of this record.
10733      * @param {String} id (optional) A new record id if you don't want to use this record's id
10734      * @return {Record}
10735      */
10736     copy : function(newId) {
10737         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10738     }
10739 };/*
10740  * Based on:
10741  * Ext JS Library 1.1.1
10742  * Copyright(c) 2006-2007, Ext JS, LLC.
10743  *
10744  * Originally Released Under LGPL - original licence link has changed is not relivant.
10745  *
10746  * Fork - LGPL
10747  * <script type="text/javascript">
10748  */
10749
10750
10751
10752 /**
10753  * @class Roo.data.Store
10754  * @extends Roo.util.Observable
10755  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10756  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10757  * <p>
10758  * 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
10759  * has no knowledge of the format of the data returned by the Proxy.<br>
10760  * <p>
10761  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10762  * instances from the data object. These records are cached and made available through accessor functions.
10763  * @constructor
10764  * Creates a new Store.
10765  * @param {Object} config A config object containing the objects needed for the Store to access data,
10766  * and read the data into Records.
10767  */
10768 Roo.data.Store = function(config){
10769     this.data = new Roo.util.MixedCollection(false);
10770     this.data.getKey = function(o){
10771         return o.id;
10772     };
10773     this.baseParams = {};
10774     // private
10775     this.paramNames = {
10776         "start" : "start",
10777         "limit" : "limit",
10778         "sort" : "sort",
10779         "dir" : "dir",
10780         "multisort" : "_multisort"
10781     };
10782
10783     if(config && config.data){
10784         this.inlineData = config.data;
10785         delete config.data;
10786     }
10787
10788     Roo.apply(this, config);
10789     
10790     if(this.reader){ // reader passed
10791         this.reader = Roo.factory(this.reader, Roo.data);
10792         this.reader.xmodule = this.xmodule || false;
10793         if(!this.recordType){
10794             this.recordType = this.reader.recordType;
10795         }
10796         if(this.reader.onMetaChange){
10797             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10798         }
10799     }
10800
10801     if(this.recordType){
10802         this.fields = this.recordType.prototype.fields;
10803     }
10804     this.modified = [];
10805
10806     this.addEvents({
10807         /**
10808          * @event datachanged
10809          * Fires when the data cache has changed, and a widget which is using this Store
10810          * as a Record cache should refresh its view.
10811          * @param {Store} this
10812          */
10813         datachanged : true,
10814         /**
10815          * @event metachange
10816          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10817          * @param {Store} this
10818          * @param {Object} meta The JSON metadata
10819          */
10820         metachange : true,
10821         /**
10822          * @event add
10823          * Fires when Records have been added to the Store
10824          * @param {Store} this
10825          * @param {Roo.data.Record[]} records The array of Records added
10826          * @param {Number} index The index at which the record(s) were added
10827          */
10828         add : true,
10829         /**
10830          * @event remove
10831          * Fires when a Record has been removed from the Store
10832          * @param {Store} this
10833          * @param {Roo.data.Record} record The Record that was removed
10834          * @param {Number} index The index at which the record was removed
10835          */
10836         remove : true,
10837         /**
10838          * @event update
10839          * Fires when a Record has been updated
10840          * @param {Store} this
10841          * @param {Roo.data.Record} record The Record that was updated
10842          * @param {String} operation The update operation being performed.  Value may be one of:
10843          * <pre><code>
10844  Roo.data.Record.EDIT
10845  Roo.data.Record.REJECT
10846  Roo.data.Record.COMMIT
10847          * </code></pre>
10848          */
10849         update : true,
10850         /**
10851          * @event clear
10852          * Fires when the data cache has been cleared.
10853          * @param {Store} this
10854          */
10855         clear : true,
10856         /**
10857          * @event beforeload
10858          * Fires before a request is made for a new data object.  If the beforeload handler returns false
10859          * the load action will be canceled.
10860          * @param {Store} this
10861          * @param {Object} options The loading options that were specified (see {@link #load} for details)
10862          */
10863         beforeload : true,
10864         /**
10865          * @event beforeloadadd
10866          * Fires after a new set of Records has been loaded.
10867          * @param {Store} this
10868          * @param {Roo.data.Record[]} records The Records that were loaded
10869          * @param {Object} options The loading options that were specified (see {@link #load} for details)
10870          */
10871         beforeloadadd : true,
10872         /**
10873          * @event load
10874          * Fires after a new set of Records has been loaded, before they are added to the store.
10875          * @param {Store} this
10876          * @param {Roo.data.Record[]} records The Records that were loaded
10877          * @param {Object} options The loading options that were specified (see {@link #load} for details)
10878          * @params {Object} return from reader
10879          */
10880         load : true,
10881         /**
10882          * @event loadexception
10883          * Fires if an exception occurs in the Proxy during loading.
10884          * Called with the signature of the Proxy's "loadexception" event.
10885          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10886          * 
10887          * @param {Proxy} 
10888          * @param {Object} return from JsonData.reader() - success, totalRecords, records
10889          * @param {Object} load options 
10890          * @param {Object} jsonData from your request (normally this contains the Exception)
10891          */
10892         loadexception : true
10893     });
10894     
10895     if(this.proxy){
10896         this.proxy = Roo.factory(this.proxy, Roo.data);
10897         this.proxy.xmodule = this.xmodule || false;
10898         this.relayEvents(this.proxy,  ["loadexception"]);
10899     }
10900     this.sortToggle = {};
10901     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10902
10903     Roo.data.Store.superclass.constructor.call(this);
10904
10905     if(this.inlineData){
10906         this.loadData(this.inlineData);
10907         delete this.inlineData;
10908     }
10909 };
10910
10911 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10912      /**
10913     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
10914     * without a remote query - used by combo/forms at present.
10915     */
10916     
10917     /**
10918     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10919     */
10920     /**
10921     * @cfg {Array} data Inline data to be loaded when the store is initialized.
10922     */
10923     /**
10924     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10925     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10926     */
10927     /**
10928     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10929     * on any HTTP request
10930     */
10931     /**
10932     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10933     */
10934     /**
10935     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10936     */
10937     multiSort: false,
10938     /**
10939     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10940     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10941     */
10942     remoteSort : false,
10943
10944     /**
10945     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10946      * loaded or when a record is removed. (defaults to false).
10947     */
10948     pruneModifiedRecords : false,
10949
10950     // private
10951     lastOptions : null,
10952
10953     /**
10954      * Add Records to the Store and fires the add event.
10955      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10956      */
10957     add : function(records){
10958         records = [].concat(records);
10959         for(var i = 0, len = records.length; i < len; i++){
10960             records[i].join(this);
10961         }
10962         var index = this.data.length;
10963         this.data.addAll(records);
10964         this.fireEvent("add", this, records, index);
10965     },
10966
10967     /**
10968      * Remove a Record from the Store and fires the remove event.
10969      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10970      */
10971     remove : function(record){
10972         var index = this.data.indexOf(record);
10973         this.data.removeAt(index);
10974         if(this.pruneModifiedRecords){
10975             this.modified.remove(record);
10976         }
10977         this.fireEvent("remove", this, record, index);
10978     },
10979
10980     /**
10981      * Remove all Records from the Store and fires the clear event.
10982      */
10983     removeAll : function(){
10984         this.data.clear();
10985         if(this.pruneModifiedRecords){
10986             this.modified = [];
10987         }
10988         this.fireEvent("clear", this);
10989     },
10990
10991     /**
10992      * Inserts Records to the Store at the given index and fires the add event.
10993      * @param {Number} index The start index at which to insert the passed Records.
10994      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10995      */
10996     insert : function(index, records){
10997         records = [].concat(records);
10998         for(var i = 0, len = records.length; i < len; i++){
10999             this.data.insert(index, records[i]);
11000             records[i].join(this);
11001         }
11002         this.fireEvent("add", this, records, index);
11003     },
11004
11005     /**
11006      * Get the index within the cache of the passed Record.
11007      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11008      * @return {Number} The index of the passed Record. Returns -1 if not found.
11009      */
11010     indexOf : function(record){
11011         return this.data.indexOf(record);
11012     },
11013
11014     /**
11015      * Get the index within the cache of the Record with the passed id.
11016      * @param {String} id The id of the Record to find.
11017      * @return {Number} The index of the Record. Returns -1 if not found.
11018      */
11019     indexOfId : function(id){
11020         return this.data.indexOfKey(id);
11021     },
11022
11023     /**
11024      * Get the Record with the specified id.
11025      * @param {String} id The id of the Record to find.
11026      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11027      */
11028     getById : function(id){
11029         return this.data.key(id);
11030     },
11031
11032     /**
11033      * Get the Record at the specified index.
11034      * @param {Number} index The index of the Record to find.
11035      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11036      */
11037     getAt : function(index){
11038         return this.data.itemAt(index);
11039     },
11040
11041     /**
11042      * Returns a range of Records between specified indices.
11043      * @param {Number} startIndex (optional) The starting index (defaults to 0)
11044      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11045      * @return {Roo.data.Record[]} An array of Records
11046      */
11047     getRange : function(start, end){
11048         return this.data.getRange(start, end);
11049     },
11050
11051     // private
11052     storeOptions : function(o){
11053         o = Roo.apply({}, o);
11054         delete o.callback;
11055         delete o.scope;
11056         this.lastOptions = o;
11057     },
11058
11059     /**
11060      * Loads the Record cache from the configured Proxy using the configured Reader.
11061      * <p>
11062      * If using remote paging, then the first load call must specify the <em>start</em>
11063      * and <em>limit</em> properties in the options.params property to establish the initial
11064      * position within the dataset, and the number of Records to cache on each read from the Proxy.
11065      * <p>
11066      * <strong>It is important to note that for remote data sources, loading is asynchronous,
11067      * and this call will return before the new data has been loaded. Perform any post-processing
11068      * in a callback function, or in a "load" event handler.</strong>
11069      * <p>
11070      * @param {Object} options An object containing properties which control loading options:<ul>
11071      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11072      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11073      * passed the following arguments:<ul>
11074      * <li>r : Roo.data.Record[]</li>
11075      * <li>options: Options object from the load call</li>
11076      * <li>success: Boolean success indicator</li></ul></li>
11077      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11078      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11079      * </ul>
11080      */
11081     load : function(options){
11082         options = options || {};
11083         if(this.fireEvent("beforeload", this, options) !== false){
11084             this.storeOptions(options);
11085             var p = Roo.apply(options.params || {}, this.baseParams);
11086             // if meta was not loaded from remote source.. try requesting it.
11087             if (!this.reader.metaFromRemote) {
11088                 p._requestMeta = 1;
11089             }
11090             if(this.sortInfo && this.remoteSort){
11091                 var pn = this.paramNames;
11092                 p[pn["sort"]] = this.sortInfo.field;
11093                 p[pn["dir"]] = this.sortInfo.direction;
11094             }
11095             if (this.multiSort) {
11096                 var pn = this.paramNames;
11097                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11098             }
11099             
11100             this.proxy.load(p, this.reader, this.loadRecords, this, options);
11101         }
11102     },
11103
11104     /**
11105      * Reloads the Record cache from the configured Proxy using the configured Reader and
11106      * the options from the last load operation performed.
11107      * @param {Object} options (optional) An object containing properties which may override the options
11108      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11109      * the most recently used options are reused).
11110      */
11111     reload : function(options){
11112         this.load(Roo.applyIf(options||{}, this.lastOptions));
11113     },
11114
11115     // private
11116     // Called as a callback by the Reader during a load operation.
11117     loadRecords : function(o, options, success){
11118         if(!o || success === false){
11119             if(success !== false){
11120                 this.fireEvent("load", this, [], options, o);
11121             }
11122             if(options.callback){
11123                 options.callback.call(options.scope || this, [], options, false);
11124             }
11125             return;
11126         }
11127         // if data returned failure - throw an exception.
11128         if (o.success === false) {
11129             // show a message if no listener is registered.
11130             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11131                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11132             }
11133             // loadmask wil be hooked into this..
11134             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11135             return;
11136         }
11137         var r = o.records, t = o.totalRecords || r.length;
11138         
11139         this.fireEvent("beforeloadadd", this, r, options, o);
11140         
11141         if(!options || options.add !== true){
11142             if(this.pruneModifiedRecords){
11143                 this.modified = [];
11144             }
11145             for(var i = 0, len = r.length; i < len; i++){
11146                 r[i].join(this);
11147             }
11148             if(this.snapshot){
11149                 this.data = this.snapshot;
11150                 delete this.snapshot;
11151             }
11152             this.data.clear();
11153             this.data.addAll(r);
11154             this.totalLength = t;
11155             this.applySort();
11156             this.fireEvent("datachanged", this);
11157         }else{
11158             this.totalLength = Math.max(t, this.data.length+r.length);
11159             this.add(r);
11160         }
11161         
11162         if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11163                 
11164             var e = new Roo.data.Record({});
11165
11166             e.set(this.parent.displayField, this.parent.emptyTitle);
11167             e.set(this.parent.valueField, '');
11168
11169             this.insert(0, e);
11170         }
11171             
11172         this.fireEvent("load", this, r, options, o);
11173         if(options.callback){
11174             options.callback.call(options.scope || this, r, options, true);
11175         }
11176     },
11177
11178
11179     /**
11180      * Loads data from a passed data block. A Reader which understands the format of the data
11181      * must have been configured in the constructor.
11182      * @param {Object} data The data block from which to read the Records.  The format of the data expected
11183      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11184      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11185      */
11186     loadData : function(o, append){
11187         var r = this.reader.readRecords(o);
11188         this.loadRecords(r, {add: append}, true);
11189     },
11190
11191     /**
11192      * Gets the number of cached records.
11193      * <p>
11194      * <em>If using paging, this may not be the total size of the dataset. If the data object
11195      * used by the Reader contains the dataset size, then the getTotalCount() function returns
11196      * the data set size</em>
11197      */
11198     getCount : function(){
11199         return this.data.length || 0;
11200     },
11201
11202     /**
11203      * Gets the total number of records in the dataset as returned by the server.
11204      * <p>
11205      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11206      * the dataset size</em>
11207      */
11208     getTotalCount : function(){
11209         return this.totalLength || 0;
11210     },
11211
11212     /**
11213      * Returns the sort state of the Store as an object with two properties:
11214      * <pre><code>
11215  field {String} The name of the field by which the Records are sorted
11216  direction {String} The sort order, "ASC" or "DESC"
11217      * </code></pre>
11218      */
11219     getSortState : function(){
11220         return this.sortInfo;
11221     },
11222
11223     // private
11224     applySort : function(){
11225         if(this.sortInfo && !this.remoteSort){
11226             var s = this.sortInfo, f = s.field;
11227             var st = this.fields.get(f).sortType;
11228             var fn = function(r1, r2){
11229                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11230                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11231             };
11232             this.data.sort(s.direction, fn);
11233             if(this.snapshot && this.snapshot != this.data){
11234                 this.snapshot.sort(s.direction, fn);
11235             }
11236         }
11237     },
11238
11239     /**
11240      * Sets the default sort column and order to be used by the next load operation.
11241      * @param {String} fieldName The name of the field to sort by.
11242      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11243      */
11244     setDefaultSort : function(field, dir){
11245         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11246     },
11247
11248     /**
11249      * Sort the Records.
11250      * If remote sorting is used, the sort is performed on the server, and the cache is
11251      * reloaded. If local sorting is used, the cache is sorted internally.
11252      * @param {String} fieldName The name of the field to sort by.
11253      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11254      */
11255     sort : function(fieldName, dir){
11256         var f = this.fields.get(fieldName);
11257         if(!dir){
11258             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11259             
11260             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11261                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11262             }else{
11263                 dir = f.sortDir;
11264             }
11265         }
11266         this.sortToggle[f.name] = dir;
11267         this.sortInfo = {field: f.name, direction: dir};
11268         if(!this.remoteSort){
11269             this.applySort();
11270             this.fireEvent("datachanged", this);
11271         }else{
11272             this.load(this.lastOptions);
11273         }
11274     },
11275
11276     /**
11277      * Calls the specified function for each of the Records in the cache.
11278      * @param {Function} fn The function to call. The Record is passed as the first parameter.
11279      * Returning <em>false</em> aborts and exits the iteration.
11280      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11281      */
11282     each : function(fn, scope){
11283         this.data.each(fn, scope);
11284     },
11285
11286     /**
11287      * Gets all records modified since the last commit.  Modified records are persisted across load operations
11288      * (e.g., during paging).
11289      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11290      */
11291     getModifiedRecords : function(){
11292         return this.modified;
11293     },
11294
11295     // private
11296     createFilterFn : function(property, value, anyMatch){
11297         if(!value.exec){ // not a regex
11298             value = String(value);
11299             if(value.length == 0){
11300                 return false;
11301             }
11302             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11303         }
11304         return function(r){
11305             return value.test(r.data[property]);
11306         };
11307     },
11308
11309     /**
11310      * Sums the value of <i>property</i> for each record between start and end and returns the result.
11311      * @param {String} property A field on your records
11312      * @param {Number} start The record index to start at (defaults to 0)
11313      * @param {Number} end The last record index to include (defaults to length - 1)
11314      * @return {Number} The sum
11315      */
11316     sum : function(property, start, end){
11317         var rs = this.data.items, v = 0;
11318         start = start || 0;
11319         end = (end || end === 0) ? end : rs.length-1;
11320
11321         for(var i = start; i <= end; i++){
11322             v += (rs[i].data[property] || 0);
11323         }
11324         return v;
11325     },
11326
11327     /**
11328      * Filter the records by a specified property.
11329      * @param {String} field A field on your records
11330      * @param {String/RegExp} value Either a string that the field
11331      * should start with or a RegExp to test against the field
11332      * @param {Boolean} anyMatch True to match any part not just the beginning
11333      */
11334     filter : function(property, value, anyMatch){
11335         var fn = this.createFilterFn(property, value, anyMatch);
11336         return fn ? this.filterBy(fn) : this.clearFilter();
11337     },
11338
11339     /**
11340      * Filter by a function. The specified function will be called with each
11341      * record in this data source. If the function returns true the record is included,
11342      * otherwise it is filtered.
11343      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11344      * @param {Object} scope (optional) The scope of the function (defaults to this)
11345      */
11346     filterBy : function(fn, scope){
11347         this.snapshot = this.snapshot || this.data;
11348         this.data = this.queryBy(fn, scope||this);
11349         this.fireEvent("datachanged", this);
11350     },
11351
11352     /**
11353      * Query the records by a specified property.
11354      * @param {String} field A field on your records
11355      * @param {String/RegExp} value Either a string that the field
11356      * should start with or a RegExp to test against the field
11357      * @param {Boolean} anyMatch True to match any part not just the beginning
11358      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11359      */
11360     query : function(property, value, anyMatch){
11361         var fn = this.createFilterFn(property, value, anyMatch);
11362         return fn ? this.queryBy(fn) : this.data.clone();
11363     },
11364
11365     /**
11366      * Query by a function. The specified function will be called with each
11367      * record in this data source. If the function returns true the record is included
11368      * in the results.
11369      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11370      * @param {Object} scope (optional) The scope of the function (defaults to this)
11371       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11372      **/
11373     queryBy : function(fn, scope){
11374         var data = this.snapshot || this.data;
11375         return data.filterBy(fn, scope||this);
11376     },
11377
11378     /**
11379      * Collects unique values for a particular dataIndex from this store.
11380      * @param {String} dataIndex The property to collect
11381      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11382      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11383      * @return {Array} An array of the unique values
11384      **/
11385     collect : function(dataIndex, allowNull, bypassFilter){
11386         var d = (bypassFilter === true && this.snapshot) ?
11387                 this.snapshot.items : this.data.items;
11388         var v, sv, r = [], l = {};
11389         for(var i = 0, len = d.length; i < len; i++){
11390             v = d[i].data[dataIndex];
11391             sv = String(v);
11392             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11393                 l[sv] = true;
11394                 r[r.length] = v;
11395             }
11396         }
11397         return r;
11398     },
11399
11400     /**
11401      * Revert to a view of the Record cache with no filtering applied.
11402      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11403      */
11404     clearFilter : function(suppressEvent){
11405         if(this.snapshot && this.snapshot != this.data){
11406             this.data = this.snapshot;
11407             delete this.snapshot;
11408             if(suppressEvent !== true){
11409                 this.fireEvent("datachanged", this);
11410             }
11411         }
11412     },
11413
11414     // private
11415     afterEdit : function(record){
11416         if(this.modified.indexOf(record) == -1){
11417             this.modified.push(record);
11418         }
11419         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11420     },
11421     
11422     // private
11423     afterReject : function(record){
11424         this.modified.remove(record);
11425         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11426     },
11427
11428     // private
11429     afterCommit : function(record){
11430         this.modified.remove(record);
11431         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11432     },
11433
11434     /**
11435      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11436      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11437      */
11438     commitChanges : function(){
11439         var m = this.modified.slice(0);
11440         this.modified = [];
11441         for(var i = 0, len = m.length; i < len; i++){
11442             m[i].commit();
11443         }
11444     },
11445
11446     /**
11447      * Cancel outstanding changes on all changed records.
11448      */
11449     rejectChanges : function(){
11450         var m = this.modified.slice(0);
11451         this.modified = [];
11452         for(var i = 0, len = m.length; i < len; i++){
11453             m[i].reject();
11454         }
11455     },
11456
11457     onMetaChange : function(meta, rtype, o){
11458         this.recordType = rtype;
11459         this.fields = rtype.prototype.fields;
11460         delete this.snapshot;
11461         this.sortInfo = meta.sortInfo || this.sortInfo;
11462         this.modified = [];
11463         this.fireEvent('metachange', this, this.reader.meta);
11464     },
11465     
11466     moveIndex : function(data, type)
11467     {
11468         var index = this.indexOf(data);
11469         
11470         var newIndex = index + type;
11471         
11472         this.remove(data);
11473         
11474         this.insert(newIndex, data);
11475         
11476     }
11477 });/*
11478  * Based on:
11479  * Ext JS Library 1.1.1
11480  * Copyright(c) 2006-2007, Ext JS, LLC.
11481  *
11482  * Originally Released Under LGPL - original licence link has changed is not relivant.
11483  *
11484  * Fork - LGPL
11485  * <script type="text/javascript">
11486  */
11487
11488 /**
11489  * @class Roo.data.SimpleStore
11490  * @extends Roo.data.Store
11491  * Small helper class to make creating Stores from Array data easier.
11492  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11493  * @cfg {Array} fields An array of field definition objects, or field name strings.
11494  * @cfg {Array} data The multi-dimensional array of data
11495  * @constructor
11496  * @param {Object} config
11497  */
11498 Roo.data.SimpleStore = function(config){
11499     Roo.data.SimpleStore.superclass.constructor.call(this, {
11500         isLocal : true,
11501         reader: new Roo.data.ArrayReader({
11502                 id: config.id
11503             },
11504             Roo.data.Record.create(config.fields)
11505         ),
11506         proxy : new Roo.data.MemoryProxy(config.data)
11507     });
11508     this.load();
11509 };
11510 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11511  * Based on:
11512  * Ext JS Library 1.1.1
11513  * Copyright(c) 2006-2007, Ext JS, LLC.
11514  *
11515  * Originally Released Under LGPL - original licence link has changed is not relivant.
11516  *
11517  * Fork - LGPL
11518  * <script type="text/javascript">
11519  */
11520
11521 /**
11522 /**
11523  * @extends Roo.data.Store
11524  * @class Roo.data.JsonStore
11525  * Small helper class to make creating Stores for JSON data easier. <br/>
11526 <pre><code>
11527 var store = new Roo.data.JsonStore({
11528     url: 'get-images.php',
11529     root: 'images',
11530     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11531 });
11532 </code></pre>
11533  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11534  * JsonReader and HttpProxy (unless inline data is provided).</b>
11535  * @cfg {Array} fields An array of field definition objects, or field name strings.
11536  * @constructor
11537  * @param {Object} config
11538  */
11539 Roo.data.JsonStore = function(c){
11540     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11541         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11542         reader: new Roo.data.JsonReader(c, c.fields)
11543     }));
11544 };
11545 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11546  * Based on:
11547  * Ext JS Library 1.1.1
11548  * Copyright(c) 2006-2007, Ext JS, LLC.
11549  *
11550  * Originally Released Under LGPL - original licence link has changed is not relivant.
11551  *
11552  * Fork - LGPL
11553  * <script type="text/javascript">
11554  */
11555
11556  
11557 Roo.data.Field = function(config){
11558     if(typeof config == "string"){
11559         config = {name: config};
11560     }
11561     Roo.apply(this, config);
11562     
11563     if(!this.type){
11564         this.type = "auto";
11565     }
11566     
11567     var st = Roo.data.SortTypes;
11568     // named sortTypes are supported, here we look them up
11569     if(typeof this.sortType == "string"){
11570         this.sortType = st[this.sortType];
11571     }
11572     
11573     // set default sortType for strings and dates
11574     if(!this.sortType){
11575         switch(this.type){
11576             case "string":
11577                 this.sortType = st.asUCString;
11578                 break;
11579             case "date":
11580                 this.sortType = st.asDate;
11581                 break;
11582             default:
11583                 this.sortType = st.none;
11584         }
11585     }
11586
11587     // define once
11588     var stripRe = /[\$,%]/g;
11589
11590     // prebuilt conversion function for this field, instead of
11591     // switching every time we're reading a value
11592     if(!this.convert){
11593         var cv, dateFormat = this.dateFormat;
11594         switch(this.type){
11595             case "":
11596             case "auto":
11597             case undefined:
11598                 cv = function(v){ return v; };
11599                 break;
11600             case "string":
11601                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11602                 break;
11603             case "int":
11604                 cv = function(v){
11605                     return v !== undefined && v !== null && v !== '' ?
11606                            parseInt(String(v).replace(stripRe, ""), 10) : '';
11607                     };
11608                 break;
11609             case "float":
11610                 cv = function(v){
11611                     return v !== undefined && v !== null && v !== '' ?
11612                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
11613                     };
11614                 break;
11615             case "bool":
11616             case "boolean":
11617                 cv = function(v){ return v === true || v === "true" || v == 1; };
11618                 break;
11619             case "date":
11620                 cv = function(v){
11621                     if(!v){
11622                         return '';
11623                     }
11624                     if(v instanceof Date){
11625                         return v;
11626                     }
11627                     if(dateFormat){
11628                         if(dateFormat == "timestamp"){
11629                             return new Date(v*1000);
11630                         }
11631                         return Date.parseDate(v, dateFormat);
11632                     }
11633                     var parsed = Date.parse(v);
11634                     return parsed ? new Date(parsed) : null;
11635                 };
11636              break;
11637             
11638         }
11639         this.convert = cv;
11640     }
11641 };
11642
11643 Roo.data.Field.prototype = {
11644     dateFormat: null,
11645     defaultValue: "",
11646     mapping: null,
11647     sortType : null,
11648     sortDir : "ASC"
11649 };/*
11650  * Based on:
11651  * Ext JS Library 1.1.1
11652  * Copyright(c) 2006-2007, Ext JS, LLC.
11653  *
11654  * Originally Released Under LGPL - original licence link has changed is not relivant.
11655  *
11656  * Fork - LGPL
11657  * <script type="text/javascript">
11658  */
11659  
11660 // Base class for reading structured data from a data source.  This class is intended to be
11661 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11662
11663 /**
11664  * @class Roo.data.DataReader
11665  * Base class for reading structured data from a data source.  This class is intended to be
11666  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11667  */
11668
11669 Roo.data.DataReader = function(meta, recordType){
11670     
11671     this.meta = meta;
11672     
11673     this.recordType = recordType instanceof Array ? 
11674         Roo.data.Record.create(recordType) : recordType;
11675 };
11676
11677 Roo.data.DataReader.prototype = {
11678      /**
11679      * Create an empty record
11680      * @param {Object} data (optional) - overlay some values
11681      * @return {Roo.data.Record} record created.
11682      */
11683     newRow :  function(d) {
11684         var da =  {};
11685         this.recordType.prototype.fields.each(function(c) {
11686             switch( c.type) {
11687                 case 'int' : da[c.name] = 0; break;
11688                 case 'date' : da[c.name] = new Date(); break;
11689                 case 'float' : da[c.name] = 0.0; break;
11690                 case 'boolean' : da[c.name] = false; break;
11691                 default : da[c.name] = ""; break;
11692             }
11693             
11694         });
11695         return new this.recordType(Roo.apply(da, d));
11696     }
11697     
11698 };/*
11699  * Based on:
11700  * Ext JS Library 1.1.1
11701  * Copyright(c) 2006-2007, Ext JS, LLC.
11702  *
11703  * Originally Released Under LGPL - original licence link has changed is not relivant.
11704  *
11705  * Fork - LGPL
11706  * <script type="text/javascript">
11707  */
11708
11709 /**
11710  * @class Roo.data.DataProxy
11711  * @extends Roo.data.Observable
11712  * This class is an abstract base class for implementations which provide retrieval of
11713  * unformatted data objects.<br>
11714  * <p>
11715  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11716  * (of the appropriate type which knows how to parse the data object) to provide a block of
11717  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11718  * <p>
11719  * Custom implementations must implement the load method as described in
11720  * {@link Roo.data.HttpProxy#load}.
11721  */
11722 Roo.data.DataProxy = function(){
11723     this.addEvents({
11724         /**
11725          * @event beforeload
11726          * Fires before a network request is made to retrieve a data object.
11727          * @param {Object} This DataProxy object.
11728          * @param {Object} params The params parameter to the load function.
11729          */
11730         beforeload : true,
11731         /**
11732          * @event load
11733          * Fires before the load method's callback is called.
11734          * @param {Object} This DataProxy object.
11735          * @param {Object} o The data object.
11736          * @param {Object} arg The callback argument object passed to the load function.
11737          */
11738         load : true,
11739         /**
11740          * @event loadexception
11741          * Fires if an Exception occurs during data retrieval.
11742          * @param {Object} This DataProxy object.
11743          * @param {Object} o The data object.
11744          * @param {Object} arg The callback argument object passed to the load function.
11745          * @param {Object} e The Exception.
11746          */
11747         loadexception : true
11748     });
11749     Roo.data.DataProxy.superclass.constructor.call(this);
11750 };
11751
11752 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11753
11754     /**
11755      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11756      */
11757 /*
11758  * Based on:
11759  * Ext JS Library 1.1.1
11760  * Copyright(c) 2006-2007, Ext JS, LLC.
11761  *
11762  * Originally Released Under LGPL - original licence link has changed is not relivant.
11763  *
11764  * Fork - LGPL
11765  * <script type="text/javascript">
11766  */
11767 /**
11768  * @class Roo.data.MemoryProxy
11769  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11770  * to the Reader when its load method is called.
11771  * @constructor
11772  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11773  */
11774 Roo.data.MemoryProxy = function(data){
11775     if (data.data) {
11776         data = data.data;
11777     }
11778     Roo.data.MemoryProxy.superclass.constructor.call(this);
11779     this.data = data;
11780 };
11781
11782 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11783     
11784     /**
11785      * Load data from the requested source (in this case an in-memory
11786      * data object passed to the constructor), read the data object into
11787      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11788      * process that block using the passed callback.
11789      * @param {Object} params This parameter is not used by the MemoryProxy class.
11790      * @param {Roo.data.DataReader} reader The Reader object which converts the data
11791      * object into a block of Roo.data.Records.
11792      * @param {Function} callback The function into which to pass the block of Roo.data.records.
11793      * The function must be passed <ul>
11794      * <li>The Record block object</li>
11795      * <li>The "arg" argument from the load function</li>
11796      * <li>A boolean success indicator</li>
11797      * </ul>
11798      * @param {Object} scope The scope in which to call the callback
11799      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11800      */
11801     load : function(params, reader, callback, scope, arg){
11802         params = params || {};
11803         var result;
11804         try {
11805             result = reader.readRecords(this.data);
11806         }catch(e){
11807             this.fireEvent("loadexception", this, arg, null, e);
11808             callback.call(scope, null, arg, false);
11809             return;
11810         }
11811         callback.call(scope, result, arg, true);
11812     },
11813     
11814     // private
11815     update : function(params, records){
11816         
11817     }
11818 });/*
11819  * Based on:
11820  * Ext JS Library 1.1.1
11821  * Copyright(c) 2006-2007, Ext JS, LLC.
11822  *
11823  * Originally Released Under LGPL - original licence link has changed is not relivant.
11824  *
11825  * Fork - LGPL
11826  * <script type="text/javascript">
11827  */
11828 /**
11829  * @class Roo.data.HttpProxy
11830  * @extends Roo.data.DataProxy
11831  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11832  * configured to reference a certain URL.<br><br>
11833  * <p>
11834  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11835  * from which the running page was served.<br><br>
11836  * <p>
11837  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11838  * <p>
11839  * Be aware that to enable the browser to parse an XML document, the server must set
11840  * the Content-Type header in the HTTP response to "text/xml".
11841  * @constructor
11842  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11843  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
11844  * will be used to make the request.
11845  */
11846 Roo.data.HttpProxy = function(conn){
11847     Roo.data.HttpProxy.superclass.constructor.call(this);
11848     // is conn a conn config or a real conn?
11849     this.conn = conn;
11850     this.useAjax = !conn || !conn.events;
11851   
11852 };
11853
11854 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11855     // thse are take from connection...
11856     
11857     /**
11858      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11859      */
11860     /**
11861      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11862      * extra parameters to each request made by this object. (defaults to undefined)
11863      */
11864     /**
11865      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11866      *  to each request made by this object. (defaults to undefined)
11867      */
11868     /**
11869      * @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)
11870      */
11871     /**
11872      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11873      */
11874      /**
11875      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11876      * @type Boolean
11877      */
11878   
11879
11880     /**
11881      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11882      * @type Boolean
11883      */
11884     /**
11885      * Return the {@link Roo.data.Connection} object being used by this Proxy.
11886      * @return {Connection} The Connection object. This object may be used to subscribe to events on
11887      * a finer-grained basis than the DataProxy events.
11888      */
11889     getConnection : function(){
11890         return this.useAjax ? Roo.Ajax : this.conn;
11891     },
11892
11893     /**
11894      * Load data from the configured {@link Roo.data.Connection}, read the data object into
11895      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11896      * process that block using the passed callback.
11897      * @param {Object} params An object containing properties which are to be used as HTTP parameters
11898      * for the request to the remote server.
11899      * @param {Roo.data.DataReader} reader The Reader object which converts the data
11900      * object into a block of Roo.data.Records.
11901      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11902      * The function must be passed <ul>
11903      * <li>The Record block object</li>
11904      * <li>The "arg" argument from the load function</li>
11905      * <li>A boolean success indicator</li>
11906      * </ul>
11907      * @param {Object} scope The scope in which to call the callback
11908      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11909      */
11910     load : function(params, reader, callback, scope, arg){
11911         if(this.fireEvent("beforeload", this, params) !== false){
11912             var  o = {
11913                 params : params || {},
11914                 request: {
11915                     callback : callback,
11916                     scope : scope,
11917                     arg : arg
11918                 },
11919                 reader: reader,
11920                 callback : this.loadResponse,
11921                 scope: this
11922             };
11923             if(this.useAjax){
11924                 Roo.applyIf(o, this.conn);
11925                 if(this.activeRequest){
11926                     Roo.Ajax.abort(this.activeRequest);
11927                 }
11928                 this.activeRequest = Roo.Ajax.request(o);
11929             }else{
11930                 this.conn.request(o);
11931             }
11932         }else{
11933             callback.call(scope||this, null, arg, false);
11934         }
11935     },
11936
11937     // private
11938     loadResponse : function(o, success, response){
11939         delete this.activeRequest;
11940         if(!success){
11941             this.fireEvent("loadexception", this, o, response);
11942             o.request.callback.call(o.request.scope, null, o.request.arg, false);
11943             return;
11944         }
11945         var result;
11946         try {
11947             result = o.reader.read(response);
11948         }catch(e){
11949             this.fireEvent("loadexception", this, o, response, e);
11950             o.request.callback.call(o.request.scope, null, o.request.arg, false);
11951             return;
11952         }
11953         
11954         this.fireEvent("load", this, o, o.request.arg);
11955         o.request.callback.call(o.request.scope, result, o.request.arg, true);
11956     },
11957
11958     // private
11959     update : function(dataSet){
11960
11961     },
11962
11963     // private
11964     updateResponse : function(dataSet){
11965
11966     }
11967 });/*
11968  * Based on:
11969  * Ext JS Library 1.1.1
11970  * Copyright(c) 2006-2007, Ext JS, LLC.
11971  *
11972  * Originally Released Under LGPL - original licence link has changed is not relivant.
11973  *
11974  * Fork - LGPL
11975  * <script type="text/javascript">
11976  */
11977
11978 /**
11979  * @class Roo.data.ScriptTagProxy
11980  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11981  * other than the originating domain of the running page.<br><br>
11982  * <p>
11983  * <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
11984  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11985  * <p>
11986  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11987  * source code that is used as the source inside a &lt;script> tag.<br><br>
11988  * <p>
11989  * In order for the browser to process the returned data, the server must wrap the data object
11990  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11991  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11992  * depending on whether the callback name was passed:
11993  * <p>
11994  * <pre><code>
11995 boolean scriptTag = false;
11996 String cb = request.getParameter("callback");
11997 if (cb != null) {
11998     scriptTag = true;
11999     response.setContentType("text/javascript");
12000 } else {
12001     response.setContentType("application/x-json");
12002 }
12003 Writer out = response.getWriter();
12004 if (scriptTag) {
12005     out.write(cb + "(");
12006 }
12007 out.print(dataBlock.toJsonString());
12008 if (scriptTag) {
12009     out.write(");");
12010 }
12011 </pre></code>
12012  *
12013  * @constructor
12014  * @param {Object} config A configuration object.
12015  */
12016 Roo.data.ScriptTagProxy = function(config){
12017     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12018     Roo.apply(this, config);
12019     this.head = document.getElementsByTagName("head")[0];
12020 };
12021
12022 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12023
12024 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12025     /**
12026      * @cfg {String} url The URL from which to request the data object.
12027      */
12028     /**
12029      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12030      */
12031     timeout : 30000,
12032     /**
12033      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12034      * the server the name of the callback function set up by the load call to process the returned data object.
12035      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12036      * javascript output which calls this named function passing the data object as its only parameter.
12037      */
12038     callbackParam : "callback",
12039     /**
12040      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12041      * name to the request.
12042      */
12043     nocache : true,
12044
12045     /**
12046      * Load data from the configured URL, read the data object into
12047      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12048      * process that block using the passed callback.
12049      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12050      * for the request to the remote server.
12051      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12052      * object into a block of Roo.data.Records.
12053      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12054      * The function must be passed <ul>
12055      * <li>The Record block object</li>
12056      * <li>The "arg" argument from the load function</li>
12057      * <li>A boolean success indicator</li>
12058      * </ul>
12059      * @param {Object} scope The scope in which to call the callback
12060      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12061      */
12062     load : function(params, reader, callback, scope, arg){
12063         if(this.fireEvent("beforeload", this, params) !== false){
12064
12065             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12066
12067             var url = this.url;
12068             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12069             if(this.nocache){
12070                 url += "&_dc=" + (new Date().getTime());
12071             }
12072             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12073             var trans = {
12074                 id : transId,
12075                 cb : "stcCallback"+transId,
12076                 scriptId : "stcScript"+transId,
12077                 params : params,
12078                 arg : arg,
12079                 url : url,
12080                 callback : callback,
12081                 scope : scope,
12082                 reader : reader
12083             };
12084             var conn = this;
12085
12086             window[trans.cb] = function(o){
12087                 conn.handleResponse(o, trans);
12088             };
12089
12090             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12091
12092             if(this.autoAbort !== false){
12093                 this.abort();
12094             }
12095
12096             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12097
12098             var script = document.createElement("script");
12099             script.setAttribute("src", url);
12100             script.setAttribute("type", "text/javascript");
12101             script.setAttribute("id", trans.scriptId);
12102             this.head.appendChild(script);
12103
12104             this.trans = trans;
12105         }else{
12106             callback.call(scope||this, null, arg, false);
12107         }
12108     },
12109
12110     // private
12111     isLoading : function(){
12112         return this.trans ? true : false;
12113     },
12114
12115     /**
12116      * Abort the current server request.
12117      */
12118     abort : function(){
12119         if(this.isLoading()){
12120             this.destroyTrans(this.trans);
12121         }
12122     },
12123
12124     // private
12125     destroyTrans : function(trans, isLoaded){
12126         this.head.removeChild(document.getElementById(trans.scriptId));
12127         clearTimeout(trans.timeoutId);
12128         if(isLoaded){
12129             window[trans.cb] = undefined;
12130             try{
12131                 delete window[trans.cb];
12132             }catch(e){}
12133         }else{
12134             // if hasn't been loaded, wait for load to remove it to prevent script error
12135             window[trans.cb] = function(){
12136                 window[trans.cb] = undefined;
12137                 try{
12138                     delete window[trans.cb];
12139                 }catch(e){}
12140             };
12141         }
12142     },
12143
12144     // private
12145     handleResponse : function(o, trans){
12146         this.trans = false;
12147         this.destroyTrans(trans, true);
12148         var result;
12149         try {
12150             result = trans.reader.readRecords(o);
12151         }catch(e){
12152             this.fireEvent("loadexception", this, o, trans.arg, e);
12153             trans.callback.call(trans.scope||window, null, trans.arg, false);
12154             return;
12155         }
12156         this.fireEvent("load", this, o, trans.arg);
12157         trans.callback.call(trans.scope||window, result, trans.arg, true);
12158     },
12159
12160     // private
12161     handleFailure : function(trans){
12162         this.trans = false;
12163         this.destroyTrans(trans, false);
12164         this.fireEvent("loadexception", this, null, trans.arg);
12165         trans.callback.call(trans.scope||window, null, trans.arg, false);
12166     }
12167 });/*
12168  * Based on:
12169  * Ext JS Library 1.1.1
12170  * Copyright(c) 2006-2007, Ext JS, LLC.
12171  *
12172  * Originally Released Under LGPL - original licence link has changed is not relivant.
12173  *
12174  * Fork - LGPL
12175  * <script type="text/javascript">
12176  */
12177
12178 /**
12179  * @class Roo.data.JsonReader
12180  * @extends Roo.data.DataReader
12181  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12182  * based on mappings in a provided Roo.data.Record constructor.
12183  * 
12184  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12185  * in the reply previously. 
12186  * 
12187  * <p>
12188  * Example code:
12189  * <pre><code>
12190 var RecordDef = Roo.data.Record.create([
12191     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
12192     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
12193 ]);
12194 var myReader = new Roo.data.JsonReader({
12195     totalProperty: "results",    // The property which contains the total dataset size (optional)
12196     root: "rows",                // The property which contains an Array of row objects
12197     id: "id"                     // The property within each row object that provides an ID for the record (optional)
12198 }, RecordDef);
12199 </code></pre>
12200  * <p>
12201  * This would consume a JSON file like this:
12202  * <pre><code>
12203 { 'results': 2, 'rows': [
12204     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12205     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12206 }
12207 </code></pre>
12208  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12209  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12210  * paged from the remote server.
12211  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12212  * @cfg {String} root name of the property which contains the Array of row objects.
12213  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12214  * @cfg {Array} fields Array of field definition objects
12215  * @constructor
12216  * Create a new JsonReader
12217  * @param {Object} meta Metadata configuration options
12218  * @param {Object} recordType Either an Array of field definition objects,
12219  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12220  */
12221 Roo.data.JsonReader = function(meta, recordType){
12222     
12223     meta = meta || {};
12224     // set some defaults:
12225     Roo.applyIf(meta, {
12226         totalProperty: 'total',
12227         successProperty : 'success',
12228         root : 'data',
12229         id : 'id'
12230     });
12231     
12232     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12233 };
12234 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12235     
12236     /**
12237      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
12238      * Used by Store query builder to append _requestMeta to params.
12239      * 
12240      */
12241     metaFromRemote : false,
12242     /**
12243      * This method is only used by a DataProxy which has retrieved data from a remote server.
12244      * @param {Object} response The XHR object which contains the JSON data in its responseText.
12245      * @return {Object} data A data block which is used by an Roo.data.Store object as
12246      * a cache of Roo.data.Records.
12247      */
12248     read : function(response){
12249         var json = response.responseText;
12250        
12251         var o = /* eval:var:o */ eval("("+json+")");
12252         if(!o) {
12253             throw {message: "JsonReader.read: Json object not found"};
12254         }
12255         
12256         if(o.metaData){
12257             
12258             delete this.ef;
12259             this.metaFromRemote = true;
12260             this.meta = o.metaData;
12261             this.recordType = Roo.data.Record.create(o.metaData.fields);
12262             this.onMetaChange(this.meta, this.recordType, o);
12263         }
12264         return this.readRecords(o);
12265     },
12266
12267     // private function a store will implement
12268     onMetaChange : function(meta, recordType, o){
12269
12270     },
12271
12272     /**
12273          * @ignore
12274          */
12275     simpleAccess: function(obj, subsc) {
12276         return obj[subsc];
12277     },
12278
12279         /**
12280          * @ignore
12281          */
12282     getJsonAccessor: function(){
12283         var re = /[\[\.]/;
12284         return function(expr) {
12285             try {
12286                 return(re.test(expr))
12287                     ? new Function("obj", "return obj." + expr)
12288                     : function(obj){
12289                         return obj[expr];
12290                     };
12291             } catch(e){}
12292             return Roo.emptyFn;
12293         };
12294     }(),
12295
12296     /**
12297      * Create a data block containing Roo.data.Records from an XML document.
12298      * @param {Object} o An object which contains an Array of row objects in the property specified
12299      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12300      * which contains the total size of the dataset.
12301      * @return {Object} data A data block which is used by an Roo.data.Store object as
12302      * a cache of Roo.data.Records.
12303      */
12304     readRecords : function(o){
12305         /**
12306          * After any data loads, the raw JSON data is available for further custom processing.
12307          * @type Object
12308          */
12309         this.o = o;
12310         var s = this.meta, Record = this.recordType,
12311             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12312
12313 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
12314         if (!this.ef) {
12315             if(s.totalProperty) {
12316                     this.getTotal = this.getJsonAccessor(s.totalProperty);
12317                 }
12318                 if(s.successProperty) {
12319                     this.getSuccess = this.getJsonAccessor(s.successProperty);
12320                 }
12321                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12322                 if (s.id) {
12323                         var g = this.getJsonAccessor(s.id);
12324                         this.getId = function(rec) {
12325                                 var r = g(rec);  
12326                                 return (r === undefined || r === "") ? null : r;
12327                         };
12328                 } else {
12329                         this.getId = function(){return null;};
12330                 }
12331             this.ef = [];
12332             for(var jj = 0; jj < fl; jj++){
12333                 f = fi[jj];
12334                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12335                 this.ef[jj] = this.getJsonAccessor(map);
12336             }
12337         }
12338
12339         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12340         if(s.totalProperty){
12341             var vt = parseInt(this.getTotal(o), 10);
12342             if(!isNaN(vt)){
12343                 totalRecords = vt;
12344             }
12345         }
12346         if(s.successProperty){
12347             var vs = this.getSuccess(o);
12348             if(vs === false || vs === 'false'){
12349                 success = false;
12350             }
12351         }
12352         var records = [];
12353         for(var i = 0; i < c; i++){
12354                 var n = root[i];
12355             var values = {};
12356             var id = this.getId(n);
12357             for(var j = 0; j < fl; j++){
12358                 f = fi[j];
12359             var v = this.ef[j](n);
12360             if (!f.convert) {
12361                 Roo.log('missing convert for ' + f.name);
12362                 Roo.log(f);
12363                 continue;
12364             }
12365             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12366             }
12367             var record = new Record(values, id);
12368             record.json = n;
12369             records[i] = record;
12370         }
12371         return {
12372             raw : o,
12373             success : success,
12374             records : records,
12375             totalRecords : totalRecords
12376         };
12377     }
12378 });/*
12379  * Based on:
12380  * Ext JS Library 1.1.1
12381  * Copyright(c) 2006-2007, Ext JS, LLC.
12382  *
12383  * Originally Released Under LGPL - original licence link has changed is not relivant.
12384  *
12385  * Fork - LGPL
12386  * <script type="text/javascript">
12387  */
12388
12389 /**
12390  * @class Roo.data.ArrayReader
12391  * @extends Roo.data.DataReader
12392  * Data reader class to create an Array of Roo.data.Record objects from an Array.
12393  * Each element of that Array represents a row of data fields. The
12394  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12395  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12396  * <p>
12397  * Example code:.
12398  * <pre><code>
12399 var RecordDef = Roo.data.Record.create([
12400     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
12401     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
12402 ]);
12403 var myReader = new Roo.data.ArrayReader({
12404     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
12405 }, RecordDef);
12406 </code></pre>
12407  * <p>
12408  * This would consume an Array like this:
12409  * <pre><code>
12410 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12411   </code></pre>
12412  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12413  * @constructor
12414  * Create a new JsonReader
12415  * @param {Object} meta Metadata configuration options.
12416  * @param {Object} recordType Either an Array of field definition objects
12417  * as specified to {@link Roo.data.Record#create},
12418  * or an {@link Roo.data.Record} object
12419  * created using {@link Roo.data.Record#create}.
12420  */
12421 Roo.data.ArrayReader = function(meta, recordType){
12422     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12423 };
12424
12425 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12426     /**
12427      * Create a data block containing Roo.data.Records from an XML document.
12428      * @param {Object} o An Array of row objects which represents the dataset.
12429      * @return {Object} data A data block which is used by an Roo.data.Store object as
12430      * a cache of Roo.data.Records.
12431      */
12432     readRecords : function(o){
12433         var sid = this.meta ? this.meta.id : null;
12434         var recordType = this.recordType, fields = recordType.prototype.fields;
12435         var records = [];
12436         var root = o;
12437             for(var i = 0; i < root.length; i++){
12438                     var n = root[i];
12439                 var values = {};
12440                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12441                 for(var j = 0, jlen = fields.length; j < jlen; j++){
12442                 var f = fields.items[j];
12443                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12444                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12445                 v = f.convert(v);
12446                 values[f.name] = v;
12447             }
12448                 var record = new recordType(values, id);
12449                 record.json = n;
12450                 records[records.length] = record;
12451             }
12452             return {
12453                 records : records,
12454                 totalRecords : records.length
12455             };
12456     }
12457 });/*
12458  * - LGPL
12459  * * 
12460  */
12461
12462 /**
12463  * @class Roo.bootstrap.ComboBox
12464  * @extends Roo.bootstrap.TriggerField
12465  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12466  * @cfg {Boolean} append (true|false) default false
12467  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12468  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12469  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12470  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12471  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12472  * @cfg {Boolean} animate default true
12473  * @cfg {Boolean} emptyResultText only for touch device
12474  * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12475  * @cfg {String} emptyTitle default ''
12476  * @constructor
12477  * Create a new ComboBox.
12478  * @param {Object} config Configuration options
12479  */
12480 Roo.bootstrap.ComboBox = function(config){
12481     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12482     this.addEvents({
12483         /**
12484          * @event expand
12485          * Fires when the dropdown list is expanded
12486         * @param {Roo.bootstrap.ComboBox} combo This combo box
12487         */
12488         'expand' : true,
12489         /**
12490          * @event collapse
12491          * Fires when the dropdown list is collapsed
12492         * @param {Roo.bootstrap.ComboBox} combo This combo box
12493         */
12494         'collapse' : true,
12495         /**
12496          * @event beforeselect
12497          * Fires before a list item is selected. Return false to cancel the selection.
12498         * @param {Roo.bootstrap.ComboBox} combo This combo box
12499         * @param {Roo.data.Record} record The data record returned from the underlying store
12500         * @param {Number} index The index of the selected item in the dropdown list
12501         */
12502         'beforeselect' : true,
12503         /**
12504          * @event select
12505          * Fires when a list item is selected
12506         * @param {Roo.bootstrap.ComboBox} combo This combo box
12507         * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12508         * @param {Number} index The index of the selected item in the dropdown list
12509         */
12510         'select' : true,
12511         /**
12512          * @event beforequery
12513          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12514          * The event object passed has these properties:
12515         * @param {Roo.bootstrap.ComboBox} combo This combo box
12516         * @param {String} query The query
12517         * @param {Boolean} forceAll true to force "all" query
12518         * @param {Boolean} cancel true to cancel the query
12519         * @param {Object} e The query event object
12520         */
12521         'beforequery': true,
12522          /**
12523          * @event add
12524          * Fires when the 'add' icon is pressed (add a listener to enable add button)
12525         * @param {Roo.bootstrap.ComboBox} combo This combo box
12526         */
12527         'add' : true,
12528         /**
12529          * @event edit
12530          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12531         * @param {Roo.bootstrap.ComboBox} combo This combo box
12532         * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12533         */
12534         'edit' : true,
12535         /**
12536          * @event remove
12537          * Fires when the remove value from the combobox array
12538         * @param {Roo.bootstrap.ComboBox} combo This combo box
12539         */
12540         'remove' : true,
12541         /**
12542          * @event afterremove
12543          * Fires when the remove value from the combobox array
12544         * @param {Roo.bootstrap.ComboBox} combo This combo box
12545         */
12546         'afterremove' : true,
12547         /**
12548          * @event specialfilter
12549          * Fires when specialfilter
12550             * @param {Roo.bootstrap.ComboBox} combo This combo box
12551             */
12552         'specialfilter' : true,
12553         /**
12554          * @event tick
12555          * Fires when tick the element
12556             * @param {Roo.bootstrap.ComboBox} combo This combo box
12557             */
12558         'tick' : true,
12559         /**
12560          * @event touchviewdisplay
12561          * Fires when touch view require special display (default is using displayField)
12562             * @param {Roo.bootstrap.ComboBox} combo This combo box
12563             * @param {Object} cfg set html .
12564             */
12565         'touchviewdisplay' : true
12566         
12567     });
12568     
12569     this.item = [];
12570     this.tickItems = [];
12571     
12572     this.selectedIndex = -1;
12573     if(this.mode == 'local'){
12574         if(config.queryDelay === undefined){
12575             this.queryDelay = 10;
12576         }
12577         if(config.minChars === undefined){
12578             this.minChars = 0;
12579         }
12580     }
12581 };
12582
12583 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12584      
12585     /**
12586      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12587      * rendering into an Roo.Editor, defaults to false)
12588      */
12589     /**
12590      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12591      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12592      */
12593     /**
12594      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12595      */
12596     /**
12597      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12598      * the dropdown list (defaults to undefined, with no header element)
12599      */
12600
12601      /**
12602      * @cfg {String/Roo.Template} tpl The template to use to render the output
12603      */
12604      
12605      /**
12606      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12607      */
12608     listWidth: undefined,
12609     /**
12610      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12611      * mode = 'remote' or 'text' if mode = 'local')
12612      */
12613     displayField: undefined,
12614     
12615     /**
12616      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12617      * mode = 'remote' or 'value' if mode = 'local'). 
12618      * Note: use of a valueField requires the user make a selection
12619      * in order for a value to be mapped.
12620      */
12621     valueField: undefined,
12622     /**
12623      * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12624      */
12625     modalTitle : '',
12626     
12627     /**
12628      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12629      * field's data value (defaults to the underlying DOM element's name)
12630      */
12631     hiddenName: undefined,
12632     /**
12633      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12634      */
12635     listClass: '',
12636     /**
12637      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12638      */
12639     selectedClass: 'active',
12640     
12641     /**
12642      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12643      */
12644     shadow:'sides',
12645     /**
12646      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12647      * anchor positions (defaults to 'tl-bl')
12648      */
12649     listAlign: 'tl-bl?',
12650     /**
12651      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12652      */
12653     maxHeight: 300,
12654     /**
12655      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
12656      * query specified by the allQuery config option (defaults to 'query')
12657      */
12658     triggerAction: 'query',
12659     /**
12660      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12661      * (defaults to 4, does not apply if editable = false)
12662      */
12663     minChars : 4,
12664     /**
12665      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12666      * delay (typeAheadDelay) if it matches a known value (defaults to false)
12667      */
12668     typeAhead: false,
12669     /**
12670      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12671      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12672      */
12673     queryDelay: 500,
12674     /**
12675      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12676      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
12677      */
12678     pageSize: 0,
12679     /**
12680      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
12681      * when editable = true (defaults to false)
12682      */
12683     selectOnFocus:false,
12684     /**
12685      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12686      */
12687     queryParam: 'query',
12688     /**
12689      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
12690      * when mode = 'remote' (defaults to 'Loading...')
12691      */
12692     loadingText: 'Loading...',
12693     /**
12694      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12695      */
12696     resizable: false,
12697     /**
12698      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12699      */
12700     handleHeight : 8,
12701     /**
12702      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12703      * traditional select (defaults to true)
12704      */
12705     editable: true,
12706     /**
12707      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12708      */
12709     allQuery: '',
12710     /**
12711      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12712      */
12713     mode: 'remote',
12714     /**
12715      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12716      * listWidth has a higher value)
12717      */
12718     minListWidth : 70,
12719     /**
12720      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12721      * allow the user to set arbitrary text into the field (defaults to false)
12722      */
12723     forceSelection:false,
12724     /**
12725      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12726      * if typeAhead = true (defaults to 250)
12727      */
12728     typeAheadDelay : 250,
12729     /**
12730      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12731      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12732      */
12733     valueNotFoundText : undefined,
12734     /**
12735      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12736      */
12737     blockFocus : false,
12738     
12739     /**
12740      * @cfg {Boolean} disableClear Disable showing of clear button.
12741      */
12742     disableClear : false,
12743     /**
12744      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
12745      */
12746     alwaysQuery : false,
12747     
12748     /**
12749      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
12750      */
12751     multiple : false,
12752     
12753     /**
12754      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12755      */
12756     invalidClass : "has-warning",
12757     
12758     /**
12759      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12760      */
12761     validClass : "has-success",
12762     
12763     /**
12764      * @cfg {Boolean} specialFilter (true|false) special filter default false
12765      */
12766     specialFilter : false,
12767     
12768     /**
12769      * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12770      */
12771     mobileTouchView : true,
12772     
12773     /**
12774      * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12775      */
12776     useNativeIOS : false,
12777     
12778     ios_options : false,
12779     
12780     //private
12781     addicon : false,
12782     editicon: false,
12783     
12784     page: 0,
12785     hasQuery: false,
12786     append: false,
12787     loadNext: false,
12788     autoFocus : true,
12789     tickable : false,
12790     btnPosition : 'right',
12791     triggerList : true,
12792     showToggleBtn : true,
12793     animate : true,
12794     emptyResultText: 'Empty',
12795     triggerText : 'Select',
12796     emptyTitle : '',
12797     
12798     // element that contains real text value.. (when hidden is used..)
12799     
12800     getAutoCreate : function()
12801     {   
12802         var cfg = false;
12803         //render
12804         /*
12805          * Render classic select for iso
12806          */
12807         
12808         if(Roo.isIOS && this.useNativeIOS){
12809             cfg = this.getAutoCreateNativeIOS();
12810             return cfg;
12811         }
12812         
12813         /*
12814          * Touch Devices
12815          */
12816         
12817         if(Roo.isTouch && this.mobileTouchView){
12818             cfg = this.getAutoCreateTouchView();
12819             return cfg;;
12820         }
12821         
12822         /*
12823          *  Normal ComboBox
12824          */
12825         if(!this.tickable){
12826             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12827             return cfg;
12828         }
12829         
12830         /*
12831          *  ComboBox with tickable selections
12832          */
12833              
12834         var align = this.labelAlign || this.parentLabelAlign();
12835         
12836         cfg = {
12837             cls : 'form-group roo-combobox-tickable' //input-group
12838         };
12839         
12840         var btn_text_select = '';
12841         var btn_text_done = '';
12842         var btn_text_cancel = '';
12843         
12844         if (this.btn_text_show) {
12845             btn_text_select = 'Select';
12846             btn_text_done = 'Done';
12847             btn_text_cancel = 'Cancel'; 
12848         }
12849         
12850         var buttons = {
12851             tag : 'div',
12852             cls : 'tickable-buttons',
12853             cn : [
12854                 {
12855                     tag : 'button',
12856                     type : 'button',
12857                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12858                     //html : this.triggerText
12859                     html: btn_text_select
12860                 },
12861                 {
12862                     tag : 'button',
12863                     type : 'button',
12864                     name : 'ok',
12865                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12866                     //html : 'Done'
12867                     html: btn_text_done
12868                 },
12869                 {
12870                     tag : 'button',
12871                     type : 'button',
12872                     name : 'cancel',
12873                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12874                     //html : 'Cancel'
12875                     html: btn_text_cancel
12876                 }
12877             ]
12878         };
12879         
12880         if(this.editable){
12881             buttons.cn.unshift({
12882                 tag: 'input',
12883                 cls: 'roo-select2-search-field-input'
12884             });
12885         }
12886         
12887         var _this = this;
12888         
12889         Roo.each(buttons.cn, function(c){
12890             if (_this.size) {
12891                 c.cls += ' btn-' + _this.size;
12892             }
12893
12894             if (_this.disabled) {
12895                 c.disabled = true;
12896             }
12897         });
12898         
12899         var box = {
12900             tag: 'div',
12901             cn: [
12902                 {
12903                     tag: 'input',
12904                     type : 'hidden',
12905                     cls: 'form-hidden-field'
12906                 },
12907                 {
12908                     tag: 'ul',
12909                     cls: 'roo-select2-choices',
12910                     cn:[
12911                         {
12912                             tag: 'li',
12913                             cls: 'roo-select2-search-field',
12914                             cn: [
12915                                 buttons
12916                             ]
12917                         }
12918                     ]
12919                 }
12920             ]
12921         };
12922         
12923         var combobox = {
12924             cls: 'roo-select2-container input-group roo-select2-container-multi',
12925             cn: [
12926                 box
12927 //                {
12928 //                    tag: 'ul',
12929 //                    cls: 'typeahead typeahead-long dropdown-menu',
12930 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
12931 //                }
12932             ]
12933         };
12934         
12935         if(this.hasFeedback && !this.allowBlank){
12936             
12937             var feedback = {
12938                 tag: 'span',
12939                 cls: 'glyphicon form-control-feedback'
12940             };
12941
12942             combobox.cn.push(feedback);
12943         }
12944         
12945         
12946         if (align ==='left' && this.fieldLabel.length) {
12947             
12948             cfg.cls += ' roo-form-group-label-left';
12949             
12950             cfg.cn = [
12951                 {
12952                     tag : 'i',
12953                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12954                     tooltip : 'This field is required'
12955                 },
12956                 {
12957                     tag: 'label',
12958                     'for' :  id,
12959                     cls : 'control-label',
12960                     html : this.fieldLabel
12961
12962                 },
12963                 {
12964                     cls : "", 
12965                     cn: [
12966                         combobox
12967                     ]
12968                 }
12969
12970             ];
12971             
12972             var labelCfg = cfg.cn[1];
12973             var contentCfg = cfg.cn[2];
12974             
12975
12976             if(this.indicatorpos == 'right'){
12977                 
12978                 cfg.cn = [
12979                     {
12980                         tag: 'label',
12981                         'for' :  id,
12982                         cls : 'control-label',
12983                         cn : [
12984                             {
12985                                 tag : 'span',
12986                                 html : this.fieldLabel
12987                             },
12988                             {
12989                                 tag : 'i',
12990                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12991                                 tooltip : 'This field is required'
12992                             }
12993                         ]
12994                     },
12995                     {
12996                         cls : "",
12997                         cn: [
12998                             combobox
12999                         ]
13000                     }
13001
13002                 ];
13003                 
13004                 
13005                 
13006                 labelCfg = cfg.cn[0];
13007                 contentCfg = cfg.cn[1];
13008             
13009             }
13010             
13011             if(this.labelWidth > 12){
13012                 labelCfg.style = "width: " + this.labelWidth + 'px';
13013             }
13014             
13015             if(this.labelWidth < 13 && this.labelmd == 0){
13016                 this.labelmd = this.labelWidth;
13017             }
13018             
13019             if(this.labellg > 0){
13020                 labelCfg.cls += ' col-lg-' + this.labellg;
13021                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13022             }
13023             
13024             if(this.labelmd > 0){
13025                 labelCfg.cls += ' col-md-' + this.labelmd;
13026                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13027             }
13028             
13029             if(this.labelsm > 0){
13030                 labelCfg.cls += ' col-sm-' + this.labelsm;
13031                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13032             }
13033             
13034             if(this.labelxs > 0){
13035                 labelCfg.cls += ' col-xs-' + this.labelxs;
13036                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13037             }
13038                 
13039                 
13040         } else if ( this.fieldLabel.length) {
13041 //                Roo.log(" label");
13042                  cfg.cn = [
13043                     {
13044                         tag : 'i',
13045                         cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13046                         tooltip : 'This field is required'
13047                     },
13048                     {
13049                         tag: 'label',
13050                         //cls : 'input-group-addon',
13051                         html : this.fieldLabel
13052                     },
13053                     combobox
13054                 ];
13055                 
13056                 if(this.indicatorpos == 'right'){
13057                     cfg.cn = [
13058                         {
13059                             tag: 'label',
13060                             //cls : 'input-group-addon',
13061                             html : this.fieldLabel
13062                         },
13063                         {
13064                             tag : 'i',
13065                             cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13066                             tooltip : 'This field is required'
13067                         },
13068                         combobox
13069                     ];
13070                     
13071                 }
13072
13073         } else {
13074             
13075 //                Roo.log(" no label && no align");
13076                 cfg = combobox
13077                      
13078                 
13079         }
13080          
13081         var settings=this;
13082         ['xs','sm','md','lg'].map(function(size){
13083             if (settings[size]) {
13084                 cfg.cls += ' col-' + size + '-' + settings[size];
13085             }
13086         });
13087         
13088         return cfg;
13089         
13090     },
13091     
13092     _initEventsCalled : false,
13093     
13094     // private
13095     initEvents: function()
13096     {   
13097         if (this._initEventsCalled) { // as we call render... prevent looping...
13098             return;
13099         }
13100         this._initEventsCalled = true;
13101         
13102         if (!this.store) {
13103             throw "can not find store for combo";
13104         }
13105         
13106         this.indicator = this.indicatorEl();
13107         
13108         this.store = Roo.factory(this.store, Roo.data);
13109         this.store.parent = this;
13110         
13111         // if we are building from html. then this element is so complex, that we can not really
13112         // use the rendered HTML.
13113         // so we have to trash and replace the previous code.
13114         if (Roo.XComponent.build_from_html) {
13115             // remove this element....
13116             var e = this.el.dom, k=0;
13117             while (e ) { e = e.previousSibling;  ++k;}
13118
13119             this.el.remove();
13120             
13121             this.el=false;
13122             this.rendered = false;
13123             
13124             this.render(this.parent().getChildContainer(true), k);
13125         }
13126         
13127         if(Roo.isIOS && this.useNativeIOS){
13128             this.initIOSView();
13129             return;
13130         }
13131         
13132         /*
13133          * Touch Devices
13134          */
13135         
13136         if(Roo.isTouch && this.mobileTouchView){
13137             this.initTouchView();
13138             return;
13139         }
13140         
13141         if(this.tickable){
13142             this.initTickableEvents();
13143             return;
13144         }
13145         
13146         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13147         
13148         if(this.hiddenName){
13149             
13150             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13151             
13152             this.hiddenField.dom.value =
13153                 this.hiddenValue !== undefined ? this.hiddenValue :
13154                 this.value !== undefined ? this.value : '';
13155
13156             // prevent input submission
13157             this.el.dom.removeAttribute('name');
13158             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13159              
13160              
13161         }
13162         //if(Roo.isGecko){
13163         //    this.el.dom.setAttribute('autocomplete', 'off');
13164         //}
13165         
13166         var cls = 'x-combo-list';
13167         
13168         //this.list = new Roo.Layer({
13169         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13170         //});
13171         
13172         var _this = this;
13173         
13174         (function(){
13175             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13176             _this.list.setWidth(lw);
13177         }).defer(100);
13178         
13179         this.list.on('mouseover', this.onViewOver, this);
13180         this.list.on('mousemove', this.onViewMove, this);
13181         this.list.on('scroll', this.onViewScroll, this);
13182         
13183         /*
13184         this.list.swallowEvent('mousewheel');
13185         this.assetHeight = 0;
13186
13187         if(this.title){
13188             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13189             this.assetHeight += this.header.getHeight();
13190         }
13191
13192         this.innerList = this.list.createChild({cls:cls+'-inner'});
13193         this.innerList.on('mouseover', this.onViewOver, this);
13194         this.innerList.on('mousemove', this.onViewMove, this);
13195         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13196         
13197         if(this.allowBlank && !this.pageSize && !this.disableClear){
13198             this.footer = this.list.createChild({cls:cls+'-ft'});
13199             this.pageTb = new Roo.Toolbar(this.footer);
13200            
13201         }
13202         if(this.pageSize){
13203             this.footer = this.list.createChild({cls:cls+'-ft'});
13204             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13205                     {pageSize: this.pageSize});
13206             
13207         }
13208         
13209         if (this.pageTb && this.allowBlank && !this.disableClear) {
13210             var _this = this;
13211             this.pageTb.add(new Roo.Toolbar.Fill(), {
13212                 cls: 'x-btn-icon x-btn-clear',
13213                 text: '&#160;',
13214                 handler: function()
13215                 {
13216                     _this.collapse();
13217                     _this.clearValue();
13218                     _this.onSelect(false, -1);
13219                 }
13220             });
13221         }
13222         if (this.footer) {
13223             this.assetHeight += this.footer.getHeight();
13224         }
13225         */
13226             
13227         if(!this.tpl){
13228             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13229         }
13230
13231         this.view = new Roo.View(this.list, this.tpl, {
13232             singleSelect:true, store: this.store, selectedClass: this.selectedClass
13233         });
13234         //this.view.wrapEl.setDisplayed(false);
13235         this.view.on('click', this.onViewClick, this);
13236         
13237         
13238         this.store.on('beforeload', this.onBeforeLoad, this);
13239         this.store.on('load', this.onLoad, this);
13240         this.store.on('loadexception', this.onLoadException, this);
13241         /*
13242         if(this.resizable){
13243             this.resizer = new Roo.Resizable(this.list,  {
13244                pinned:true, handles:'se'
13245             });
13246             this.resizer.on('resize', function(r, w, h){
13247                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13248                 this.listWidth = w;
13249                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13250                 this.restrictHeight();
13251             }, this);
13252             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13253         }
13254         */
13255         if(!this.editable){
13256             this.editable = true;
13257             this.setEditable(false);
13258         }
13259         
13260         /*
13261         
13262         if (typeof(this.events.add.listeners) != 'undefined') {
13263             
13264             this.addicon = this.wrap.createChild(
13265                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
13266        
13267             this.addicon.on('click', function(e) {
13268                 this.fireEvent('add', this);
13269             }, this);
13270         }
13271         if (typeof(this.events.edit.listeners) != 'undefined') {
13272             
13273             this.editicon = this.wrap.createChild(
13274                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
13275             if (this.addicon) {
13276                 this.editicon.setStyle('margin-left', '40px');
13277             }
13278             this.editicon.on('click', function(e) {
13279                 
13280                 // we fire even  if inothing is selected..
13281                 this.fireEvent('edit', this, this.lastData );
13282                 
13283             }, this);
13284         }
13285         */
13286         
13287         this.keyNav = new Roo.KeyNav(this.inputEl(), {
13288             "up" : function(e){
13289                 this.inKeyMode = true;
13290                 this.selectPrev();
13291             },
13292
13293             "down" : function(e){
13294                 if(!this.isExpanded()){
13295                     this.onTriggerClick();
13296                 }else{
13297                     this.inKeyMode = true;
13298                     this.selectNext();
13299                 }
13300             },
13301
13302             "enter" : function(e){
13303 //                this.onViewClick();
13304                 //return true;
13305                 this.collapse();
13306                 
13307                 if(this.fireEvent("specialkey", this, e)){
13308                     this.onViewClick(false);
13309                 }
13310                 
13311                 return true;
13312             },
13313
13314             "esc" : function(e){
13315                 this.collapse();
13316             },
13317
13318             "tab" : function(e){
13319                 this.collapse();
13320                 
13321                 if(this.fireEvent("specialkey", this, e)){
13322                     this.onViewClick(false);
13323                 }
13324                 
13325                 return true;
13326             },
13327
13328             scope : this,
13329
13330             doRelay : function(foo, bar, hname){
13331                 if(hname == 'down' || this.scope.isExpanded()){
13332                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13333                 }
13334                 return true;
13335             },
13336
13337             forceKeyDown: true
13338         });
13339         
13340         
13341         this.queryDelay = Math.max(this.queryDelay || 10,
13342                 this.mode == 'local' ? 10 : 250);
13343         
13344         
13345         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13346         
13347         if(this.typeAhead){
13348             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13349         }
13350         if(this.editable !== false){
13351             this.inputEl().on("keyup", this.onKeyUp, this);
13352         }
13353         if(this.forceSelection){
13354             this.inputEl().on('blur', this.doForce, this);
13355         }
13356         
13357         if(this.multiple){
13358             this.choices = this.el.select('ul.roo-select2-choices', true).first();
13359             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13360         }
13361     },
13362     
13363     initTickableEvents: function()
13364     {   
13365         this.createList();
13366         
13367         if(this.hiddenName){
13368             
13369             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13370             
13371             this.hiddenField.dom.value =
13372                 this.hiddenValue !== undefined ? this.hiddenValue :
13373                 this.value !== undefined ? this.value : '';
13374
13375             // prevent input submission
13376             this.el.dom.removeAttribute('name');
13377             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13378              
13379              
13380         }
13381         
13382 //        this.list = this.el.select('ul.dropdown-menu',true).first();
13383         
13384         this.choices = this.el.select('ul.roo-select2-choices', true).first();
13385         this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13386         if(this.triggerList){
13387             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13388         }
13389          
13390         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13391         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13392         
13393         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13394         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13395         
13396         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13397         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13398         
13399         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13400         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13401         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13402         
13403         this.okBtn.hide();
13404         this.cancelBtn.hide();
13405         
13406         var _this = this;
13407         
13408         (function(){
13409             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13410             _this.list.setWidth(lw);
13411         }).defer(100);
13412         
13413         this.list.on('mouseover', this.onViewOver, this);
13414         this.list.on('mousemove', this.onViewMove, this);
13415         
13416         this.list.on('scroll', this.onViewScroll, this);
13417         
13418         if(!this.tpl){
13419             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>';
13420         }
13421
13422         this.view = new Roo.View(this.list, this.tpl, {
13423             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13424         });
13425         
13426         //this.view.wrapEl.setDisplayed(false);
13427         this.view.on('click', this.onViewClick, this);
13428         
13429         
13430         
13431         this.store.on('beforeload', this.onBeforeLoad, this);
13432         this.store.on('load', this.onLoad, this);
13433         this.store.on('loadexception', this.onLoadException, this);
13434         
13435         if(this.editable){
13436             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13437                 "up" : function(e){
13438                     this.inKeyMode = true;
13439                     this.selectPrev();
13440                 },
13441
13442                 "down" : function(e){
13443                     this.inKeyMode = true;
13444                     this.selectNext();
13445                 },
13446
13447                 "enter" : function(e){
13448                     if(this.fireEvent("specialkey", this, e)){
13449                         this.onViewClick(false);
13450                     }
13451                     
13452                     return true;
13453                 },
13454
13455                 "esc" : function(e){
13456                     this.onTickableFooterButtonClick(e, false, false);
13457                 },
13458
13459                 "tab" : function(e){
13460                     this.fireEvent("specialkey", this, e);
13461                     
13462                     this.onTickableFooterButtonClick(e, false, false);
13463                     
13464                     return true;
13465                 },
13466
13467                 scope : this,
13468
13469                 doRelay : function(e, fn, key){
13470                     if(this.scope.isExpanded()){
13471                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13472                     }
13473                     return true;
13474                 },
13475
13476                 forceKeyDown: true
13477             });
13478         }
13479         
13480         this.queryDelay = Math.max(this.queryDelay || 10,
13481                 this.mode == 'local' ? 10 : 250);
13482         
13483         
13484         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13485         
13486         if(this.typeAhead){
13487             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13488         }
13489         
13490         if(this.editable !== false){
13491             this.tickableInputEl().on("keyup", this.onKeyUp, this);
13492         }
13493         
13494         this.indicator = this.indicatorEl();
13495         
13496         if(this.indicator){
13497             this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13498             this.indicator.hide();
13499         }
13500         
13501     },
13502
13503     onDestroy : function(){
13504         if(this.view){
13505             this.view.setStore(null);
13506             this.view.el.removeAllListeners();
13507             this.view.el.remove();
13508             this.view.purgeListeners();
13509         }
13510         if(this.list){
13511             this.list.dom.innerHTML  = '';
13512         }
13513         
13514         if(this.store){
13515             this.store.un('beforeload', this.onBeforeLoad, this);
13516             this.store.un('load', this.onLoad, this);
13517             this.store.un('loadexception', this.onLoadException, this);
13518         }
13519         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13520     },
13521
13522     // private
13523     fireKey : function(e){
13524         if(e.isNavKeyPress() && !this.list.isVisible()){
13525             this.fireEvent("specialkey", this, e);
13526         }
13527     },
13528
13529     // private
13530     onResize: function(w, h){
13531 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13532 //        
13533 //        if(typeof w != 'number'){
13534 //            // we do not handle it!?!?
13535 //            return;
13536 //        }
13537 //        var tw = this.trigger.getWidth();
13538 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
13539 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
13540 //        var x = w - tw;
13541 //        this.inputEl().setWidth( this.adjustWidth('input', x));
13542 //            
13543 //        //this.trigger.setStyle('left', x+'px');
13544 //        
13545 //        if(this.list && this.listWidth === undefined){
13546 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13547 //            this.list.setWidth(lw);
13548 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13549 //        }
13550         
13551     
13552         
13553     },
13554
13555     /**
13556      * Allow or prevent the user from directly editing the field text.  If false is passed,
13557      * the user will only be able to select from the items defined in the dropdown list.  This method
13558      * is the runtime equivalent of setting the 'editable' config option at config time.
13559      * @param {Boolean} value True to allow the user to directly edit the field text
13560      */
13561     setEditable : function(value){
13562         if(value == this.editable){
13563             return;
13564         }
13565         this.editable = value;
13566         if(!value){
13567             this.inputEl().dom.setAttribute('readOnly', true);
13568             this.inputEl().on('mousedown', this.onTriggerClick,  this);
13569             this.inputEl().addClass('x-combo-noedit');
13570         }else{
13571             this.inputEl().dom.setAttribute('readOnly', false);
13572             this.inputEl().un('mousedown', this.onTriggerClick,  this);
13573             this.inputEl().removeClass('x-combo-noedit');
13574         }
13575     },
13576
13577     // private
13578     
13579     onBeforeLoad : function(combo,opts){
13580         if(!this.hasFocus){
13581             return;
13582         }
13583          if (!opts.add) {
13584             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13585          }
13586         this.restrictHeight();
13587         this.selectedIndex = -1;
13588     },
13589
13590     // private
13591     onLoad : function(){
13592         
13593         this.hasQuery = false;
13594         
13595         if(!this.hasFocus){
13596             return;
13597         }
13598         
13599         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13600             this.loading.hide();
13601         }
13602         
13603         if(this.store.getCount() > 0){
13604             
13605             this.expand();
13606             this.restrictHeight();
13607             if(this.lastQuery == this.allQuery){
13608                 if(this.editable && !this.tickable){
13609                     this.inputEl().dom.select();
13610                 }
13611                 
13612                 if(
13613                     !this.selectByValue(this.value, true) &&
13614                     this.autoFocus && 
13615                     (
13616                         !this.store.lastOptions ||
13617                         typeof(this.store.lastOptions.add) == 'undefined' || 
13618                         this.store.lastOptions.add != true
13619                     )
13620                 ){
13621                     this.select(0, true);
13622                 }
13623             }else{
13624                 if(this.autoFocus){
13625                     this.selectNext();
13626                 }
13627                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13628                     this.taTask.delay(this.typeAheadDelay);
13629                 }
13630             }
13631         }else{
13632             this.onEmptyResults();
13633         }
13634         
13635         //this.el.focus();
13636     },
13637     // private
13638     onLoadException : function()
13639     {
13640         this.hasQuery = false;
13641         
13642         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13643             this.loading.hide();
13644         }
13645         
13646         if(this.tickable && this.editable){
13647             return;
13648         }
13649         
13650         this.collapse();
13651         // only causes errors at present
13652         //Roo.log(this.store.reader.jsonData);
13653         //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13654             // fixme
13655             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13656         //}
13657         
13658         
13659     },
13660     // private
13661     onTypeAhead : function(){
13662         if(this.store.getCount() > 0){
13663             var r = this.store.getAt(0);
13664             var newValue = r.data[this.displayField];
13665             var len = newValue.length;
13666             var selStart = this.getRawValue().length;
13667             
13668             if(selStart != len){
13669                 this.setRawValue(newValue);
13670                 this.selectText(selStart, newValue.length);
13671             }
13672         }
13673     },
13674
13675     // private
13676     onSelect : function(record, index){
13677         
13678         if(this.fireEvent('beforeselect', this, record, index) !== false){
13679         
13680             this.setFromData(index > -1 ? record.data : false);
13681             
13682             this.collapse();
13683             this.fireEvent('select', this, record, index);
13684         }
13685     },
13686
13687     /**
13688      * Returns the currently selected field value or empty string if no value is set.
13689      * @return {String} value The selected value
13690      */
13691     getValue : function()
13692     {
13693         if(Roo.isIOS && this.useNativeIOS){
13694             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13695         }
13696         
13697         if(this.multiple){
13698             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13699         }
13700         
13701         if(this.valueField){
13702             return typeof this.value != 'undefined' ? this.value : '';
13703         }else{
13704             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13705         }
13706     },
13707     
13708     getRawValue : function()
13709     {
13710         if(Roo.isIOS && this.useNativeIOS){
13711             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13712         }
13713         
13714         var v = this.inputEl().getValue();
13715         
13716         return v;
13717     },
13718
13719     /**
13720      * Clears any text/value currently set in the field
13721      */
13722     clearValue : function(){
13723         
13724         if(this.hiddenField){
13725             this.hiddenField.dom.value = '';
13726         }
13727         this.value = '';
13728         this.setRawValue('');
13729         this.lastSelectionText = '';
13730         this.lastData = false;
13731         
13732         var close = this.closeTriggerEl();
13733         
13734         if(close){
13735             close.hide();
13736         }
13737         
13738         this.validate();
13739         
13740     },
13741
13742     /**
13743      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
13744      * will be displayed in the field.  If the value does not match the data value of an existing item,
13745      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13746      * Otherwise the field will be blank (although the value will still be set).
13747      * @param {String} value The value to match
13748      */
13749     setValue : function(v)
13750     {
13751         if(Roo.isIOS && this.useNativeIOS){
13752             this.setIOSValue(v);
13753             return;
13754         }
13755         
13756         if(this.multiple){
13757             this.syncValue();
13758             return;
13759         }
13760         
13761         var text = v;
13762         if(this.valueField){
13763             var r = this.findRecord(this.valueField, v);
13764             if(r){
13765                 text = r.data[this.displayField];
13766             }else if(this.valueNotFoundText !== undefined){
13767                 text = this.valueNotFoundText;
13768             }
13769         }
13770         this.lastSelectionText = text;
13771         if(this.hiddenField){
13772             this.hiddenField.dom.value = v;
13773         }
13774         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13775         this.value = v;
13776         
13777         var close = this.closeTriggerEl();
13778         
13779         if(close){
13780             (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13781         }
13782         
13783         this.validate();
13784     },
13785     /**
13786      * @property {Object} the last set data for the element
13787      */
13788     
13789     lastData : false,
13790     /**
13791      * Sets the value of the field based on a object which is related to the record format for the store.
13792      * @param {Object} value the value to set as. or false on reset?
13793      */
13794     setFromData : function(o){
13795         
13796         if(this.multiple){
13797             this.addItem(o);
13798             return;
13799         }
13800             
13801         var dv = ''; // display value
13802         var vv = ''; // value value..
13803         this.lastData = o;
13804         if (this.displayField) {
13805             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13806         } else {
13807             // this is an error condition!!!
13808             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
13809         }
13810         
13811         if(this.valueField){
13812             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13813         }
13814         
13815         var close = this.closeTriggerEl();
13816         
13817         if(close){
13818             if(dv.length || vv * 1 > 0){
13819                 close.show() ;
13820                 this.blockFocus=true;
13821             } else {
13822                 close.hide();
13823             }             
13824         }
13825         
13826         if(this.hiddenField){
13827             this.hiddenField.dom.value = vv;
13828             
13829             this.lastSelectionText = dv;
13830             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13831             this.value = vv;
13832             return;
13833         }
13834         // no hidden field.. - we store the value in 'value', but still display
13835         // display field!!!!
13836         this.lastSelectionText = dv;
13837         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13838         this.value = vv;
13839         
13840         
13841         
13842     },
13843     // private
13844     reset : function(){
13845         // overridden so that last data is reset..
13846         
13847         if(this.multiple){
13848             this.clearItem();
13849             return;
13850         }
13851         
13852         this.setValue(this.originalValue);
13853         //this.clearInvalid();
13854         this.lastData = false;
13855         if (this.view) {
13856             this.view.clearSelections();
13857         }
13858         
13859         this.validate();
13860     },
13861     // private
13862     findRecord : function(prop, value){
13863         var record;
13864         if(this.store.getCount() > 0){
13865             this.store.each(function(r){
13866                 if(r.data[prop] == value){
13867                     record = r;
13868                     return false;
13869                 }
13870                 return true;
13871             });
13872         }
13873         return record;
13874     },
13875     
13876     getName: function()
13877     {
13878         // returns hidden if it's set..
13879         if (!this.rendered) {return ''};
13880         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
13881         
13882     },
13883     // private
13884     onViewMove : function(e, t){
13885         this.inKeyMode = false;
13886     },
13887
13888     // private
13889     onViewOver : function(e, t){
13890         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13891             return;
13892         }
13893         var item = this.view.findItemFromChild(t);
13894         
13895         if(item){
13896             var index = this.view.indexOf(item);
13897             this.select(index, false);
13898         }
13899     },
13900
13901     // private
13902     onViewClick : function(view, doFocus, el, e)
13903     {
13904         var index = this.view.getSelectedIndexes()[0];
13905         
13906         var r = this.store.getAt(index);
13907         
13908         if(this.tickable){
13909             
13910             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13911                 return;
13912             }
13913             
13914             var rm = false;
13915             var _this = this;
13916             
13917             Roo.each(this.tickItems, function(v,k){
13918                 
13919                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13920                     Roo.log(v);
13921                     _this.tickItems.splice(k, 1);
13922                     
13923                     if(typeof(e) == 'undefined' && view == false){
13924                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13925                     }
13926                     
13927                     rm = true;
13928                     return;
13929                 }
13930             });
13931             
13932             if(rm){
13933                 return;
13934             }
13935             
13936             if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13937                 this.tickItems.push(r.data);
13938             }
13939             
13940             if(typeof(e) == 'undefined' && view == false){
13941                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13942             }
13943                     
13944             return;
13945         }
13946         
13947         if(r){
13948             this.onSelect(r, index);
13949         }
13950         if(doFocus !== false && !this.blockFocus){
13951             this.inputEl().focus();
13952         }
13953     },
13954
13955     // private
13956     restrictHeight : function(){
13957         //this.innerList.dom.style.height = '';
13958         //var inner = this.innerList.dom;
13959         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13960         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13961         //this.list.beginUpdate();
13962         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13963         this.list.alignTo(this.inputEl(), this.listAlign);
13964         this.list.alignTo(this.inputEl(), this.listAlign);
13965         //this.list.endUpdate();
13966     },
13967
13968     // private
13969     onEmptyResults : function(){
13970         
13971         if(this.tickable && this.editable){
13972             this.restrictHeight();
13973             return;
13974         }
13975         
13976         this.collapse();
13977     },
13978
13979     /**
13980      * Returns true if the dropdown list is expanded, else false.
13981      */
13982     isExpanded : function(){
13983         return this.list.isVisible();
13984     },
13985
13986     /**
13987      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13988      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13989      * @param {String} value The data value of the item to select
13990      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13991      * selected item if it is not currently in view (defaults to true)
13992      * @return {Boolean} True if the value matched an item in the list, else false
13993      */
13994     selectByValue : function(v, scrollIntoView){
13995         if(v !== undefined && v !== null){
13996             var r = this.findRecord(this.valueField || this.displayField, v);
13997             if(r){
13998                 this.select(this.store.indexOf(r), scrollIntoView);
13999                 return true;
14000             }
14001         }
14002         return false;
14003     },
14004
14005     /**
14006      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14007      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14008      * @param {Number} index The zero-based index of the list item to select
14009      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14010      * selected item if it is not currently in view (defaults to true)
14011      */
14012     select : function(index, scrollIntoView){
14013         this.selectedIndex = index;
14014         this.view.select(index);
14015         if(scrollIntoView !== false){
14016             var el = this.view.getNode(index);
14017             /*
14018              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14019              */
14020             if(el){
14021                 this.list.scrollChildIntoView(el, false);
14022             }
14023         }
14024     },
14025
14026     // private
14027     selectNext : function(){
14028         var ct = this.store.getCount();
14029         if(ct > 0){
14030             if(this.selectedIndex == -1){
14031                 this.select(0);
14032             }else if(this.selectedIndex < ct-1){
14033                 this.select(this.selectedIndex+1);
14034             }
14035         }
14036     },
14037
14038     // private
14039     selectPrev : function(){
14040         var ct = this.store.getCount();
14041         if(ct > 0){
14042             if(this.selectedIndex == -1){
14043                 this.select(0);
14044             }else if(this.selectedIndex != 0){
14045                 this.select(this.selectedIndex-1);
14046             }
14047         }
14048     },
14049
14050     // private
14051     onKeyUp : function(e){
14052         if(this.editable !== false && !e.isSpecialKey()){
14053             this.lastKey = e.getKey();
14054             this.dqTask.delay(this.queryDelay);
14055         }
14056     },
14057
14058     // private
14059     validateBlur : function(){
14060         return !this.list || !this.list.isVisible();   
14061     },
14062
14063     // private
14064     initQuery : function(){
14065         
14066         var v = this.getRawValue();
14067         
14068         if(this.tickable && this.editable){
14069             v = this.tickableInputEl().getValue();
14070         }
14071         
14072         this.doQuery(v);
14073     },
14074
14075     // private
14076     doForce : function(){
14077         if(this.inputEl().dom.value.length > 0){
14078             this.inputEl().dom.value =
14079                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14080              
14081         }
14082     },
14083
14084     /**
14085      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
14086      * query allowing the query action to be canceled if needed.
14087      * @param {String} query The SQL query to execute
14088      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14089      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
14090      * saved in the current store (defaults to false)
14091      */
14092     doQuery : function(q, forceAll){
14093         
14094         if(q === undefined || q === null){
14095             q = '';
14096         }
14097         var qe = {
14098             query: q,
14099             forceAll: forceAll,
14100             combo: this,
14101             cancel:false
14102         };
14103         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14104             return false;
14105         }
14106         q = qe.query;
14107         
14108         forceAll = qe.forceAll;
14109         if(forceAll === true || (q.length >= this.minChars)){
14110             
14111             this.hasQuery = true;
14112             
14113             if(this.lastQuery != q || this.alwaysQuery){
14114                 this.lastQuery = q;
14115                 if(this.mode == 'local'){
14116                     this.selectedIndex = -1;
14117                     if(forceAll){
14118                         this.store.clearFilter();
14119                     }else{
14120                         
14121                         if(this.specialFilter){
14122                             this.fireEvent('specialfilter', this);
14123                             this.onLoad();
14124                             return;
14125                         }
14126                         
14127                         this.store.filter(this.displayField, q);
14128                     }
14129                     
14130                     this.store.fireEvent("datachanged", this.store);
14131                     
14132                     this.onLoad();
14133                     
14134                     
14135                 }else{
14136                     
14137                     this.store.baseParams[this.queryParam] = q;
14138                     
14139                     var options = {params : this.getParams(q)};
14140                     
14141                     if(this.loadNext){
14142                         options.add = true;
14143                         options.params.start = this.page * this.pageSize;
14144                     }
14145                     
14146                     this.store.load(options);
14147                     
14148                     /*
14149                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
14150                      *  we should expand the list on onLoad
14151                      *  so command out it
14152                      */
14153 //                    this.expand();
14154                 }
14155             }else{
14156                 this.selectedIndex = -1;
14157                 this.onLoad();   
14158             }
14159         }
14160         
14161         this.loadNext = false;
14162     },
14163     
14164     // private
14165     getParams : function(q){
14166         var p = {};
14167         //p[this.queryParam] = q;
14168         
14169         if(this.pageSize){
14170             p.start = 0;
14171             p.limit = this.pageSize;
14172         }
14173         return p;
14174     },
14175
14176     /**
14177      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14178      */
14179     collapse : function(){
14180         if(!this.isExpanded()){
14181             return;
14182         }
14183         
14184         this.list.hide();
14185         
14186         this.hasFocus = false;
14187         
14188         if(this.tickable){
14189             this.okBtn.hide();
14190             this.cancelBtn.hide();
14191             this.trigger.show();
14192             
14193             if(this.editable){
14194                 this.tickableInputEl().dom.value = '';
14195                 this.tickableInputEl().blur();
14196             }
14197             
14198         }
14199         
14200         Roo.get(document).un('mousedown', this.collapseIf, this);
14201         Roo.get(document).un('mousewheel', this.collapseIf, this);
14202         if (!this.editable) {
14203             Roo.get(document).un('keydown', this.listKeyPress, this);
14204         }
14205         this.fireEvent('collapse', this);
14206         
14207         this.validate();
14208     },
14209
14210     // private
14211     collapseIf : function(e){
14212         var in_combo  = e.within(this.el);
14213         var in_list =  e.within(this.list);
14214         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14215         
14216         if (in_combo || in_list || is_list) {
14217             //e.stopPropagation();
14218             return;
14219         }
14220         
14221         if(this.tickable){
14222             this.onTickableFooterButtonClick(e, false, false);
14223         }
14224
14225         this.collapse();
14226         
14227     },
14228
14229     /**
14230      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14231      */
14232     expand : function(){
14233        
14234         if(this.isExpanded() || !this.hasFocus){
14235             return;
14236         }
14237         
14238         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14239         this.list.setWidth(lw);
14240         
14241         Roo.log('expand');
14242         
14243         this.list.show();
14244         
14245         this.restrictHeight();
14246         
14247         if(this.tickable){
14248             
14249             this.tickItems = Roo.apply([], this.item);
14250             
14251             this.okBtn.show();
14252             this.cancelBtn.show();
14253             this.trigger.hide();
14254             
14255             if(this.editable){
14256                 this.tickableInputEl().focus();
14257             }
14258             
14259         }
14260         
14261         Roo.get(document).on('mousedown', this.collapseIf, this);
14262         Roo.get(document).on('mousewheel', this.collapseIf, this);
14263         if (!this.editable) {
14264             Roo.get(document).on('keydown', this.listKeyPress, this);
14265         }
14266         
14267         this.fireEvent('expand', this);
14268     },
14269
14270     // private
14271     // Implements the default empty TriggerField.onTriggerClick function
14272     onTriggerClick : function(e)
14273     {
14274         Roo.log('trigger click');
14275         
14276         if(this.disabled || !this.triggerList){
14277             return;
14278         }
14279         
14280         this.page = 0;
14281         this.loadNext = false;
14282         
14283         if(this.isExpanded()){
14284             this.collapse();
14285             if (!this.blockFocus) {
14286                 this.inputEl().focus();
14287             }
14288             
14289         }else {
14290             this.hasFocus = true;
14291             if(this.triggerAction == 'all') {
14292                 this.doQuery(this.allQuery, true);
14293             } else {
14294                 this.doQuery(this.getRawValue());
14295             }
14296             if (!this.blockFocus) {
14297                 this.inputEl().focus();
14298             }
14299         }
14300     },
14301     
14302     onTickableTriggerClick : function(e)
14303     {
14304         if(this.disabled){
14305             return;
14306         }
14307         
14308         this.page = 0;
14309         this.loadNext = false;
14310         this.hasFocus = true;
14311         
14312         if(this.triggerAction == 'all') {
14313             this.doQuery(this.allQuery, true);
14314         } else {
14315             this.doQuery(this.getRawValue());
14316         }
14317     },
14318     
14319     onSearchFieldClick : function(e)
14320     {
14321         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14322             this.onTickableFooterButtonClick(e, false, false);
14323             return;
14324         }
14325         
14326         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14327             return;
14328         }
14329         
14330         this.page = 0;
14331         this.loadNext = false;
14332         this.hasFocus = true;
14333         
14334         if(this.triggerAction == 'all') {
14335             this.doQuery(this.allQuery, true);
14336         } else {
14337             this.doQuery(this.getRawValue());
14338         }
14339     },
14340     
14341     listKeyPress : function(e)
14342     {
14343         //Roo.log('listkeypress');
14344         // scroll to first matching element based on key pres..
14345         if (e.isSpecialKey()) {
14346             return false;
14347         }
14348         var k = String.fromCharCode(e.getKey()).toUpperCase();
14349         //Roo.log(k);
14350         var match  = false;
14351         var csel = this.view.getSelectedNodes();
14352         var cselitem = false;
14353         if (csel.length) {
14354             var ix = this.view.indexOf(csel[0]);
14355             cselitem  = this.store.getAt(ix);
14356             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14357                 cselitem = false;
14358             }
14359             
14360         }
14361         
14362         this.store.each(function(v) { 
14363             if (cselitem) {
14364                 // start at existing selection.
14365                 if (cselitem.id == v.id) {
14366                     cselitem = false;
14367                 }
14368                 return true;
14369             }
14370                 
14371             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14372                 match = this.store.indexOf(v);
14373                 return false;
14374             }
14375             return true;
14376         }, this);
14377         
14378         if (match === false) {
14379             return true; // no more action?
14380         }
14381         // scroll to?
14382         this.view.select(match);
14383         var sn = Roo.get(this.view.getSelectedNodes()[0]);
14384         sn.scrollIntoView(sn.dom.parentNode, false);
14385     },
14386     
14387     onViewScroll : function(e, t){
14388         
14389         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){
14390             return;
14391         }
14392         
14393         this.hasQuery = true;
14394         
14395         this.loading = this.list.select('.loading', true).first();
14396         
14397         if(this.loading === null){
14398             this.list.createChild({
14399                 tag: 'div',
14400                 cls: 'loading roo-select2-more-results roo-select2-active',
14401                 html: 'Loading more results...'
14402             });
14403             
14404             this.loading = this.list.select('.loading', true).first();
14405             
14406             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14407             
14408             this.loading.hide();
14409         }
14410         
14411         this.loading.show();
14412         
14413         var _combo = this;
14414         
14415         this.page++;
14416         this.loadNext = true;
14417         
14418         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14419         
14420         return;
14421     },
14422     
14423     addItem : function(o)
14424     {   
14425         var dv = ''; // display value
14426         
14427         if (this.displayField) {
14428             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14429         } else {
14430             // this is an error condition!!!
14431             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14432         }
14433         
14434         if(!dv.length){
14435             return;
14436         }
14437         
14438         var choice = this.choices.createChild({
14439             tag: 'li',
14440             cls: 'roo-select2-search-choice',
14441             cn: [
14442                 {
14443                     tag: 'div',
14444                     html: dv
14445                 },
14446                 {
14447                     tag: 'a',
14448                     href: '#',
14449                     cls: 'roo-select2-search-choice-close fa fa-times',
14450                     tabindex: '-1'
14451                 }
14452             ]
14453             
14454         }, this.searchField);
14455         
14456         var close = choice.select('a.roo-select2-search-choice-close', true).first();
14457         
14458         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14459         
14460         this.item.push(o);
14461         
14462         this.lastData = o;
14463         
14464         this.syncValue();
14465         
14466         this.inputEl().dom.value = '';
14467         
14468         this.validate();
14469     },
14470     
14471     onRemoveItem : function(e, _self, o)
14472     {
14473         e.preventDefault();
14474         
14475         this.lastItem = Roo.apply([], this.item);
14476         
14477         var index = this.item.indexOf(o.data) * 1;
14478         
14479         if( index < 0){
14480             Roo.log('not this item?!');
14481             return;
14482         }
14483         
14484         this.item.splice(index, 1);
14485         o.item.remove();
14486         
14487         this.syncValue();
14488         
14489         this.fireEvent('remove', this, e);
14490         
14491         this.validate();
14492         
14493     },
14494     
14495     syncValue : function()
14496     {
14497         if(!this.item.length){
14498             this.clearValue();
14499             return;
14500         }
14501             
14502         var value = [];
14503         var _this = this;
14504         Roo.each(this.item, function(i){
14505             if(_this.valueField){
14506                 value.push(i[_this.valueField]);
14507                 return;
14508             }
14509
14510             value.push(i);
14511         });
14512
14513         this.value = value.join(',');
14514
14515         if(this.hiddenField){
14516             this.hiddenField.dom.value = this.value;
14517         }
14518         
14519         this.store.fireEvent("datachanged", this.store);
14520         
14521         this.validate();
14522     },
14523     
14524     clearItem : function()
14525     {
14526         if(!this.multiple){
14527             return;
14528         }
14529         
14530         this.item = [];
14531         
14532         Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14533            c.remove();
14534         });
14535         
14536         this.syncValue();
14537         
14538         this.validate();
14539         
14540         if(this.tickable && !Roo.isTouch){
14541             this.view.refresh();
14542         }
14543     },
14544     
14545     inputEl: function ()
14546     {
14547         if(Roo.isIOS && this.useNativeIOS){
14548             return this.el.select('select.roo-ios-select', true).first();
14549         }
14550         
14551         if(Roo.isTouch && this.mobileTouchView){
14552             return this.el.select('input.form-control',true).first();
14553         }
14554         
14555         if(this.tickable){
14556             return this.searchField;
14557         }
14558         
14559         return this.el.select('input.form-control',true).first();
14560     },
14561     
14562     onTickableFooterButtonClick : function(e, btn, el)
14563     {
14564         e.preventDefault();
14565         
14566         this.lastItem = Roo.apply([], this.item);
14567         
14568         if(btn && btn.name == 'cancel'){
14569             this.tickItems = Roo.apply([], this.item);
14570             this.collapse();
14571             return;
14572         }
14573         
14574         this.clearItem();
14575         
14576         var _this = this;
14577         
14578         Roo.each(this.tickItems, function(o){
14579             _this.addItem(o);
14580         });
14581         
14582         this.collapse();
14583         
14584     },
14585     
14586     validate : function()
14587     {
14588         var v = this.getRawValue();
14589         
14590         if(this.multiple){
14591             v = this.getValue();
14592         }
14593         
14594         if(this.disabled || this.allowBlank || v.length){
14595             this.markValid();
14596             return true;
14597         }
14598         
14599         this.markInvalid();
14600         return false;
14601     },
14602     
14603     tickableInputEl : function()
14604     {
14605         if(!this.tickable || !this.editable){
14606             return this.inputEl();
14607         }
14608         
14609         return this.inputEl().select('.roo-select2-search-field-input', true).first();
14610     },
14611     
14612     
14613     getAutoCreateTouchView : function()
14614     {
14615         var id = Roo.id();
14616         
14617         var cfg = {
14618             cls: 'form-group' //input-group
14619         };
14620         
14621         var input =  {
14622             tag: 'input',
14623             id : id,
14624             type : this.inputType,
14625             cls : 'form-control x-combo-noedit',
14626             autocomplete: 'new-password',
14627             placeholder : this.placeholder || '',
14628             readonly : true
14629         };
14630         
14631         if (this.name) {
14632             input.name = this.name;
14633         }
14634         
14635         if (this.size) {
14636             input.cls += ' input-' + this.size;
14637         }
14638         
14639         if (this.disabled) {
14640             input.disabled = true;
14641         }
14642         
14643         var inputblock = {
14644             cls : '',
14645             cn : [
14646                 input
14647             ]
14648         };
14649         
14650         if(this.before){
14651             inputblock.cls += ' input-group';
14652             
14653             inputblock.cn.unshift({
14654                 tag :'span',
14655                 cls : 'input-group-addon',
14656                 html : this.before
14657             });
14658         }
14659         
14660         if(this.removable && !this.multiple){
14661             inputblock.cls += ' roo-removable';
14662             
14663             inputblock.cn.push({
14664                 tag: 'button',
14665                 html : 'x',
14666                 cls : 'roo-combo-removable-btn close'
14667             });
14668         }
14669
14670         if(this.hasFeedback && !this.allowBlank){
14671             
14672             inputblock.cls += ' has-feedback';
14673             
14674             inputblock.cn.push({
14675                 tag: 'span',
14676                 cls: 'glyphicon form-control-feedback'
14677             });
14678             
14679         }
14680         
14681         if (this.after) {
14682             
14683             inputblock.cls += (this.before) ? '' : ' input-group';
14684             
14685             inputblock.cn.push({
14686                 tag :'span',
14687                 cls : 'input-group-addon',
14688                 html : this.after
14689             });
14690         }
14691
14692         var box = {
14693             tag: 'div',
14694             cn: [
14695                 {
14696                     tag: 'input',
14697                     type : 'hidden',
14698                     cls: 'form-hidden-field'
14699                 },
14700                 inputblock
14701             ]
14702             
14703         };
14704         
14705         if(this.multiple){
14706             box = {
14707                 tag: 'div',
14708                 cn: [
14709                     {
14710                         tag: 'input',
14711                         type : 'hidden',
14712                         cls: 'form-hidden-field'
14713                     },
14714                     {
14715                         tag: 'ul',
14716                         cls: 'roo-select2-choices',
14717                         cn:[
14718                             {
14719                                 tag: 'li',
14720                                 cls: 'roo-select2-search-field',
14721                                 cn: [
14722
14723                                     inputblock
14724                                 ]
14725                             }
14726                         ]
14727                     }
14728                 ]
14729             }
14730         };
14731         
14732         var combobox = {
14733             cls: 'roo-select2-container input-group roo-touchview-combobox ',
14734             cn: [
14735                 box
14736             ]
14737         };
14738         
14739         if(!this.multiple && this.showToggleBtn){
14740             
14741             var caret = {
14742                         tag: 'span',
14743                         cls: 'caret'
14744             };
14745             
14746             if (this.caret != false) {
14747                 caret = {
14748                      tag: 'i',
14749                      cls: 'fa fa-' + this.caret
14750                 };
14751                 
14752             }
14753             
14754             combobox.cn.push({
14755                 tag :'span',
14756                 cls : 'input-group-addon btn dropdown-toggle',
14757                 cn : [
14758                     caret,
14759                     {
14760                         tag: 'span',
14761                         cls: 'combobox-clear',
14762                         cn  : [
14763                             {
14764                                 tag : 'i',
14765                                 cls: 'icon-remove'
14766                             }
14767                         ]
14768                     }
14769                 ]
14770
14771             })
14772         }
14773         
14774         if(this.multiple){
14775             combobox.cls += ' roo-select2-container-multi';
14776         }
14777         
14778         var align = this.labelAlign || this.parentLabelAlign();
14779         
14780         if (align ==='left' && this.fieldLabel.length) {
14781
14782             cfg.cn = [
14783                 {
14784                    tag : 'i',
14785                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14786                    tooltip : 'This field is required'
14787                 },
14788                 {
14789                     tag: 'label',
14790                     cls : 'control-label',
14791                     html : this.fieldLabel
14792
14793                 },
14794                 {
14795                     cls : '', 
14796                     cn: [
14797                         combobox
14798                     ]
14799                 }
14800             ];
14801             
14802             var labelCfg = cfg.cn[1];
14803             var contentCfg = cfg.cn[2];
14804             
14805
14806             if(this.indicatorpos == 'right'){
14807                 cfg.cn = [
14808                     {
14809                         tag: 'label',
14810                         'for' :  id,
14811                         cls : 'control-label',
14812                         cn : [
14813                             {
14814                                 tag : 'span',
14815                                 html : this.fieldLabel
14816                             },
14817                             {
14818                                 tag : 'i',
14819                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14820                                 tooltip : 'This field is required'
14821                             }
14822                         ]
14823                     },
14824                     {
14825                         cls : "",
14826                         cn: [
14827                             combobox
14828                         ]
14829                     }
14830
14831                 ];
14832                 
14833                 labelCfg = cfg.cn[0];
14834                 contentCfg = cfg.cn[1];
14835             }
14836             
14837            
14838             
14839             if(this.labelWidth > 12){
14840                 labelCfg.style = "width: " + this.labelWidth + 'px';
14841             }
14842             
14843             if(this.labelWidth < 13 && this.labelmd == 0){
14844                 this.labelmd = this.labelWidth;
14845             }
14846             
14847             if(this.labellg > 0){
14848                 labelCfg.cls += ' col-lg-' + this.labellg;
14849                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14850             }
14851             
14852             if(this.labelmd > 0){
14853                 labelCfg.cls += ' col-md-' + this.labelmd;
14854                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14855             }
14856             
14857             if(this.labelsm > 0){
14858                 labelCfg.cls += ' col-sm-' + this.labelsm;
14859                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14860             }
14861             
14862             if(this.labelxs > 0){
14863                 labelCfg.cls += ' col-xs-' + this.labelxs;
14864                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14865             }
14866                 
14867                 
14868         } else if ( this.fieldLabel.length) {
14869             cfg.cn = [
14870                 {
14871                    tag : 'i',
14872                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14873                    tooltip : 'This field is required'
14874                 },
14875                 {
14876                     tag: 'label',
14877                     cls : 'control-label',
14878                     html : this.fieldLabel
14879
14880                 },
14881                 {
14882                     cls : '', 
14883                     cn: [
14884                         combobox
14885                     ]
14886                 }
14887             ];
14888             
14889             if(this.indicatorpos == 'right'){
14890                 cfg.cn = [
14891                     {
14892                         tag: 'label',
14893                         cls : 'control-label',
14894                         html : this.fieldLabel,
14895                         cn : [
14896                             {
14897                                tag : 'i',
14898                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14899                                tooltip : 'This field is required'
14900                             }
14901                         ]
14902                     },
14903                     {
14904                         cls : '', 
14905                         cn: [
14906                             combobox
14907                         ]
14908                     }
14909                 ];
14910             }
14911         } else {
14912             cfg.cn = combobox;    
14913         }
14914         
14915         
14916         var settings = this;
14917         
14918         ['xs','sm','md','lg'].map(function(size){
14919             if (settings[size]) {
14920                 cfg.cls += ' col-' + size + '-' + settings[size];
14921             }
14922         });
14923         
14924         return cfg;
14925     },
14926     
14927     initTouchView : function()
14928     {
14929         this.renderTouchView();
14930         
14931         this.touchViewEl.on('scroll', function(){
14932             this.el.dom.scrollTop = 0;
14933         }, this);
14934         
14935         this.originalValue = this.getValue();
14936         
14937         this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14938         
14939         this.inputEl().on("click", this.showTouchView, this);
14940         if (this.triggerEl) {
14941             this.triggerEl.on("click", this.showTouchView, this);
14942         }
14943         
14944         
14945         this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14946         this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14947         
14948         this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14949         
14950         this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14951         this.store.on('load', this.onTouchViewLoad, this);
14952         this.store.on('loadexception', this.onTouchViewLoadException, this);
14953         
14954         if(this.hiddenName){
14955             
14956             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14957             
14958             this.hiddenField.dom.value =
14959                 this.hiddenValue !== undefined ? this.hiddenValue :
14960                 this.value !== undefined ? this.value : '';
14961         
14962             this.el.dom.removeAttribute('name');
14963             this.hiddenField.dom.setAttribute('name', this.hiddenName);
14964         }
14965         
14966         if(this.multiple){
14967             this.choices = this.el.select('ul.roo-select2-choices', true).first();
14968             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14969         }
14970         
14971         if(this.removable && !this.multiple){
14972             var close = this.closeTriggerEl();
14973             if(close){
14974                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14975                 close.on('click', this.removeBtnClick, this, close);
14976             }
14977         }
14978         /*
14979          * fix the bug in Safari iOS8
14980          */
14981         this.inputEl().on("focus", function(e){
14982             document.activeElement.blur();
14983         }, this);
14984         
14985         return;
14986         
14987         
14988     },
14989     
14990     renderTouchView : function()
14991     {
14992         this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14993         this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14994         
14995         this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14996         this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14997         
14998         this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14999         this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15000         this.touchViewBodyEl.setStyle('overflow', 'auto');
15001         
15002         this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15003         this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15004         
15005         this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15006         this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15007         
15008     },
15009     
15010     showTouchView : function()
15011     {
15012         if(this.disabled){
15013             return;
15014         }
15015         
15016         this.touchViewHeaderEl.hide();
15017
15018         if(this.modalTitle.length){
15019             this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15020             this.touchViewHeaderEl.show();
15021         }
15022
15023         this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15024         this.touchViewEl.show();
15025
15026         this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15027         
15028         //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15029         //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15030
15031         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15032
15033         if(this.modalTitle.length){
15034             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15035         }
15036         
15037         this.touchViewBodyEl.setHeight(bodyHeight);
15038
15039         if(this.animate){
15040             var _this = this;
15041             (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15042         }else{
15043             this.touchViewEl.addClass('in');
15044         }
15045
15046         this.doTouchViewQuery();
15047         
15048     },
15049     
15050     hideTouchView : function()
15051     {
15052         this.touchViewEl.removeClass('in');
15053
15054         if(this.animate){
15055             var _this = this;
15056             (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15057         }else{
15058             this.touchViewEl.setStyle('display', 'none');
15059         }
15060         
15061     },
15062     
15063     setTouchViewValue : function()
15064     {
15065         if(this.multiple){
15066             this.clearItem();
15067         
15068             var _this = this;
15069
15070             Roo.each(this.tickItems, function(o){
15071                 this.addItem(o);
15072             }, this);
15073         }
15074         
15075         this.hideTouchView();
15076     },
15077     
15078     doTouchViewQuery : function()
15079     {
15080         var qe = {
15081             query: '',
15082             forceAll: true,
15083             combo: this,
15084             cancel:false
15085         };
15086         
15087         if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15088             return false;
15089         }
15090         
15091         if(!this.alwaysQuery || this.mode == 'local'){
15092             this.onTouchViewLoad();
15093             return;
15094         }
15095         
15096         this.store.load();
15097     },
15098     
15099     onTouchViewBeforeLoad : function(combo,opts)
15100     {
15101         return;
15102     },
15103
15104     // private
15105     onTouchViewLoad : function()
15106     {
15107         if(this.store.getCount() < 1){
15108             this.onTouchViewEmptyResults();
15109             return;
15110         }
15111         
15112         this.clearTouchView();
15113         
15114         var rawValue = this.getRawValue();
15115         
15116         var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15117         
15118         this.tickItems = [];
15119         
15120         this.store.data.each(function(d, rowIndex){
15121             var row = this.touchViewListGroup.createChild(template);
15122             
15123             if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15124                 row.addClass(d.data.cls);
15125             }
15126             
15127             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15128                 var cfg = {
15129                     data : d.data,
15130                     html : d.data[this.displayField]
15131                 };
15132                 
15133                 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15134                     row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15135                 }
15136             }
15137             row.removeClass('selected');
15138             if(!this.multiple && this.valueField &&
15139                     typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15140             {
15141                 // radio buttons..
15142                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15143                 row.addClass('selected');
15144             }
15145             
15146             if(this.multiple && this.valueField &&
15147                     typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15148             {
15149                 
15150                 // checkboxes...
15151                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15152                 this.tickItems.push(d.data);
15153             }
15154             
15155             row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15156             
15157         }, this);
15158         
15159         var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15160         
15161         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15162
15163         if(this.modalTitle.length){
15164             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15165         }
15166
15167         var listHeight = this.touchViewListGroup.getHeight();
15168         
15169         var _this = this;
15170         
15171         if(firstChecked && listHeight > bodyHeight){
15172             (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15173         }
15174         
15175     },
15176     
15177     onTouchViewLoadException : function()
15178     {
15179         this.hideTouchView();
15180     },
15181     
15182     onTouchViewEmptyResults : function()
15183     {
15184         this.clearTouchView();
15185         
15186         this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15187         
15188         this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15189         
15190     },
15191     
15192     clearTouchView : function()
15193     {
15194         this.touchViewListGroup.dom.innerHTML = '';
15195     },
15196     
15197     onTouchViewClick : function(e, el, o)
15198     {
15199         e.preventDefault();
15200         
15201         var row = o.row;
15202         var rowIndex = o.rowIndex;
15203         
15204         var r = this.store.getAt(rowIndex);
15205         
15206         if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15207             
15208             if(!this.multiple){
15209                 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15210                     c.dom.removeAttribute('checked');
15211                 }, this);
15212
15213                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15214
15215                 this.setFromData(r.data);
15216
15217                 var close = this.closeTriggerEl();
15218
15219                 if(close){
15220                     close.show();
15221                 }
15222
15223                 this.hideTouchView();
15224
15225                 this.fireEvent('select', this, r, rowIndex);
15226
15227                 return;
15228             }
15229
15230             if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15231                 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15232                 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15233                 return;
15234             }
15235
15236             row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15237             this.addItem(r.data);
15238             this.tickItems.push(r.data);
15239         }
15240     },
15241     
15242     getAutoCreateNativeIOS : function()
15243     {
15244         var cfg = {
15245             cls: 'form-group' //input-group,
15246         };
15247         
15248         var combobox =  {
15249             tag: 'select',
15250             cls : 'roo-ios-select'
15251         };
15252         
15253         if (this.name) {
15254             combobox.name = this.name;
15255         }
15256         
15257         if (this.disabled) {
15258             combobox.disabled = true;
15259         }
15260         
15261         var settings = this;
15262         
15263         ['xs','sm','md','lg'].map(function(size){
15264             if (settings[size]) {
15265                 cfg.cls += ' col-' + size + '-' + settings[size];
15266             }
15267         });
15268         
15269         cfg.cn = combobox;
15270         
15271         return cfg;
15272         
15273     },
15274     
15275     initIOSView : function()
15276     {
15277         this.store.on('load', this.onIOSViewLoad, this);
15278         
15279         return;
15280     },
15281     
15282     onIOSViewLoad : function()
15283     {
15284         if(this.store.getCount() < 1){
15285             return;
15286         }
15287         
15288         this.clearIOSView();
15289         
15290         if(this.allowBlank) {
15291             
15292             var default_text = '-- SELECT --';
15293             
15294             if(this.placeholder.length){
15295                 default_text = this.placeholder;
15296             }
15297             
15298             if(this.emptyTitle.length){
15299                 default_text += ' - ' + this.emptyTitle + ' -';
15300             }
15301             
15302             var opt = this.inputEl().createChild({
15303                 tag: 'option',
15304                 value : 0,
15305                 html : default_text
15306             });
15307             
15308             var o = {};
15309             o[this.valueField] = 0;
15310             o[this.displayField] = default_text;
15311             
15312             this.ios_options.push({
15313                 data : o,
15314                 el : opt
15315             });
15316             
15317         }
15318         
15319         this.store.data.each(function(d, rowIndex){
15320             
15321             var html = '';
15322             
15323             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15324                 html = d.data[this.displayField];
15325             }
15326             
15327             var value = '';
15328             
15329             if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15330                 value = d.data[this.valueField];
15331             }
15332             
15333             var option = {
15334                 tag: 'option',
15335                 value : value,
15336                 html : html
15337             };
15338             
15339             if(this.value == d.data[this.valueField]){
15340                 option['selected'] = true;
15341             }
15342             
15343             var opt = this.inputEl().createChild(option);
15344             
15345             this.ios_options.push({
15346                 data : d.data,
15347                 el : opt
15348             });
15349             
15350         }, this);
15351         
15352         this.inputEl().on('change', function(){
15353            this.fireEvent('select', this);
15354         }, this);
15355         
15356     },
15357     
15358     clearIOSView: function()
15359     {
15360         this.inputEl().dom.innerHTML = '';
15361         
15362         this.ios_options = [];
15363     },
15364     
15365     setIOSValue: function(v)
15366     {
15367         this.value = v;
15368         
15369         if(!this.ios_options){
15370             return;
15371         }
15372         
15373         Roo.each(this.ios_options, function(opts){
15374            
15375            opts.el.dom.removeAttribute('selected');
15376            
15377            if(opts.data[this.valueField] != v){
15378                return;
15379            }
15380            
15381            opts.el.dom.setAttribute('selected', true);
15382            
15383         }, this);
15384     }
15385
15386     /** 
15387     * @cfg {Boolean} grow 
15388     * @hide 
15389     */
15390     /** 
15391     * @cfg {Number} growMin 
15392     * @hide 
15393     */
15394     /** 
15395     * @cfg {Number} growMax 
15396     * @hide 
15397     */
15398     /**
15399      * @hide
15400      * @method autoSize
15401      */
15402 });
15403
15404 Roo.apply(Roo.bootstrap.ComboBox,  {
15405     
15406     header : {
15407         tag: 'div',
15408         cls: 'modal-header',
15409         cn: [
15410             {
15411                 tag: 'h4',
15412                 cls: 'modal-title'
15413             }
15414         ]
15415     },
15416     
15417     body : {
15418         tag: 'div',
15419         cls: 'modal-body',
15420         cn: [
15421             {
15422                 tag: 'ul',
15423                 cls: 'list-group'
15424             }
15425         ]
15426     },
15427     
15428     listItemRadio : {
15429         tag: 'li',
15430         cls: 'list-group-item',
15431         cn: [
15432             {
15433                 tag: 'span',
15434                 cls: 'roo-combobox-list-group-item-value'
15435             },
15436             {
15437                 tag: 'div',
15438                 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15439                 cn: [
15440                     {
15441                         tag: 'input',
15442                         type: 'radio'
15443                     },
15444                     {
15445                         tag: 'label'
15446                     }
15447                 ]
15448             }
15449         ]
15450     },
15451     
15452     listItemCheckbox : {
15453         tag: 'li',
15454         cls: 'list-group-item',
15455         cn: [
15456             {
15457                 tag: 'span',
15458                 cls: 'roo-combobox-list-group-item-value'
15459             },
15460             {
15461                 tag: 'div',
15462                 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15463                 cn: [
15464                     {
15465                         tag: 'input',
15466                         type: 'checkbox'
15467                     },
15468                     {
15469                         tag: 'label'
15470                     }
15471                 ]
15472             }
15473         ]
15474     },
15475     
15476     emptyResult : {
15477         tag: 'div',
15478         cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15479     },
15480     
15481     footer : {
15482         tag: 'div',
15483         cls: 'modal-footer',
15484         cn: [
15485             {
15486                 tag: 'div',
15487                 cls: 'row',
15488                 cn: [
15489                     {
15490                         tag: 'div',
15491                         cls: 'col-xs-6 text-left',
15492                         cn: {
15493                             tag: 'button',
15494                             cls: 'btn btn-danger roo-touch-view-cancel',
15495                             html: 'Cancel'
15496                         }
15497                     },
15498                     {
15499                         tag: 'div',
15500                         cls: 'col-xs-6 text-right',
15501                         cn: {
15502                             tag: 'button',
15503                             cls: 'btn btn-success roo-touch-view-ok',
15504                             html: 'OK'
15505                         }
15506                     }
15507                 ]
15508             }
15509         ]
15510         
15511     }
15512 });
15513
15514 Roo.apply(Roo.bootstrap.ComboBox,  {
15515     
15516     touchViewTemplate : {
15517         tag: 'div',
15518         cls: 'modal fade roo-combobox-touch-view',
15519         cn: [
15520             {
15521                 tag: 'div',
15522                 cls: 'modal-dialog',
15523                 style : 'position:fixed', // we have to fix position....
15524                 cn: [
15525                     {
15526                         tag: 'div',
15527                         cls: 'modal-content',
15528                         cn: [
15529                             Roo.bootstrap.ComboBox.header,
15530                             Roo.bootstrap.ComboBox.body,
15531                             Roo.bootstrap.ComboBox.footer
15532                         ]
15533                     }
15534                 ]
15535             }
15536         ]
15537     }
15538 });/*
15539  * Based on:
15540  * Ext JS Library 1.1.1
15541  * Copyright(c) 2006-2007, Ext JS, LLC.
15542  *
15543  * Originally Released Under LGPL - original licence link has changed is not relivant.
15544  *
15545  * Fork - LGPL
15546  * <script type="text/javascript">
15547  */
15548
15549 /**
15550  * @class Roo.View
15551  * @extends Roo.util.Observable
15552  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
15553  * This class also supports single and multi selection modes. <br>
15554  * Create a data model bound view:
15555  <pre><code>
15556  var store = new Roo.data.Store(...);
15557
15558  var view = new Roo.View({
15559     el : "my-element",
15560     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
15561  
15562     singleSelect: true,
15563     selectedClass: "ydataview-selected",
15564     store: store
15565  });
15566
15567  // listen for node click?
15568  view.on("click", function(vw, index, node, e){
15569  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15570  });
15571
15572  // load XML data
15573  dataModel.load("foobar.xml");
15574  </code></pre>
15575  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15576  * <br><br>
15577  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15578  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15579  * 
15580  * Note: old style constructor is still suported (container, template, config)
15581  * 
15582  * @constructor
15583  * Create a new View
15584  * @param {Object} config The config object
15585  * 
15586  */
15587 Roo.View = function(config, depreciated_tpl, depreciated_config){
15588     
15589     this.parent = false;
15590     
15591     if (typeof(depreciated_tpl) == 'undefined') {
15592         // new way.. - universal constructor.
15593         Roo.apply(this, config);
15594         this.el  = Roo.get(this.el);
15595     } else {
15596         // old format..
15597         this.el  = Roo.get(config);
15598         this.tpl = depreciated_tpl;
15599         Roo.apply(this, depreciated_config);
15600     }
15601     this.wrapEl  = this.el.wrap().wrap();
15602     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15603     
15604     
15605     if(typeof(this.tpl) == "string"){
15606         this.tpl = new Roo.Template(this.tpl);
15607     } else {
15608         // support xtype ctors..
15609         this.tpl = new Roo.factory(this.tpl, Roo);
15610     }
15611     
15612     
15613     this.tpl.compile();
15614     
15615     /** @private */
15616     this.addEvents({
15617         /**
15618          * @event beforeclick
15619          * Fires before a click is processed. Returns false to cancel the default action.
15620          * @param {Roo.View} this
15621          * @param {Number} index The index of the target node
15622          * @param {HTMLElement} node The target node
15623          * @param {Roo.EventObject} e The raw event object
15624          */
15625             "beforeclick" : true,
15626         /**
15627          * @event click
15628          * Fires when a template node is clicked.
15629          * @param {Roo.View} this
15630          * @param {Number} index The index of the target node
15631          * @param {HTMLElement} node The target node
15632          * @param {Roo.EventObject} e The raw event object
15633          */
15634             "click" : true,
15635         /**
15636          * @event dblclick
15637          * Fires when a template node is double clicked.
15638          * @param {Roo.View} this
15639          * @param {Number} index The index of the target node
15640          * @param {HTMLElement} node The target node
15641          * @param {Roo.EventObject} e The raw event object
15642          */
15643             "dblclick" : true,
15644         /**
15645          * @event contextmenu
15646          * Fires when a template node is right clicked.
15647          * @param {Roo.View} this
15648          * @param {Number} index The index of the target node
15649          * @param {HTMLElement} node The target node
15650          * @param {Roo.EventObject} e The raw event object
15651          */
15652             "contextmenu" : true,
15653         /**
15654          * @event selectionchange
15655          * Fires when the selected nodes change.
15656          * @param {Roo.View} this
15657          * @param {Array} selections Array of the selected nodes
15658          */
15659             "selectionchange" : true,
15660     
15661         /**
15662          * @event beforeselect
15663          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15664          * @param {Roo.View} this
15665          * @param {HTMLElement} node The node to be selected
15666          * @param {Array} selections Array of currently selected nodes
15667          */
15668             "beforeselect" : true,
15669         /**
15670          * @event preparedata
15671          * Fires on every row to render, to allow you to change the data.
15672          * @param {Roo.View} this
15673          * @param {Object} data to be rendered (change this)
15674          */
15675           "preparedata" : true
15676           
15677           
15678         });
15679
15680
15681
15682     this.el.on({
15683         "click": this.onClick,
15684         "dblclick": this.onDblClick,
15685         "contextmenu": this.onContextMenu,
15686         scope:this
15687     });
15688
15689     this.selections = [];
15690     this.nodes = [];
15691     this.cmp = new Roo.CompositeElementLite([]);
15692     if(this.store){
15693         this.store = Roo.factory(this.store, Roo.data);
15694         this.setStore(this.store, true);
15695     }
15696     
15697     if ( this.footer && this.footer.xtype) {
15698            
15699          var fctr = this.wrapEl.appendChild(document.createElement("div"));
15700         
15701         this.footer.dataSource = this.store;
15702         this.footer.container = fctr;
15703         this.footer = Roo.factory(this.footer, Roo);
15704         fctr.insertFirst(this.el);
15705         
15706         // this is a bit insane - as the paging toolbar seems to detach the el..
15707 //        dom.parentNode.parentNode.parentNode
15708          // they get detached?
15709     }
15710     
15711     
15712     Roo.View.superclass.constructor.call(this);
15713     
15714     
15715 };
15716
15717 Roo.extend(Roo.View, Roo.util.Observable, {
15718     
15719      /**
15720      * @cfg {Roo.data.Store} store Data store to load data from.
15721      */
15722     store : false,
15723     
15724     /**
15725      * @cfg {String|Roo.Element} el The container element.
15726      */
15727     el : '',
15728     
15729     /**
15730      * @cfg {String|Roo.Template} tpl The template used by this View 
15731      */
15732     tpl : false,
15733     /**
15734      * @cfg {String} dataName the named area of the template to use as the data area
15735      *                          Works with domtemplates roo-name="name"
15736      */
15737     dataName: false,
15738     /**
15739      * @cfg {String} selectedClass The css class to add to selected nodes
15740      */
15741     selectedClass : "x-view-selected",
15742      /**
15743      * @cfg {String} emptyText The empty text to show when nothing is loaded.
15744      */
15745     emptyText : "",
15746     
15747     /**
15748      * @cfg {String} text to display on mask (default Loading)
15749      */
15750     mask : false,
15751     /**
15752      * @cfg {Boolean} multiSelect Allow multiple selection
15753      */
15754     multiSelect : false,
15755     /**
15756      * @cfg {Boolean} singleSelect Allow single selection
15757      */
15758     singleSelect:  false,
15759     
15760     /**
15761      * @cfg {Boolean} toggleSelect - selecting 
15762      */
15763     toggleSelect : false,
15764     
15765     /**
15766      * @cfg {Boolean} tickable - selecting 
15767      */
15768     tickable : false,
15769     
15770     /**
15771      * Returns the element this view is bound to.
15772      * @return {Roo.Element}
15773      */
15774     getEl : function(){
15775         return this.wrapEl;
15776     },
15777     
15778     
15779
15780     /**
15781      * Refreshes the view. - called by datachanged on the store. - do not call directly.
15782      */
15783     refresh : function(){
15784         //Roo.log('refresh');
15785         var t = this.tpl;
15786         
15787         // if we are using something like 'domtemplate', then
15788         // the what gets used is:
15789         // t.applySubtemplate(NAME, data, wrapping data..)
15790         // the outer template then get' applied with
15791         //     the store 'extra data'
15792         // and the body get's added to the
15793         //      roo-name="data" node?
15794         //      <span class='roo-tpl-{name}'></span> ?????
15795         
15796         
15797         
15798         this.clearSelections();
15799         this.el.update("");
15800         var html = [];
15801         var records = this.store.getRange();
15802         if(records.length < 1) {
15803             
15804             // is this valid??  = should it render a template??
15805             
15806             this.el.update(this.emptyText);
15807             return;
15808         }
15809         var el = this.el;
15810         if (this.dataName) {
15811             this.el.update(t.apply(this.store.meta)); //????
15812             el = this.el.child('.roo-tpl-' + this.dataName);
15813         }
15814         
15815         for(var i = 0, len = records.length; i < len; i++){
15816             var data = this.prepareData(records[i].data, i, records[i]);
15817             this.fireEvent("preparedata", this, data, i, records[i]);
15818             
15819             var d = Roo.apply({}, data);
15820             
15821             if(this.tickable){
15822                 Roo.apply(d, {'roo-id' : Roo.id()});
15823                 
15824                 var _this = this;
15825             
15826                 Roo.each(this.parent.item, function(item){
15827                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15828                         return;
15829                     }
15830                     Roo.apply(d, {'roo-data-checked' : 'checked'});
15831                 });
15832             }
15833             
15834             html[html.length] = Roo.util.Format.trim(
15835                 this.dataName ?
15836                     t.applySubtemplate(this.dataName, d, this.store.meta) :
15837                     t.apply(d)
15838             );
15839         }
15840         
15841         
15842         
15843         el.update(html.join(""));
15844         this.nodes = el.dom.childNodes;
15845         this.updateIndexes(0);
15846     },
15847     
15848
15849     /**
15850      * Function to override to reformat the data that is sent to
15851      * the template for each node.
15852      * DEPRICATED - use the preparedata event handler.
15853      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15854      * a JSON object for an UpdateManager bound view).
15855      */
15856     prepareData : function(data, index, record)
15857     {
15858         this.fireEvent("preparedata", this, data, index, record);
15859         return data;
15860     },
15861
15862     onUpdate : function(ds, record){
15863         // Roo.log('on update');   
15864         this.clearSelections();
15865         var index = this.store.indexOf(record);
15866         var n = this.nodes[index];
15867         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15868         n.parentNode.removeChild(n);
15869         this.updateIndexes(index, index);
15870     },
15871
15872     
15873     
15874 // --------- FIXME     
15875     onAdd : function(ds, records, index)
15876     {
15877         //Roo.log(['on Add', ds, records, index] );        
15878         this.clearSelections();
15879         if(this.nodes.length == 0){
15880             this.refresh();
15881             return;
15882         }
15883         var n = this.nodes[index];
15884         for(var i = 0, len = records.length; i < len; i++){
15885             var d = this.prepareData(records[i].data, i, records[i]);
15886             if(n){
15887                 this.tpl.insertBefore(n, d);
15888             }else{
15889                 
15890                 this.tpl.append(this.el, d);
15891             }
15892         }
15893         this.updateIndexes(index);
15894     },
15895
15896     onRemove : function(ds, record, index){
15897        // Roo.log('onRemove');
15898         this.clearSelections();
15899         var el = this.dataName  ?
15900             this.el.child('.roo-tpl-' + this.dataName) :
15901             this.el; 
15902         
15903         el.dom.removeChild(this.nodes[index]);
15904         this.updateIndexes(index);
15905     },
15906
15907     /**
15908      * Refresh an individual node.
15909      * @param {Number} index
15910      */
15911     refreshNode : function(index){
15912         this.onUpdate(this.store, this.store.getAt(index));
15913     },
15914
15915     updateIndexes : function(startIndex, endIndex){
15916         var ns = this.nodes;
15917         startIndex = startIndex || 0;
15918         endIndex = endIndex || ns.length - 1;
15919         for(var i = startIndex; i <= endIndex; i++){
15920             ns[i].nodeIndex = i;
15921         }
15922     },
15923
15924     /**
15925      * Changes the data store this view uses and refresh the view.
15926      * @param {Store} store
15927      */
15928     setStore : function(store, initial){
15929         if(!initial && this.store){
15930             this.store.un("datachanged", this.refresh);
15931             this.store.un("add", this.onAdd);
15932             this.store.un("remove", this.onRemove);
15933             this.store.un("update", this.onUpdate);
15934             this.store.un("clear", this.refresh);
15935             this.store.un("beforeload", this.onBeforeLoad);
15936             this.store.un("load", this.onLoad);
15937             this.store.un("loadexception", this.onLoad);
15938         }
15939         if(store){
15940           
15941             store.on("datachanged", this.refresh, this);
15942             store.on("add", this.onAdd, this);
15943             store.on("remove", this.onRemove, this);
15944             store.on("update", this.onUpdate, this);
15945             store.on("clear", this.refresh, this);
15946             store.on("beforeload", this.onBeforeLoad, this);
15947             store.on("load", this.onLoad, this);
15948             store.on("loadexception", this.onLoad, this);
15949         }
15950         
15951         if(store){
15952             this.refresh();
15953         }
15954     },
15955     /**
15956      * onbeforeLoad - masks the loading area.
15957      *
15958      */
15959     onBeforeLoad : function(store,opts)
15960     {
15961          //Roo.log('onBeforeLoad');   
15962         if (!opts.add) {
15963             this.el.update("");
15964         }
15965         this.el.mask(this.mask ? this.mask : "Loading" ); 
15966     },
15967     onLoad : function ()
15968     {
15969         this.el.unmask();
15970     },
15971     
15972
15973     /**
15974      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15975      * @param {HTMLElement} node
15976      * @return {HTMLElement} The template node
15977      */
15978     findItemFromChild : function(node){
15979         var el = this.dataName  ?
15980             this.el.child('.roo-tpl-' + this.dataName,true) :
15981             this.el.dom; 
15982         
15983         if(!node || node.parentNode == el){
15984                     return node;
15985             }
15986             var p = node.parentNode;
15987             while(p && p != el){
15988             if(p.parentNode == el){
15989                 return p;
15990             }
15991             p = p.parentNode;
15992         }
15993             return null;
15994     },
15995
15996     /** @ignore */
15997     onClick : function(e){
15998         var item = this.findItemFromChild(e.getTarget());
15999         if(item){
16000             var index = this.indexOf(item);
16001             if(this.onItemClick(item, index, e) !== false){
16002                 this.fireEvent("click", this, index, item, e);
16003             }
16004         }else{
16005             this.clearSelections();
16006         }
16007     },
16008
16009     /** @ignore */
16010     onContextMenu : function(e){
16011         var item = this.findItemFromChild(e.getTarget());
16012         if(item){
16013             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16014         }
16015     },
16016
16017     /** @ignore */
16018     onDblClick : function(e){
16019         var item = this.findItemFromChild(e.getTarget());
16020         if(item){
16021             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16022         }
16023     },
16024
16025     onItemClick : function(item, index, e)
16026     {
16027         if(this.fireEvent("beforeclick", this, index, item, e) === false){
16028             return false;
16029         }
16030         if (this.toggleSelect) {
16031             var m = this.isSelected(item) ? 'unselect' : 'select';
16032             //Roo.log(m);
16033             var _t = this;
16034             _t[m](item, true, false);
16035             return true;
16036         }
16037         if(this.multiSelect || this.singleSelect){
16038             if(this.multiSelect && e.shiftKey && this.lastSelection){
16039                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16040             }else{
16041                 this.select(item, this.multiSelect && e.ctrlKey);
16042                 this.lastSelection = item;
16043             }
16044             
16045             if(!this.tickable){
16046                 e.preventDefault();
16047             }
16048             
16049         }
16050         return true;
16051     },
16052
16053     /**
16054      * Get the number of selected nodes.
16055      * @return {Number}
16056      */
16057     getSelectionCount : function(){
16058         return this.selections.length;
16059     },
16060
16061     /**
16062      * Get the currently selected nodes.
16063      * @return {Array} An array of HTMLElements
16064      */
16065     getSelectedNodes : function(){
16066         return this.selections;
16067     },
16068
16069     /**
16070      * Get the indexes of the selected nodes.
16071      * @return {Array}
16072      */
16073     getSelectedIndexes : function(){
16074         var indexes = [], s = this.selections;
16075         for(var i = 0, len = s.length; i < len; i++){
16076             indexes.push(s[i].nodeIndex);
16077         }
16078         return indexes;
16079     },
16080
16081     /**
16082      * Clear all selections
16083      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16084      */
16085     clearSelections : function(suppressEvent){
16086         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16087             this.cmp.elements = this.selections;
16088             this.cmp.removeClass(this.selectedClass);
16089             this.selections = [];
16090             if(!suppressEvent){
16091                 this.fireEvent("selectionchange", this, this.selections);
16092             }
16093         }
16094     },
16095
16096     /**
16097      * Returns true if the passed node is selected
16098      * @param {HTMLElement/Number} node The node or node index
16099      * @return {Boolean}
16100      */
16101     isSelected : function(node){
16102         var s = this.selections;
16103         if(s.length < 1){
16104             return false;
16105         }
16106         node = this.getNode(node);
16107         return s.indexOf(node) !== -1;
16108     },
16109
16110     /**
16111      * Selects nodes.
16112      * @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
16113      * @param {Boolean} keepExisting (optional) true to keep existing selections
16114      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16115      */
16116     select : function(nodeInfo, keepExisting, suppressEvent){
16117         if(nodeInfo instanceof Array){
16118             if(!keepExisting){
16119                 this.clearSelections(true);
16120             }
16121             for(var i = 0, len = nodeInfo.length; i < len; i++){
16122                 this.select(nodeInfo[i], true, true);
16123             }
16124             return;
16125         } 
16126         var node = this.getNode(nodeInfo);
16127         if(!node || this.isSelected(node)){
16128             return; // already selected.
16129         }
16130         if(!keepExisting){
16131             this.clearSelections(true);
16132         }
16133         
16134         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16135             Roo.fly(node).addClass(this.selectedClass);
16136             this.selections.push(node);
16137             if(!suppressEvent){
16138                 this.fireEvent("selectionchange", this, this.selections);
16139             }
16140         }
16141         
16142         
16143     },
16144       /**
16145      * Unselects nodes.
16146      * @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
16147      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16148      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16149      */
16150     unselect : function(nodeInfo, keepExisting, suppressEvent)
16151     {
16152         if(nodeInfo instanceof Array){
16153             Roo.each(this.selections, function(s) {
16154                 this.unselect(s, nodeInfo);
16155             }, this);
16156             return;
16157         }
16158         var node = this.getNode(nodeInfo);
16159         if(!node || !this.isSelected(node)){
16160             //Roo.log("not selected");
16161             return; // not selected.
16162         }
16163         // fireevent???
16164         var ns = [];
16165         Roo.each(this.selections, function(s) {
16166             if (s == node ) {
16167                 Roo.fly(node).removeClass(this.selectedClass);
16168
16169                 return;
16170             }
16171             ns.push(s);
16172         },this);
16173         
16174         this.selections= ns;
16175         this.fireEvent("selectionchange", this, this.selections);
16176     },
16177
16178     /**
16179      * Gets a template node.
16180      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16181      * @return {HTMLElement} The node or null if it wasn't found
16182      */
16183     getNode : function(nodeInfo){
16184         if(typeof nodeInfo == "string"){
16185             return document.getElementById(nodeInfo);
16186         }else if(typeof nodeInfo == "number"){
16187             return this.nodes[nodeInfo];
16188         }
16189         return nodeInfo;
16190     },
16191
16192     /**
16193      * Gets a range template nodes.
16194      * @param {Number} startIndex
16195      * @param {Number} endIndex
16196      * @return {Array} An array of nodes
16197      */
16198     getNodes : function(start, end){
16199         var ns = this.nodes;
16200         start = start || 0;
16201         end = typeof end == "undefined" ? ns.length - 1 : end;
16202         var nodes = [];
16203         if(start <= end){
16204             for(var i = start; i <= end; i++){
16205                 nodes.push(ns[i]);
16206             }
16207         } else{
16208             for(var i = start; i >= end; i--){
16209                 nodes.push(ns[i]);
16210             }
16211         }
16212         return nodes;
16213     },
16214
16215     /**
16216      * Finds the index of the passed node
16217      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16218      * @return {Number} The index of the node or -1
16219      */
16220     indexOf : function(node){
16221         node = this.getNode(node);
16222         if(typeof node.nodeIndex == "number"){
16223             return node.nodeIndex;
16224         }
16225         var ns = this.nodes;
16226         for(var i = 0, len = ns.length; i < len; i++){
16227             if(ns[i] == node){
16228                 return i;
16229             }
16230         }
16231         return -1;
16232     }
16233 });
16234 /*
16235  * - LGPL
16236  *
16237  * based on jquery fullcalendar
16238  * 
16239  */
16240
16241 Roo.bootstrap = Roo.bootstrap || {};
16242 /**
16243  * @class Roo.bootstrap.Calendar
16244  * @extends Roo.bootstrap.Component
16245  * Bootstrap Calendar class
16246  * @cfg {Boolean} loadMask (true|false) default false
16247  * @cfg {Object} header generate the user specific header of the calendar, default false
16248
16249  * @constructor
16250  * Create a new Container
16251  * @param {Object} config The config object
16252  */
16253
16254
16255
16256 Roo.bootstrap.Calendar = function(config){
16257     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16258      this.addEvents({
16259         /**
16260              * @event select
16261              * Fires when a date is selected
16262              * @param {DatePicker} this
16263              * @param {Date} date The selected date
16264              */
16265         'select': true,
16266         /**
16267              * @event monthchange
16268              * Fires when the displayed month changes 
16269              * @param {DatePicker} this
16270              * @param {Date} date The selected month
16271              */
16272         'monthchange': true,
16273         /**
16274              * @event evententer
16275              * Fires when mouse over an event
16276              * @param {Calendar} this
16277              * @param {event} Event
16278              */
16279         'evententer': true,
16280         /**
16281              * @event eventleave
16282              * Fires when the mouse leaves an
16283              * @param {Calendar} this
16284              * @param {event}
16285              */
16286         'eventleave': true,
16287         /**
16288              * @event eventclick
16289              * Fires when the mouse click an
16290              * @param {Calendar} this
16291              * @param {event}
16292              */
16293         'eventclick': true
16294         
16295     });
16296
16297 };
16298
16299 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
16300     
16301      /**
16302      * @cfg {Number} startDay
16303      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16304      */
16305     startDay : 0,
16306     
16307     loadMask : false,
16308     
16309     header : false,
16310       
16311     getAutoCreate : function(){
16312         
16313         
16314         var fc_button = function(name, corner, style, content ) {
16315             return Roo.apply({},{
16316                 tag : 'span',
16317                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
16318                          (corner.length ?
16319                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16320                             ''
16321                         ),
16322                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16323                 unselectable: 'on'
16324             });
16325         };
16326         
16327         var header = {};
16328         
16329         if(!this.header){
16330             header = {
16331                 tag : 'table',
16332                 cls : 'fc-header',
16333                 style : 'width:100%',
16334                 cn : [
16335                     {
16336                         tag: 'tr',
16337                         cn : [
16338                             {
16339                                 tag : 'td',
16340                                 cls : 'fc-header-left',
16341                                 cn : [
16342                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
16343                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
16344                                     { tag: 'span', cls: 'fc-header-space' },
16345                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
16346
16347
16348                                 ]
16349                             },
16350
16351                             {
16352                                 tag : 'td',
16353                                 cls : 'fc-header-center',
16354                                 cn : [
16355                                     {
16356                                         tag: 'span',
16357                                         cls: 'fc-header-title',
16358                                         cn : {
16359                                             tag: 'H2',
16360                                             html : 'month / year'
16361                                         }
16362                                     }
16363
16364                                 ]
16365                             },
16366                             {
16367                                 tag : 'td',
16368                                 cls : 'fc-header-right',
16369                                 cn : [
16370                               /*      fc_button('month', 'left', '', 'month' ),
16371                                     fc_button('week', '', '', 'week' ),
16372                                     fc_button('day', 'right', '', 'day' )
16373                                 */    
16374
16375                                 ]
16376                             }
16377
16378                         ]
16379                     }
16380                 ]
16381             };
16382         }
16383         
16384         header = this.header;
16385         
16386        
16387         var cal_heads = function() {
16388             var ret = [];
16389             // fixme - handle this.
16390             
16391             for (var i =0; i < Date.dayNames.length; i++) {
16392                 var d = Date.dayNames[i];
16393                 ret.push({
16394                     tag: 'th',
16395                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16396                     html : d.substring(0,3)
16397                 });
16398                 
16399             }
16400             ret[0].cls += ' fc-first';
16401             ret[6].cls += ' fc-last';
16402             return ret;
16403         };
16404         var cal_cell = function(n) {
16405             return  {
16406                 tag: 'td',
16407                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16408                 cn : [
16409                     {
16410                         cn : [
16411                             {
16412                                 cls: 'fc-day-number',
16413                                 html: 'D'
16414                             },
16415                             {
16416                                 cls: 'fc-day-content',
16417                              
16418                                 cn : [
16419                                      {
16420                                         style: 'position: relative;' // height: 17px;
16421                                     }
16422                                 ]
16423                             }
16424                             
16425                             
16426                         ]
16427                     }
16428                 ]
16429                 
16430             }
16431         };
16432         var cal_rows = function() {
16433             
16434             var ret = [];
16435             for (var r = 0; r < 6; r++) {
16436                 var row= {
16437                     tag : 'tr',
16438                     cls : 'fc-week',
16439                     cn : []
16440                 };
16441                 
16442                 for (var i =0; i < Date.dayNames.length; i++) {
16443                     var d = Date.dayNames[i];
16444                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16445
16446                 }
16447                 row.cn[0].cls+=' fc-first';
16448                 row.cn[0].cn[0].style = 'min-height:90px';
16449                 row.cn[6].cls+=' fc-last';
16450                 ret.push(row);
16451                 
16452             }
16453             ret[0].cls += ' fc-first';
16454             ret[4].cls += ' fc-prev-last';
16455             ret[5].cls += ' fc-last';
16456             return ret;
16457             
16458         };
16459         
16460         var cal_table = {
16461             tag: 'table',
16462             cls: 'fc-border-separate',
16463             style : 'width:100%',
16464             cellspacing  : 0,
16465             cn : [
16466                 { 
16467                     tag: 'thead',
16468                     cn : [
16469                         { 
16470                             tag: 'tr',
16471                             cls : 'fc-first fc-last',
16472                             cn : cal_heads()
16473                         }
16474                     ]
16475                 },
16476                 { 
16477                     tag: 'tbody',
16478                     cn : cal_rows()
16479                 }
16480                   
16481             ]
16482         };
16483          
16484          var cfg = {
16485             cls : 'fc fc-ltr',
16486             cn : [
16487                 header,
16488                 {
16489                     cls : 'fc-content',
16490                     style : "position: relative;",
16491                     cn : [
16492                         {
16493                             cls : 'fc-view fc-view-month fc-grid',
16494                             style : 'position: relative',
16495                             unselectable : 'on',
16496                             cn : [
16497                                 {
16498                                     cls : 'fc-event-container',
16499                                     style : 'position:absolute;z-index:8;top:0;left:0;'
16500                                 },
16501                                 cal_table
16502                             ]
16503                         }
16504                     ]
16505     
16506                 }
16507            ] 
16508             
16509         };
16510         
16511          
16512         
16513         return cfg;
16514     },
16515     
16516     
16517     initEvents : function()
16518     {
16519         if(!this.store){
16520             throw "can not find store for calendar";
16521         }
16522         
16523         var mark = {
16524             tag: "div",
16525             cls:"x-dlg-mask",
16526             style: "text-align:center",
16527             cn: [
16528                 {
16529                     tag: "div",
16530                     style: "background-color:white;width:50%;margin:250 auto",
16531                     cn: [
16532                         {
16533                             tag: "img",
16534                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
16535                         },
16536                         {
16537                             tag: "span",
16538                             html: "Loading"
16539                         }
16540                         
16541                     ]
16542                 }
16543             ]
16544         };
16545         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16546         
16547         var size = this.el.select('.fc-content', true).first().getSize();
16548         this.maskEl.setSize(size.width, size.height);
16549         this.maskEl.enableDisplayMode("block");
16550         if(!this.loadMask){
16551             this.maskEl.hide();
16552         }
16553         
16554         this.store = Roo.factory(this.store, Roo.data);
16555         this.store.on('load', this.onLoad, this);
16556         this.store.on('beforeload', this.onBeforeLoad, this);
16557         
16558         this.resize();
16559         
16560         this.cells = this.el.select('.fc-day',true);
16561         //Roo.log(this.cells);
16562         this.textNodes = this.el.query('.fc-day-number');
16563         this.cells.addClassOnOver('fc-state-hover');
16564         
16565         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16566         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16567         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16568         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16569         
16570         this.on('monthchange', this.onMonthChange, this);
16571         
16572         this.update(new Date().clearTime());
16573     },
16574     
16575     resize : function() {
16576         var sz  = this.el.getSize();
16577         
16578         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16579         this.el.select('.fc-day-content div',true).setHeight(34);
16580     },
16581     
16582     
16583     // private
16584     showPrevMonth : function(e){
16585         this.update(this.activeDate.add("mo", -1));
16586     },
16587     showToday : function(e){
16588         this.update(new Date().clearTime());
16589     },
16590     // private
16591     showNextMonth : function(e){
16592         this.update(this.activeDate.add("mo", 1));
16593     },
16594
16595     // private
16596     showPrevYear : function(){
16597         this.update(this.activeDate.add("y", -1));
16598     },
16599
16600     // private
16601     showNextYear : function(){
16602         this.update(this.activeDate.add("y", 1));
16603     },
16604
16605     
16606    // private
16607     update : function(date)
16608     {
16609         var vd = this.activeDate;
16610         this.activeDate = date;
16611 //        if(vd && this.el){
16612 //            var t = date.getTime();
16613 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16614 //                Roo.log('using add remove');
16615 //                
16616 //                this.fireEvent('monthchange', this, date);
16617 //                
16618 //                this.cells.removeClass("fc-state-highlight");
16619 //                this.cells.each(function(c){
16620 //                   if(c.dateValue == t){
16621 //                       c.addClass("fc-state-highlight");
16622 //                       setTimeout(function(){
16623 //                            try{c.dom.firstChild.focus();}catch(e){}
16624 //                       }, 50);
16625 //                       return false;
16626 //                   }
16627 //                   return true;
16628 //                });
16629 //                return;
16630 //            }
16631 //        }
16632         
16633         var days = date.getDaysInMonth();
16634         
16635         var firstOfMonth = date.getFirstDateOfMonth();
16636         var startingPos = firstOfMonth.getDay()-this.startDay;
16637         
16638         if(startingPos < this.startDay){
16639             startingPos += 7;
16640         }
16641         
16642         var pm = date.add(Date.MONTH, -1);
16643         var prevStart = pm.getDaysInMonth()-startingPos;
16644 //        
16645         this.cells = this.el.select('.fc-day',true);
16646         this.textNodes = this.el.query('.fc-day-number');
16647         this.cells.addClassOnOver('fc-state-hover');
16648         
16649         var cells = this.cells.elements;
16650         var textEls = this.textNodes;
16651         
16652         Roo.each(cells, function(cell){
16653             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16654         });
16655         
16656         days += startingPos;
16657
16658         // convert everything to numbers so it's fast
16659         var day = 86400000;
16660         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16661         //Roo.log(d);
16662         //Roo.log(pm);
16663         //Roo.log(prevStart);
16664         
16665         var today = new Date().clearTime().getTime();
16666         var sel = date.clearTime().getTime();
16667         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16668         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16669         var ddMatch = this.disabledDatesRE;
16670         var ddText = this.disabledDatesText;
16671         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16672         var ddaysText = this.disabledDaysText;
16673         var format = this.format;
16674         
16675         var setCellClass = function(cal, cell){
16676             cell.row = 0;
16677             cell.events = [];
16678             cell.more = [];
16679             //Roo.log('set Cell Class');
16680             cell.title = "";
16681             var t = d.getTime();
16682             
16683             //Roo.log(d);
16684             
16685             cell.dateValue = t;
16686             if(t == today){
16687                 cell.className += " fc-today";
16688                 cell.className += " fc-state-highlight";
16689                 cell.title = cal.todayText;
16690             }
16691             if(t == sel){
16692                 // disable highlight in other month..
16693                 //cell.className += " fc-state-highlight";
16694                 
16695             }
16696             // disabling
16697             if(t < min) {
16698                 cell.className = " fc-state-disabled";
16699                 cell.title = cal.minText;
16700                 return;
16701             }
16702             if(t > max) {
16703                 cell.className = " fc-state-disabled";
16704                 cell.title = cal.maxText;
16705                 return;
16706             }
16707             if(ddays){
16708                 if(ddays.indexOf(d.getDay()) != -1){
16709                     cell.title = ddaysText;
16710                     cell.className = " fc-state-disabled";
16711                 }
16712             }
16713             if(ddMatch && format){
16714                 var fvalue = d.dateFormat(format);
16715                 if(ddMatch.test(fvalue)){
16716                     cell.title = ddText.replace("%0", fvalue);
16717                     cell.className = " fc-state-disabled";
16718                 }
16719             }
16720             
16721             if (!cell.initialClassName) {
16722                 cell.initialClassName = cell.dom.className;
16723             }
16724             
16725             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
16726         };
16727
16728         var i = 0;
16729         
16730         for(; i < startingPos; i++) {
16731             textEls[i].innerHTML = (++prevStart);
16732             d.setDate(d.getDate()+1);
16733             
16734             cells[i].className = "fc-past fc-other-month";
16735             setCellClass(this, cells[i]);
16736         }
16737         
16738         var intDay = 0;
16739         
16740         for(; i < days; i++){
16741             intDay = i - startingPos + 1;
16742             textEls[i].innerHTML = (intDay);
16743             d.setDate(d.getDate()+1);
16744             
16745             cells[i].className = ''; // "x-date-active";
16746             setCellClass(this, cells[i]);
16747         }
16748         var extraDays = 0;
16749         
16750         for(; i < 42; i++) {
16751             textEls[i].innerHTML = (++extraDays);
16752             d.setDate(d.getDate()+1);
16753             
16754             cells[i].className = "fc-future fc-other-month";
16755             setCellClass(this, cells[i]);
16756         }
16757         
16758         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16759         
16760         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16761         
16762         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16763         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16764         
16765         if(totalRows != 6){
16766             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16767             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16768         }
16769         
16770         this.fireEvent('monthchange', this, date);
16771         
16772         
16773         /*
16774         if(!this.internalRender){
16775             var main = this.el.dom.firstChild;
16776             var w = main.offsetWidth;
16777             this.el.setWidth(w + this.el.getBorderWidth("lr"));
16778             Roo.fly(main).setWidth(w);
16779             this.internalRender = true;
16780             // opera does not respect the auto grow header center column
16781             // then, after it gets a width opera refuses to recalculate
16782             // without a second pass
16783             if(Roo.isOpera && !this.secondPass){
16784                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16785                 this.secondPass = true;
16786                 this.update.defer(10, this, [date]);
16787             }
16788         }
16789         */
16790         
16791     },
16792     
16793     findCell : function(dt) {
16794         dt = dt.clearTime().getTime();
16795         var ret = false;
16796         this.cells.each(function(c){
16797             //Roo.log("check " +c.dateValue + '?=' + dt);
16798             if(c.dateValue == dt){
16799                 ret = c;
16800                 return false;
16801             }
16802             return true;
16803         });
16804         
16805         return ret;
16806     },
16807     
16808     findCells : function(ev) {
16809         var s = ev.start.clone().clearTime().getTime();
16810        // Roo.log(s);
16811         var e= ev.end.clone().clearTime().getTime();
16812        // Roo.log(e);
16813         var ret = [];
16814         this.cells.each(function(c){
16815              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16816             
16817             if(c.dateValue > e){
16818                 return ;
16819             }
16820             if(c.dateValue < s){
16821                 return ;
16822             }
16823             ret.push(c);
16824         });
16825         
16826         return ret;    
16827     },
16828     
16829 //    findBestRow: function(cells)
16830 //    {
16831 //        var ret = 0;
16832 //        
16833 //        for (var i =0 ; i < cells.length;i++) {
16834 //            ret  = Math.max(cells[i].rows || 0,ret);
16835 //        }
16836 //        return ret;
16837 //        
16838 //    },
16839     
16840     
16841     addItem : function(ev)
16842     {
16843         // look for vertical location slot in
16844         var cells = this.findCells(ev);
16845         
16846 //        ev.row = this.findBestRow(cells);
16847         
16848         // work out the location.
16849         
16850         var crow = false;
16851         var rows = [];
16852         for(var i =0; i < cells.length; i++) {
16853             
16854             cells[i].row = cells[0].row;
16855             
16856             if(i == 0){
16857                 cells[i].row = cells[i].row + 1;
16858             }
16859             
16860             if (!crow) {
16861                 crow = {
16862                     start : cells[i],
16863                     end :  cells[i]
16864                 };
16865                 continue;
16866             }
16867             if (crow.start.getY() == cells[i].getY()) {
16868                 // on same row.
16869                 crow.end = cells[i];
16870                 continue;
16871             }
16872             // different row.
16873             rows.push(crow);
16874             crow = {
16875                 start: cells[i],
16876                 end : cells[i]
16877             };
16878             
16879         }
16880         
16881         rows.push(crow);
16882         ev.els = [];
16883         ev.rows = rows;
16884         ev.cells = cells;
16885         
16886         cells[0].events.push(ev);
16887         
16888         this.calevents.push(ev);
16889     },
16890     
16891     clearEvents: function() {
16892         
16893         if(!this.calevents){
16894             return;
16895         }
16896         
16897         Roo.each(this.cells.elements, function(c){
16898             c.row = 0;
16899             c.events = [];
16900             c.more = [];
16901         });
16902         
16903         Roo.each(this.calevents, function(e) {
16904             Roo.each(e.els, function(el) {
16905                 el.un('mouseenter' ,this.onEventEnter, this);
16906                 el.un('mouseleave' ,this.onEventLeave, this);
16907                 el.remove();
16908             },this);
16909         },this);
16910         
16911         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16912             e.remove();
16913         });
16914         
16915     },
16916     
16917     renderEvents: function()
16918     {   
16919         var _this = this;
16920         
16921         this.cells.each(function(c) {
16922             
16923             if(c.row < 5){
16924                 return;
16925             }
16926             
16927             var ev = c.events;
16928             
16929             var r = 4;
16930             if(c.row != c.events.length){
16931                 r = 4 - (4 - (c.row - c.events.length));
16932             }
16933             
16934             c.events = ev.slice(0, r);
16935             c.more = ev.slice(r);
16936             
16937             if(c.more.length && c.more.length == 1){
16938                 c.events.push(c.more.pop());
16939             }
16940             
16941             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16942             
16943         });
16944             
16945         this.cells.each(function(c) {
16946             
16947             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16948             
16949             
16950             for (var e = 0; e < c.events.length; e++){
16951                 var ev = c.events[e];
16952                 var rows = ev.rows;
16953                 
16954                 for(var i = 0; i < rows.length; i++) {
16955                 
16956                     // how many rows should it span..
16957
16958                     var  cfg = {
16959                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16960                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16961
16962                         unselectable : "on",
16963                         cn : [
16964                             {
16965                                 cls: 'fc-event-inner',
16966                                 cn : [
16967     //                                {
16968     //                                  tag:'span',
16969     //                                  cls: 'fc-event-time',
16970     //                                  html : cells.length > 1 ? '' : ev.time
16971     //                                },
16972                                     {
16973                                       tag:'span',
16974                                       cls: 'fc-event-title',
16975                                       html : String.format('{0}', ev.title)
16976                                     }
16977
16978
16979                                 ]
16980                             },
16981                             {
16982                                 cls: 'ui-resizable-handle ui-resizable-e',
16983                                 html : '&nbsp;&nbsp;&nbsp'
16984                             }
16985
16986                         ]
16987                     };
16988
16989                     if (i == 0) {
16990                         cfg.cls += ' fc-event-start';
16991                     }
16992                     if ((i+1) == rows.length) {
16993                         cfg.cls += ' fc-event-end';
16994                     }
16995
16996                     var ctr = _this.el.select('.fc-event-container',true).first();
16997                     var cg = ctr.createChild(cfg);
16998
16999                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17000                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17001
17002                     var r = (c.more.length) ? 1 : 0;
17003                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
17004                     cg.setWidth(ebox.right - sbox.x -2);
17005
17006                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17007                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17008                     cg.on('click', _this.onEventClick, _this, ev);
17009
17010                     ev.els.push(cg);
17011                     
17012                 }
17013                 
17014             }
17015             
17016             
17017             if(c.more.length){
17018                 var  cfg = {
17019                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17020                     style : 'position: absolute',
17021                     unselectable : "on",
17022                     cn : [
17023                         {
17024                             cls: 'fc-event-inner',
17025                             cn : [
17026                                 {
17027                                   tag:'span',
17028                                   cls: 'fc-event-title',
17029                                   html : 'More'
17030                                 }
17031
17032
17033                             ]
17034                         },
17035                         {
17036                             cls: 'ui-resizable-handle ui-resizable-e',
17037                             html : '&nbsp;&nbsp;&nbsp'
17038                         }
17039
17040                     ]
17041                 };
17042
17043                 var ctr = _this.el.select('.fc-event-container',true).first();
17044                 var cg = ctr.createChild(cfg);
17045
17046                 var sbox = c.select('.fc-day-content',true).first().getBox();
17047                 var ebox = c.select('.fc-day-content',true).first().getBox();
17048                 //Roo.log(cg);
17049                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
17050                 cg.setWidth(ebox.right - sbox.x -2);
17051
17052                 cg.on('click', _this.onMoreEventClick, _this, c.more);
17053                 
17054             }
17055             
17056         });
17057         
17058         
17059         
17060     },
17061     
17062     onEventEnter: function (e, el,event,d) {
17063         this.fireEvent('evententer', this, el, event);
17064     },
17065     
17066     onEventLeave: function (e, el,event,d) {
17067         this.fireEvent('eventleave', this, el, event);
17068     },
17069     
17070     onEventClick: function (e, el,event,d) {
17071         this.fireEvent('eventclick', this, el, event);
17072     },
17073     
17074     onMonthChange: function () {
17075         this.store.load();
17076     },
17077     
17078     onMoreEventClick: function(e, el, more)
17079     {
17080         var _this = this;
17081         
17082         this.calpopover.placement = 'right';
17083         this.calpopover.setTitle('More');
17084         
17085         this.calpopover.setContent('');
17086         
17087         var ctr = this.calpopover.el.select('.popover-content', true).first();
17088         
17089         Roo.each(more, function(m){
17090             var cfg = {
17091                 cls : 'fc-event-hori fc-event-draggable',
17092                 html : m.title
17093             };
17094             var cg = ctr.createChild(cfg);
17095             
17096             cg.on('click', _this.onEventClick, _this, m);
17097         });
17098         
17099         this.calpopover.show(el);
17100         
17101         
17102     },
17103     
17104     onLoad: function () 
17105     {   
17106         this.calevents = [];
17107         var cal = this;
17108         
17109         if(this.store.getCount() > 0){
17110             this.store.data.each(function(d){
17111                cal.addItem({
17112                     id : d.data.id,
17113                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17114                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17115                     time : d.data.start_time,
17116                     title : d.data.title,
17117                     description : d.data.description,
17118                     venue : d.data.venue
17119                 });
17120             });
17121         }
17122         
17123         this.renderEvents();
17124         
17125         if(this.calevents.length && this.loadMask){
17126             this.maskEl.hide();
17127         }
17128     },
17129     
17130     onBeforeLoad: function()
17131     {
17132         this.clearEvents();
17133         if(this.loadMask){
17134             this.maskEl.show();
17135         }
17136     }
17137 });
17138
17139  
17140  /*
17141  * - LGPL
17142  *
17143  * element
17144  * 
17145  */
17146
17147 /**
17148  * @class Roo.bootstrap.Popover
17149  * @extends Roo.bootstrap.Component
17150  * Bootstrap Popover class
17151  * @cfg {String} html contents of the popover   (or false to use children..)
17152  * @cfg {String} title of popover (or false to hide)
17153  * @cfg {String} placement how it is placed
17154  * @cfg {String} trigger click || hover (or false to trigger manually)
17155  * @cfg {String} over what (parent or false to trigger manually.)
17156  * @cfg {Number} delay - delay before showing
17157  
17158  * @constructor
17159  * Create a new Popover
17160  * @param {Object} config The config object
17161  */
17162
17163 Roo.bootstrap.Popover = function(config){
17164     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17165     
17166     this.addEvents({
17167         // raw events
17168          /**
17169          * @event show
17170          * After the popover show
17171          * 
17172          * @param {Roo.bootstrap.Popover} this
17173          */
17174         "show" : true,
17175         /**
17176          * @event hide
17177          * After the popover hide
17178          * 
17179          * @param {Roo.bootstrap.Popover} this
17180          */
17181         "hide" : true
17182     });
17183 };
17184
17185 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
17186     
17187     title: 'Fill in a title',
17188     html: false,
17189     
17190     placement : 'right',
17191     trigger : 'hover', // hover
17192     
17193     delay : 0,
17194     
17195     over: 'parent',
17196     
17197     can_build_overlaid : false,
17198     
17199     getChildContainer : function()
17200     {
17201         return this.el.select('.popover-content',true).first();
17202     },
17203     
17204     getAutoCreate : function(){
17205          
17206         var cfg = {
17207            cls : 'popover roo-dynamic',
17208            style: 'display:block',
17209            cn : [
17210                 {
17211                     cls : 'arrow'
17212                 },
17213                 {
17214                     cls : 'popover-inner',
17215                     cn : [
17216                         {
17217                             tag: 'h3',
17218                             cls: 'popover-title',
17219                             html : this.title
17220                         },
17221                         {
17222                             cls : 'popover-content',
17223                             html : this.html
17224                         }
17225                     ]
17226                     
17227                 }
17228            ]
17229         };
17230         
17231         return cfg;
17232     },
17233     setTitle: function(str)
17234     {
17235         this.title = str;
17236         this.el.select('.popover-title',true).first().dom.innerHTML = str;
17237     },
17238     setContent: function(str)
17239     {
17240         this.html = str;
17241         this.el.select('.popover-content',true).first().dom.innerHTML = str;
17242     },
17243     // as it get's added to the bottom of the page.
17244     onRender : function(ct, position)
17245     {
17246         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17247         if(!this.el){
17248             var cfg = Roo.apply({},  this.getAutoCreate());
17249             cfg.id = Roo.id();
17250             
17251             if (this.cls) {
17252                 cfg.cls += ' ' + this.cls;
17253             }
17254             if (this.style) {
17255                 cfg.style = this.style;
17256             }
17257             //Roo.log("adding to ");
17258             this.el = Roo.get(document.body).createChild(cfg, position);
17259 //            Roo.log(this.el);
17260         }
17261         this.initEvents();
17262     },
17263     
17264     initEvents : function()
17265     {
17266         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17267         this.el.enableDisplayMode('block');
17268         this.el.hide();
17269         if (this.over === false) {
17270             return; 
17271         }
17272         if (this.triggers === false) {
17273             return;
17274         }
17275         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17276         var triggers = this.trigger ? this.trigger.split(' ') : [];
17277         Roo.each(triggers, function(trigger) {
17278         
17279             if (trigger == 'click') {
17280                 on_el.on('click', this.toggle, this);
17281             } else if (trigger != 'manual') {
17282                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
17283                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17284       
17285                 on_el.on(eventIn  ,this.enter, this);
17286                 on_el.on(eventOut, this.leave, this);
17287             }
17288         }, this);
17289         
17290     },
17291     
17292     
17293     // private
17294     timeout : null,
17295     hoverState : null,
17296     
17297     toggle : function () {
17298         this.hoverState == 'in' ? this.leave() : this.enter();
17299     },
17300     
17301     enter : function () {
17302         
17303         clearTimeout(this.timeout);
17304     
17305         this.hoverState = 'in';
17306     
17307         if (!this.delay || !this.delay.show) {
17308             this.show();
17309             return;
17310         }
17311         var _t = this;
17312         this.timeout = setTimeout(function () {
17313             if (_t.hoverState == 'in') {
17314                 _t.show();
17315             }
17316         }, this.delay.show)
17317     },
17318     
17319     leave : function() {
17320         clearTimeout(this.timeout);
17321     
17322         this.hoverState = 'out';
17323     
17324         if (!this.delay || !this.delay.hide) {
17325             this.hide();
17326             return;
17327         }
17328         var _t = this;
17329         this.timeout = setTimeout(function () {
17330             if (_t.hoverState == 'out') {
17331                 _t.hide();
17332             }
17333         }, this.delay.hide)
17334     },
17335     
17336     show : function (on_el)
17337     {
17338         if (!on_el) {
17339             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17340         }
17341         
17342         // set content.
17343         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17344         if (this.html !== false) {
17345             this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17346         }
17347         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17348         if (!this.title.length) {
17349             this.el.select('.popover-title',true).hide();
17350         }
17351         
17352         var placement = typeof this.placement == 'function' ?
17353             this.placement.call(this, this.el, on_el) :
17354             this.placement;
17355             
17356         var autoToken = /\s?auto?\s?/i;
17357         var autoPlace = autoToken.test(placement);
17358         if (autoPlace) {
17359             placement = placement.replace(autoToken, '') || 'top';
17360         }
17361         
17362         //this.el.detach()
17363         //this.el.setXY([0,0]);
17364         this.el.show();
17365         this.el.dom.style.display='block';
17366         this.el.addClass(placement);
17367         
17368         //this.el.appendTo(on_el);
17369         
17370         var p = this.getPosition();
17371         var box = this.el.getBox();
17372         
17373         if (autoPlace) {
17374             // fixme..
17375         }
17376         var align = Roo.bootstrap.Popover.alignment[placement];
17377         
17378 //        Roo.log(align);
17379         this.el.alignTo(on_el, align[0],align[1]);
17380         //var arrow = this.el.select('.arrow',true).first();
17381         //arrow.set(align[2], 
17382         
17383         this.el.addClass('in');
17384         
17385         
17386         if (this.el.hasClass('fade')) {
17387             // fade it?
17388         }
17389         
17390         this.hoverState = 'in';
17391         
17392         this.fireEvent('show', this);
17393         
17394     },
17395     hide : function()
17396     {
17397         this.el.setXY([0,0]);
17398         this.el.removeClass('in');
17399         this.el.hide();
17400         this.hoverState = null;
17401         
17402         this.fireEvent('hide', this);
17403     }
17404     
17405 });
17406
17407 Roo.bootstrap.Popover.alignment = {
17408     'left' : ['r-l', [-10,0], 'right'],
17409     'right' : ['l-r', [10,0], 'left'],
17410     'bottom' : ['t-b', [0,10], 'top'],
17411     'top' : [ 'b-t', [0,-10], 'bottom']
17412 };
17413
17414  /*
17415  * - LGPL
17416  *
17417  * Progress
17418  * 
17419  */
17420
17421 /**
17422  * @class Roo.bootstrap.Progress
17423  * @extends Roo.bootstrap.Component
17424  * Bootstrap Progress class
17425  * @cfg {Boolean} striped striped of the progress bar
17426  * @cfg {Boolean} active animated of the progress bar
17427  * 
17428  * 
17429  * @constructor
17430  * Create a new Progress
17431  * @param {Object} config The config object
17432  */
17433
17434 Roo.bootstrap.Progress = function(config){
17435     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17436 };
17437
17438 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
17439     
17440     striped : false,
17441     active: false,
17442     
17443     getAutoCreate : function(){
17444         var cfg = {
17445             tag: 'div',
17446             cls: 'progress'
17447         };
17448         
17449         
17450         if(this.striped){
17451             cfg.cls += ' progress-striped';
17452         }
17453       
17454         if(this.active){
17455             cfg.cls += ' active';
17456         }
17457         
17458         
17459         return cfg;
17460     }
17461    
17462 });
17463
17464  
17465
17466  /*
17467  * - LGPL
17468  *
17469  * ProgressBar
17470  * 
17471  */
17472
17473 /**
17474  * @class Roo.bootstrap.ProgressBar
17475  * @extends Roo.bootstrap.Component
17476  * Bootstrap ProgressBar class
17477  * @cfg {Number} aria_valuenow aria-value now
17478  * @cfg {Number} aria_valuemin aria-value min
17479  * @cfg {Number} aria_valuemax aria-value max
17480  * @cfg {String} label label for the progress bar
17481  * @cfg {String} panel (success | info | warning | danger )
17482  * @cfg {String} role role of the progress bar
17483  * @cfg {String} sr_only text
17484  * 
17485  * 
17486  * @constructor
17487  * Create a new ProgressBar
17488  * @param {Object} config The config object
17489  */
17490
17491 Roo.bootstrap.ProgressBar = function(config){
17492     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17493 };
17494
17495 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
17496     
17497     aria_valuenow : 0,
17498     aria_valuemin : 0,
17499     aria_valuemax : 100,
17500     label : false,
17501     panel : false,
17502     role : false,
17503     sr_only: false,
17504     
17505     getAutoCreate : function()
17506     {
17507         
17508         var cfg = {
17509             tag: 'div',
17510             cls: 'progress-bar',
17511             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17512         };
17513         
17514         if(this.sr_only){
17515             cfg.cn = {
17516                 tag: 'span',
17517                 cls: 'sr-only',
17518                 html: this.sr_only
17519             }
17520         }
17521         
17522         if(this.role){
17523             cfg.role = this.role;
17524         }
17525         
17526         if(this.aria_valuenow){
17527             cfg['aria-valuenow'] = this.aria_valuenow;
17528         }
17529         
17530         if(this.aria_valuemin){
17531             cfg['aria-valuemin'] = this.aria_valuemin;
17532         }
17533         
17534         if(this.aria_valuemax){
17535             cfg['aria-valuemax'] = this.aria_valuemax;
17536         }
17537         
17538         if(this.label && !this.sr_only){
17539             cfg.html = this.label;
17540         }
17541         
17542         if(this.panel){
17543             cfg.cls += ' progress-bar-' + this.panel;
17544         }
17545         
17546         return cfg;
17547     },
17548     
17549     update : function(aria_valuenow)
17550     {
17551         this.aria_valuenow = aria_valuenow;
17552         
17553         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17554     }
17555    
17556 });
17557
17558  
17559
17560  /*
17561  * - LGPL
17562  *
17563  * column
17564  * 
17565  */
17566
17567 /**
17568  * @class Roo.bootstrap.TabGroup
17569  * @extends Roo.bootstrap.Column
17570  * Bootstrap Column class
17571  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17572  * @cfg {Boolean} carousel true to make the group behave like a carousel
17573  * @cfg {Boolean} bullets show bullets for the panels
17574  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17575  * @cfg {Number} timer auto slide timer .. default 0 millisecond
17576  * @cfg {Boolean} showarrow (true|false) show arrow default true
17577  * 
17578  * @constructor
17579  * Create a new TabGroup
17580  * @param {Object} config The config object
17581  */
17582
17583 Roo.bootstrap.TabGroup = function(config){
17584     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17585     if (!this.navId) {
17586         this.navId = Roo.id();
17587     }
17588     this.tabs = [];
17589     Roo.bootstrap.TabGroup.register(this);
17590     
17591 };
17592
17593 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
17594     
17595     carousel : false,
17596     transition : false,
17597     bullets : 0,
17598     timer : 0,
17599     autoslide : false,
17600     slideFn : false,
17601     slideOnTouch : false,
17602     showarrow : true,
17603     
17604     getAutoCreate : function()
17605     {
17606         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17607         
17608         cfg.cls += ' tab-content';
17609         
17610         if (this.carousel) {
17611             cfg.cls += ' carousel slide';
17612             
17613             cfg.cn = [{
17614                cls : 'carousel-inner',
17615                cn : []
17616             }];
17617         
17618             if(this.bullets  && !Roo.isTouch){
17619                 
17620                 var bullets = {
17621                     cls : 'carousel-bullets',
17622                     cn : []
17623                 };
17624                
17625                 if(this.bullets_cls){
17626                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17627                 }
17628                 
17629                 bullets.cn.push({
17630                     cls : 'clear'
17631                 });
17632                 
17633                 cfg.cn[0].cn.push(bullets);
17634             }
17635             
17636             if(this.showarrow){
17637                 cfg.cn[0].cn.push({
17638                     tag : 'div',
17639                     class : 'carousel-arrow',
17640                     cn : [
17641                         {
17642                             tag : 'div',
17643                             class : 'carousel-prev',
17644                             cn : [
17645                                 {
17646                                     tag : 'i',
17647                                     class : 'fa fa-chevron-left'
17648                                 }
17649                             ]
17650                         },
17651                         {
17652                             tag : 'div',
17653                             class : 'carousel-next',
17654                             cn : [
17655                                 {
17656                                     tag : 'i',
17657                                     class : 'fa fa-chevron-right'
17658                                 }
17659                             ]
17660                         }
17661                     ]
17662                 });
17663             }
17664             
17665         }
17666         
17667         return cfg;
17668     },
17669     
17670     initEvents:  function()
17671     {
17672 //        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17673 //            this.el.on("touchstart", this.onTouchStart, this);
17674 //        }
17675         
17676         if(this.autoslide){
17677             var _this = this;
17678             
17679             this.slideFn = window.setInterval(function() {
17680                 _this.showPanelNext();
17681             }, this.timer);
17682         }
17683         
17684         if(this.showarrow){
17685             this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17686             this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17687         }
17688         
17689         
17690     },
17691     
17692 //    onTouchStart : function(e, el, o)
17693 //    {
17694 //        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17695 //            return;
17696 //        }
17697 //        
17698 //        this.showPanelNext();
17699 //    },
17700     
17701     
17702     getChildContainer : function()
17703     {
17704         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17705     },
17706     
17707     /**
17708     * register a Navigation item
17709     * @param {Roo.bootstrap.NavItem} the navitem to add
17710     */
17711     register : function(item)
17712     {
17713         this.tabs.push( item);
17714         item.navId = this.navId; // not really needed..
17715         this.addBullet();
17716     
17717     },
17718     
17719     getActivePanel : function()
17720     {
17721         var r = false;
17722         Roo.each(this.tabs, function(t) {
17723             if (t.active) {
17724                 r = t;
17725                 return false;
17726             }
17727             return null;
17728         });
17729         return r;
17730         
17731     },
17732     getPanelByName : function(n)
17733     {
17734         var r = false;
17735         Roo.each(this.tabs, function(t) {
17736             if (t.tabId == n) {
17737                 r = t;
17738                 return false;
17739             }
17740             return null;
17741         });
17742         return r;
17743     },
17744     indexOfPanel : function(p)
17745     {
17746         var r = false;
17747         Roo.each(this.tabs, function(t,i) {
17748             if (t.tabId == p.tabId) {
17749                 r = i;
17750                 return false;
17751             }
17752             return null;
17753         });
17754         return r;
17755     },
17756     /**
17757      * show a specific panel
17758      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17759      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17760      */
17761     showPanel : function (pan)
17762     {
17763         if(this.transition || typeof(pan) == 'undefined'){
17764             Roo.log("waiting for the transitionend");
17765             return;
17766         }
17767         
17768         if (typeof(pan) == 'number') {
17769             pan = this.tabs[pan];
17770         }
17771         
17772         if (typeof(pan) == 'string') {
17773             pan = this.getPanelByName(pan);
17774         }
17775         
17776         var cur = this.getActivePanel();
17777         
17778         if(!pan || !cur){
17779             Roo.log('pan or acitve pan is undefined');
17780             return false;
17781         }
17782         
17783         if (pan.tabId == this.getActivePanel().tabId) {
17784             return true;
17785         }
17786         
17787         if (false === cur.fireEvent('beforedeactivate')) {
17788             return false;
17789         }
17790         
17791         if(this.bullets > 0 && !Roo.isTouch){
17792             this.setActiveBullet(this.indexOfPanel(pan));
17793         }
17794         
17795         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17796             
17797             this.transition = true;
17798             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
17799             var lr = dir == 'next' ? 'left' : 'right';
17800             pan.el.addClass(dir); // or prev
17801             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17802             cur.el.addClass(lr); // or right
17803             pan.el.addClass(lr);
17804             
17805             var _this = this;
17806             cur.el.on('transitionend', function() {
17807                 Roo.log("trans end?");
17808                 
17809                 pan.el.removeClass([lr,dir]);
17810                 pan.setActive(true);
17811                 
17812                 cur.el.removeClass([lr]);
17813                 cur.setActive(false);
17814                 
17815                 _this.transition = false;
17816                 
17817             }, this, { single:  true } );
17818             
17819             return true;
17820         }
17821         
17822         cur.setActive(false);
17823         pan.setActive(true);
17824         
17825         return true;
17826         
17827     },
17828     showPanelNext : function()
17829     {
17830         var i = this.indexOfPanel(this.getActivePanel());
17831         
17832         if (i >= this.tabs.length - 1 && !this.autoslide) {
17833             return;
17834         }
17835         
17836         if (i >= this.tabs.length - 1 && this.autoslide) {
17837             i = -1;
17838         }
17839         
17840         this.showPanel(this.tabs[i+1]);
17841     },
17842     
17843     showPanelPrev : function()
17844     {
17845         var i = this.indexOfPanel(this.getActivePanel());
17846         
17847         if (i  < 1 && !this.autoslide) {
17848             return;
17849         }
17850         
17851         if (i < 1 && this.autoslide) {
17852             i = this.tabs.length;
17853         }
17854         
17855         this.showPanel(this.tabs[i-1]);
17856     },
17857     
17858     
17859     addBullet: function()
17860     {
17861         if(!this.bullets || Roo.isTouch){
17862             return;
17863         }
17864         var ctr = this.el.select('.carousel-bullets',true).first();
17865         var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17866         var bullet = ctr.createChild({
17867             cls : 'bullet bullet-' + i
17868         },ctr.dom.lastChild);
17869         
17870         
17871         var _this = this;
17872         
17873         bullet.on('click', (function(e, el, o, ii, t){
17874
17875             e.preventDefault();
17876
17877             this.showPanel(ii);
17878
17879             if(this.autoslide && this.slideFn){
17880                 clearInterval(this.slideFn);
17881                 this.slideFn = window.setInterval(function() {
17882                     _this.showPanelNext();
17883                 }, this.timer);
17884             }
17885
17886         }).createDelegate(this, [i, bullet], true));
17887                 
17888         
17889     },
17890      
17891     setActiveBullet : function(i)
17892     {
17893         if(Roo.isTouch){
17894             return;
17895         }
17896         
17897         Roo.each(this.el.select('.bullet', true).elements, function(el){
17898             el.removeClass('selected');
17899         });
17900
17901         var bullet = this.el.select('.bullet-' + i, true).first();
17902         
17903         if(!bullet){
17904             return;
17905         }
17906         
17907         bullet.addClass('selected');
17908     }
17909     
17910     
17911   
17912 });
17913
17914  
17915
17916  
17917  
17918 Roo.apply(Roo.bootstrap.TabGroup, {
17919     
17920     groups: {},
17921      /**
17922     * register a Navigation Group
17923     * @param {Roo.bootstrap.NavGroup} the navgroup to add
17924     */
17925     register : function(navgrp)
17926     {
17927         this.groups[navgrp.navId] = navgrp;
17928         
17929     },
17930     /**
17931     * fetch a Navigation Group based on the navigation ID
17932     * if one does not exist , it will get created.
17933     * @param {string} the navgroup to add
17934     * @returns {Roo.bootstrap.NavGroup} the navgroup 
17935     */
17936     get: function(navId) {
17937         if (typeof(this.groups[navId]) == 'undefined') {
17938             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17939         }
17940         return this.groups[navId] ;
17941     }
17942     
17943     
17944     
17945 });
17946
17947  /*
17948  * - LGPL
17949  *
17950  * TabPanel
17951  * 
17952  */
17953
17954 /**
17955  * @class Roo.bootstrap.TabPanel
17956  * @extends Roo.bootstrap.Component
17957  * Bootstrap TabPanel class
17958  * @cfg {Boolean} active panel active
17959  * @cfg {String} html panel content
17960  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17961  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17962  * @cfg {String} href click to link..
17963  * 
17964  * 
17965  * @constructor
17966  * Create a new TabPanel
17967  * @param {Object} config The config object
17968  */
17969
17970 Roo.bootstrap.TabPanel = function(config){
17971     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17972     this.addEvents({
17973         /**
17974              * @event changed
17975              * Fires when the active status changes
17976              * @param {Roo.bootstrap.TabPanel} this
17977              * @param {Boolean} state the new state
17978             
17979          */
17980         'changed': true,
17981         /**
17982              * @event beforedeactivate
17983              * Fires before a tab is de-activated - can be used to do validation on a form.
17984              * @param {Roo.bootstrap.TabPanel} this
17985              * @return {Boolean} false if there is an error
17986             
17987          */
17988         'beforedeactivate': true
17989      });
17990     
17991     this.tabId = this.tabId || Roo.id();
17992   
17993 };
17994
17995 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
17996     
17997     active: false,
17998     html: false,
17999     tabId: false,
18000     navId : false,
18001     href : '',
18002     
18003     getAutoCreate : function(){
18004         var cfg = {
18005             tag: 'div',
18006             // item is needed for carousel - not sure if it has any effect otherwise
18007             cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18008             html: this.html || ''
18009         };
18010         
18011         if(this.active){
18012             cfg.cls += ' active';
18013         }
18014         
18015         if(this.tabId){
18016             cfg.tabId = this.tabId;
18017         }
18018         
18019         
18020         return cfg;
18021     },
18022     
18023     initEvents:  function()
18024     {
18025         var p = this.parent();
18026         
18027         this.navId = this.navId || p.navId;
18028         
18029         if (typeof(this.navId) != 'undefined') {
18030             // not really needed.. but just in case.. parent should be a NavGroup.
18031             var tg = Roo.bootstrap.TabGroup.get(this.navId);
18032             
18033             tg.register(this);
18034             
18035             var i = tg.tabs.length - 1;
18036             
18037             if(this.active && tg.bullets > 0 && i < tg.bullets){
18038                 tg.setActiveBullet(i);
18039             }
18040         }
18041         
18042         this.el.on('click', this.onClick, this);
18043         
18044         if(Roo.isTouch){
18045             this.el.on("touchstart", this.onTouchStart, this);
18046             this.el.on("touchmove", this.onTouchMove, this);
18047             this.el.on("touchend", this.onTouchEnd, this);
18048         }
18049         
18050     },
18051     
18052     onRender : function(ct, position)
18053     {
18054         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18055     },
18056     
18057     setActive : function(state)
18058     {
18059         Roo.log("panel - set active " + this.tabId + "=" + state);
18060         
18061         this.active = state;
18062         if (!state) {
18063             this.el.removeClass('active');
18064             
18065         } else  if (!this.el.hasClass('active')) {
18066             this.el.addClass('active');
18067         }
18068         
18069         this.fireEvent('changed', this, state);
18070     },
18071     
18072     onClick : function(e)
18073     {
18074         e.preventDefault();
18075         
18076         if(!this.href.length){
18077             return;
18078         }
18079         
18080         window.location.href = this.href;
18081     },
18082     
18083     startX : 0,
18084     startY : 0,
18085     endX : 0,
18086     endY : 0,
18087     swiping : false,
18088     
18089     onTouchStart : function(e)
18090     {
18091         this.swiping = false;
18092         
18093         this.startX = e.browserEvent.touches[0].clientX;
18094         this.startY = e.browserEvent.touches[0].clientY;
18095     },
18096     
18097     onTouchMove : function(e)
18098     {
18099         this.swiping = true;
18100         
18101         this.endX = e.browserEvent.touches[0].clientX;
18102         this.endY = e.browserEvent.touches[0].clientY;
18103     },
18104     
18105     onTouchEnd : function(e)
18106     {
18107         if(!this.swiping){
18108             this.onClick(e);
18109             return;
18110         }
18111         
18112         var tabGroup = this.parent();
18113         
18114         if(this.endX > this.startX){ // swiping right
18115             tabGroup.showPanelPrev();
18116             return;
18117         }
18118         
18119         if(this.startX > this.endX){ // swiping left
18120             tabGroup.showPanelNext();
18121             return;
18122         }
18123     }
18124     
18125     
18126 });
18127  
18128
18129  
18130
18131  /*
18132  * - LGPL
18133  *
18134  * DateField
18135  * 
18136  */
18137
18138 /**
18139  * @class Roo.bootstrap.DateField
18140  * @extends Roo.bootstrap.Input
18141  * Bootstrap DateField class
18142  * @cfg {Number} weekStart default 0
18143  * @cfg {String} viewMode default empty, (months|years)
18144  * @cfg {String} minViewMode default empty, (months|years)
18145  * @cfg {Number} startDate default -Infinity
18146  * @cfg {Number} endDate default Infinity
18147  * @cfg {Boolean} todayHighlight default false
18148  * @cfg {Boolean} todayBtn default false
18149  * @cfg {Boolean} calendarWeeks default false
18150  * @cfg {Object} daysOfWeekDisabled default empty
18151  * @cfg {Boolean} singleMode default false (true | false)
18152  * 
18153  * @cfg {Boolean} keyboardNavigation default true
18154  * @cfg {String} language default en
18155  * 
18156  * @constructor
18157  * Create a new DateField
18158  * @param {Object} config The config object
18159  */
18160
18161 Roo.bootstrap.DateField = function(config){
18162     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18163      this.addEvents({
18164             /**
18165              * @event show
18166              * Fires when this field show.
18167              * @param {Roo.bootstrap.DateField} this
18168              * @param {Mixed} date The date value
18169              */
18170             show : true,
18171             /**
18172              * @event show
18173              * Fires when this field hide.
18174              * @param {Roo.bootstrap.DateField} this
18175              * @param {Mixed} date The date value
18176              */
18177             hide : true,
18178             /**
18179              * @event select
18180              * Fires when select a date.
18181              * @param {Roo.bootstrap.DateField} this
18182              * @param {Mixed} date The date value
18183              */
18184             select : true,
18185             /**
18186              * @event beforeselect
18187              * Fires when before select a date.
18188              * @param {Roo.bootstrap.DateField} this
18189              * @param {Mixed} date The date value
18190              */
18191             beforeselect : true
18192         });
18193 };
18194
18195 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
18196     
18197     /**
18198      * @cfg {String} format
18199      * The default date format string which can be overriden for localization support.  The format must be
18200      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18201      */
18202     format : "m/d/y",
18203     /**
18204      * @cfg {String} altFormats
18205      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18206      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18207      */
18208     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18209     
18210     weekStart : 0,
18211     
18212     viewMode : '',
18213     
18214     minViewMode : '',
18215     
18216     todayHighlight : false,
18217     
18218     todayBtn: false,
18219     
18220     language: 'en',
18221     
18222     keyboardNavigation: true,
18223     
18224     calendarWeeks: false,
18225     
18226     startDate: -Infinity,
18227     
18228     endDate: Infinity,
18229     
18230     daysOfWeekDisabled: [],
18231     
18232     _events: [],
18233     
18234     singleMode : false,
18235     
18236     UTCDate: function()
18237     {
18238         return new Date(Date.UTC.apply(Date, arguments));
18239     },
18240     
18241     UTCToday: function()
18242     {
18243         var today = new Date();
18244         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18245     },
18246     
18247     getDate: function() {
18248             var d = this.getUTCDate();
18249             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18250     },
18251     
18252     getUTCDate: function() {
18253             return this.date;
18254     },
18255     
18256     setDate: function(d) {
18257             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18258     },
18259     
18260     setUTCDate: function(d) {
18261             this.date = d;
18262             this.setValue(this.formatDate(this.date));
18263     },
18264         
18265     onRender: function(ct, position)
18266     {
18267         
18268         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18269         
18270         this.language = this.language || 'en';
18271         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18272         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18273         
18274         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18275         this.format = this.format || 'm/d/y';
18276         this.isInline = false;
18277         this.isInput = true;
18278         this.component = this.el.select('.add-on', true).first() || false;
18279         this.component = (this.component && this.component.length === 0) ? false : this.component;
18280         this.hasInput = this.component && this.inputEl().length;
18281         
18282         if (typeof(this.minViewMode === 'string')) {
18283             switch (this.minViewMode) {
18284                 case 'months':
18285                     this.minViewMode = 1;
18286                     break;
18287                 case 'years':
18288                     this.minViewMode = 2;
18289                     break;
18290                 default:
18291                     this.minViewMode = 0;
18292                     break;
18293             }
18294         }
18295         
18296         if (typeof(this.viewMode === 'string')) {
18297             switch (this.viewMode) {
18298                 case 'months':
18299                     this.viewMode = 1;
18300                     break;
18301                 case 'years':
18302                     this.viewMode = 2;
18303                     break;
18304                 default:
18305                     this.viewMode = 0;
18306                     break;
18307             }
18308         }
18309                 
18310         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18311         
18312 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18313         
18314         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18315         
18316         this.picker().on('mousedown', this.onMousedown, this);
18317         this.picker().on('click', this.onClick, this);
18318         
18319         this.picker().addClass('datepicker-dropdown');
18320         
18321         this.startViewMode = this.viewMode;
18322         
18323         if(this.singleMode){
18324             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18325                 v.setVisibilityMode(Roo.Element.DISPLAY);
18326                 v.hide();
18327             });
18328             
18329             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18330                 v.setStyle('width', '189px');
18331             });
18332         }
18333         
18334         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18335             if(!this.calendarWeeks){
18336                 v.remove();
18337                 return;
18338             }
18339             
18340             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18341             v.attr('colspan', function(i, val){
18342                 return parseInt(val) + 1;
18343             });
18344         });
18345                         
18346         
18347         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18348         
18349         this.setStartDate(this.startDate);
18350         this.setEndDate(this.endDate);
18351         
18352         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18353         
18354         this.fillDow();
18355         this.fillMonths();
18356         this.update();
18357         this.showMode();
18358         
18359         if(this.isInline) {
18360             this.show();
18361         }
18362     },
18363     
18364     picker : function()
18365     {
18366         return this.pickerEl;
18367 //        return this.el.select('.datepicker', true).first();
18368     },
18369     
18370     fillDow: function()
18371     {
18372         var dowCnt = this.weekStart;
18373         
18374         var dow = {
18375             tag: 'tr',
18376             cn: [
18377                 
18378             ]
18379         };
18380         
18381         if(this.calendarWeeks){
18382             dow.cn.push({
18383                 tag: 'th',
18384                 cls: 'cw',
18385                 html: '&nbsp;'
18386             })
18387         }
18388         
18389         while (dowCnt < this.weekStart + 7) {
18390             dow.cn.push({
18391                 tag: 'th',
18392                 cls: 'dow',
18393                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18394             });
18395         }
18396         
18397         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18398     },
18399     
18400     fillMonths: function()
18401     {    
18402         var i = 0;
18403         var months = this.picker().select('>.datepicker-months td', true).first();
18404         
18405         months.dom.innerHTML = '';
18406         
18407         while (i < 12) {
18408             var month = {
18409                 tag: 'span',
18410                 cls: 'month',
18411                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18412             };
18413             
18414             months.createChild(month);
18415         }
18416         
18417     },
18418     
18419     update: function()
18420     {
18421         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;
18422         
18423         if (this.date < this.startDate) {
18424             this.viewDate = new Date(this.startDate);
18425         } else if (this.date > this.endDate) {
18426             this.viewDate = new Date(this.endDate);
18427         } else {
18428             this.viewDate = new Date(this.date);
18429         }
18430         
18431         this.fill();
18432     },
18433     
18434     fill: function() 
18435     {
18436         var d = new Date(this.viewDate),
18437                 year = d.getUTCFullYear(),
18438                 month = d.getUTCMonth(),
18439                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18440                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18441                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18442                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18443                 currentDate = this.date && this.date.valueOf(),
18444                 today = this.UTCToday();
18445         
18446         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18447         
18448 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18449         
18450 //        this.picker.select('>tfoot th.today').
18451 //                                              .text(dates[this.language].today)
18452 //                                              .toggle(this.todayBtn !== false);
18453     
18454         this.updateNavArrows();
18455         this.fillMonths();
18456                                                 
18457         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18458         
18459         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18460          
18461         prevMonth.setUTCDate(day);
18462         
18463         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18464         
18465         var nextMonth = new Date(prevMonth);
18466         
18467         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18468         
18469         nextMonth = nextMonth.valueOf();
18470         
18471         var fillMonths = false;
18472         
18473         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18474         
18475         while(prevMonth.valueOf() < nextMonth) {
18476             var clsName = '';
18477             
18478             if (prevMonth.getUTCDay() === this.weekStart) {
18479                 if(fillMonths){
18480                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18481                 }
18482                     
18483                 fillMonths = {
18484                     tag: 'tr',
18485                     cn: []
18486                 };
18487                 
18488                 if(this.calendarWeeks){
18489                     // ISO 8601: First week contains first thursday.
18490                     // ISO also states week starts on Monday, but we can be more abstract here.
18491                     var
18492                     // Start of current week: based on weekstart/current date
18493                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18494                     // Thursday of this week
18495                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18496                     // First Thursday of year, year from thursday
18497                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18498                     // Calendar week: ms between thursdays, div ms per day, div 7 days
18499                     calWeek =  (th - yth) / 864e5 / 7 + 1;
18500                     
18501                     fillMonths.cn.push({
18502                         tag: 'td',
18503                         cls: 'cw',
18504                         html: calWeek
18505                     });
18506                 }
18507             }
18508             
18509             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18510                 clsName += ' old';
18511             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18512                 clsName += ' new';
18513             }
18514             if (this.todayHighlight &&
18515                 prevMonth.getUTCFullYear() == today.getFullYear() &&
18516                 prevMonth.getUTCMonth() == today.getMonth() &&
18517                 prevMonth.getUTCDate() == today.getDate()) {
18518                 clsName += ' today';
18519             }
18520             
18521             if (currentDate && prevMonth.valueOf() === currentDate) {
18522                 clsName += ' active';
18523             }
18524             
18525             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18526                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18527                     clsName += ' disabled';
18528             }
18529             
18530             fillMonths.cn.push({
18531                 tag: 'td',
18532                 cls: 'day ' + clsName,
18533                 html: prevMonth.getDate()
18534             });
18535             
18536             prevMonth.setDate(prevMonth.getDate()+1);
18537         }
18538           
18539         var currentYear = this.date && this.date.getUTCFullYear();
18540         var currentMonth = this.date && this.date.getUTCMonth();
18541         
18542         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18543         
18544         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18545             v.removeClass('active');
18546             
18547             if(currentYear === year && k === currentMonth){
18548                 v.addClass('active');
18549             }
18550             
18551             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18552                 v.addClass('disabled');
18553             }
18554             
18555         });
18556         
18557         
18558         year = parseInt(year/10, 10) * 10;
18559         
18560         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18561         
18562         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18563         
18564         year -= 1;
18565         for (var i = -1; i < 11; i++) {
18566             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18567                 tag: 'span',
18568                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18569                 html: year
18570             });
18571             
18572             year += 1;
18573         }
18574     },
18575     
18576     showMode: function(dir) 
18577     {
18578         if (dir) {
18579             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18580         }
18581         
18582         Roo.each(this.picker().select('>div',true).elements, function(v){
18583             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18584             v.hide();
18585         });
18586         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18587     },
18588     
18589     place: function()
18590     {
18591         if(this.isInline) {
18592             return;
18593         }
18594         
18595         this.picker().removeClass(['bottom', 'top']);
18596         
18597         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18598             /*
18599              * place to the top of element!
18600              *
18601              */
18602             
18603             this.picker().addClass('top');
18604             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18605             
18606             return;
18607         }
18608         
18609         this.picker().addClass('bottom');
18610         
18611         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18612     },
18613     
18614     parseDate : function(value)
18615     {
18616         if(!value || value instanceof Date){
18617             return value;
18618         }
18619         var v = Date.parseDate(value, this.format);
18620         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18621             v = Date.parseDate(value, 'Y-m-d');
18622         }
18623         if(!v && this.altFormats){
18624             if(!this.altFormatsArray){
18625                 this.altFormatsArray = this.altFormats.split("|");
18626             }
18627             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18628                 v = Date.parseDate(value, this.altFormatsArray[i]);
18629             }
18630         }
18631         return v;
18632     },
18633     
18634     formatDate : function(date, fmt)
18635     {   
18636         return (!date || !(date instanceof Date)) ?
18637         date : date.dateFormat(fmt || this.format);
18638     },
18639     
18640     onFocus : function()
18641     {
18642         Roo.bootstrap.DateField.superclass.onFocus.call(this);
18643         this.show();
18644     },
18645     
18646     onBlur : function()
18647     {
18648         Roo.bootstrap.DateField.superclass.onBlur.call(this);
18649         
18650         var d = this.inputEl().getValue();
18651         
18652         this.setValue(d);
18653                 
18654         this.hide();
18655     },
18656     
18657     show : function()
18658     {
18659         this.picker().show();
18660         this.update();
18661         this.place();
18662         
18663         this.fireEvent('show', this, this.date);
18664     },
18665     
18666     hide : function()
18667     {
18668         if(this.isInline) {
18669             return;
18670         }
18671         this.picker().hide();
18672         this.viewMode = this.startViewMode;
18673         this.showMode();
18674         
18675         this.fireEvent('hide', this, this.date);
18676         
18677     },
18678     
18679     onMousedown: function(e)
18680     {
18681         e.stopPropagation();
18682         e.preventDefault();
18683     },
18684     
18685     keyup: function(e)
18686     {
18687         Roo.bootstrap.DateField.superclass.keyup.call(this);
18688         this.update();
18689     },
18690
18691     setValue: function(v)
18692     {
18693         if(this.fireEvent('beforeselect', this, v) !== false){
18694             var d = new Date(this.parseDate(v) ).clearTime();
18695         
18696             if(isNaN(d.getTime())){
18697                 this.date = this.viewDate = '';
18698                 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18699                 return;
18700             }
18701
18702             v = this.formatDate(d);
18703
18704             Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18705
18706             this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18707
18708             this.update();
18709
18710             this.fireEvent('select', this, this.date);
18711         }
18712     },
18713     
18714     getValue: function()
18715     {
18716         return this.formatDate(this.date);
18717     },
18718     
18719     fireKey: function(e)
18720     {
18721         if (!this.picker().isVisible()){
18722             if (e.keyCode == 27) { // allow escape to hide and re-show picker
18723                 this.show();
18724             }
18725             return;
18726         }
18727         
18728         var dateChanged = false,
18729         dir, day, month,
18730         newDate, newViewDate;
18731         
18732         switch(e.keyCode){
18733             case 27: // escape
18734                 this.hide();
18735                 e.preventDefault();
18736                 break;
18737             case 37: // left
18738             case 39: // right
18739                 if (!this.keyboardNavigation) {
18740                     break;
18741                 }
18742                 dir = e.keyCode == 37 ? -1 : 1;
18743                 
18744                 if (e.ctrlKey){
18745                     newDate = this.moveYear(this.date, dir);
18746                     newViewDate = this.moveYear(this.viewDate, dir);
18747                 } else if (e.shiftKey){
18748                     newDate = this.moveMonth(this.date, dir);
18749                     newViewDate = this.moveMonth(this.viewDate, dir);
18750                 } else {
18751                     newDate = new Date(this.date);
18752                     newDate.setUTCDate(this.date.getUTCDate() + dir);
18753                     newViewDate = new Date(this.viewDate);
18754                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18755                 }
18756                 if (this.dateWithinRange(newDate)){
18757                     this.date = newDate;
18758                     this.viewDate = newViewDate;
18759                     this.setValue(this.formatDate(this.date));
18760 //                    this.update();
18761                     e.preventDefault();
18762                     dateChanged = true;
18763                 }
18764                 break;
18765             case 38: // up
18766             case 40: // down
18767                 if (!this.keyboardNavigation) {
18768                     break;
18769                 }
18770                 dir = e.keyCode == 38 ? -1 : 1;
18771                 if (e.ctrlKey){
18772                     newDate = this.moveYear(this.date, dir);
18773                     newViewDate = this.moveYear(this.viewDate, dir);
18774                 } else if (e.shiftKey){
18775                     newDate = this.moveMonth(this.date, dir);
18776                     newViewDate = this.moveMonth(this.viewDate, dir);
18777                 } else {
18778                     newDate = new Date(this.date);
18779                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18780                     newViewDate = new Date(this.viewDate);
18781                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18782                 }
18783                 if (this.dateWithinRange(newDate)){
18784                     this.date = newDate;
18785                     this.viewDate = newViewDate;
18786                     this.setValue(this.formatDate(this.date));
18787 //                    this.update();
18788                     e.preventDefault();
18789                     dateChanged = true;
18790                 }
18791                 break;
18792             case 13: // enter
18793                 this.setValue(this.formatDate(this.date));
18794                 this.hide();
18795                 e.preventDefault();
18796                 break;
18797             case 9: // tab
18798                 this.setValue(this.formatDate(this.date));
18799                 this.hide();
18800                 break;
18801             case 16: // shift
18802             case 17: // ctrl
18803             case 18: // alt
18804                 break;
18805             default :
18806                 this.hide();
18807                 
18808         }
18809     },
18810     
18811     
18812     onClick: function(e) 
18813     {
18814         e.stopPropagation();
18815         e.preventDefault();
18816         
18817         var target = e.getTarget();
18818         
18819         if(target.nodeName.toLowerCase() === 'i'){
18820             target = Roo.get(target).dom.parentNode;
18821         }
18822         
18823         var nodeName = target.nodeName;
18824         var className = target.className;
18825         var html = target.innerHTML;
18826         //Roo.log(nodeName);
18827         
18828         switch(nodeName.toLowerCase()) {
18829             case 'th':
18830                 switch(className) {
18831                     case 'switch':
18832                         this.showMode(1);
18833                         break;
18834                     case 'prev':
18835                     case 'next':
18836                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18837                         switch(this.viewMode){
18838                                 case 0:
18839                                         this.viewDate = this.moveMonth(this.viewDate, dir);
18840                                         break;
18841                                 case 1:
18842                                 case 2:
18843                                         this.viewDate = this.moveYear(this.viewDate, dir);
18844                                         break;
18845                         }
18846                         this.fill();
18847                         break;
18848                     case 'today':
18849                         var date = new Date();
18850                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18851 //                        this.fill()
18852                         this.setValue(this.formatDate(this.date));
18853                         
18854                         this.hide();
18855                         break;
18856                 }
18857                 break;
18858             case 'span':
18859                 if (className.indexOf('disabled') < 0) {
18860                     this.viewDate.setUTCDate(1);
18861                     if (className.indexOf('month') > -1) {
18862                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18863                     } else {
18864                         var year = parseInt(html, 10) || 0;
18865                         this.viewDate.setUTCFullYear(year);
18866                         
18867                     }
18868                     
18869                     if(this.singleMode){
18870                         this.setValue(this.formatDate(this.viewDate));
18871                         this.hide();
18872                         return;
18873                     }
18874                     
18875                     this.showMode(-1);
18876                     this.fill();
18877                 }
18878                 break;
18879                 
18880             case 'td':
18881                 //Roo.log(className);
18882                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18883                     var day = parseInt(html, 10) || 1;
18884                     var year = this.viewDate.getUTCFullYear(),
18885                         month = this.viewDate.getUTCMonth();
18886
18887                     if (className.indexOf('old') > -1) {
18888                         if(month === 0 ){
18889                             month = 11;
18890                             year -= 1;
18891                         }else{
18892                             month -= 1;
18893                         }
18894                     } else if (className.indexOf('new') > -1) {
18895                         if (month == 11) {
18896                             month = 0;
18897                             year += 1;
18898                         } else {
18899                             month += 1;
18900                         }
18901                     }
18902                     //Roo.log([year,month,day]);
18903                     this.date = this.UTCDate(year, month, day,0,0,0,0);
18904                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18905 //                    this.fill();
18906                     //Roo.log(this.formatDate(this.date));
18907                     this.setValue(this.formatDate(this.date));
18908                     this.hide();
18909                 }
18910                 break;
18911         }
18912     },
18913     
18914     setStartDate: function(startDate)
18915     {
18916         this.startDate = startDate || -Infinity;
18917         if (this.startDate !== -Infinity) {
18918             this.startDate = this.parseDate(this.startDate);
18919         }
18920         this.update();
18921         this.updateNavArrows();
18922     },
18923
18924     setEndDate: function(endDate)
18925     {
18926         this.endDate = endDate || Infinity;
18927         if (this.endDate !== Infinity) {
18928             this.endDate = this.parseDate(this.endDate);
18929         }
18930         this.update();
18931         this.updateNavArrows();
18932     },
18933     
18934     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18935     {
18936         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18937         if (typeof(this.daysOfWeekDisabled) !== 'object') {
18938             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18939         }
18940         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18941             return parseInt(d, 10);
18942         });
18943         this.update();
18944         this.updateNavArrows();
18945     },
18946     
18947     updateNavArrows: function() 
18948     {
18949         if(this.singleMode){
18950             return;
18951         }
18952         
18953         var d = new Date(this.viewDate),
18954         year = d.getUTCFullYear(),
18955         month = d.getUTCMonth();
18956         
18957         Roo.each(this.picker().select('.prev', true).elements, function(v){
18958             v.show();
18959             switch (this.viewMode) {
18960                 case 0:
18961
18962                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18963                         v.hide();
18964                     }
18965                     break;
18966                 case 1:
18967                 case 2:
18968                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18969                         v.hide();
18970                     }
18971                     break;
18972             }
18973         });
18974         
18975         Roo.each(this.picker().select('.next', true).elements, function(v){
18976             v.show();
18977             switch (this.viewMode) {
18978                 case 0:
18979
18980                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18981                         v.hide();
18982                     }
18983                     break;
18984                 case 1:
18985                 case 2:
18986                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18987                         v.hide();
18988                     }
18989                     break;
18990             }
18991         })
18992     },
18993     
18994     moveMonth: function(date, dir)
18995     {
18996         if (!dir) {
18997             return date;
18998         }
18999         var new_date = new Date(date.valueOf()),
19000         day = new_date.getUTCDate(),
19001         month = new_date.getUTCMonth(),
19002         mag = Math.abs(dir),
19003         new_month, test;
19004         dir = dir > 0 ? 1 : -1;
19005         if (mag == 1){
19006             test = dir == -1
19007             // If going back one month, make sure month is not current month
19008             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19009             ? function(){
19010                 return new_date.getUTCMonth() == month;
19011             }
19012             // If going forward one month, make sure month is as expected
19013             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19014             : function(){
19015                 return new_date.getUTCMonth() != new_month;
19016             };
19017             new_month = month + dir;
19018             new_date.setUTCMonth(new_month);
19019             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19020             if (new_month < 0 || new_month > 11) {
19021                 new_month = (new_month + 12) % 12;
19022             }
19023         } else {
19024             // For magnitudes >1, move one month at a time...
19025             for (var i=0; i<mag; i++) {
19026                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19027                 new_date = this.moveMonth(new_date, dir);
19028             }
19029             // ...then reset the day, keeping it in the new month
19030             new_month = new_date.getUTCMonth();
19031             new_date.setUTCDate(day);
19032             test = function(){
19033                 return new_month != new_date.getUTCMonth();
19034             };
19035         }
19036         // Common date-resetting loop -- if date is beyond end of month, make it
19037         // end of month
19038         while (test()){
19039             new_date.setUTCDate(--day);
19040             new_date.setUTCMonth(new_month);
19041         }
19042         return new_date;
19043     },
19044
19045     moveYear: function(date, dir)
19046     {
19047         return this.moveMonth(date, dir*12);
19048     },
19049
19050     dateWithinRange: function(date)
19051     {
19052         return date >= this.startDate && date <= this.endDate;
19053     },
19054
19055     
19056     remove: function() 
19057     {
19058         this.picker().remove();
19059     },
19060     
19061     validateValue : function(value)
19062     {
19063         if(value.length < 1)  {
19064             if(this.allowBlank){
19065                 return true;
19066             }
19067             return false;
19068         }
19069         
19070         if(value.length < this.minLength){
19071             return false;
19072         }
19073         if(value.length > this.maxLength){
19074             return false;
19075         }
19076         if(this.vtype){
19077             var vt = Roo.form.VTypes;
19078             if(!vt[this.vtype](value, this)){
19079                 return false;
19080             }
19081         }
19082         if(typeof this.validator == "function"){
19083             var msg = this.validator(value);
19084             if(msg !== true){
19085                 return false;
19086             }
19087         }
19088         
19089         if(this.regex && !this.regex.test(value)){
19090             return false;
19091         }
19092         
19093         if(typeof(this.parseDate(value)) == 'undefined'){
19094             return false;
19095         }
19096         
19097         if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19098             return false;
19099         }      
19100         
19101         if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19102             return false;
19103         } 
19104         
19105         
19106         return true;
19107     }
19108    
19109 });
19110
19111 Roo.apply(Roo.bootstrap.DateField,  {
19112     
19113     head : {
19114         tag: 'thead',
19115         cn: [
19116         {
19117             tag: 'tr',
19118             cn: [
19119             {
19120                 tag: 'th',
19121                 cls: 'prev',
19122                 html: '<i class="fa fa-arrow-left"/>'
19123             },
19124             {
19125                 tag: 'th',
19126                 cls: 'switch',
19127                 colspan: '5'
19128             },
19129             {
19130                 tag: 'th',
19131                 cls: 'next',
19132                 html: '<i class="fa fa-arrow-right"/>'
19133             }
19134
19135             ]
19136         }
19137         ]
19138     },
19139     
19140     content : {
19141         tag: 'tbody',
19142         cn: [
19143         {
19144             tag: 'tr',
19145             cn: [
19146             {
19147                 tag: 'td',
19148                 colspan: '7'
19149             }
19150             ]
19151         }
19152         ]
19153     },
19154     
19155     footer : {
19156         tag: 'tfoot',
19157         cn: [
19158         {
19159             tag: 'tr',
19160             cn: [
19161             {
19162                 tag: 'th',
19163                 colspan: '7',
19164                 cls: 'today'
19165             }
19166                     
19167             ]
19168         }
19169         ]
19170     },
19171     
19172     dates:{
19173         en: {
19174             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19175             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19176             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19177             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19178             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19179             today: "Today"
19180         }
19181     },
19182     
19183     modes: [
19184     {
19185         clsName: 'days',
19186         navFnc: 'Month',
19187         navStep: 1
19188     },
19189     {
19190         clsName: 'months',
19191         navFnc: 'FullYear',
19192         navStep: 1
19193     },
19194     {
19195         clsName: 'years',
19196         navFnc: 'FullYear',
19197         navStep: 10
19198     }]
19199 });
19200
19201 Roo.apply(Roo.bootstrap.DateField,  {
19202   
19203     template : {
19204         tag: 'div',
19205         cls: 'datepicker dropdown-menu roo-dynamic',
19206         cn: [
19207         {
19208             tag: 'div',
19209             cls: 'datepicker-days',
19210             cn: [
19211             {
19212                 tag: 'table',
19213                 cls: 'table-condensed',
19214                 cn:[
19215                 Roo.bootstrap.DateField.head,
19216                 {
19217                     tag: 'tbody'
19218                 },
19219                 Roo.bootstrap.DateField.footer
19220                 ]
19221             }
19222             ]
19223         },
19224         {
19225             tag: 'div',
19226             cls: 'datepicker-months',
19227             cn: [
19228             {
19229                 tag: 'table',
19230                 cls: 'table-condensed',
19231                 cn:[
19232                 Roo.bootstrap.DateField.head,
19233                 Roo.bootstrap.DateField.content,
19234                 Roo.bootstrap.DateField.footer
19235                 ]
19236             }
19237             ]
19238         },
19239         {
19240             tag: 'div',
19241             cls: 'datepicker-years',
19242             cn: [
19243             {
19244                 tag: 'table',
19245                 cls: 'table-condensed',
19246                 cn:[
19247                 Roo.bootstrap.DateField.head,
19248                 Roo.bootstrap.DateField.content,
19249                 Roo.bootstrap.DateField.footer
19250                 ]
19251             }
19252             ]
19253         }
19254         ]
19255     }
19256 });
19257
19258  
19259
19260  /*
19261  * - LGPL
19262  *
19263  * TimeField
19264  * 
19265  */
19266
19267 /**
19268  * @class Roo.bootstrap.TimeField
19269  * @extends Roo.bootstrap.Input
19270  * Bootstrap DateField class
19271  * 
19272  * 
19273  * @constructor
19274  * Create a new TimeField
19275  * @param {Object} config The config object
19276  */
19277
19278 Roo.bootstrap.TimeField = function(config){
19279     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19280     this.addEvents({
19281             /**
19282              * @event show
19283              * Fires when this field show.
19284              * @param {Roo.bootstrap.DateField} thisthis
19285              * @param {Mixed} date The date value
19286              */
19287             show : true,
19288             /**
19289              * @event show
19290              * Fires when this field hide.
19291              * @param {Roo.bootstrap.DateField} this
19292              * @param {Mixed} date The date value
19293              */
19294             hide : true,
19295             /**
19296              * @event select
19297              * Fires when select a date.
19298              * @param {Roo.bootstrap.DateField} this
19299              * @param {Mixed} date The date value
19300              */
19301             select : true
19302         });
19303 };
19304
19305 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
19306     
19307     /**
19308      * @cfg {String} format
19309      * The default time format string which can be overriden for localization support.  The format must be
19310      * valid according to {@link Date#parseDate} (defaults to 'H:i').
19311      */
19312     format : "H:i",
19313        
19314     onRender: function(ct, position)
19315     {
19316         
19317         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19318                 
19319         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19320         
19321         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19322         
19323         this.pop = this.picker().select('>.datepicker-time',true).first();
19324         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19325         
19326         this.picker().on('mousedown', this.onMousedown, this);
19327         this.picker().on('click', this.onClick, this);
19328         
19329         this.picker().addClass('datepicker-dropdown');
19330     
19331         this.fillTime();
19332         this.update();
19333             
19334         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19335         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19336         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19337         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19338         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19339         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19340
19341     },
19342     
19343     fireKey: function(e){
19344         if (!this.picker().isVisible()){
19345             if (e.keyCode == 27) { // allow escape to hide and re-show picker
19346                 this.show();
19347             }
19348             return;
19349         }
19350
19351         e.preventDefault();
19352         
19353         switch(e.keyCode){
19354             case 27: // escape
19355                 this.hide();
19356                 break;
19357             case 37: // left
19358             case 39: // right
19359                 this.onTogglePeriod();
19360                 break;
19361             case 38: // up
19362                 this.onIncrementMinutes();
19363                 break;
19364             case 40: // down
19365                 this.onDecrementMinutes();
19366                 break;
19367             case 13: // enter
19368             case 9: // tab
19369                 this.setTime();
19370                 break;
19371         }
19372     },
19373     
19374     onClick: function(e) {
19375         e.stopPropagation();
19376         e.preventDefault();
19377     },
19378     
19379     picker : function()
19380     {
19381         return this.el.select('.datepicker', true).first();
19382     },
19383     
19384     fillTime: function()
19385     {    
19386         var time = this.pop.select('tbody', true).first();
19387         
19388         time.dom.innerHTML = '';
19389         
19390         time.createChild({
19391             tag: 'tr',
19392             cn: [
19393                 {
19394                     tag: 'td',
19395                     cn: [
19396                         {
19397                             tag: 'a',
19398                             href: '#',
19399                             cls: 'btn',
19400                             cn: [
19401                                 {
19402                                     tag: 'span',
19403                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
19404                                 }
19405                             ]
19406                         } 
19407                     ]
19408                 },
19409                 {
19410                     tag: 'td',
19411                     cls: 'separator'
19412                 },
19413                 {
19414                     tag: 'td',
19415                     cn: [
19416                         {
19417                             tag: 'a',
19418                             href: '#',
19419                             cls: 'btn',
19420                             cn: [
19421                                 {
19422                                     tag: 'span',
19423                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
19424                                 }
19425                             ]
19426                         }
19427                     ]
19428                 },
19429                 {
19430                     tag: 'td',
19431                     cls: 'separator'
19432                 }
19433             ]
19434         });
19435         
19436         time.createChild({
19437             tag: 'tr',
19438             cn: [
19439                 {
19440                     tag: 'td',
19441                     cn: [
19442                         {
19443                             tag: 'span',
19444                             cls: 'timepicker-hour',
19445                             html: '00'
19446                         }  
19447                     ]
19448                 },
19449                 {
19450                     tag: 'td',
19451                     cls: 'separator',
19452                     html: ':'
19453                 },
19454                 {
19455                     tag: 'td',
19456                     cn: [
19457                         {
19458                             tag: 'span',
19459                             cls: 'timepicker-minute',
19460                             html: '00'
19461                         }  
19462                     ]
19463                 },
19464                 {
19465                     tag: 'td',
19466                     cls: 'separator'
19467                 },
19468                 {
19469                     tag: 'td',
19470                     cn: [
19471                         {
19472                             tag: 'button',
19473                             type: 'button',
19474                             cls: 'btn btn-primary period',
19475                             html: 'AM'
19476                             
19477                         }
19478                     ]
19479                 }
19480             ]
19481         });
19482         
19483         time.createChild({
19484             tag: 'tr',
19485             cn: [
19486                 {
19487                     tag: 'td',
19488                     cn: [
19489                         {
19490                             tag: 'a',
19491                             href: '#',
19492                             cls: 'btn',
19493                             cn: [
19494                                 {
19495                                     tag: 'span',
19496                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
19497                                 }
19498                             ]
19499                         }
19500                     ]
19501                 },
19502                 {
19503                     tag: 'td',
19504                     cls: 'separator'
19505                 },
19506                 {
19507                     tag: 'td',
19508                     cn: [
19509                         {
19510                             tag: 'a',
19511                             href: '#',
19512                             cls: 'btn',
19513                             cn: [
19514                                 {
19515                                     tag: 'span',
19516                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
19517                                 }
19518                             ]
19519                         }
19520                     ]
19521                 },
19522                 {
19523                     tag: 'td',
19524                     cls: 'separator'
19525                 }
19526             ]
19527         });
19528         
19529     },
19530     
19531     update: function()
19532     {
19533         
19534         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19535         
19536         this.fill();
19537     },
19538     
19539     fill: function() 
19540     {
19541         var hours = this.time.getHours();
19542         var minutes = this.time.getMinutes();
19543         var period = 'AM';
19544         
19545         if(hours > 11){
19546             period = 'PM';
19547         }
19548         
19549         if(hours == 0){
19550             hours = 12;
19551         }
19552         
19553         
19554         if(hours > 12){
19555             hours = hours - 12;
19556         }
19557         
19558         if(hours < 10){
19559             hours = '0' + hours;
19560         }
19561         
19562         if(minutes < 10){
19563             minutes = '0' + minutes;
19564         }
19565         
19566         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19567         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19568         this.pop.select('button', true).first().dom.innerHTML = period;
19569         
19570     },
19571     
19572     place: function()
19573     {   
19574         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19575         
19576         var cls = ['bottom'];
19577         
19578         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19579             cls.pop();
19580             cls.push('top');
19581         }
19582         
19583         cls.push('right');
19584         
19585         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19586             cls.pop();
19587             cls.push('left');
19588         }
19589         
19590         this.picker().addClass(cls.join('-'));
19591         
19592         var _this = this;
19593         
19594         Roo.each(cls, function(c){
19595             if(c == 'bottom'){
19596                 _this.picker().setTop(_this.inputEl().getHeight());
19597                 return;
19598             }
19599             if(c == 'top'){
19600                 _this.picker().setTop(0 - _this.picker().getHeight());
19601                 return;
19602             }
19603             
19604             if(c == 'left'){
19605                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19606                 return;
19607             }
19608             if(c == 'right'){
19609                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19610                 return;
19611             }
19612         });
19613         
19614     },
19615   
19616     onFocus : function()
19617     {
19618         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19619         this.show();
19620     },
19621     
19622     onBlur : function()
19623     {
19624         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19625         this.hide();
19626     },
19627     
19628     show : function()
19629     {
19630         this.picker().show();
19631         this.pop.show();
19632         this.update();
19633         this.place();
19634         
19635         this.fireEvent('show', this, this.date);
19636     },
19637     
19638     hide : function()
19639     {
19640         this.picker().hide();
19641         this.pop.hide();
19642         
19643         this.fireEvent('hide', this, this.date);
19644     },
19645     
19646     setTime : function()
19647     {
19648         this.hide();
19649         this.setValue(this.time.format(this.format));
19650         
19651         this.fireEvent('select', this, this.date);
19652         
19653         
19654     },
19655     
19656     onMousedown: function(e){
19657         e.stopPropagation();
19658         e.preventDefault();
19659     },
19660     
19661     onIncrementHours: function()
19662     {
19663         Roo.log('onIncrementHours');
19664         this.time = this.time.add(Date.HOUR, 1);
19665         this.update();
19666         
19667     },
19668     
19669     onDecrementHours: function()
19670     {
19671         Roo.log('onDecrementHours');
19672         this.time = this.time.add(Date.HOUR, -1);
19673         this.update();
19674     },
19675     
19676     onIncrementMinutes: function()
19677     {
19678         Roo.log('onIncrementMinutes');
19679         this.time = this.time.add(Date.MINUTE, 1);
19680         this.update();
19681     },
19682     
19683     onDecrementMinutes: function()
19684     {
19685         Roo.log('onDecrementMinutes');
19686         this.time = this.time.add(Date.MINUTE, -1);
19687         this.update();
19688     },
19689     
19690     onTogglePeriod: function()
19691     {
19692         Roo.log('onTogglePeriod');
19693         this.time = this.time.add(Date.HOUR, 12);
19694         this.update();
19695     }
19696     
19697    
19698 });
19699
19700 Roo.apply(Roo.bootstrap.TimeField,  {
19701     
19702     content : {
19703         tag: 'tbody',
19704         cn: [
19705             {
19706                 tag: 'tr',
19707                 cn: [
19708                 {
19709                     tag: 'td',
19710                     colspan: '7'
19711                 }
19712                 ]
19713             }
19714         ]
19715     },
19716     
19717     footer : {
19718         tag: 'tfoot',
19719         cn: [
19720             {
19721                 tag: 'tr',
19722                 cn: [
19723                 {
19724                     tag: 'th',
19725                     colspan: '7',
19726                     cls: '',
19727                     cn: [
19728                         {
19729                             tag: 'button',
19730                             cls: 'btn btn-info ok',
19731                             html: 'OK'
19732                         }
19733                     ]
19734                 }
19735
19736                 ]
19737             }
19738         ]
19739     }
19740 });
19741
19742 Roo.apply(Roo.bootstrap.TimeField,  {
19743   
19744     template : {
19745         tag: 'div',
19746         cls: 'datepicker dropdown-menu',
19747         cn: [
19748             {
19749                 tag: 'div',
19750                 cls: 'datepicker-time',
19751                 cn: [
19752                 {
19753                     tag: 'table',
19754                     cls: 'table-condensed',
19755                     cn:[
19756                     Roo.bootstrap.TimeField.content,
19757                     Roo.bootstrap.TimeField.footer
19758                     ]
19759                 }
19760                 ]
19761             }
19762         ]
19763     }
19764 });
19765
19766  
19767
19768  /*
19769  * - LGPL
19770  *
19771  * MonthField
19772  * 
19773  */
19774
19775 /**
19776  * @class Roo.bootstrap.MonthField
19777  * @extends Roo.bootstrap.Input
19778  * Bootstrap MonthField class
19779  * 
19780  * @cfg {String} language default en
19781  * 
19782  * @constructor
19783  * Create a new MonthField
19784  * @param {Object} config The config object
19785  */
19786
19787 Roo.bootstrap.MonthField = function(config){
19788     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19789     
19790     this.addEvents({
19791         /**
19792          * @event show
19793          * Fires when this field show.
19794          * @param {Roo.bootstrap.MonthField} this
19795          * @param {Mixed} date The date value
19796          */
19797         show : true,
19798         /**
19799          * @event show
19800          * Fires when this field hide.
19801          * @param {Roo.bootstrap.MonthField} this
19802          * @param {Mixed} date The date value
19803          */
19804         hide : true,
19805         /**
19806          * @event select
19807          * Fires when select a date.
19808          * @param {Roo.bootstrap.MonthField} this
19809          * @param {String} oldvalue The old value
19810          * @param {String} newvalue The new value
19811          */
19812         select : true
19813     });
19814 };
19815
19816 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
19817     
19818     onRender: function(ct, position)
19819     {
19820         
19821         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19822         
19823         this.language = this.language || 'en';
19824         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19825         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19826         
19827         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19828         this.isInline = false;
19829         this.isInput = true;
19830         this.component = this.el.select('.add-on', true).first() || false;
19831         this.component = (this.component && this.component.length === 0) ? false : this.component;
19832         this.hasInput = this.component && this.inputEL().length;
19833         
19834         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19835         
19836         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19837         
19838         this.picker().on('mousedown', this.onMousedown, this);
19839         this.picker().on('click', this.onClick, this);
19840         
19841         this.picker().addClass('datepicker-dropdown');
19842         
19843         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19844             v.setStyle('width', '189px');
19845         });
19846         
19847         this.fillMonths();
19848         
19849         this.update();
19850         
19851         if(this.isInline) {
19852             this.show();
19853         }
19854         
19855     },
19856     
19857     setValue: function(v, suppressEvent)
19858     {   
19859         var o = this.getValue();
19860         
19861         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19862         
19863         this.update();
19864
19865         if(suppressEvent !== true){
19866             this.fireEvent('select', this, o, v);
19867         }
19868         
19869     },
19870     
19871     getValue: function()
19872     {
19873         return this.value;
19874     },
19875     
19876     onClick: function(e) 
19877     {
19878         e.stopPropagation();
19879         e.preventDefault();
19880         
19881         var target = e.getTarget();
19882         
19883         if(target.nodeName.toLowerCase() === 'i'){
19884             target = Roo.get(target).dom.parentNode;
19885         }
19886         
19887         var nodeName = target.nodeName;
19888         var className = target.className;
19889         var html = target.innerHTML;
19890         
19891         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19892             return;
19893         }
19894         
19895         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19896         
19897         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19898         
19899         this.hide();
19900                         
19901     },
19902     
19903     picker : function()
19904     {
19905         return this.pickerEl;
19906     },
19907     
19908     fillMonths: function()
19909     {    
19910         var i = 0;
19911         var months = this.picker().select('>.datepicker-months td', true).first();
19912         
19913         months.dom.innerHTML = '';
19914         
19915         while (i < 12) {
19916             var month = {
19917                 tag: 'span',
19918                 cls: 'month',
19919                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19920             };
19921             
19922             months.createChild(month);
19923         }
19924         
19925     },
19926     
19927     update: function()
19928     {
19929         var _this = this;
19930         
19931         if(typeof(this.vIndex) == 'undefined' && this.value.length){
19932             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19933         }
19934         
19935         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19936             e.removeClass('active');
19937             
19938             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19939                 e.addClass('active');
19940             }
19941         })
19942     },
19943     
19944     place: function()
19945     {
19946         if(this.isInline) {
19947             return;
19948         }
19949         
19950         this.picker().removeClass(['bottom', 'top']);
19951         
19952         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19953             /*
19954              * place to the top of element!
19955              *
19956              */
19957             
19958             this.picker().addClass('top');
19959             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19960             
19961             return;
19962         }
19963         
19964         this.picker().addClass('bottom');
19965         
19966         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19967     },
19968     
19969     onFocus : function()
19970     {
19971         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19972         this.show();
19973     },
19974     
19975     onBlur : function()
19976     {
19977         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19978         
19979         var d = this.inputEl().getValue();
19980         
19981         this.setValue(d);
19982                 
19983         this.hide();
19984     },
19985     
19986     show : function()
19987     {
19988         this.picker().show();
19989         this.picker().select('>.datepicker-months', true).first().show();
19990         this.update();
19991         this.place();
19992         
19993         this.fireEvent('show', this, this.date);
19994     },
19995     
19996     hide : function()
19997     {
19998         if(this.isInline) {
19999             return;
20000         }
20001         this.picker().hide();
20002         this.fireEvent('hide', this, this.date);
20003         
20004     },
20005     
20006     onMousedown: function(e)
20007     {
20008         e.stopPropagation();
20009         e.preventDefault();
20010     },
20011     
20012     keyup: function(e)
20013     {
20014         Roo.bootstrap.MonthField.superclass.keyup.call(this);
20015         this.update();
20016     },
20017
20018     fireKey: function(e)
20019     {
20020         if (!this.picker().isVisible()){
20021             if (e.keyCode == 27)   {// allow escape to hide and re-show picker
20022                 this.show();
20023             }
20024             return;
20025         }
20026         
20027         var dir;
20028         
20029         switch(e.keyCode){
20030             case 27: // escape
20031                 this.hide();
20032                 e.preventDefault();
20033                 break;
20034             case 37: // left
20035             case 39: // right
20036                 dir = e.keyCode == 37 ? -1 : 1;
20037                 
20038                 this.vIndex = this.vIndex + dir;
20039                 
20040                 if(this.vIndex < 0){
20041                     this.vIndex = 0;
20042                 }
20043                 
20044                 if(this.vIndex > 11){
20045                     this.vIndex = 11;
20046                 }
20047                 
20048                 if(isNaN(this.vIndex)){
20049                     this.vIndex = 0;
20050                 }
20051                 
20052                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20053                 
20054                 break;
20055             case 38: // up
20056             case 40: // down
20057                 
20058                 dir = e.keyCode == 38 ? -1 : 1;
20059                 
20060                 this.vIndex = this.vIndex + dir * 4;
20061                 
20062                 if(this.vIndex < 0){
20063                     this.vIndex = 0;
20064                 }
20065                 
20066                 if(this.vIndex > 11){
20067                     this.vIndex = 11;
20068                 }
20069                 
20070                 if(isNaN(this.vIndex)){
20071                     this.vIndex = 0;
20072                 }
20073                 
20074                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20075                 break;
20076                 
20077             case 13: // enter
20078                 
20079                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20080                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20081                 }
20082                 
20083                 this.hide();
20084                 e.preventDefault();
20085                 break;
20086             case 9: // tab
20087                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20088                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20089                 }
20090                 this.hide();
20091                 break;
20092             case 16: // shift
20093             case 17: // ctrl
20094             case 18: // alt
20095                 break;
20096             default :
20097                 this.hide();
20098                 
20099         }
20100     },
20101     
20102     remove: function() 
20103     {
20104         this.picker().remove();
20105     }
20106    
20107 });
20108
20109 Roo.apply(Roo.bootstrap.MonthField,  {
20110     
20111     content : {
20112         tag: 'tbody',
20113         cn: [
20114         {
20115             tag: 'tr',
20116             cn: [
20117             {
20118                 tag: 'td',
20119                 colspan: '7'
20120             }
20121             ]
20122         }
20123         ]
20124     },
20125     
20126     dates:{
20127         en: {
20128             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20129             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20130         }
20131     }
20132 });
20133
20134 Roo.apply(Roo.bootstrap.MonthField,  {
20135   
20136     template : {
20137         tag: 'div',
20138         cls: 'datepicker dropdown-menu roo-dynamic',
20139         cn: [
20140             {
20141                 tag: 'div',
20142                 cls: 'datepicker-months',
20143                 cn: [
20144                 {
20145                     tag: 'table',
20146                     cls: 'table-condensed',
20147                     cn:[
20148                         Roo.bootstrap.DateField.content
20149                     ]
20150                 }
20151                 ]
20152             }
20153         ]
20154     }
20155 });
20156
20157  
20158
20159  
20160  /*
20161  * - LGPL
20162  *
20163  * CheckBox
20164  * 
20165  */
20166
20167 /**
20168  * @class Roo.bootstrap.CheckBox
20169  * @extends Roo.bootstrap.Input
20170  * Bootstrap CheckBox class
20171  * 
20172  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20173  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20174  * @cfg {String} boxLabel The text that appears beside the checkbox
20175  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20176  * @cfg {Boolean} checked initnal the element
20177  * @cfg {Boolean} inline inline the element (default false)
20178  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20179  * @cfg {String} tooltip label tooltip
20180  * 
20181  * @constructor
20182  * Create a new CheckBox
20183  * @param {Object} config The config object
20184  */
20185
20186 Roo.bootstrap.CheckBox = function(config){
20187     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20188    
20189     this.addEvents({
20190         /**
20191         * @event check
20192         * Fires when the element is checked or unchecked.
20193         * @param {Roo.bootstrap.CheckBox} this This input
20194         * @param {Boolean} checked The new checked value
20195         */
20196        check : true,
20197        /**
20198         * @event click
20199         * Fires when the element is click.
20200         * @param {Roo.bootstrap.CheckBox} this This input
20201         */
20202        click : true
20203     });
20204     
20205 };
20206
20207 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
20208   
20209     inputType: 'checkbox',
20210     inputValue: 1,
20211     valueOff: 0,
20212     boxLabel: false,
20213     checked: false,
20214     weight : false,
20215     inline: false,
20216     tooltip : '',
20217     
20218     getAutoCreate : function()
20219     {
20220         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20221         
20222         var id = Roo.id();
20223         
20224         var cfg = {};
20225         
20226         cfg.cls = 'form-group ' + this.inputType; //input-group
20227         
20228         if(this.inline){
20229             cfg.cls += ' ' + this.inputType + '-inline';
20230         }
20231         
20232         var input =  {
20233             tag: 'input',
20234             id : id,
20235             type : this.inputType,
20236             value : this.inputValue,
20237             cls : 'roo-' + this.inputType, //'form-box',
20238             placeholder : this.placeholder || ''
20239             
20240         };
20241         
20242         if(this.inputType != 'radio'){
20243             var hidden =  {
20244                 tag: 'input',
20245                 type : 'hidden',
20246                 cls : 'roo-hidden-value',
20247                 value : this.checked ? this.inputValue : this.valueOff
20248             };
20249         }
20250         
20251             
20252         if (this.weight) { // Validity check?
20253             cfg.cls += " " + this.inputType + "-" + this.weight;
20254         }
20255         
20256         if (this.disabled) {
20257             input.disabled=true;
20258         }
20259         
20260         if(this.checked){
20261             input.checked = this.checked;
20262         }
20263         
20264         if (this.name) {
20265             
20266             input.name = this.name;
20267             
20268             if(this.inputType != 'radio'){
20269                 hidden.name = this.name;
20270                 input.name = '_hidden_' + this.name;
20271             }
20272         }
20273         
20274         if (this.size) {
20275             input.cls += ' input-' + this.size;
20276         }
20277         
20278         var settings=this;
20279         
20280         ['xs','sm','md','lg'].map(function(size){
20281             if (settings[size]) {
20282                 cfg.cls += ' col-' + size + '-' + settings[size];
20283             }
20284         });
20285         
20286         var inputblock = input;
20287          
20288         if (this.before || this.after) {
20289             
20290             inputblock = {
20291                 cls : 'input-group',
20292                 cn :  [] 
20293             };
20294             
20295             if (this.before) {
20296                 inputblock.cn.push({
20297                     tag :'span',
20298                     cls : 'input-group-addon',
20299                     html : this.before
20300                 });
20301             }
20302             
20303             inputblock.cn.push(input);
20304             
20305             if(this.inputType != 'radio'){
20306                 inputblock.cn.push(hidden);
20307             }
20308             
20309             if (this.after) {
20310                 inputblock.cn.push({
20311                     tag :'span',
20312                     cls : 'input-group-addon',
20313                     html : this.after
20314                 });
20315             }
20316             
20317         }
20318         
20319         if (align ==='left' && this.fieldLabel.length) {
20320 //                Roo.log("left and has label");
20321             cfg.cn = [
20322                 {
20323                     tag: 'label',
20324                     'for' :  id,
20325                     cls : 'control-label',
20326                     html : this.fieldLabel
20327                 },
20328                 {
20329                     cls : "", 
20330                     cn: [
20331                         inputblock
20332                     ]
20333                 }
20334             ];
20335             
20336             if(this.labelWidth > 12){
20337                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20338             }
20339             
20340             if(this.labelWidth < 13 && this.labelmd == 0){
20341                 this.labelmd = this.labelWidth;
20342             }
20343             
20344             if(this.labellg > 0){
20345                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20346                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20347             }
20348             
20349             if(this.labelmd > 0){
20350                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20351                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20352             }
20353             
20354             if(this.labelsm > 0){
20355                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20356                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20357             }
20358             
20359             if(this.labelxs > 0){
20360                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20361                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20362             }
20363             
20364         } else if ( this.fieldLabel.length) {
20365 //                Roo.log(" label");
20366                 cfg.cn = [
20367                    
20368                     {
20369                         tag: this.boxLabel ? 'span' : 'label',
20370                         'for': id,
20371                         cls: 'control-label box-input-label',
20372                         //cls : 'input-group-addon',
20373                         html : this.fieldLabel
20374                     },
20375                     
20376                     inputblock
20377                     
20378                 ];
20379
20380         } else {
20381             
20382 //                Roo.log(" no label && no align");
20383                 cfg.cn = [  inputblock ] ;
20384                 
20385                 
20386         }
20387         
20388         if(this.boxLabel){
20389              var boxLabelCfg = {
20390                 tag: 'label',
20391                 //'for': id, // box label is handled by onclick - so no for...
20392                 cls: 'box-label',
20393                 html: this.boxLabel
20394             };
20395             
20396             if(this.tooltip){
20397                 boxLabelCfg.tooltip = this.tooltip;
20398             }
20399              
20400             cfg.cn.push(boxLabelCfg);
20401         }
20402         
20403         if(this.inputType != 'radio'){
20404             cfg.cn.push(hidden);
20405         }
20406         
20407         return cfg;
20408         
20409     },
20410     
20411     /**
20412      * return the real input element.
20413      */
20414     inputEl: function ()
20415     {
20416         return this.el.select('input.roo-' + this.inputType,true).first();
20417     },
20418     hiddenEl: function ()
20419     {
20420         return this.el.select('input.roo-hidden-value',true).first();
20421     },
20422     
20423     labelEl: function()
20424     {
20425         return this.el.select('label.control-label',true).first();
20426     },
20427     /* depricated... */
20428     
20429     label: function()
20430     {
20431         return this.labelEl();
20432     },
20433     
20434     boxLabelEl: function()
20435     {
20436         return this.el.select('label.box-label',true).first();
20437     },
20438     
20439     initEvents : function()
20440     {
20441 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20442         
20443         this.inputEl().on('click', this.onClick,  this);
20444         
20445         if (this.boxLabel) { 
20446             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
20447         }
20448         
20449         this.startValue = this.getValue();
20450         
20451         if(this.groupId){
20452             Roo.bootstrap.CheckBox.register(this);
20453         }
20454     },
20455     
20456     onClick : function(e)
20457     {   
20458         if(this.fireEvent('click', this, e) !== false){
20459             this.setChecked(!this.checked);
20460         }
20461         
20462     },
20463     
20464     setChecked : function(state,suppressEvent)
20465     {
20466         this.startValue = this.getValue();
20467
20468         if(this.inputType == 'radio'){
20469             
20470             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20471                 e.dom.checked = false;
20472             });
20473             
20474             this.inputEl().dom.checked = true;
20475             
20476             this.inputEl().dom.value = this.inputValue;
20477             
20478             if(suppressEvent !== true){
20479                 this.fireEvent('check', this, true);
20480             }
20481             
20482             this.validate();
20483             
20484             return;
20485         }
20486         
20487         this.checked = state;
20488         
20489         this.inputEl().dom.checked = state;
20490         
20491         
20492         this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20493         
20494         if(suppressEvent !== true){
20495             this.fireEvent('check', this, state);
20496         }
20497         
20498         this.validate();
20499     },
20500     
20501     getValue : function()
20502     {
20503         if(this.inputType == 'radio'){
20504             return this.getGroupValue();
20505         }
20506         
20507         return this.hiddenEl().dom.value;
20508         
20509     },
20510     
20511     getGroupValue : function()
20512     {
20513         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20514             return '';
20515         }
20516         
20517         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20518     },
20519     
20520     setValue : function(v,suppressEvent)
20521     {
20522         if(this.inputType == 'radio'){
20523             this.setGroupValue(v, suppressEvent);
20524             return;
20525         }
20526         
20527         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20528         
20529         this.validate();
20530     },
20531     
20532     setGroupValue : function(v, suppressEvent)
20533     {
20534         this.startValue = this.getValue();
20535         
20536         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20537             e.dom.checked = false;
20538             
20539             if(e.dom.value == v){
20540                 e.dom.checked = true;
20541             }
20542         });
20543         
20544         if(suppressEvent !== true){
20545             this.fireEvent('check', this, true);
20546         }
20547
20548         this.validate();
20549         
20550         return;
20551     },
20552     
20553     validate : function()
20554     {
20555         if(
20556                 this.disabled || 
20557                 (this.inputType == 'radio' && this.validateRadio()) ||
20558                 (this.inputType == 'checkbox' && this.validateCheckbox())
20559         ){
20560             this.markValid();
20561             return true;
20562         }
20563         
20564         this.markInvalid();
20565         return false;
20566     },
20567     
20568     validateRadio : function()
20569     {
20570         if(this.allowBlank){
20571             return true;
20572         }
20573         
20574         var valid = false;
20575         
20576         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20577             if(!e.dom.checked){
20578                 return;
20579             }
20580             
20581             valid = true;
20582             
20583             return false;
20584         });
20585         
20586         return valid;
20587     },
20588     
20589     validateCheckbox : function()
20590     {
20591         if(!this.groupId){
20592             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20593             //return (this.getValue() == this.inputValue) ? true : false;
20594         }
20595         
20596         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20597         
20598         if(!group){
20599             return false;
20600         }
20601         
20602         var r = false;
20603         
20604         for(var i in group){
20605             if(group[i].el.isVisible(true)){
20606                 r = false;
20607                 break;
20608             }
20609             
20610             r = true;
20611         }
20612         
20613         for(var i in group){
20614             if(r){
20615                 break;
20616             }
20617             
20618             r = (group[i].getValue() == group[i].inputValue) ? true : false;
20619         }
20620         
20621         return r;
20622     },
20623     
20624     /**
20625      * Mark this field as valid
20626      */
20627     markValid : function()
20628     {
20629         var _this = this;
20630         
20631         this.fireEvent('valid', this);
20632         
20633         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20634         
20635         if(this.groupId){
20636             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20637         }
20638         
20639         if(label){
20640             label.markValid();
20641         }
20642
20643         if(this.inputType == 'radio'){
20644             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20645                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20646                 e.findParent('.form-group', false, true).addClass(_this.validClass);
20647             });
20648             
20649             return;
20650         }
20651
20652         if(!this.groupId){
20653             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20654             this.el.findParent('.form-group', false, true).addClass(this.validClass);
20655             return;
20656         }
20657         
20658         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20659         
20660         if(!group){
20661             return;
20662         }
20663         
20664         for(var i in group){
20665             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20666             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20667         }
20668     },
20669     
20670      /**
20671      * Mark this field as invalid
20672      * @param {String} msg The validation message
20673      */
20674     markInvalid : function(msg)
20675     {
20676         if(this.allowBlank){
20677             return;
20678         }
20679         
20680         var _this = this;
20681         
20682         this.fireEvent('invalid', this, msg);
20683         
20684         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20685         
20686         if(this.groupId){
20687             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20688         }
20689         
20690         if(label){
20691             label.markInvalid();
20692         }
20693             
20694         if(this.inputType == 'radio'){
20695             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20696                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20697                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20698             });
20699             
20700             return;
20701         }
20702         
20703         if(!this.groupId){
20704             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20705             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20706             return;
20707         }
20708         
20709         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20710         
20711         if(!group){
20712             return;
20713         }
20714         
20715         for(var i in group){
20716             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20717             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20718         }
20719         
20720     },
20721     
20722     clearInvalid : function()
20723     {
20724         Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20725         
20726         // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20727         
20728         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20729         
20730         if (label && label.iconEl) {
20731             label.iconEl.removeClass(label.validClass);
20732             label.iconEl.removeClass(label.invalidClass);
20733         }
20734     },
20735     
20736     disable : function()
20737     {
20738         if(this.inputType != 'radio'){
20739             Roo.bootstrap.CheckBox.superclass.disable.call(this);
20740             return;
20741         }
20742         
20743         var _this = this;
20744         
20745         if(this.rendered){
20746             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20747                 _this.getActionEl().addClass(this.disabledClass);
20748                 e.dom.disabled = true;
20749             });
20750         }
20751         
20752         this.disabled = true;
20753         this.fireEvent("disable", this);
20754         return this;
20755     },
20756
20757     enable : function()
20758     {
20759         if(this.inputType != 'radio'){
20760             Roo.bootstrap.CheckBox.superclass.enable.call(this);
20761             return;
20762         }
20763         
20764         var _this = this;
20765         
20766         if(this.rendered){
20767             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20768                 _this.getActionEl().removeClass(this.disabledClass);
20769                 e.dom.disabled = false;
20770             });
20771         }
20772         
20773         this.disabled = false;
20774         this.fireEvent("enable", this);
20775         return this;
20776     },
20777     
20778     setBoxLabel : function(v)
20779     {
20780         this.boxLabel = v;
20781         
20782         if(this.rendered){
20783             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20784         }
20785     }
20786
20787 });
20788
20789 Roo.apply(Roo.bootstrap.CheckBox, {
20790     
20791     groups: {},
20792     
20793      /**
20794     * register a CheckBox Group
20795     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20796     */
20797     register : function(checkbox)
20798     {
20799         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20800             this.groups[checkbox.groupId] = {};
20801         }
20802         
20803         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20804             return;
20805         }
20806         
20807         this.groups[checkbox.groupId][checkbox.name] = checkbox;
20808         
20809     },
20810     /**
20811     * fetch a CheckBox Group based on the group ID
20812     * @param {string} the group ID
20813     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20814     */
20815     get: function(groupId) {
20816         if (typeof(this.groups[groupId]) == 'undefined') {
20817             return false;
20818         }
20819         
20820         return this.groups[groupId] ;
20821     }
20822     
20823     
20824 });
20825 /*
20826  * - LGPL
20827  *
20828  * RadioItem
20829  * 
20830  */
20831
20832 /**
20833  * @class Roo.bootstrap.Radio
20834  * @extends Roo.bootstrap.Component
20835  * Bootstrap Radio class
20836  * @cfg {String} boxLabel - the label associated
20837  * @cfg {String} value - the value of radio
20838  * 
20839  * @constructor
20840  * Create a new Radio
20841  * @param {Object} config The config object
20842  */
20843 Roo.bootstrap.Radio = function(config){
20844     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20845     
20846 };
20847
20848 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20849     
20850     boxLabel : '',
20851     
20852     value : '',
20853     
20854     getAutoCreate : function()
20855     {
20856         var cfg = {
20857             tag : 'div',
20858             cls : 'form-group radio',
20859             cn : [
20860                 {
20861                     tag : 'label',
20862                     cls : 'box-label',
20863                     html : this.boxLabel
20864                 }
20865             ]
20866         };
20867         
20868         return cfg;
20869     },
20870     
20871     initEvents : function() 
20872     {
20873         this.parent().register(this);
20874         
20875         this.el.on('click', this.onClick, this);
20876         
20877     },
20878     
20879     onClick : function()
20880     {
20881         this.setChecked(true);
20882     },
20883     
20884     setChecked : function(state, suppressEvent)
20885     {
20886         this.parent().setValue(this.value, suppressEvent);
20887         
20888     },
20889     
20890     setBoxLabel : function(v)
20891     {
20892         this.boxLabel = v;
20893         
20894         if(this.rendered){
20895             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20896         }
20897     }
20898     
20899 });
20900  
20901
20902  /*
20903  * - LGPL
20904  *
20905  * Input
20906  * 
20907  */
20908
20909 /**
20910  * @class Roo.bootstrap.SecurePass
20911  * @extends Roo.bootstrap.Input
20912  * Bootstrap SecurePass class
20913  *
20914  * 
20915  * @constructor
20916  * Create a new SecurePass
20917  * @param {Object} config The config object
20918  */
20919  
20920 Roo.bootstrap.SecurePass = function (config) {
20921     // these go here, so the translation tool can replace them..
20922     this.errors = {
20923         PwdEmpty: "Please type a password, and then retype it to confirm.",
20924         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20925         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20926         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20927         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20928         FNInPwd: "Your password can't contain your first name. Please type a different password.",
20929         LNInPwd: "Your password can't contain your last name. Please type a different password.",
20930         TooWeak: "Your password is Too Weak."
20931     },
20932     this.meterLabel = "Password strength:";
20933     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20934     this.meterClass = [
20935         "roo-password-meter-tooweak", 
20936         "roo-password-meter-weak", 
20937         "roo-password-meter-medium", 
20938         "roo-password-meter-strong", 
20939         "roo-password-meter-grey"
20940     ];
20941     
20942     this.errors = {};
20943     
20944     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20945 }
20946
20947 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20948     /**
20949      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20950      * {
20951      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
20952      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20953      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20954      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20955      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20956      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
20957      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
20958      * })
20959      */
20960     // private
20961     
20962     meterWidth: 300,
20963     errorMsg :'',    
20964     errors: false,
20965     imageRoot: '/',
20966     /**
20967      * @cfg {String/Object} Label for the strength meter (defaults to
20968      * 'Password strength:')
20969      */
20970     // private
20971     meterLabel: '',
20972     /**
20973      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20974      * ['Weak', 'Medium', 'Strong'])
20975      */
20976     // private    
20977     pwdStrengths: false,    
20978     // private
20979     strength: 0,
20980     // private
20981     _lastPwd: null,
20982     // private
20983     kCapitalLetter: 0,
20984     kSmallLetter: 1,
20985     kDigit: 2,
20986     kPunctuation: 3,
20987     
20988     insecure: false,
20989     // private
20990     initEvents: function ()
20991     {
20992         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20993
20994         if (this.el.is('input[type=password]') && Roo.isSafari) {
20995             this.el.on('keydown', this.SafariOnKeyDown, this);
20996         }
20997
20998         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20999     },
21000     // private
21001     onRender: function (ct, position)
21002     {
21003         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21004         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21005         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21006
21007         this.trigger.createChild({
21008                    cn: [
21009                     {
21010                     //id: 'PwdMeter',
21011                     tag: 'div',
21012                     cls: 'roo-password-meter-grey col-xs-12',
21013                     style: {
21014                         //width: 0,
21015                         //width: this.meterWidth + 'px'                                                
21016                         }
21017                     },
21018                     {                            
21019                          cls: 'roo-password-meter-text'                          
21020                     }
21021                 ]            
21022         });
21023
21024          
21025         if (this.hideTrigger) {
21026             this.trigger.setDisplayed(false);
21027         }
21028         this.setSize(this.width || '', this.height || '');
21029     },
21030     // private
21031     onDestroy: function ()
21032     {
21033         if (this.trigger) {
21034             this.trigger.removeAllListeners();
21035             this.trigger.remove();
21036         }
21037         if (this.wrap) {
21038             this.wrap.remove();
21039         }
21040         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21041     },
21042     // private
21043     checkStrength: function ()
21044     {
21045         var pwd = this.inputEl().getValue();
21046         if (pwd == this._lastPwd) {
21047             return;
21048         }
21049
21050         var strength;
21051         if (this.ClientSideStrongPassword(pwd)) {
21052             strength = 3;
21053         } else if (this.ClientSideMediumPassword(pwd)) {
21054             strength = 2;
21055         } else if (this.ClientSideWeakPassword(pwd)) {
21056             strength = 1;
21057         } else {
21058             strength = 0;
21059         }
21060         
21061         Roo.log('strength1: ' + strength);
21062         
21063         //var pm = this.trigger.child('div/div/div').dom;
21064         var pm = this.trigger.child('div/div');
21065         pm.removeClass(this.meterClass);
21066         pm.addClass(this.meterClass[strength]);
21067                 
21068         
21069         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21070                 
21071         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21072         
21073         this._lastPwd = pwd;
21074     },
21075     reset: function ()
21076     {
21077         Roo.bootstrap.SecurePass.superclass.reset.call(this);
21078         
21079         this._lastPwd = '';
21080         
21081         var pm = this.trigger.child('div/div');
21082         pm.removeClass(this.meterClass);
21083         pm.addClass('roo-password-meter-grey');        
21084         
21085         
21086         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21087         
21088         pt.innerHTML = '';
21089         this.inputEl().dom.type='password';
21090     },
21091     // private
21092     validateValue: function (value)
21093     {
21094         
21095         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21096             return false;
21097         }
21098         if (value.length == 0) {
21099             if (this.allowBlank) {
21100                 this.clearInvalid();
21101                 return true;
21102             }
21103
21104             this.markInvalid(this.errors.PwdEmpty);
21105             this.errorMsg = this.errors.PwdEmpty;
21106             return false;
21107         }
21108         
21109         if(this.insecure){
21110             return true;
21111         }
21112         
21113         if ('[\x21-\x7e]*'.match(value)) {
21114             this.markInvalid(this.errors.PwdBadChar);
21115             this.errorMsg = this.errors.PwdBadChar;
21116             return false;
21117         }
21118         if (value.length < 6) {
21119             this.markInvalid(this.errors.PwdShort);
21120             this.errorMsg = this.errors.PwdShort;
21121             return false;
21122         }
21123         if (value.length > 16) {
21124             this.markInvalid(this.errors.PwdLong);
21125             this.errorMsg = this.errors.PwdLong;
21126             return false;
21127         }
21128         var strength;
21129         if (this.ClientSideStrongPassword(value)) {
21130             strength = 3;
21131         } else if (this.ClientSideMediumPassword(value)) {
21132             strength = 2;
21133         } else if (this.ClientSideWeakPassword(value)) {
21134             strength = 1;
21135         } else {
21136             strength = 0;
21137         }
21138
21139         
21140         if (strength < 2) {
21141             //this.markInvalid(this.errors.TooWeak);
21142             this.errorMsg = this.errors.TooWeak;
21143             //return false;
21144         }
21145         
21146         
21147         console.log('strength2: ' + strength);
21148         
21149         //var pm = this.trigger.child('div/div/div').dom;
21150         
21151         var pm = this.trigger.child('div/div');
21152         pm.removeClass(this.meterClass);
21153         pm.addClass(this.meterClass[strength]);
21154                 
21155         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21156                 
21157         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21158         
21159         this.errorMsg = ''; 
21160         return true;
21161     },
21162     // private
21163     CharacterSetChecks: function (type)
21164     {
21165         this.type = type;
21166         this.fResult = false;
21167     },
21168     // private
21169     isctype: function (character, type)
21170     {
21171         switch (type) {  
21172             case this.kCapitalLetter:
21173                 if (character >= 'A' && character <= 'Z') {
21174                     return true;
21175                 }
21176                 break;
21177             
21178             case this.kSmallLetter:
21179                 if (character >= 'a' && character <= 'z') {
21180                     return true;
21181                 }
21182                 break;
21183             
21184             case this.kDigit:
21185                 if (character >= '0' && character <= '9') {
21186                     return true;
21187                 }
21188                 break;
21189             
21190             case this.kPunctuation:
21191                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21192                     return true;
21193                 }
21194                 break;
21195             
21196             default:
21197                 return false;
21198         }
21199
21200     },
21201     // private
21202     IsLongEnough: function (pwd, size)
21203     {
21204         return !(pwd == null || isNaN(size) || pwd.length < size);
21205     },
21206     // private
21207     SpansEnoughCharacterSets: function (word, nb)
21208     {
21209         if (!this.IsLongEnough(word, nb))
21210         {
21211             return false;
21212         }
21213
21214         var characterSetChecks = new Array(
21215             new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21216             new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21217         );
21218         
21219         for (var index = 0; index < word.length; ++index) {
21220             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21221                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21222                     characterSetChecks[nCharSet].fResult = true;
21223                     break;
21224                 }
21225             }
21226         }
21227
21228         var nCharSets = 0;
21229         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21230             if (characterSetChecks[nCharSet].fResult) {
21231                 ++nCharSets;
21232             }
21233         }
21234
21235         if (nCharSets < nb) {
21236             return false;
21237         }
21238         return true;
21239     },
21240     // private
21241     ClientSideStrongPassword: function (pwd)
21242     {
21243         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21244     },
21245     // private
21246     ClientSideMediumPassword: function (pwd)
21247     {
21248         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21249     },
21250     // private
21251     ClientSideWeakPassword: function (pwd)
21252     {
21253         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21254     }
21255           
21256 })//<script type="text/javascript">
21257
21258 /*
21259  * Based  Ext JS Library 1.1.1
21260  * Copyright(c) 2006-2007, Ext JS, LLC.
21261  * LGPL
21262  *
21263  */
21264  
21265 /**
21266  * @class Roo.HtmlEditorCore
21267  * @extends Roo.Component
21268  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21269  *
21270  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21271  */
21272
21273 Roo.HtmlEditorCore = function(config){
21274     
21275     
21276     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21277     
21278     
21279     this.addEvents({
21280         /**
21281          * @event initialize
21282          * Fires when the editor is fully initialized (including the iframe)
21283          * @param {Roo.HtmlEditorCore} this
21284          */
21285         initialize: true,
21286         /**
21287          * @event activate
21288          * Fires when the editor is first receives the focus. Any insertion must wait
21289          * until after this event.
21290          * @param {Roo.HtmlEditorCore} this
21291          */
21292         activate: true,
21293          /**
21294          * @event beforesync
21295          * Fires before the textarea is updated with content from the editor iframe. Return false
21296          * to cancel the sync.
21297          * @param {Roo.HtmlEditorCore} this
21298          * @param {String} html
21299          */
21300         beforesync: true,
21301          /**
21302          * @event beforepush
21303          * Fires before the iframe editor is updated with content from the textarea. Return false
21304          * to cancel the push.
21305          * @param {Roo.HtmlEditorCore} this
21306          * @param {String} html
21307          */
21308         beforepush: true,
21309          /**
21310          * @event sync
21311          * Fires when the textarea is updated with content from the editor iframe.
21312          * @param {Roo.HtmlEditorCore} this
21313          * @param {String} html
21314          */
21315         sync: true,
21316          /**
21317          * @event push
21318          * Fires when the iframe editor is updated with content from the textarea.
21319          * @param {Roo.HtmlEditorCore} this
21320          * @param {String} html
21321          */
21322         push: true,
21323         
21324         /**
21325          * @event editorevent
21326          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21327          * @param {Roo.HtmlEditorCore} this
21328          */
21329         editorevent: true
21330         
21331     });
21332     
21333     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21334     
21335     // defaults : white / black...
21336     this.applyBlacklists();
21337     
21338     
21339     
21340 };
21341
21342
21343 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
21344
21345
21346      /**
21347      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
21348      */
21349     
21350     owner : false,
21351     
21352      /**
21353      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
21354      *                        Roo.resizable.
21355      */
21356     resizable : false,
21357      /**
21358      * @cfg {Number} height (in pixels)
21359      */   
21360     height: 300,
21361    /**
21362      * @cfg {Number} width (in pixels)
21363      */   
21364     width: 500,
21365     
21366     /**
21367      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21368      * 
21369      */
21370     stylesheets: false,
21371     
21372     // id of frame..
21373     frameId: false,
21374     
21375     // private properties
21376     validationEvent : false,
21377     deferHeight: true,
21378     initialized : false,
21379     activated : false,
21380     sourceEditMode : false,
21381     onFocus : Roo.emptyFn,
21382     iframePad:3,
21383     hideMode:'offsets',
21384     
21385     clearUp: true,
21386     
21387     // blacklist + whitelisted elements..
21388     black: false,
21389     white: false,
21390      
21391     bodyCls : '',
21392
21393     /**
21394      * Protected method that will not generally be called directly. It
21395      * is called when the editor initializes the iframe with HTML contents. Override this method if you
21396      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21397      */
21398     getDocMarkup : function(){
21399         // body styles..
21400         var st = '';
21401         
21402         // inherit styels from page...?? 
21403         if (this.stylesheets === false) {
21404             
21405             Roo.get(document.head).select('style').each(function(node) {
21406                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21407             });
21408             
21409             Roo.get(document.head).select('link').each(function(node) { 
21410                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21411             });
21412             
21413         } else if (!this.stylesheets.length) {
21414                 // simple..
21415                 st = '<style type="text/css">' +
21416                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21417                    '</style>';
21418         } else { 
21419             st = '<style type="text/css">' +
21420                     this.stylesheets +
21421                 '</style>';
21422         }
21423         
21424         st +=  '<style type="text/css">' +
21425             'IMG { cursor: pointer } ' +
21426         '</style>';
21427
21428         var cls = 'roo-htmleditor-body';
21429         
21430         if(this.bodyCls.length){
21431             cls += ' ' + this.bodyCls;
21432         }
21433         
21434         return '<html><head>' + st  +
21435             //<style type="text/css">' +
21436             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21437             //'</style>' +
21438             ' </head><body class="' +  cls + '"></body></html>';
21439     },
21440
21441     // private
21442     onRender : function(ct, position)
21443     {
21444         var _t = this;
21445         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21446         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21447         
21448         
21449         this.el.dom.style.border = '0 none';
21450         this.el.dom.setAttribute('tabIndex', -1);
21451         this.el.addClass('x-hidden hide');
21452         
21453         
21454         
21455         if(Roo.isIE){ // fix IE 1px bogus margin
21456             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21457         }
21458        
21459         
21460         this.frameId = Roo.id();
21461         
21462          
21463         
21464         var iframe = this.owner.wrap.createChild({
21465             tag: 'iframe',
21466             cls: 'form-control', // bootstrap..
21467             id: this.frameId,
21468             name: this.frameId,
21469             frameBorder : 'no',
21470             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
21471         }, this.el
21472         );
21473         
21474         
21475         this.iframe = iframe.dom;
21476
21477          this.assignDocWin();
21478         
21479         this.doc.designMode = 'on';
21480        
21481         this.doc.open();
21482         this.doc.write(this.getDocMarkup());
21483         this.doc.close();
21484
21485         
21486         var task = { // must defer to wait for browser to be ready
21487             run : function(){
21488                 //console.log("run task?" + this.doc.readyState);
21489                 this.assignDocWin();
21490                 if(this.doc.body || this.doc.readyState == 'complete'){
21491                     try {
21492                         this.doc.designMode="on";
21493                     } catch (e) {
21494                         return;
21495                     }
21496                     Roo.TaskMgr.stop(task);
21497                     this.initEditor.defer(10, this);
21498                 }
21499             },
21500             interval : 10,
21501             duration: 10000,
21502             scope: this
21503         };
21504         Roo.TaskMgr.start(task);
21505
21506     },
21507
21508     // private
21509     onResize : function(w, h)
21510     {
21511          Roo.log('resize: ' +w + ',' + h );
21512         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21513         if(!this.iframe){
21514             return;
21515         }
21516         if(typeof w == 'number'){
21517             
21518             this.iframe.style.width = w + 'px';
21519         }
21520         if(typeof h == 'number'){
21521             
21522             this.iframe.style.height = h + 'px';
21523             if(this.doc){
21524                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21525             }
21526         }
21527         
21528     },
21529
21530     /**
21531      * Toggles the editor between standard and source edit mode.
21532      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21533      */
21534     toggleSourceEdit : function(sourceEditMode){
21535         
21536         this.sourceEditMode = sourceEditMode === true;
21537         
21538         if(this.sourceEditMode){
21539  
21540             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
21541             
21542         }else{
21543             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21544             //this.iframe.className = '';
21545             this.deferFocus();
21546         }
21547         //this.setSize(this.owner.wrap.getSize());
21548         //this.fireEvent('editmodechange', this, this.sourceEditMode);
21549     },
21550
21551     
21552   
21553
21554     /**
21555      * Protected method that will not generally be called directly. If you need/want
21556      * custom HTML cleanup, this is the method you should override.
21557      * @param {String} html The HTML to be cleaned
21558      * return {String} The cleaned HTML
21559      */
21560     cleanHtml : function(html){
21561         html = String(html);
21562         if(html.length > 5){
21563             if(Roo.isSafari){ // strip safari nonsense
21564                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21565             }
21566         }
21567         if(html == '&nbsp;'){
21568             html = '';
21569         }
21570         return html;
21571     },
21572
21573     /**
21574      * HTML Editor -> Textarea
21575      * Protected method that will not generally be called directly. Syncs the contents
21576      * of the editor iframe with the textarea.
21577      */
21578     syncValue : function(){
21579         if(this.initialized){
21580             var bd = (this.doc.body || this.doc.documentElement);
21581             //this.cleanUpPaste(); -- this is done else where and causes havoc..
21582             var html = bd.innerHTML;
21583             if(Roo.isSafari){
21584                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21585                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21586                 if(m && m[1]){
21587                     html = '<div style="'+m[0]+'">' + html + '</div>';
21588                 }
21589             }
21590             html = this.cleanHtml(html);
21591             // fix up the special chars.. normaly like back quotes in word...
21592             // however we do not want to do this with chinese..
21593             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21594                 var cc = b.charCodeAt();
21595                 if (
21596                     (cc >= 0x4E00 && cc < 0xA000 ) ||
21597                     (cc >= 0x3400 && cc < 0x4E00 ) ||
21598                     (cc >= 0xf900 && cc < 0xfb00 )
21599                 ) {
21600                         return b;
21601                 }
21602                 return "&#"+cc+";" 
21603             });
21604             if(this.owner.fireEvent('beforesync', this, html) !== false){
21605                 this.el.dom.value = html;
21606                 this.owner.fireEvent('sync', this, html);
21607             }
21608         }
21609     },
21610
21611     /**
21612      * Protected method that will not generally be called directly. Pushes the value of the textarea
21613      * into the iframe editor.
21614      */
21615     pushValue : function(){
21616         if(this.initialized){
21617             var v = this.el.dom.value.trim();
21618             
21619 //            if(v.length < 1){
21620 //                v = '&#160;';
21621 //            }
21622             
21623             if(this.owner.fireEvent('beforepush', this, v) !== false){
21624                 var d = (this.doc.body || this.doc.documentElement);
21625                 d.innerHTML = v;
21626                 this.cleanUpPaste();
21627                 this.el.dom.value = d.innerHTML;
21628                 this.owner.fireEvent('push', this, v);
21629             }
21630         }
21631     },
21632
21633     // private
21634     deferFocus : function(){
21635         this.focus.defer(10, this);
21636     },
21637
21638     // doc'ed in Field
21639     focus : function(){
21640         if(this.win && !this.sourceEditMode){
21641             this.win.focus();
21642         }else{
21643             this.el.focus();
21644         }
21645     },
21646     
21647     assignDocWin: function()
21648     {
21649         var iframe = this.iframe;
21650         
21651          if(Roo.isIE){
21652             this.doc = iframe.contentWindow.document;
21653             this.win = iframe.contentWindow;
21654         } else {
21655 //            if (!Roo.get(this.frameId)) {
21656 //                return;
21657 //            }
21658 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21659 //            this.win = Roo.get(this.frameId).dom.contentWindow;
21660             
21661             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21662                 return;
21663             }
21664             
21665             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21666             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21667         }
21668     },
21669     
21670     // private
21671     initEditor : function(){
21672         //console.log("INIT EDITOR");
21673         this.assignDocWin();
21674         
21675         
21676         
21677         this.doc.designMode="on";
21678         this.doc.open();
21679         this.doc.write(this.getDocMarkup());
21680         this.doc.close();
21681         
21682         var dbody = (this.doc.body || this.doc.documentElement);
21683         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21684         // this copies styles from the containing element into thsi one..
21685         // not sure why we need all of this..
21686         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21687         
21688         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21689         //ss['background-attachment'] = 'fixed'; // w3c
21690         dbody.bgProperties = 'fixed'; // ie
21691         //Roo.DomHelper.applyStyles(dbody, ss);
21692         Roo.EventManager.on(this.doc, {
21693             //'mousedown': this.onEditorEvent,
21694             'mouseup': this.onEditorEvent,
21695             'dblclick': this.onEditorEvent,
21696             'click': this.onEditorEvent,
21697             'keyup': this.onEditorEvent,
21698             buffer:100,
21699             scope: this
21700         });
21701         if(Roo.isGecko){
21702             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21703         }
21704         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21705             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21706         }
21707         this.initialized = true;
21708
21709         this.owner.fireEvent('initialize', this);
21710         this.pushValue();
21711     },
21712
21713     // private
21714     onDestroy : function(){
21715         
21716         
21717         
21718         if(this.rendered){
21719             
21720             //for (var i =0; i < this.toolbars.length;i++) {
21721             //    // fixme - ask toolbars for heights?
21722             //    this.toolbars[i].onDestroy();
21723            // }
21724             
21725             //this.wrap.dom.innerHTML = '';
21726             //this.wrap.remove();
21727         }
21728     },
21729
21730     // private
21731     onFirstFocus : function(){
21732         
21733         this.assignDocWin();
21734         
21735         
21736         this.activated = true;
21737          
21738     
21739         if(Roo.isGecko){ // prevent silly gecko errors
21740             this.win.focus();
21741             var s = this.win.getSelection();
21742             if(!s.focusNode || s.focusNode.nodeType != 3){
21743                 var r = s.getRangeAt(0);
21744                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21745                 r.collapse(true);
21746                 this.deferFocus();
21747             }
21748             try{
21749                 this.execCmd('useCSS', true);
21750                 this.execCmd('styleWithCSS', false);
21751             }catch(e){}
21752         }
21753         this.owner.fireEvent('activate', this);
21754     },
21755
21756     // private
21757     adjustFont: function(btn){
21758         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21759         //if(Roo.isSafari){ // safari
21760         //    adjust *= 2;
21761        // }
21762         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21763         if(Roo.isSafari){ // safari
21764             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21765             v =  (v < 10) ? 10 : v;
21766             v =  (v > 48) ? 48 : v;
21767             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21768             
21769         }
21770         
21771         
21772         v = Math.max(1, v+adjust);
21773         
21774         this.execCmd('FontSize', v  );
21775     },
21776
21777     onEditorEvent : function(e)
21778     {
21779         this.owner.fireEvent('editorevent', this, e);
21780       //  this.updateToolbar();
21781         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21782     },
21783
21784     insertTag : function(tg)
21785     {
21786         // could be a bit smarter... -> wrap the current selected tRoo..
21787         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21788             
21789             range = this.createRange(this.getSelection());
21790             var wrappingNode = this.doc.createElement(tg.toLowerCase());
21791             wrappingNode.appendChild(range.extractContents());
21792             range.insertNode(wrappingNode);
21793
21794             return;
21795             
21796             
21797             
21798         }
21799         this.execCmd("formatblock",   tg);
21800         
21801     },
21802     
21803     insertText : function(txt)
21804     {
21805         
21806         
21807         var range = this.createRange();
21808         range.deleteContents();
21809                //alert(Sender.getAttribute('label'));
21810                
21811         range.insertNode(this.doc.createTextNode(txt));
21812     } ,
21813     
21814      
21815
21816     /**
21817      * Executes a Midas editor command on the editor document and performs necessary focus and
21818      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21819      * @param {String} cmd The Midas command
21820      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21821      */
21822     relayCmd : function(cmd, value){
21823         this.win.focus();
21824         this.execCmd(cmd, value);
21825         this.owner.fireEvent('editorevent', this);
21826         //this.updateToolbar();
21827         this.owner.deferFocus();
21828     },
21829
21830     /**
21831      * Executes a Midas editor command directly on the editor document.
21832      * For visual commands, you should use {@link #relayCmd} instead.
21833      * <b>This should only be called after the editor is initialized.</b>
21834      * @param {String} cmd The Midas command
21835      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21836      */
21837     execCmd : function(cmd, value){
21838         this.doc.execCommand(cmd, false, value === undefined ? null : value);
21839         this.syncValue();
21840     },
21841  
21842  
21843    
21844     /**
21845      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21846      * to insert tRoo.
21847      * @param {String} text | dom node.. 
21848      */
21849     insertAtCursor : function(text)
21850     {
21851         
21852         if(!this.activated){
21853             return;
21854         }
21855         /*
21856         if(Roo.isIE){
21857             this.win.focus();
21858             var r = this.doc.selection.createRange();
21859             if(r){
21860                 r.collapse(true);
21861                 r.pasteHTML(text);
21862                 this.syncValue();
21863                 this.deferFocus();
21864             
21865             }
21866             return;
21867         }
21868         */
21869         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21870             this.win.focus();
21871             
21872             
21873             // from jquery ui (MIT licenced)
21874             var range, node;
21875             var win = this.win;
21876             
21877             if (win.getSelection && win.getSelection().getRangeAt) {
21878                 range = win.getSelection().getRangeAt(0);
21879                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21880                 range.insertNode(node);
21881             } else if (win.document.selection && win.document.selection.createRange) {
21882                 // no firefox support
21883                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21884                 win.document.selection.createRange().pasteHTML(txt);
21885             } else {
21886                 // no firefox support
21887                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21888                 this.execCmd('InsertHTML', txt);
21889             } 
21890             
21891             this.syncValue();
21892             
21893             this.deferFocus();
21894         }
21895     },
21896  // private
21897     mozKeyPress : function(e){
21898         if(e.ctrlKey){
21899             var c = e.getCharCode(), cmd;
21900           
21901             if(c > 0){
21902                 c = String.fromCharCode(c).toLowerCase();
21903                 switch(c){
21904                     case 'b':
21905                         cmd = 'bold';
21906                         break;
21907                     case 'i':
21908                         cmd = 'italic';
21909                         break;
21910                     
21911                     case 'u':
21912                         cmd = 'underline';
21913                         break;
21914                     
21915                     case 'v':
21916                         this.cleanUpPaste.defer(100, this);
21917                         return;
21918                         
21919                 }
21920                 if(cmd){
21921                     this.win.focus();
21922                     this.execCmd(cmd);
21923                     this.deferFocus();
21924                     e.preventDefault();
21925                 }
21926                 
21927             }
21928         }
21929     },
21930
21931     // private
21932     fixKeys : function(){ // load time branching for fastest keydown performance
21933         if(Roo.isIE){
21934             return function(e){
21935                 var k = e.getKey(), r;
21936                 if(k == e.TAB){
21937                     e.stopEvent();
21938                     r = this.doc.selection.createRange();
21939                     if(r){
21940                         r.collapse(true);
21941                         r.pasteHTML('&#160;&#160;&#160;&#160;');
21942                         this.deferFocus();
21943                     }
21944                     return;
21945                 }
21946                 
21947                 if(k == e.ENTER){
21948                     r = this.doc.selection.createRange();
21949                     if(r){
21950                         var target = r.parentElement();
21951                         if(!target || target.tagName.toLowerCase() != 'li'){
21952                             e.stopEvent();
21953                             r.pasteHTML('<br />');
21954                             r.collapse(false);
21955                             r.select();
21956                         }
21957                     }
21958                 }
21959                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21960                     this.cleanUpPaste.defer(100, this);
21961                     return;
21962                 }
21963                 
21964                 
21965             };
21966         }else if(Roo.isOpera){
21967             return function(e){
21968                 var k = e.getKey();
21969                 if(k == e.TAB){
21970                     e.stopEvent();
21971                     this.win.focus();
21972                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
21973                     this.deferFocus();
21974                 }
21975                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21976                     this.cleanUpPaste.defer(100, this);
21977                     return;
21978                 }
21979                 
21980             };
21981         }else if(Roo.isSafari){
21982             return function(e){
21983                 var k = e.getKey();
21984                 
21985                 if(k == e.TAB){
21986                     e.stopEvent();
21987                     this.execCmd('InsertText','\t');
21988                     this.deferFocus();
21989                     return;
21990                 }
21991                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21992                     this.cleanUpPaste.defer(100, this);
21993                     return;
21994                 }
21995                 
21996              };
21997         }
21998     }(),
21999     
22000     getAllAncestors: function()
22001     {
22002         var p = this.getSelectedNode();
22003         var a = [];
22004         if (!p) {
22005             a.push(p); // push blank onto stack..
22006             p = this.getParentElement();
22007         }
22008         
22009         
22010         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22011             a.push(p);
22012             p = p.parentNode;
22013         }
22014         a.push(this.doc.body);
22015         return a;
22016     },
22017     lastSel : false,
22018     lastSelNode : false,
22019     
22020     
22021     getSelection : function() 
22022     {
22023         this.assignDocWin();
22024         return Roo.isIE ? this.doc.selection : this.win.getSelection();
22025     },
22026     
22027     getSelectedNode: function() 
22028     {
22029         // this may only work on Gecko!!!
22030         
22031         // should we cache this!!!!
22032         
22033         
22034         
22035          
22036         var range = this.createRange(this.getSelection()).cloneRange();
22037         
22038         if (Roo.isIE) {
22039             var parent = range.parentElement();
22040             while (true) {
22041                 var testRange = range.duplicate();
22042                 testRange.moveToElementText(parent);
22043                 if (testRange.inRange(range)) {
22044                     break;
22045                 }
22046                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22047                     break;
22048                 }
22049                 parent = parent.parentElement;
22050             }
22051             return parent;
22052         }
22053         
22054         // is ancestor a text element.
22055         var ac =  range.commonAncestorContainer;
22056         if (ac.nodeType == 3) {
22057             ac = ac.parentNode;
22058         }
22059         
22060         var ar = ac.childNodes;
22061          
22062         var nodes = [];
22063         var other_nodes = [];
22064         var has_other_nodes = false;
22065         for (var i=0;i<ar.length;i++) {
22066             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
22067                 continue;
22068             }
22069             // fullly contained node.
22070             
22071             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22072                 nodes.push(ar[i]);
22073                 continue;
22074             }
22075             
22076             // probably selected..
22077             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22078                 other_nodes.push(ar[i]);
22079                 continue;
22080             }
22081             // outer..
22082             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
22083                 continue;
22084             }
22085             
22086             
22087             has_other_nodes = true;
22088         }
22089         if (!nodes.length && other_nodes.length) {
22090             nodes= other_nodes;
22091         }
22092         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22093             return false;
22094         }
22095         
22096         return nodes[0];
22097     },
22098     createRange: function(sel)
22099     {
22100         // this has strange effects when using with 
22101         // top toolbar - not sure if it's a great idea.
22102         //this.editor.contentWindow.focus();
22103         if (typeof sel != "undefined") {
22104             try {
22105                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22106             } catch(e) {
22107                 return this.doc.createRange();
22108             }
22109         } else {
22110             return this.doc.createRange();
22111         }
22112     },
22113     getParentElement: function()
22114     {
22115         
22116         this.assignDocWin();
22117         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22118         
22119         var range = this.createRange(sel);
22120          
22121         try {
22122             var p = range.commonAncestorContainer;
22123             while (p.nodeType == 3) { // text node
22124                 p = p.parentNode;
22125             }
22126             return p;
22127         } catch (e) {
22128             return null;
22129         }
22130     
22131     },
22132     /***
22133      *
22134      * Range intersection.. the hard stuff...
22135      *  '-1' = before
22136      *  '0' = hits..
22137      *  '1' = after.
22138      *         [ -- selected range --- ]
22139      *   [fail]                        [fail]
22140      *
22141      *    basically..
22142      *      if end is before start or  hits it. fail.
22143      *      if start is after end or hits it fail.
22144      *
22145      *   if either hits (but other is outside. - then it's not 
22146      *   
22147      *    
22148      **/
22149     
22150     
22151     // @see http://www.thismuchiknow.co.uk/?p=64.
22152     rangeIntersectsNode : function(range, node)
22153     {
22154         var nodeRange = node.ownerDocument.createRange();
22155         try {
22156             nodeRange.selectNode(node);
22157         } catch (e) {
22158             nodeRange.selectNodeContents(node);
22159         }
22160     
22161         var rangeStartRange = range.cloneRange();
22162         rangeStartRange.collapse(true);
22163     
22164         var rangeEndRange = range.cloneRange();
22165         rangeEndRange.collapse(false);
22166     
22167         var nodeStartRange = nodeRange.cloneRange();
22168         nodeStartRange.collapse(true);
22169     
22170         var nodeEndRange = nodeRange.cloneRange();
22171         nodeEndRange.collapse(false);
22172     
22173         return rangeStartRange.compareBoundaryPoints(
22174                  Range.START_TO_START, nodeEndRange) == -1 &&
22175                rangeEndRange.compareBoundaryPoints(
22176                  Range.START_TO_START, nodeStartRange) == 1;
22177         
22178          
22179     },
22180     rangeCompareNode : function(range, node)
22181     {
22182         var nodeRange = node.ownerDocument.createRange();
22183         try {
22184             nodeRange.selectNode(node);
22185         } catch (e) {
22186             nodeRange.selectNodeContents(node);
22187         }
22188         
22189         
22190         range.collapse(true);
22191     
22192         nodeRange.collapse(true);
22193      
22194         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22195         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
22196          
22197         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22198         
22199         var nodeIsBefore   =  ss == 1;
22200         var nodeIsAfter    = ee == -1;
22201         
22202         if (nodeIsBefore && nodeIsAfter) {
22203             return 0; // outer
22204         }
22205         if (!nodeIsBefore && nodeIsAfter) {
22206             return 1; //right trailed.
22207         }
22208         
22209         if (nodeIsBefore && !nodeIsAfter) {
22210             return 2;  // left trailed.
22211         }
22212         // fully contined.
22213         return 3;
22214     },
22215
22216     // private? - in a new class?
22217     cleanUpPaste :  function()
22218     {
22219         // cleans up the whole document..
22220         Roo.log('cleanuppaste');
22221         
22222         this.cleanUpChildren(this.doc.body);
22223         var clean = this.cleanWordChars(this.doc.body.innerHTML);
22224         if (clean != this.doc.body.innerHTML) {
22225             this.doc.body.innerHTML = clean;
22226         }
22227         
22228     },
22229     
22230     cleanWordChars : function(input) {// change the chars to hex code
22231         var he = Roo.HtmlEditorCore;
22232         
22233         var output = input;
22234         Roo.each(he.swapCodes, function(sw) { 
22235             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22236             
22237             output = output.replace(swapper, sw[1]);
22238         });
22239         
22240         return output;
22241     },
22242     
22243     
22244     cleanUpChildren : function (n)
22245     {
22246         if (!n.childNodes.length) {
22247             return;
22248         }
22249         for (var i = n.childNodes.length-1; i > -1 ; i--) {
22250            this.cleanUpChild(n.childNodes[i]);
22251         }
22252     },
22253     
22254     
22255         
22256     
22257     cleanUpChild : function (node)
22258     {
22259         var ed = this;
22260         //console.log(node);
22261         if (node.nodeName == "#text") {
22262             // clean up silly Windows -- stuff?
22263             return; 
22264         }
22265         if (node.nodeName == "#comment") {
22266             node.parentNode.removeChild(node);
22267             // clean up silly Windows -- stuff?
22268             return; 
22269         }
22270         var lcname = node.tagName.toLowerCase();
22271         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22272         // whitelist of tags..
22273         
22274         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22275             // remove node.
22276             node.parentNode.removeChild(node);
22277             return;
22278             
22279         }
22280         
22281         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22282         
22283         // remove <a name=....> as rendering on yahoo mailer is borked with this.
22284         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22285         
22286         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22287         //    remove_keep_children = true;
22288         //}
22289         
22290         if (remove_keep_children) {
22291             this.cleanUpChildren(node);
22292             // inserts everything just before this node...
22293             while (node.childNodes.length) {
22294                 var cn = node.childNodes[0];
22295                 node.removeChild(cn);
22296                 node.parentNode.insertBefore(cn, node);
22297             }
22298             node.parentNode.removeChild(node);
22299             return;
22300         }
22301         
22302         if (!node.attributes || !node.attributes.length) {
22303             this.cleanUpChildren(node);
22304             return;
22305         }
22306         
22307         function cleanAttr(n,v)
22308         {
22309             
22310             if (v.match(/^\./) || v.match(/^\//)) {
22311                 return;
22312             }
22313             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22314                 return;
22315             }
22316             if (v.match(/^#/)) {
22317                 return;
22318             }
22319 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22320             node.removeAttribute(n);
22321             
22322         }
22323         
22324         var cwhite = this.cwhite;
22325         var cblack = this.cblack;
22326             
22327         function cleanStyle(n,v)
22328         {
22329             if (v.match(/expression/)) { //XSS?? should we even bother..
22330                 node.removeAttribute(n);
22331                 return;
22332             }
22333             
22334             var parts = v.split(/;/);
22335             var clean = [];
22336             
22337             Roo.each(parts, function(p) {
22338                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22339                 if (!p.length) {
22340                     return true;
22341                 }
22342                 var l = p.split(':').shift().replace(/\s+/g,'');
22343                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22344                 
22345                 if ( cwhite.length && cblack.indexOf(l) > -1) {
22346 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22347                     //node.removeAttribute(n);
22348                     return true;
22349                 }
22350                 //Roo.log()
22351                 // only allow 'c whitelisted system attributes'
22352                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
22353 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22354                     //node.removeAttribute(n);
22355                     return true;
22356                 }
22357                 
22358                 
22359                  
22360                 
22361                 clean.push(p);
22362                 return true;
22363             });
22364             if (clean.length) { 
22365                 node.setAttribute(n, clean.join(';'));
22366             } else {
22367                 node.removeAttribute(n);
22368             }
22369             
22370         }
22371         
22372         
22373         for (var i = node.attributes.length-1; i > -1 ; i--) {
22374             var a = node.attributes[i];
22375             //console.log(a);
22376             
22377             if (a.name.toLowerCase().substr(0,2)=='on')  {
22378                 node.removeAttribute(a.name);
22379                 continue;
22380             }
22381             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22382                 node.removeAttribute(a.name);
22383                 continue;
22384             }
22385             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22386                 cleanAttr(a.name,a.value); // fixme..
22387                 continue;
22388             }
22389             if (a.name == 'style') {
22390                 cleanStyle(a.name,a.value);
22391                 continue;
22392             }
22393             /// clean up MS crap..
22394             // tecnically this should be a list of valid class'es..
22395             
22396             
22397             if (a.name == 'class') {
22398                 if (a.value.match(/^Mso/)) {
22399                     node.className = '';
22400                 }
22401                 
22402                 if (a.value.match(/^body$/)) {
22403                     node.className = '';
22404                 }
22405                 continue;
22406             }
22407             
22408             // style cleanup!?
22409             // class cleanup?
22410             
22411         }
22412         
22413         
22414         this.cleanUpChildren(node);
22415         
22416         
22417     },
22418     
22419     /**
22420      * Clean up MS wordisms...
22421      */
22422     cleanWord : function(node)
22423     {
22424         
22425         
22426         if (!node) {
22427             this.cleanWord(this.doc.body);
22428             return;
22429         }
22430         if (node.nodeName == "#text") {
22431             // clean up silly Windows -- stuff?
22432             return; 
22433         }
22434         if (node.nodeName == "#comment") {
22435             node.parentNode.removeChild(node);
22436             // clean up silly Windows -- stuff?
22437             return; 
22438         }
22439         
22440         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22441             node.parentNode.removeChild(node);
22442             return;
22443         }
22444         
22445         // remove - but keep children..
22446         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22447             while (node.childNodes.length) {
22448                 var cn = node.childNodes[0];
22449                 node.removeChild(cn);
22450                 node.parentNode.insertBefore(cn, node);
22451             }
22452             node.parentNode.removeChild(node);
22453             this.iterateChildren(node, this.cleanWord);
22454             return;
22455         }
22456         // clean styles
22457         if (node.className.length) {
22458             
22459             var cn = node.className.split(/\W+/);
22460             var cna = [];
22461             Roo.each(cn, function(cls) {
22462                 if (cls.match(/Mso[a-zA-Z]+/)) {
22463                     return;
22464                 }
22465                 cna.push(cls);
22466             });
22467             node.className = cna.length ? cna.join(' ') : '';
22468             if (!cna.length) {
22469                 node.removeAttribute("class");
22470             }
22471         }
22472         
22473         if (node.hasAttribute("lang")) {
22474             node.removeAttribute("lang");
22475         }
22476         
22477         if (node.hasAttribute("style")) {
22478             
22479             var styles = node.getAttribute("style").split(";");
22480             var nstyle = [];
22481             Roo.each(styles, function(s) {
22482                 if (!s.match(/:/)) {
22483                     return;
22484                 }
22485                 var kv = s.split(":");
22486                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22487                     return;
22488                 }
22489                 // what ever is left... we allow.
22490                 nstyle.push(s);
22491             });
22492             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22493             if (!nstyle.length) {
22494                 node.removeAttribute('style');
22495             }
22496         }
22497         this.iterateChildren(node, this.cleanWord);
22498         
22499         
22500         
22501     },
22502     /**
22503      * iterateChildren of a Node, calling fn each time, using this as the scole..
22504      * @param {DomNode} node node to iterate children of.
22505      * @param {Function} fn method of this class to call on each item.
22506      */
22507     iterateChildren : function(node, fn)
22508     {
22509         if (!node.childNodes.length) {
22510                 return;
22511         }
22512         for (var i = node.childNodes.length-1; i > -1 ; i--) {
22513            fn.call(this, node.childNodes[i])
22514         }
22515     },
22516     
22517     
22518     /**
22519      * cleanTableWidths.
22520      *
22521      * Quite often pasting from word etc.. results in tables with column and widths.
22522      * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22523      *
22524      */
22525     cleanTableWidths : function(node)
22526     {
22527          
22528          
22529         if (!node) {
22530             this.cleanTableWidths(this.doc.body);
22531             return;
22532         }
22533         
22534         // ignore list...
22535         if (node.nodeName == "#text" || node.nodeName == "#comment") {
22536             return; 
22537         }
22538         Roo.log(node.tagName);
22539         if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22540             this.iterateChildren(node, this.cleanTableWidths);
22541             return;
22542         }
22543         if (node.hasAttribute('width')) {
22544             node.removeAttribute('width');
22545         }
22546         
22547          
22548         if (node.hasAttribute("style")) {
22549             // pretty basic...
22550             
22551             var styles = node.getAttribute("style").split(";");
22552             var nstyle = [];
22553             Roo.each(styles, function(s) {
22554                 if (!s.match(/:/)) {
22555                     return;
22556                 }
22557                 var kv = s.split(":");
22558                 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22559                     return;
22560                 }
22561                 // what ever is left... we allow.
22562                 nstyle.push(s);
22563             });
22564             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22565             if (!nstyle.length) {
22566                 node.removeAttribute('style');
22567             }
22568         }
22569         
22570         this.iterateChildren(node, this.cleanTableWidths);
22571         
22572         
22573     },
22574     
22575     
22576     
22577     
22578     domToHTML : function(currentElement, depth, nopadtext) {
22579         
22580         depth = depth || 0;
22581         nopadtext = nopadtext || false;
22582     
22583         if (!currentElement) {
22584             return this.domToHTML(this.doc.body);
22585         }
22586         
22587         //Roo.log(currentElement);
22588         var j;
22589         var allText = false;
22590         var nodeName = currentElement.nodeName;
22591         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22592         
22593         if  (nodeName == '#text') {
22594             
22595             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22596         }
22597         
22598         
22599         var ret = '';
22600         if (nodeName != 'BODY') {
22601              
22602             var i = 0;
22603             // Prints the node tagName, such as <A>, <IMG>, etc
22604             if (tagName) {
22605                 var attr = [];
22606                 for(i = 0; i < currentElement.attributes.length;i++) {
22607                     // quoting?
22608                     var aname = currentElement.attributes.item(i).name;
22609                     if (!currentElement.attributes.item(i).value.length) {
22610                         continue;
22611                     }
22612                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22613                 }
22614                 
22615                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22616             } 
22617             else {
22618                 
22619                 // eack
22620             }
22621         } else {
22622             tagName = false;
22623         }
22624         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22625             return ret;
22626         }
22627         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22628             nopadtext = true;
22629         }
22630         
22631         
22632         // Traverse the tree
22633         i = 0;
22634         var currentElementChild = currentElement.childNodes.item(i);
22635         var allText = true;
22636         var innerHTML  = '';
22637         lastnode = '';
22638         while (currentElementChild) {
22639             // Formatting code (indent the tree so it looks nice on the screen)
22640             var nopad = nopadtext;
22641             if (lastnode == 'SPAN') {
22642                 nopad  = true;
22643             }
22644             // text
22645             if  (currentElementChild.nodeName == '#text') {
22646                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22647                 toadd = nopadtext ? toadd : toadd.trim();
22648                 if (!nopad && toadd.length > 80) {
22649                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
22650                 }
22651                 innerHTML  += toadd;
22652                 
22653                 i++;
22654                 currentElementChild = currentElement.childNodes.item(i);
22655                 lastNode = '';
22656                 continue;
22657             }
22658             allText = false;
22659             
22660             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
22661                 
22662             // Recursively traverse the tree structure of the child node
22663             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
22664             lastnode = currentElementChild.nodeName;
22665             i++;
22666             currentElementChild=currentElement.childNodes.item(i);
22667         }
22668         
22669         ret += innerHTML;
22670         
22671         if (!allText) {
22672                 // The remaining code is mostly for formatting the tree
22673             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
22674         }
22675         
22676         
22677         if (tagName) {
22678             ret+= "</"+tagName+">";
22679         }
22680         return ret;
22681         
22682     },
22683         
22684     applyBlacklists : function()
22685     {
22686         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
22687         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
22688         
22689         this.white = [];
22690         this.black = [];
22691         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22692             if (b.indexOf(tag) > -1) {
22693                 return;
22694             }
22695             this.white.push(tag);
22696             
22697         }, this);
22698         
22699         Roo.each(w, function(tag) {
22700             if (b.indexOf(tag) > -1) {
22701                 return;
22702             }
22703             if (this.white.indexOf(tag) > -1) {
22704                 return;
22705             }
22706             this.white.push(tag);
22707             
22708         }, this);
22709         
22710         
22711         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22712             if (w.indexOf(tag) > -1) {
22713                 return;
22714             }
22715             this.black.push(tag);
22716             
22717         }, this);
22718         
22719         Roo.each(b, function(tag) {
22720             if (w.indexOf(tag) > -1) {
22721                 return;
22722             }
22723             if (this.black.indexOf(tag) > -1) {
22724                 return;
22725             }
22726             this.black.push(tag);
22727             
22728         }, this);
22729         
22730         
22731         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
22732         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
22733         
22734         this.cwhite = [];
22735         this.cblack = [];
22736         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22737             if (b.indexOf(tag) > -1) {
22738                 return;
22739             }
22740             this.cwhite.push(tag);
22741             
22742         }, this);
22743         
22744         Roo.each(w, function(tag) {
22745             if (b.indexOf(tag) > -1) {
22746                 return;
22747             }
22748             if (this.cwhite.indexOf(tag) > -1) {
22749                 return;
22750             }
22751             this.cwhite.push(tag);
22752             
22753         }, this);
22754         
22755         
22756         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22757             if (w.indexOf(tag) > -1) {
22758                 return;
22759             }
22760             this.cblack.push(tag);
22761             
22762         }, this);
22763         
22764         Roo.each(b, function(tag) {
22765             if (w.indexOf(tag) > -1) {
22766                 return;
22767             }
22768             if (this.cblack.indexOf(tag) > -1) {
22769                 return;
22770             }
22771             this.cblack.push(tag);
22772             
22773         }, this);
22774     },
22775     
22776     setStylesheets : function(stylesheets)
22777     {
22778         if(typeof(stylesheets) == 'string'){
22779             Roo.get(this.iframe.contentDocument.head).createChild({
22780                 tag : 'link',
22781                 rel : 'stylesheet',
22782                 type : 'text/css',
22783                 href : stylesheets
22784             });
22785             
22786             return;
22787         }
22788         var _this = this;
22789      
22790         Roo.each(stylesheets, function(s) {
22791             if(!s.length){
22792                 return;
22793             }
22794             
22795             Roo.get(_this.iframe.contentDocument.head).createChild({
22796                 tag : 'link',
22797                 rel : 'stylesheet',
22798                 type : 'text/css',
22799                 href : s
22800             });
22801         });
22802
22803         
22804     },
22805     
22806     removeStylesheets : function()
22807     {
22808         var _this = this;
22809         
22810         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22811             s.remove();
22812         });
22813     },
22814     
22815     setStyle : function(style)
22816     {
22817         Roo.get(this.iframe.contentDocument.head).createChild({
22818             tag : 'style',
22819             type : 'text/css',
22820             html : style
22821         });
22822
22823         return;
22824     }
22825     
22826     // hide stuff that is not compatible
22827     /**
22828      * @event blur
22829      * @hide
22830      */
22831     /**
22832      * @event change
22833      * @hide
22834      */
22835     /**
22836      * @event focus
22837      * @hide
22838      */
22839     /**
22840      * @event specialkey
22841      * @hide
22842      */
22843     /**
22844      * @cfg {String} fieldClass @hide
22845      */
22846     /**
22847      * @cfg {String} focusClass @hide
22848      */
22849     /**
22850      * @cfg {String} autoCreate @hide
22851      */
22852     /**
22853      * @cfg {String} inputType @hide
22854      */
22855     /**
22856      * @cfg {String} invalidClass @hide
22857      */
22858     /**
22859      * @cfg {String} invalidText @hide
22860      */
22861     /**
22862      * @cfg {String} msgFx @hide
22863      */
22864     /**
22865      * @cfg {String} validateOnBlur @hide
22866      */
22867 });
22868
22869 Roo.HtmlEditorCore.white = [
22870         'area', 'br', 'img', 'input', 'hr', 'wbr',
22871         
22872        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
22873        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
22874        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
22875        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
22876        'table',   'ul',         'xmp', 
22877        
22878        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
22879       'thead',   'tr', 
22880      
22881       'dir', 'menu', 'ol', 'ul', 'dl',
22882        
22883       'embed',  'object'
22884 ];
22885
22886
22887 Roo.HtmlEditorCore.black = [
22888     //    'embed',  'object', // enable - backend responsiblity to clean thiese
22889         'applet', // 
22890         'base',   'basefont', 'bgsound', 'blink',  'body', 
22891         'frame',  'frameset', 'head',    'html',   'ilayer', 
22892         'iframe', 'layer',  'link',     'meta',    'object',   
22893         'script', 'style' ,'title',  'xml' // clean later..
22894 ];
22895 Roo.HtmlEditorCore.clean = [
22896     'script', 'style', 'title', 'xml'
22897 ];
22898 Roo.HtmlEditorCore.remove = [
22899     'font'
22900 ];
22901 // attributes..
22902
22903 Roo.HtmlEditorCore.ablack = [
22904     'on'
22905 ];
22906     
22907 Roo.HtmlEditorCore.aclean = [ 
22908     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
22909 ];
22910
22911 // protocols..
22912 Roo.HtmlEditorCore.pwhite= [
22913         'http',  'https',  'mailto'
22914 ];
22915
22916 // white listed style attributes.
22917 Roo.HtmlEditorCore.cwhite= [
22918       //  'text-align', /// default is to allow most things..
22919       
22920          
22921 //        'font-size'//??
22922 ];
22923
22924 // black listed style attributes.
22925 Roo.HtmlEditorCore.cblack= [
22926       //  'font-size' -- this can be set by the project 
22927 ];
22928
22929
22930 Roo.HtmlEditorCore.swapCodes   =[ 
22931     [    8211, "--" ], 
22932     [    8212, "--" ], 
22933     [    8216,  "'" ],  
22934     [    8217, "'" ],  
22935     [    8220, '"' ],  
22936     [    8221, '"' ],  
22937     [    8226, "*" ],  
22938     [    8230, "..." ]
22939 ]; 
22940
22941     /*
22942  * - LGPL
22943  *
22944  * HtmlEditor
22945  * 
22946  */
22947
22948 /**
22949  * @class Roo.bootstrap.HtmlEditor
22950  * @extends Roo.bootstrap.TextArea
22951  * Bootstrap HtmlEditor class
22952
22953  * @constructor
22954  * Create a new HtmlEditor
22955  * @param {Object} config The config object
22956  */
22957
22958 Roo.bootstrap.HtmlEditor = function(config){
22959     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22960     if (!this.toolbars) {
22961         this.toolbars = [];
22962     }
22963     
22964     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22965     this.addEvents({
22966             /**
22967              * @event initialize
22968              * Fires when the editor is fully initialized (including the iframe)
22969              * @param {HtmlEditor} this
22970              */
22971             initialize: true,
22972             /**
22973              * @event activate
22974              * Fires when the editor is first receives the focus. Any insertion must wait
22975              * until after this event.
22976              * @param {HtmlEditor} this
22977              */
22978             activate: true,
22979              /**
22980              * @event beforesync
22981              * Fires before the textarea is updated with content from the editor iframe. Return false
22982              * to cancel the sync.
22983              * @param {HtmlEditor} this
22984              * @param {String} html
22985              */
22986             beforesync: true,
22987              /**
22988              * @event beforepush
22989              * Fires before the iframe editor is updated with content from the textarea. Return false
22990              * to cancel the push.
22991              * @param {HtmlEditor} this
22992              * @param {String} html
22993              */
22994             beforepush: true,
22995              /**
22996              * @event sync
22997              * Fires when the textarea is updated with content from the editor iframe.
22998              * @param {HtmlEditor} this
22999              * @param {String} html
23000              */
23001             sync: true,
23002              /**
23003              * @event push
23004              * Fires when the iframe editor is updated with content from the textarea.
23005              * @param {HtmlEditor} this
23006              * @param {String} html
23007              */
23008             push: true,
23009              /**
23010              * @event editmodechange
23011              * Fires when the editor switches edit modes
23012              * @param {HtmlEditor} this
23013              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23014              */
23015             editmodechange: true,
23016             /**
23017              * @event editorevent
23018              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23019              * @param {HtmlEditor} this
23020              */
23021             editorevent: true,
23022             /**
23023              * @event firstfocus
23024              * Fires when on first focus - needed by toolbars..
23025              * @param {HtmlEditor} this
23026              */
23027             firstfocus: true,
23028             /**
23029              * @event autosave
23030              * Auto save the htmlEditor value as a file into Events
23031              * @param {HtmlEditor} this
23032              */
23033             autosave: true,
23034             /**
23035              * @event savedpreview
23036              * preview the saved version of htmlEditor
23037              * @param {HtmlEditor} this
23038              */
23039             savedpreview: true
23040         });
23041 };
23042
23043
23044 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
23045     
23046     
23047       /**
23048      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23049      */
23050     toolbars : false,
23051     
23052      /**
23053     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23054     */
23055     btns : [],
23056    
23057      /**
23058      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
23059      *                        Roo.resizable.
23060      */
23061     resizable : false,
23062      /**
23063      * @cfg {Number} height (in pixels)
23064      */   
23065     height: 300,
23066    /**
23067      * @cfg {Number} width (in pixels)
23068      */   
23069     width: false,
23070     
23071     /**
23072      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23073      * 
23074      */
23075     stylesheets: false,
23076     
23077     // id of frame..
23078     frameId: false,
23079     
23080     // private properties
23081     validationEvent : false,
23082     deferHeight: true,
23083     initialized : false,
23084     activated : false,
23085     
23086     onFocus : Roo.emptyFn,
23087     iframePad:3,
23088     hideMode:'offsets',
23089     
23090     tbContainer : false,
23091     
23092     bodyCls : '',
23093     
23094     toolbarContainer :function() {
23095         return this.wrap.select('.x-html-editor-tb',true).first();
23096     },
23097
23098     /**
23099      * Protected method that will not generally be called directly. It
23100      * is called when the editor creates its toolbar. Override this method if you need to
23101      * add custom toolbar buttons.
23102      * @param {HtmlEditor} editor
23103      */
23104     createToolbar : function(){
23105         Roo.log('renewing');
23106         Roo.log("create toolbars");
23107         
23108         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23109         this.toolbars[0].render(this.toolbarContainer());
23110         
23111         return;
23112         
23113 //        if (!editor.toolbars || !editor.toolbars.length) {
23114 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23115 //        }
23116 //        
23117 //        for (var i =0 ; i < editor.toolbars.length;i++) {
23118 //            editor.toolbars[i] = Roo.factory(
23119 //                    typeof(editor.toolbars[i]) == 'string' ?
23120 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
23121 //                Roo.bootstrap.HtmlEditor);
23122 //            editor.toolbars[i].init(editor);
23123 //        }
23124     },
23125
23126      
23127     // private
23128     onRender : function(ct, position)
23129     {
23130        // Roo.log("Call onRender: " + this.xtype);
23131         var _t = this;
23132         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23133       
23134         this.wrap = this.inputEl().wrap({
23135             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23136         });
23137         
23138         this.editorcore.onRender(ct, position);
23139          
23140         if (this.resizable) {
23141             this.resizeEl = new Roo.Resizable(this.wrap, {
23142                 pinned : true,
23143                 wrap: true,
23144                 dynamic : true,
23145                 minHeight : this.height,
23146                 height: this.height,
23147                 handles : this.resizable,
23148                 width: this.width,
23149                 listeners : {
23150                     resize : function(r, w, h) {
23151                         _t.onResize(w,h); // -something
23152                     }
23153                 }
23154             });
23155             
23156         }
23157         this.createToolbar(this);
23158        
23159         
23160         if(!this.width && this.resizable){
23161             this.setSize(this.wrap.getSize());
23162         }
23163         if (this.resizeEl) {
23164             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23165             // should trigger onReize..
23166         }
23167         
23168     },
23169
23170     // private
23171     onResize : function(w, h)
23172     {
23173         Roo.log('resize: ' +w + ',' + h );
23174         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23175         var ew = false;
23176         var eh = false;
23177         
23178         if(this.inputEl() ){
23179             if(typeof w == 'number'){
23180                 var aw = w - this.wrap.getFrameWidth('lr');
23181                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23182                 ew = aw;
23183             }
23184             if(typeof h == 'number'){
23185                  var tbh = -11;  // fixme it needs to tool bar size!
23186                 for (var i =0; i < this.toolbars.length;i++) {
23187                     // fixme - ask toolbars for heights?
23188                     tbh += this.toolbars[i].el.getHeight();
23189                     //if (this.toolbars[i].footer) {
23190                     //    tbh += this.toolbars[i].footer.el.getHeight();
23191                     //}
23192                 }
23193               
23194                 
23195                 
23196                 
23197                 
23198                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23199                 ah -= 5; // knock a few pixes off for look..
23200                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23201                 var eh = ah;
23202             }
23203         }
23204         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23205         this.editorcore.onResize(ew,eh);
23206         
23207     },
23208
23209     /**
23210      * Toggles the editor between standard and source edit mode.
23211      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23212      */
23213     toggleSourceEdit : function(sourceEditMode)
23214     {
23215         this.editorcore.toggleSourceEdit(sourceEditMode);
23216         
23217         if(this.editorcore.sourceEditMode){
23218             Roo.log('editor - showing textarea');
23219             
23220 //            Roo.log('in');
23221 //            Roo.log(this.syncValue());
23222             this.syncValue();
23223             this.inputEl().removeClass(['hide', 'x-hidden']);
23224             this.inputEl().dom.removeAttribute('tabIndex');
23225             this.inputEl().focus();
23226         }else{
23227             Roo.log('editor - hiding textarea');
23228 //            Roo.log('out')
23229 //            Roo.log(this.pushValue()); 
23230             this.pushValue();
23231             
23232             this.inputEl().addClass(['hide', 'x-hidden']);
23233             this.inputEl().dom.setAttribute('tabIndex', -1);
23234             //this.deferFocus();
23235         }
23236          
23237         if(this.resizable){
23238             this.setSize(this.wrap.getSize());
23239         }
23240         
23241         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23242     },
23243  
23244     // private (for BoxComponent)
23245     adjustSize : Roo.BoxComponent.prototype.adjustSize,
23246
23247     // private (for BoxComponent)
23248     getResizeEl : function(){
23249         return this.wrap;
23250     },
23251
23252     // private (for BoxComponent)
23253     getPositionEl : function(){
23254         return this.wrap;
23255     },
23256
23257     // private
23258     initEvents : function(){
23259         this.originalValue = this.getValue();
23260     },
23261
23262 //    /**
23263 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23264 //     * @method
23265 //     */
23266 //    markInvalid : Roo.emptyFn,
23267 //    /**
23268 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23269 //     * @method
23270 //     */
23271 //    clearInvalid : Roo.emptyFn,
23272
23273     setValue : function(v){
23274         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23275         this.editorcore.pushValue();
23276     },
23277
23278      
23279     // private
23280     deferFocus : function(){
23281         this.focus.defer(10, this);
23282     },
23283
23284     // doc'ed in Field
23285     focus : function(){
23286         this.editorcore.focus();
23287         
23288     },
23289       
23290
23291     // private
23292     onDestroy : function(){
23293         
23294         
23295         
23296         if(this.rendered){
23297             
23298             for (var i =0; i < this.toolbars.length;i++) {
23299                 // fixme - ask toolbars for heights?
23300                 this.toolbars[i].onDestroy();
23301             }
23302             
23303             this.wrap.dom.innerHTML = '';
23304             this.wrap.remove();
23305         }
23306     },
23307
23308     // private
23309     onFirstFocus : function(){
23310         //Roo.log("onFirstFocus");
23311         this.editorcore.onFirstFocus();
23312          for (var i =0; i < this.toolbars.length;i++) {
23313             this.toolbars[i].onFirstFocus();
23314         }
23315         
23316     },
23317     
23318     // private
23319     syncValue : function()
23320     {   
23321         this.editorcore.syncValue();
23322     },
23323     
23324     pushValue : function()
23325     {   
23326         this.editorcore.pushValue();
23327     }
23328      
23329     
23330     // hide stuff that is not compatible
23331     /**
23332      * @event blur
23333      * @hide
23334      */
23335     /**
23336      * @event change
23337      * @hide
23338      */
23339     /**
23340      * @event focus
23341      * @hide
23342      */
23343     /**
23344      * @event specialkey
23345      * @hide
23346      */
23347     /**
23348      * @cfg {String} fieldClass @hide
23349      */
23350     /**
23351      * @cfg {String} focusClass @hide
23352      */
23353     /**
23354      * @cfg {String} autoCreate @hide
23355      */
23356     /**
23357      * @cfg {String} inputType @hide
23358      */
23359     /**
23360      * @cfg {String} invalidClass @hide
23361      */
23362     /**
23363      * @cfg {String} invalidText @hide
23364      */
23365     /**
23366      * @cfg {String} msgFx @hide
23367      */
23368     /**
23369      * @cfg {String} validateOnBlur @hide
23370      */
23371 });
23372  
23373     
23374    
23375    
23376    
23377       
23378 Roo.namespace('Roo.bootstrap.htmleditor');
23379 /**
23380  * @class Roo.bootstrap.HtmlEditorToolbar1
23381  * Basic Toolbar
23382  * 
23383  * Usage:
23384  *
23385  new Roo.bootstrap.HtmlEditor({
23386     ....
23387     toolbars : [
23388         new Roo.bootstrap.HtmlEditorToolbar1({
23389             disable : { fonts: 1 , format: 1, ..., ... , ...],
23390             btns : [ .... ]
23391         })
23392     }
23393      
23394  * 
23395  * @cfg {Object} disable List of elements to disable..
23396  * @cfg {Array} btns List of additional buttons.
23397  * 
23398  * 
23399  * NEEDS Extra CSS? 
23400  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23401  */
23402  
23403 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23404 {
23405     
23406     Roo.apply(this, config);
23407     
23408     // default disabled, based on 'good practice'..
23409     this.disable = this.disable || {};
23410     Roo.applyIf(this.disable, {
23411         fontSize : true,
23412         colors : true,
23413         specialElements : true
23414     });
23415     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23416     
23417     this.editor = config.editor;
23418     this.editorcore = config.editor.editorcore;
23419     
23420     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23421     
23422     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23423     // dont call parent... till later.
23424 }
23425 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
23426      
23427     bar : true,
23428     
23429     editor : false,
23430     editorcore : false,
23431     
23432     
23433     formats : [
23434         "p" ,  
23435         "h1","h2","h3","h4","h5","h6", 
23436         "pre", "code", 
23437         "abbr", "acronym", "address", "cite", "samp", "var",
23438         'div','span'
23439     ],
23440     
23441     onRender : function(ct, position)
23442     {
23443        // Roo.log("Call onRender: " + this.xtype);
23444         
23445        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23446        Roo.log(this.el);
23447        this.el.dom.style.marginBottom = '0';
23448        var _this = this;
23449        var editorcore = this.editorcore;
23450        var editor= this.editor;
23451        
23452        var children = [];
23453        var btn = function(id,cmd , toggle, handler, html){
23454        
23455             var  event = toggle ? 'toggle' : 'click';
23456        
23457             var a = {
23458                 size : 'sm',
23459                 xtype: 'Button',
23460                 xns: Roo.bootstrap,
23461                 glyphicon : id,
23462                 cmd : id || cmd,
23463                 enableToggle:toggle !== false,
23464                 html : html || '',
23465                 pressed : toggle ? false : null,
23466                 listeners : {}
23467             };
23468             a.listeners[toggle ? 'toggle' : 'click'] = function() {
23469                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
23470             };
23471             children.push(a);
23472             return a;
23473        }
23474        
23475     //    var cb_box = function...
23476         
23477         var style = {
23478                 xtype: 'Button',
23479                 size : 'sm',
23480                 xns: Roo.bootstrap,
23481                 glyphicon : 'font',
23482                 //html : 'submit'
23483                 menu : {
23484                     xtype: 'Menu',
23485                     xns: Roo.bootstrap,
23486                     items:  []
23487                 }
23488         };
23489         Roo.each(this.formats, function(f) {
23490             style.menu.items.push({
23491                 xtype :'MenuItem',
23492                 xns: Roo.bootstrap,
23493                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23494                 tagname : f,
23495                 listeners : {
23496                     click : function()
23497                     {
23498                         editorcore.insertTag(this.tagname);
23499                         editor.focus();
23500                     }
23501                 }
23502                 
23503             });
23504         });
23505         children.push(style);   
23506         
23507         btn('bold',false,true);
23508         btn('italic',false,true);
23509         btn('align-left', 'justifyleft',true);
23510         btn('align-center', 'justifycenter',true);
23511         btn('align-right' , 'justifyright',true);
23512         btn('link', false, false, function(btn) {
23513             //Roo.log("create link?");
23514             var url = prompt(this.createLinkText, this.defaultLinkValue);
23515             if(url && url != 'http:/'+'/'){
23516                 this.editorcore.relayCmd('createlink', url);
23517             }
23518         }),
23519         btn('list','insertunorderedlist',true);
23520         btn('pencil', false,true, function(btn){
23521                 Roo.log(this);
23522                 this.toggleSourceEdit(btn.pressed);
23523         });
23524         
23525         if (this.editor.btns.length > 0) {
23526             for (var i = 0; i<this.editor.btns.length; i++) {
23527                 children.push(this.editor.btns[i]);
23528             }
23529         }
23530         
23531         /*
23532         var cog = {
23533                 xtype: 'Button',
23534                 size : 'sm',
23535                 xns: Roo.bootstrap,
23536                 glyphicon : 'cog',
23537                 //html : 'submit'
23538                 menu : {
23539                     xtype: 'Menu',
23540                     xns: Roo.bootstrap,
23541                     items:  []
23542                 }
23543         };
23544         
23545         cog.menu.items.push({
23546             xtype :'MenuItem',
23547             xns: Roo.bootstrap,
23548             html : Clean styles,
23549             tagname : f,
23550             listeners : {
23551                 click : function()
23552                 {
23553                     editorcore.insertTag(this.tagname);
23554                     editor.focus();
23555                 }
23556             }
23557             
23558         });
23559        */
23560         
23561          
23562        this.xtype = 'NavSimplebar';
23563         
23564         for(var i=0;i< children.length;i++) {
23565             
23566             this.buttons.add(this.addxtypeChild(children[i]));
23567             
23568         }
23569         
23570         editor.on('editorevent', this.updateToolbar, this);
23571     },
23572     onBtnClick : function(id)
23573     {
23574        this.editorcore.relayCmd(id);
23575        this.editorcore.focus();
23576     },
23577     
23578     /**
23579      * Protected method that will not generally be called directly. It triggers
23580      * a toolbar update by reading the markup state of the current selection in the editor.
23581      */
23582     updateToolbar: function(){
23583
23584         if(!this.editorcore.activated){
23585             this.editor.onFirstFocus(); // is this neeed?
23586             return;
23587         }
23588
23589         var btns = this.buttons; 
23590         var doc = this.editorcore.doc;
23591         btns.get('bold').setActive(doc.queryCommandState('bold'));
23592         btns.get('italic').setActive(doc.queryCommandState('italic'));
23593         //btns.get('underline').setActive(doc.queryCommandState('underline'));
23594         
23595         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23596         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23597         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23598         
23599         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23600         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23601          /*
23602         
23603         var ans = this.editorcore.getAllAncestors();
23604         if (this.formatCombo) {
23605             
23606             
23607             var store = this.formatCombo.store;
23608             this.formatCombo.setValue("");
23609             for (var i =0; i < ans.length;i++) {
23610                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23611                     // select it..
23612                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23613                     break;
23614                 }
23615             }
23616         }
23617         
23618         
23619         
23620         // hides menus... - so this cant be on a menu...
23621         Roo.bootstrap.MenuMgr.hideAll();
23622         */
23623         Roo.bootstrap.MenuMgr.hideAll();
23624         //this.editorsyncValue();
23625     },
23626     onFirstFocus: function() {
23627         this.buttons.each(function(item){
23628            item.enable();
23629         });
23630     },
23631     toggleSourceEdit : function(sourceEditMode){
23632         
23633           
23634         if(sourceEditMode){
23635             Roo.log("disabling buttons");
23636            this.buttons.each( function(item){
23637                 if(item.cmd != 'pencil'){
23638                     item.disable();
23639                 }
23640             });
23641           
23642         }else{
23643             Roo.log("enabling buttons");
23644             if(this.editorcore.initialized){
23645                 this.buttons.each( function(item){
23646                     item.enable();
23647                 });
23648             }
23649             
23650         }
23651         Roo.log("calling toggole on editor");
23652         // tell the editor that it's been pressed..
23653         this.editor.toggleSourceEdit(sourceEditMode);
23654        
23655     }
23656 });
23657
23658
23659
23660
23661
23662 /**
23663  * @class Roo.bootstrap.Table.AbstractSelectionModel
23664  * @extends Roo.util.Observable
23665  * Abstract base class for grid SelectionModels.  It provides the interface that should be
23666  * implemented by descendant classes.  This class should not be directly instantiated.
23667  * @constructor
23668  */
23669 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23670     this.locked = false;
23671     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23672 };
23673
23674
23675 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
23676     /** @ignore Called by the grid automatically. Do not call directly. */
23677     init : function(grid){
23678         this.grid = grid;
23679         this.initEvents();
23680     },
23681
23682     /**
23683      * Locks the selections.
23684      */
23685     lock : function(){
23686         this.locked = true;
23687     },
23688
23689     /**
23690      * Unlocks the selections.
23691      */
23692     unlock : function(){
23693         this.locked = false;
23694     },
23695
23696     /**
23697      * Returns true if the selections are locked.
23698      * @return {Boolean}
23699      */
23700     isLocked : function(){
23701         return this.locked;
23702     }
23703 });
23704 /**
23705  * @extends Roo.bootstrap.Table.AbstractSelectionModel
23706  * @class Roo.bootstrap.Table.RowSelectionModel
23707  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23708  * It supports multiple selections and keyboard selection/navigation. 
23709  * @constructor
23710  * @param {Object} config
23711  */
23712
23713 Roo.bootstrap.Table.RowSelectionModel = function(config){
23714     Roo.apply(this, config);
23715     this.selections = new Roo.util.MixedCollection(false, function(o){
23716         return o.id;
23717     });
23718
23719     this.last = false;
23720     this.lastActive = false;
23721
23722     this.addEvents({
23723         /**
23724              * @event selectionchange
23725              * Fires when the selection changes
23726              * @param {SelectionModel} this
23727              */
23728             "selectionchange" : true,
23729         /**
23730              * @event afterselectionchange
23731              * Fires after the selection changes (eg. by key press or clicking)
23732              * @param {SelectionModel} this
23733              */
23734             "afterselectionchange" : true,
23735         /**
23736              * @event beforerowselect
23737              * Fires when a row is selected being selected, return false to cancel.
23738              * @param {SelectionModel} this
23739              * @param {Number} rowIndex The selected index
23740              * @param {Boolean} keepExisting False if other selections will be cleared
23741              */
23742             "beforerowselect" : true,
23743         /**
23744              * @event rowselect
23745              * Fires when a row is selected.
23746              * @param {SelectionModel} this
23747              * @param {Number} rowIndex The selected index
23748              * @param {Roo.data.Record} r The record
23749              */
23750             "rowselect" : true,
23751         /**
23752              * @event rowdeselect
23753              * Fires when a row is deselected.
23754              * @param {SelectionModel} this
23755              * @param {Number} rowIndex The selected index
23756              */
23757         "rowdeselect" : true
23758     });
23759     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23760     this.locked = false;
23761  };
23762
23763 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
23764     /**
23765      * @cfg {Boolean} singleSelect
23766      * True to allow selection of only one row at a time (defaults to false)
23767      */
23768     singleSelect : false,
23769
23770     // private
23771     initEvents : function()
23772     {
23773
23774         //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23775         //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
23776         //}else{ // allow click to work like normal
23777          //   this.grid.on("rowclick", this.handleDragableRowClick, this);
23778         //}
23779         //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23780         this.grid.on("rowclick", this.handleMouseDown, this);
23781         
23782         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23783             "up" : function(e){
23784                 if(!e.shiftKey){
23785                     this.selectPrevious(e.shiftKey);
23786                 }else if(this.last !== false && this.lastActive !== false){
23787                     var last = this.last;
23788                     this.selectRange(this.last,  this.lastActive-1);
23789                     this.grid.getView().focusRow(this.lastActive);
23790                     if(last !== false){
23791                         this.last = last;
23792                     }
23793                 }else{
23794                     this.selectFirstRow();
23795                 }
23796                 this.fireEvent("afterselectionchange", this);
23797             },
23798             "down" : function(e){
23799                 if(!e.shiftKey){
23800                     this.selectNext(e.shiftKey);
23801                 }else if(this.last !== false && this.lastActive !== false){
23802                     var last = this.last;
23803                     this.selectRange(this.last,  this.lastActive+1);
23804                     this.grid.getView().focusRow(this.lastActive);
23805                     if(last !== false){
23806                         this.last = last;
23807                     }
23808                 }else{
23809                     this.selectFirstRow();
23810                 }
23811                 this.fireEvent("afterselectionchange", this);
23812             },
23813             scope: this
23814         });
23815         this.grid.store.on('load', function(){
23816             this.selections.clear();
23817         },this);
23818         /*
23819         var view = this.grid.view;
23820         view.on("refresh", this.onRefresh, this);
23821         view.on("rowupdated", this.onRowUpdated, this);
23822         view.on("rowremoved", this.onRemove, this);
23823         */
23824     },
23825
23826     // private
23827     onRefresh : function()
23828     {
23829         var ds = this.grid.store, i, v = this.grid.view;
23830         var s = this.selections;
23831         s.each(function(r){
23832             if((i = ds.indexOfId(r.id)) != -1){
23833                 v.onRowSelect(i);
23834             }else{
23835                 s.remove(r);
23836             }
23837         });
23838     },
23839
23840     // private
23841     onRemove : function(v, index, r){
23842         this.selections.remove(r);
23843     },
23844
23845     // private
23846     onRowUpdated : function(v, index, r){
23847         if(this.isSelected(r)){
23848             v.onRowSelect(index);
23849         }
23850     },
23851
23852     /**
23853      * Select records.
23854      * @param {Array} records The records to select
23855      * @param {Boolean} keepExisting (optional) True to keep existing selections
23856      */
23857     selectRecords : function(records, keepExisting)
23858     {
23859         if(!keepExisting){
23860             this.clearSelections();
23861         }
23862             var ds = this.grid.store;
23863         for(var i = 0, len = records.length; i < len; i++){
23864             this.selectRow(ds.indexOf(records[i]), true);
23865         }
23866     },
23867
23868     /**
23869      * Gets the number of selected rows.
23870      * @return {Number}
23871      */
23872     getCount : function(){
23873         return this.selections.length;
23874     },
23875
23876     /**
23877      * Selects the first row in the grid.
23878      */
23879     selectFirstRow : function(){
23880         this.selectRow(0);
23881     },
23882
23883     /**
23884      * Select the last row.
23885      * @param {Boolean} keepExisting (optional) True to keep existing selections
23886      */
23887     selectLastRow : function(keepExisting){
23888         //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23889         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23890     },
23891
23892     /**
23893      * Selects the row immediately following the last selected row.
23894      * @param {Boolean} keepExisting (optional) True to keep existing selections
23895      */
23896     selectNext : function(keepExisting)
23897     {
23898             if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23899             this.selectRow(this.last+1, keepExisting);
23900             this.grid.getView().focusRow(this.last);
23901         }
23902     },
23903
23904     /**
23905      * Selects the row that precedes the last selected row.
23906      * @param {Boolean} keepExisting (optional) True to keep existing selections
23907      */
23908     selectPrevious : function(keepExisting){
23909         if(this.last){
23910             this.selectRow(this.last-1, keepExisting);
23911             this.grid.getView().focusRow(this.last);
23912         }
23913     },
23914
23915     /**
23916      * Returns the selected records
23917      * @return {Array} Array of selected records
23918      */
23919     getSelections : function(){
23920         return [].concat(this.selections.items);
23921     },
23922
23923     /**
23924      * Returns the first selected record.
23925      * @return {Record}
23926      */
23927     getSelected : function(){
23928         return this.selections.itemAt(0);
23929     },
23930
23931
23932     /**
23933      * Clears all selections.
23934      */
23935     clearSelections : function(fast)
23936     {
23937         if(this.locked) {
23938             return;
23939         }
23940         if(fast !== true){
23941                 var ds = this.grid.store;
23942             var s = this.selections;
23943             s.each(function(r){
23944                 this.deselectRow(ds.indexOfId(r.id));
23945             }, this);
23946             s.clear();
23947         }else{
23948             this.selections.clear();
23949         }
23950         this.last = false;
23951     },
23952
23953
23954     /**
23955      * Selects all rows.
23956      */
23957     selectAll : function(){
23958         if(this.locked) {
23959             return;
23960         }
23961         this.selections.clear();
23962         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23963             this.selectRow(i, true);
23964         }
23965     },
23966
23967     /**
23968      * Returns True if there is a selection.
23969      * @return {Boolean}
23970      */
23971     hasSelection : function(){
23972         return this.selections.length > 0;
23973     },
23974
23975     /**
23976      * Returns True if the specified row is selected.
23977      * @param {Number/Record} record The record or index of the record to check
23978      * @return {Boolean}
23979      */
23980     isSelected : function(index){
23981             var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23982         return (r && this.selections.key(r.id) ? true : false);
23983     },
23984
23985     /**
23986      * Returns True if the specified record id is selected.
23987      * @param {String} id The id of record to check
23988      * @return {Boolean}
23989      */
23990     isIdSelected : function(id){
23991         return (this.selections.key(id) ? true : false);
23992     },
23993
23994
23995     // private
23996     handleMouseDBClick : function(e, t){
23997         
23998     },
23999     // private
24000     handleMouseDown : function(e, t)
24001     {
24002             var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24003         if(this.isLocked() || rowIndex < 0 ){
24004             return;
24005         };
24006         if(e.shiftKey && this.last !== false){
24007             var last = this.last;
24008             this.selectRange(last, rowIndex, e.ctrlKey);
24009             this.last = last; // reset the last
24010             t.focus();
24011     
24012         }else{
24013             var isSelected = this.isSelected(rowIndex);
24014             //Roo.log("select row:" + rowIndex);
24015             if(isSelected){
24016                 this.deselectRow(rowIndex);
24017             } else {
24018                         this.selectRow(rowIndex, true);
24019             }
24020     
24021             /*
24022                 if(e.button !== 0 && isSelected){
24023                 alert('rowIndex 2: ' + rowIndex);
24024                     view.focusRow(rowIndex);
24025                 }else if(e.ctrlKey && isSelected){
24026                     this.deselectRow(rowIndex);
24027                 }else if(!isSelected){
24028                     this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24029                     view.focusRow(rowIndex);
24030                 }
24031             */
24032         }
24033         this.fireEvent("afterselectionchange", this);
24034     },
24035     // private
24036     handleDragableRowClick :  function(grid, rowIndex, e) 
24037     {
24038         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24039             this.selectRow(rowIndex, false);
24040             grid.view.focusRow(rowIndex);
24041              this.fireEvent("afterselectionchange", this);
24042         }
24043     },
24044     
24045     /**
24046      * Selects multiple rows.
24047      * @param {Array} rows Array of the indexes of the row to select
24048      * @param {Boolean} keepExisting (optional) True to keep existing selections
24049      */
24050     selectRows : function(rows, keepExisting){
24051         if(!keepExisting){
24052             this.clearSelections();
24053         }
24054         for(var i = 0, len = rows.length; i < len; i++){
24055             this.selectRow(rows[i], true);
24056         }
24057     },
24058
24059     /**
24060      * Selects a range of rows. All rows in between startRow and endRow are also selected.
24061      * @param {Number} startRow The index of the first row in the range
24062      * @param {Number} endRow The index of the last row in the range
24063      * @param {Boolean} keepExisting (optional) True to retain existing selections
24064      */
24065     selectRange : function(startRow, endRow, keepExisting){
24066         if(this.locked) {
24067             return;
24068         }
24069         if(!keepExisting){
24070             this.clearSelections();
24071         }
24072         if(startRow <= endRow){
24073             for(var i = startRow; i <= endRow; i++){
24074                 this.selectRow(i, true);
24075             }
24076         }else{
24077             for(var i = startRow; i >= endRow; i--){
24078                 this.selectRow(i, true);
24079             }
24080         }
24081     },
24082
24083     /**
24084      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24085      * @param {Number} startRow The index of the first row in the range
24086      * @param {Number} endRow The index of the last row in the range
24087      */
24088     deselectRange : function(startRow, endRow, preventViewNotify){
24089         if(this.locked) {
24090             return;
24091         }
24092         for(var i = startRow; i <= endRow; i++){
24093             this.deselectRow(i, preventViewNotify);
24094         }
24095     },
24096
24097     /**
24098      * Selects a row.
24099      * @param {Number} row The index of the row to select
24100      * @param {Boolean} keepExisting (optional) True to keep existing selections
24101      */
24102     selectRow : function(index, keepExisting, preventViewNotify)
24103     {
24104             if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24105             return;
24106         }
24107         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24108             if(!keepExisting || this.singleSelect){
24109                 this.clearSelections();
24110             }
24111             
24112             var r = this.grid.store.getAt(index);
24113             //console.log('selectRow - record id :' + r.id);
24114             
24115             this.selections.add(r);
24116             this.last = this.lastActive = index;
24117             if(!preventViewNotify){
24118                 var proxy = new Roo.Element(
24119                                 this.grid.getRowDom(index)
24120                 );
24121                 proxy.addClass('bg-info info');
24122             }
24123             this.fireEvent("rowselect", this, index, r);
24124             this.fireEvent("selectionchange", this);
24125         }
24126     },
24127
24128     /**
24129      * Deselects a row.
24130      * @param {Number} row The index of the row to deselect
24131      */
24132     deselectRow : function(index, preventViewNotify)
24133     {
24134         if(this.locked) {
24135             return;
24136         }
24137         if(this.last == index){
24138             this.last = false;
24139         }
24140         if(this.lastActive == index){
24141             this.lastActive = false;
24142         }
24143         
24144         var r = this.grid.store.getAt(index);
24145         if (!r) {
24146             return;
24147         }
24148         
24149         this.selections.remove(r);
24150         //.console.log('deselectRow - record id :' + r.id);
24151         if(!preventViewNotify){
24152         
24153             var proxy = new Roo.Element(
24154                 this.grid.getRowDom(index)
24155             );
24156             proxy.removeClass('bg-info info');
24157         }
24158         this.fireEvent("rowdeselect", this, index);
24159         this.fireEvent("selectionchange", this);
24160     },
24161
24162     // private
24163     restoreLast : function(){
24164         if(this._last){
24165             this.last = this._last;
24166         }
24167     },
24168
24169     // private
24170     acceptsNav : function(row, col, cm){
24171         return !cm.isHidden(col) && cm.isCellEditable(col, row);
24172     },
24173
24174     // private
24175     onEditorKey : function(field, e){
24176         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24177         if(k == e.TAB){
24178             e.stopEvent();
24179             ed.completeEdit();
24180             if(e.shiftKey){
24181                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24182             }else{
24183                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24184             }
24185         }else if(k == e.ENTER && !e.ctrlKey){
24186             e.stopEvent();
24187             ed.completeEdit();
24188             if(e.shiftKey){
24189                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24190             }else{
24191                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24192             }
24193         }else if(k == e.ESC){
24194             ed.cancelEdit();
24195         }
24196         if(newCell){
24197             g.startEditing(newCell[0], newCell[1]);
24198         }
24199     }
24200 });
24201 /*
24202  * Based on:
24203  * Ext JS Library 1.1.1
24204  * Copyright(c) 2006-2007, Ext JS, LLC.
24205  *
24206  * Originally Released Under LGPL - original licence link has changed is not relivant.
24207  *
24208  * Fork - LGPL
24209  * <script type="text/javascript">
24210  */
24211  
24212 /**
24213  * @class Roo.bootstrap.PagingToolbar
24214  * @extends Roo.bootstrap.NavSimplebar
24215  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24216  * @constructor
24217  * Create a new PagingToolbar
24218  * @param {Object} config The config object
24219  * @param {Roo.data.Store} store
24220  */
24221 Roo.bootstrap.PagingToolbar = function(config)
24222 {
24223     // old args format still supported... - xtype is prefered..
24224         // created from xtype...
24225     
24226     this.ds = config.dataSource;
24227     
24228     if (config.store && !this.ds) {
24229         this.store= Roo.factory(config.store, Roo.data);
24230         this.ds = this.store;
24231         this.ds.xmodule = this.xmodule || false;
24232     }
24233     
24234     this.toolbarItems = [];
24235     if (config.items) {
24236         this.toolbarItems = config.items;
24237     }
24238     
24239     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24240     
24241     this.cursor = 0;
24242     
24243     if (this.ds) { 
24244         this.bind(this.ds);
24245     }
24246     
24247     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24248     
24249 };
24250
24251 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24252     /**
24253      * @cfg {Roo.data.Store} dataSource
24254      * The underlying data store providing the paged data
24255      */
24256     /**
24257      * @cfg {String/HTMLElement/Element} container
24258      * container The id or element that will contain the toolbar
24259      */
24260     /**
24261      * @cfg {Boolean} displayInfo
24262      * True to display the displayMsg (defaults to false)
24263      */
24264     /**
24265      * @cfg {Number} pageSize
24266      * The number of records to display per page (defaults to 20)
24267      */
24268     pageSize: 20,
24269     /**
24270      * @cfg {String} displayMsg
24271      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24272      */
24273     displayMsg : 'Displaying {0} - {1} of {2}',
24274     /**
24275      * @cfg {String} emptyMsg
24276      * The message to display when no records are found (defaults to "No data to display")
24277      */
24278     emptyMsg : 'No data to display',
24279     /**
24280      * Customizable piece of the default paging text (defaults to "Page")
24281      * @type String
24282      */
24283     beforePageText : "Page",
24284     /**
24285      * Customizable piece of the default paging text (defaults to "of %0")
24286      * @type String
24287      */
24288     afterPageText : "of {0}",
24289     /**
24290      * Customizable piece of the default paging text (defaults to "First Page")
24291      * @type String
24292      */
24293     firstText : "First Page",
24294     /**
24295      * Customizable piece of the default paging text (defaults to "Previous Page")
24296      * @type String
24297      */
24298     prevText : "Previous Page",
24299     /**
24300      * Customizable piece of the default paging text (defaults to "Next Page")
24301      * @type String
24302      */
24303     nextText : "Next Page",
24304     /**
24305      * Customizable piece of the default paging text (defaults to "Last Page")
24306      * @type String
24307      */
24308     lastText : "Last Page",
24309     /**
24310      * Customizable piece of the default paging text (defaults to "Refresh")
24311      * @type String
24312      */
24313     refreshText : "Refresh",
24314
24315     buttons : false,
24316     // private
24317     onRender : function(ct, position) 
24318     {
24319         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24320         this.navgroup.parentId = this.id;
24321         this.navgroup.onRender(this.el, null);
24322         // add the buttons to the navgroup
24323         
24324         if(this.displayInfo){
24325             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24326             this.displayEl = this.el.select('.x-paging-info', true).first();
24327 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24328 //            this.displayEl = navel.el.select('span',true).first();
24329         }
24330         
24331         var _this = this;
24332         
24333         if(this.buttons){
24334             Roo.each(_this.buttons, function(e){ // this might need to use render????
24335                Roo.factory(e).onRender(_this.el, null);
24336             });
24337         }
24338             
24339         Roo.each(_this.toolbarItems, function(e) {
24340             _this.navgroup.addItem(e);
24341         });
24342         
24343         
24344         this.first = this.navgroup.addItem({
24345             tooltip: this.firstText,
24346             cls: "prev",
24347             icon : 'fa fa-backward',
24348             disabled: true,
24349             preventDefault: true,
24350             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24351         });
24352         
24353         this.prev =  this.navgroup.addItem({
24354             tooltip: this.prevText,
24355             cls: "prev",
24356             icon : 'fa fa-step-backward',
24357             disabled: true,
24358             preventDefault: true,
24359             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
24360         });
24361     //this.addSeparator();
24362         
24363         
24364         var field = this.navgroup.addItem( {
24365             tagtype : 'span',
24366             cls : 'x-paging-position',
24367             
24368             html : this.beforePageText  +
24369                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24370                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
24371          } ); //?? escaped?
24372         
24373         this.field = field.el.select('input', true).first();
24374         this.field.on("keydown", this.onPagingKeydown, this);
24375         this.field.on("focus", function(){this.dom.select();});
24376     
24377     
24378         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
24379         //this.field.setHeight(18);
24380         //this.addSeparator();
24381         this.next = this.navgroup.addItem({
24382             tooltip: this.nextText,
24383             cls: "next",
24384             html : ' <i class="fa fa-step-forward">',
24385             disabled: true,
24386             preventDefault: true,
24387             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
24388         });
24389         this.last = this.navgroup.addItem({
24390             tooltip: this.lastText,
24391             icon : 'fa fa-forward',
24392             cls: "next",
24393             disabled: true,
24394             preventDefault: true,
24395             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
24396         });
24397     //this.addSeparator();
24398         this.loading = this.navgroup.addItem({
24399             tooltip: this.refreshText,
24400             icon: 'fa fa-refresh',
24401             preventDefault: true,
24402             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24403         });
24404         
24405     },
24406
24407     // private
24408     updateInfo : function(){
24409         if(this.displayEl){
24410             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24411             var msg = count == 0 ?
24412                 this.emptyMsg :
24413                 String.format(
24414                     this.displayMsg,
24415                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
24416                 );
24417             this.displayEl.update(msg);
24418         }
24419     },
24420
24421     // private
24422     onLoad : function(ds, r, o)
24423     {
24424         this.cursor = o.params ? o.params.start : 0;
24425         var d = this.getPageData(),
24426             ap = d.activePage,
24427             ps = d.pages;
24428         
24429         
24430         this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24431         this.field.dom.value = ap;
24432         this.first.setDisabled(ap == 1);
24433         this.prev.setDisabled(ap == 1);
24434         this.next.setDisabled(ap == ps);
24435         this.last.setDisabled(ap == ps);
24436         this.loading.enable();
24437         this.updateInfo();
24438     },
24439
24440     // private
24441     getPageData : function(){
24442         var total = this.ds.getTotalCount();
24443         return {
24444             total : total,
24445             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24446             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24447         };
24448     },
24449
24450     // private
24451     onLoadError : function(){
24452         this.loading.enable();
24453     },
24454
24455     // private
24456     onPagingKeydown : function(e){
24457         var k = e.getKey();
24458         var d = this.getPageData();
24459         if(k == e.RETURN){
24460             var v = this.field.dom.value, pageNum;
24461             if(!v || isNaN(pageNum = parseInt(v, 10))){
24462                 this.field.dom.value = d.activePage;
24463                 return;
24464             }
24465             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24466             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24467             e.stopEvent();
24468         }
24469         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))
24470         {
24471           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24472           this.field.dom.value = pageNum;
24473           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24474           e.stopEvent();
24475         }
24476         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24477         {
24478           var v = this.field.dom.value, pageNum; 
24479           var increment = (e.shiftKey) ? 10 : 1;
24480           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24481                 increment *= -1;
24482           }
24483           if(!v || isNaN(pageNum = parseInt(v, 10))) {
24484             this.field.dom.value = d.activePage;
24485             return;
24486           }
24487           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24488           {
24489             this.field.dom.value = parseInt(v, 10) + increment;
24490             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24491             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24492           }
24493           e.stopEvent();
24494         }
24495     },
24496
24497     // private
24498     beforeLoad : function(){
24499         if(this.loading){
24500             this.loading.disable();
24501         }
24502     },
24503
24504     // private
24505     onClick : function(which){
24506         
24507         var ds = this.ds;
24508         if (!ds) {
24509             return;
24510         }
24511         
24512         switch(which){
24513             case "first":
24514                 ds.load({params:{start: 0, limit: this.pageSize}});
24515             break;
24516             case "prev":
24517                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24518             break;
24519             case "next":
24520                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24521             break;
24522             case "last":
24523                 var total = ds.getTotalCount();
24524                 var extra = total % this.pageSize;
24525                 var lastStart = extra ? (total - extra) : total-this.pageSize;
24526                 ds.load({params:{start: lastStart, limit: this.pageSize}});
24527             break;
24528             case "refresh":
24529                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24530             break;
24531         }
24532     },
24533
24534     /**
24535      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24536      * @param {Roo.data.Store} store The data store to unbind
24537      */
24538     unbind : function(ds){
24539         ds.un("beforeload", this.beforeLoad, this);
24540         ds.un("load", this.onLoad, this);
24541         ds.un("loadexception", this.onLoadError, this);
24542         ds.un("remove", this.updateInfo, this);
24543         ds.un("add", this.updateInfo, this);
24544         this.ds = undefined;
24545     },
24546
24547     /**
24548      * Binds the paging toolbar to the specified {@link Roo.data.Store}
24549      * @param {Roo.data.Store} store The data store to bind
24550      */
24551     bind : function(ds){
24552         ds.on("beforeload", this.beforeLoad, this);
24553         ds.on("load", this.onLoad, this);
24554         ds.on("loadexception", this.onLoadError, this);
24555         ds.on("remove", this.updateInfo, this);
24556         ds.on("add", this.updateInfo, this);
24557         this.ds = ds;
24558     }
24559 });/*
24560  * - LGPL
24561  *
24562  * element
24563  * 
24564  */
24565
24566 /**
24567  * @class Roo.bootstrap.MessageBar
24568  * @extends Roo.bootstrap.Component
24569  * Bootstrap MessageBar class
24570  * @cfg {String} html contents of the MessageBar
24571  * @cfg {String} weight (info | success | warning | danger) default info
24572  * @cfg {String} beforeClass insert the bar before the given class
24573  * @cfg {Boolean} closable (true | false) default false
24574  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24575  * 
24576  * @constructor
24577  * Create a new Element
24578  * @param {Object} config The config object
24579  */
24580
24581 Roo.bootstrap.MessageBar = function(config){
24582     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24583 };
24584
24585 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
24586     
24587     html: '',
24588     weight: 'info',
24589     closable: false,
24590     fixed: false,
24591     beforeClass: 'bootstrap-sticky-wrap',
24592     
24593     getAutoCreate : function(){
24594         
24595         var cfg = {
24596             tag: 'div',
24597             cls: 'alert alert-dismissable alert-' + this.weight,
24598             cn: [
24599                 {
24600                     tag: 'span',
24601                     cls: 'message',
24602                     html: this.html || ''
24603                 }
24604             ]
24605         };
24606         
24607         if(this.fixed){
24608             cfg.cls += ' alert-messages-fixed';
24609         }
24610         
24611         if(this.closable){
24612             cfg.cn.push({
24613                 tag: 'button',
24614                 cls: 'close',
24615                 html: 'x'
24616             });
24617         }
24618         
24619         return cfg;
24620     },
24621     
24622     onRender : function(ct, position)
24623     {
24624         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24625         
24626         if(!this.el){
24627             var cfg = Roo.apply({},  this.getAutoCreate());
24628             cfg.id = Roo.id();
24629             
24630             if (this.cls) {
24631                 cfg.cls += ' ' + this.cls;
24632             }
24633             if (this.style) {
24634                 cfg.style = this.style;
24635             }
24636             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24637             
24638             this.el.setVisibilityMode(Roo.Element.DISPLAY);
24639         }
24640         
24641         this.el.select('>button.close').on('click', this.hide, this);
24642         
24643     },
24644     
24645     show : function()
24646     {
24647         if (!this.rendered) {
24648             this.render();
24649         }
24650         
24651         this.el.show();
24652         
24653         this.fireEvent('show', this);
24654         
24655     },
24656     
24657     hide : function()
24658     {
24659         if (!this.rendered) {
24660             this.render();
24661         }
24662         
24663         this.el.hide();
24664         
24665         this.fireEvent('hide', this);
24666     },
24667     
24668     update : function()
24669     {
24670 //        var e = this.el.dom.firstChild;
24671 //        
24672 //        if(this.closable){
24673 //            e = e.nextSibling;
24674 //        }
24675 //        
24676 //        e.data = this.html || '';
24677
24678         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24679     }
24680    
24681 });
24682
24683  
24684
24685      /*
24686  * - LGPL
24687  *
24688  * Graph
24689  * 
24690  */
24691
24692
24693 /**
24694  * @class Roo.bootstrap.Graph
24695  * @extends Roo.bootstrap.Component
24696  * Bootstrap Graph class
24697 > Prameters
24698  -sm {number} sm 4
24699  -md {number} md 5
24700  @cfg {String} graphtype  bar | vbar | pie
24701  @cfg {number} g_x coodinator | centre x (pie)
24702  @cfg {number} g_y coodinator | centre y (pie)
24703  @cfg {number} g_r radius (pie)
24704  @cfg {number} g_height height of the chart (respected by all elements in the set)
24705  @cfg {number} g_width width of the chart (respected by all elements in the set)
24706  @cfg {Object} title The title of the chart
24707     
24708  -{Array}  values
24709  -opts (object) options for the chart 
24710      o {
24711      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24712      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24713      o vgutter (number)
24714      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.
24715      o stacked (boolean) whether or not to tread values as in a stacked bar chart
24716      o to
24717      o stretch (boolean)
24718      o }
24719  -opts (object) options for the pie
24720      o{
24721      o cut
24722      o startAngle (number)
24723      o endAngle (number)
24724      } 
24725  *
24726  * @constructor
24727  * Create a new Input
24728  * @param {Object} config The config object
24729  */
24730
24731 Roo.bootstrap.Graph = function(config){
24732     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24733     
24734     this.addEvents({
24735         // img events
24736         /**
24737          * @event click
24738          * The img click event for the img.
24739          * @param {Roo.EventObject} e
24740          */
24741         "click" : true
24742     });
24743 };
24744
24745 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
24746     
24747     sm: 4,
24748     md: 5,
24749     graphtype: 'bar',
24750     g_height: 250,
24751     g_width: 400,
24752     g_x: 50,
24753     g_y: 50,
24754     g_r: 30,
24755     opts:{
24756         //g_colors: this.colors,
24757         g_type: 'soft',
24758         g_gutter: '20%'
24759
24760     },
24761     title : false,
24762
24763     getAutoCreate : function(){
24764         
24765         var cfg = {
24766             tag: 'div',
24767             html : null
24768         };
24769         
24770         
24771         return  cfg;
24772     },
24773
24774     onRender : function(ct,position){
24775         
24776         
24777         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24778         
24779         if (typeof(Raphael) == 'undefined') {
24780             Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24781             return;
24782         }
24783         
24784         this.raphael = Raphael(this.el.dom);
24785         
24786                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24787                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24788                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24789                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24790                 /*
24791                 r.text(160, 10, "Single Series Chart").attr(txtattr);
24792                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24793                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24794                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24795                 
24796                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24797                 r.barchart(330, 10, 300, 220, data1);
24798                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24799                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24800                 */
24801                 
24802                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24803                 // r.barchart(30, 30, 560, 250,  xdata, {
24804                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24805                 //     axis : "0 0 1 1",
24806                 //     axisxlabels :  xdata
24807                 //     //yvalues : cols,
24808                    
24809                 // });
24810 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24811 //        
24812 //        this.load(null,xdata,{
24813 //                axis : "0 0 1 1",
24814 //                axisxlabels :  xdata
24815 //                });
24816
24817     },
24818
24819     load : function(graphtype,xdata,opts)
24820     {
24821         this.raphael.clear();
24822         if(!graphtype) {
24823             graphtype = this.graphtype;
24824         }
24825         if(!opts){
24826             opts = this.opts;
24827         }
24828         var r = this.raphael,
24829             fin = function () {
24830                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24831             },
24832             fout = function () {
24833                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24834             },
24835             pfin = function() {
24836                 this.sector.stop();
24837                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24838
24839                 if (this.label) {
24840                     this.label[0].stop();
24841                     this.label[0].attr({ r: 7.5 });
24842                     this.label[1].attr({ "font-weight": 800 });
24843                 }
24844             },
24845             pfout = function() {
24846                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24847
24848                 if (this.label) {
24849                     this.label[0].animate({ r: 5 }, 500, "bounce");
24850                     this.label[1].attr({ "font-weight": 400 });
24851                 }
24852             };
24853
24854         switch(graphtype){
24855             case 'bar':
24856                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24857                 break;
24858             case 'hbar':
24859                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24860                 break;
24861             case 'pie':
24862 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
24863 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24864 //            
24865                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24866                 
24867                 break;
24868
24869         }
24870         
24871         if(this.title){
24872             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24873         }
24874         
24875     },
24876     
24877     setTitle: function(o)
24878     {
24879         this.title = o;
24880     },
24881     
24882     initEvents: function() {
24883         
24884         if(!this.href){
24885             this.el.on('click', this.onClick, this);
24886         }
24887     },
24888     
24889     onClick : function(e)
24890     {
24891         Roo.log('img onclick');
24892         this.fireEvent('click', this, e);
24893     }
24894    
24895 });
24896
24897  
24898 /*
24899  * - LGPL
24900  *
24901  * numberBox
24902  * 
24903  */
24904 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24905
24906 /**
24907  * @class Roo.bootstrap.dash.NumberBox
24908  * @extends Roo.bootstrap.Component
24909  * Bootstrap NumberBox class
24910  * @cfg {String} headline Box headline
24911  * @cfg {String} content Box content
24912  * @cfg {String} icon Box icon
24913  * @cfg {String} footer Footer text
24914  * @cfg {String} fhref Footer href
24915  * 
24916  * @constructor
24917  * Create a new NumberBox
24918  * @param {Object} config The config object
24919  */
24920
24921
24922 Roo.bootstrap.dash.NumberBox = function(config){
24923     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24924     
24925 };
24926
24927 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
24928     
24929     headline : '',
24930     content : '',
24931     icon : '',
24932     footer : '',
24933     fhref : '',
24934     ficon : '',
24935     
24936     getAutoCreate : function(){
24937         
24938         var cfg = {
24939             tag : 'div',
24940             cls : 'small-box ',
24941             cn : [
24942                 {
24943                     tag : 'div',
24944                     cls : 'inner',
24945                     cn :[
24946                         {
24947                             tag : 'h3',
24948                             cls : 'roo-headline',
24949                             html : this.headline
24950                         },
24951                         {
24952                             tag : 'p',
24953                             cls : 'roo-content',
24954                             html : this.content
24955                         }
24956                     ]
24957                 }
24958             ]
24959         };
24960         
24961         if(this.icon){
24962             cfg.cn.push({
24963                 tag : 'div',
24964                 cls : 'icon',
24965                 cn :[
24966                     {
24967                         tag : 'i',
24968                         cls : 'ion ' + this.icon
24969                     }
24970                 ]
24971             });
24972         }
24973         
24974         if(this.footer){
24975             var footer = {
24976                 tag : 'a',
24977                 cls : 'small-box-footer',
24978                 href : this.fhref || '#',
24979                 html : this.footer
24980             };
24981             
24982             cfg.cn.push(footer);
24983             
24984         }
24985         
24986         return  cfg;
24987     },
24988
24989     onRender : function(ct,position){
24990         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24991
24992
24993        
24994                 
24995     },
24996
24997     setHeadline: function (value)
24998     {
24999         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25000     },
25001     
25002     setFooter: function (value, href)
25003     {
25004         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25005         
25006         if(href){
25007             this.el.select('a.small-box-footer',true).first().attr('href', href);
25008         }
25009         
25010     },
25011
25012     setContent: function (value)
25013     {
25014         this.el.select('.roo-content',true).first().dom.innerHTML = value;
25015     },
25016
25017     initEvents: function() 
25018     {   
25019         
25020     }
25021     
25022 });
25023
25024  
25025 /*
25026  * - LGPL
25027  *
25028  * TabBox
25029  * 
25030  */
25031 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25032
25033 /**
25034  * @class Roo.bootstrap.dash.TabBox
25035  * @extends Roo.bootstrap.Component
25036  * Bootstrap TabBox class
25037  * @cfg {String} title Title of the TabBox
25038  * @cfg {String} icon Icon of the TabBox
25039  * @cfg {Boolean} showtabs (true|false) show the tabs default true
25040  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25041  * 
25042  * @constructor
25043  * Create a new TabBox
25044  * @param {Object} config The config object
25045  */
25046
25047
25048 Roo.bootstrap.dash.TabBox = function(config){
25049     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25050     this.addEvents({
25051         // raw events
25052         /**
25053          * @event addpane
25054          * When a pane is added
25055          * @param {Roo.bootstrap.dash.TabPane} pane
25056          */
25057         "addpane" : true,
25058         /**
25059          * @event activatepane
25060          * When a pane is activated
25061          * @param {Roo.bootstrap.dash.TabPane} pane
25062          */
25063         "activatepane" : true
25064         
25065          
25066     });
25067     
25068     this.panes = [];
25069 };
25070
25071 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
25072
25073     title : '',
25074     icon : false,
25075     showtabs : true,
25076     tabScrollable : false,
25077     
25078     getChildContainer : function()
25079     {
25080         return this.el.select('.tab-content', true).first();
25081     },
25082     
25083     getAutoCreate : function(){
25084         
25085         var header = {
25086             tag: 'li',
25087             cls: 'pull-left header',
25088             html: this.title,
25089             cn : []
25090         };
25091         
25092         if(this.icon){
25093             header.cn.push({
25094                 tag: 'i',
25095                 cls: 'fa ' + this.icon
25096             });
25097         }
25098         
25099         var h = {
25100             tag: 'ul',
25101             cls: 'nav nav-tabs pull-right',
25102             cn: [
25103                 header
25104             ]
25105         };
25106         
25107         if(this.tabScrollable){
25108             h = {
25109                 tag: 'div',
25110                 cls: 'tab-header',
25111                 cn: [
25112                     {
25113                         tag: 'ul',
25114                         cls: 'nav nav-tabs pull-right',
25115                         cn: [
25116                             header
25117                         ]
25118                     }
25119                 ]
25120             };
25121         }
25122         
25123         var cfg = {
25124             tag: 'div',
25125             cls: 'nav-tabs-custom',
25126             cn: [
25127                 h,
25128                 {
25129                     tag: 'div',
25130                     cls: 'tab-content no-padding',
25131                     cn: []
25132                 }
25133             ]
25134         };
25135
25136         return  cfg;
25137     },
25138     initEvents : function()
25139     {
25140         //Roo.log('add add pane handler');
25141         this.on('addpane', this.onAddPane, this);
25142     },
25143      /**
25144      * Updates the box title
25145      * @param {String} html to set the title to.
25146      */
25147     setTitle : function(value)
25148     {
25149         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25150     },
25151     onAddPane : function(pane)
25152     {
25153         this.panes.push(pane);
25154         //Roo.log('addpane');
25155         //Roo.log(pane);
25156         // tabs are rendere left to right..
25157         if(!this.showtabs){
25158             return;
25159         }
25160         
25161         var ctr = this.el.select('.nav-tabs', true).first();
25162          
25163          
25164         var existing = ctr.select('.nav-tab',true);
25165         var qty = existing.getCount();;
25166         
25167         
25168         var tab = ctr.createChild({
25169             tag : 'li',
25170             cls : 'nav-tab' + (qty ? '' : ' active'),
25171             cn : [
25172                 {
25173                     tag : 'a',
25174                     href:'#',
25175                     html : pane.title
25176                 }
25177             ]
25178         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25179         pane.tab = tab;
25180         
25181         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25182         if (!qty) {
25183             pane.el.addClass('active');
25184         }
25185         
25186                 
25187     },
25188     onTabClick : function(ev,un,ob,pane)
25189     {
25190         //Roo.log('tab - prev default');
25191         ev.preventDefault();
25192         
25193         
25194         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25195         pane.tab.addClass('active');
25196         //Roo.log(pane.title);
25197         this.getChildContainer().select('.tab-pane',true).removeClass('active');
25198         // technically we should have a deactivate event.. but maybe add later.
25199         // and it should not de-activate the selected tab...
25200         this.fireEvent('activatepane', pane);
25201         pane.el.addClass('active');
25202         pane.fireEvent('activate');
25203         
25204         
25205     },
25206     
25207     getActivePane : function()
25208     {
25209         var r = false;
25210         Roo.each(this.panes, function(p) {
25211             if(p.el.hasClass('active')){
25212                 r = p;
25213                 return false;
25214             }
25215             
25216             return;
25217         });
25218         
25219         return r;
25220     }
25221     
25222     
25223 });
25224
25225  
25226 /*
25227  * - LGPL
25228  *
25229  * Tab pane
25230  * 
25231  */
25232 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25233 /**
25234  * @class Roo.bootstrap.TabPane
25235  * @extends Roo.bootstrap.Component
25236  * Bootstrap TabPane class
25237  * @cfg {Boolean} active (false | true) Default false
25238  * @cfg {String} title title of panel
25239
25240  * 
25241  * @constructor
25242  * Create a new TabPane
25243  * @param {Object} config The config object
25244  */
25245
25246 Roo.bootstrap.dash.TabPane = function(config){
25247     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25248     
25249     this.addEvents({
25250         // raw events
25251         /**
25252          * @event activate
25253          * When a pane is activated
25254          * @param {Roo.bootstrap.dash.TabPane} pane
25255          */
25256         "activate" : true
25257          
25258     });
25259 };
25260
25261 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
25262     
25263     active : false,
25264     title : '',
25265     
25266     // the tabBox that this is attached to.
25267     tab : false,
25268      
25269     getAutoCreate : function() 
25270     {
25271         var cfg = {
25272             tag: 'div',
25273             cls: 'tab-pane'
25274         };
25275         
25276         if(this.active){
25277             cfg.cls += ' active';
25278         }
25279         
25280         return cfg;
25281     },
25282     initEvents  : function()
25283     {
25284         //Roo.log('trigger add pane handler');
25285         this.parent().fireEvent('addpane', this)
25286     },
25287     
25288      /**
25289      * Updates the tab title 
25290      * @param {String} html to set the title to.
25291      */
25292     setTitle: function(str)
25293     {
25294         if (!this.tab) {
25295             return;
25296         }
25297         this.title = str;
25298         this.tab.select('a', true).first().dom.innerHTML = str;
25299         
25300     }
25301     
25302     
25303     
25304 });
25305
25306  
25307
25308
25309  /*
25310  * - LGPL
25311  *
25312  * menu
25313  * 
25314  */
25315 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25316
25317 /**
25318  * @class Roo.bootstrap.menu.Menu
25319  * @extends Roo.bootstrap.Component
25320  * Bootstrap Menu class - container for Menu
25321  * @cfg {String} html Text of the menu
25322  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25323  * @cfg {String} icon Font awesome icon
25324  * @cfg {String} pos Menu align to (top | bottom) default bottom
25325  * 
25326  * 
25327  * @constructor
25328  * Create a new Menu
25329  * @param {Object} config The config object
25330  */
25331
25332
25333 Roo.bootstrap.menu.Menu = function(config){
25334     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25335     
25336     this.addEvents({
25337         /**
25338          * @event beforeshow
25339          * Fires before this menu is displayed
25340          * @param {Roo.bootstrap.menu.Menu} this
25341          */
25342         beforeshow : true,
25343         /**
25344          * @event beforehide
25345          * Fires before this menu is hidden
25346          * @param {Roo.bootstrap.menu.Menu} this
25347          */
25348         beforehide : true,
25349         /**
25350          * @event show
25351          * Fires after this menu is displayed
25352          * @param {Roo.bootstrap.menu.Menu} this
25353          */
25354         show : true,
25355         /**
25356          * @event hide
25357          * Fires after this menu is hidden
25358          * @param {Roo.bootstrap.menu.Menu} this
25359          */
25360         hide : true,
25361         /**
25362          * @event click
25363          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25364          * @param {Roo.bootstrap.menu.Menu} this
25365          * @param {Roo.EventObject} e
25366          */
25367         click : true
25368     });
25369     
25370 };
25371
25372 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
25373     
25374     submenu : false,
25375     html : '',
25376     weight : 'default',
25377     icon : false,
25378     pos : 'bottom',
25379     
25380     
25381     getChildContainer : function() {
25382         if(this.isSubMenu){
25383             return this.el;
25384         }
25385         
25386         return this.el.select('ul.dropdown-menu', true).first();  
25387     },
25388     
25389     getAutoCreate : function()
25390     {
25391         var text = [
25392             {
25393                 tag : 'span',
25394                 cls : 'roo-menu-text',
25395                 html : this.html
25396             }
25397         ];
25398         
25399         if(this.icon){
25400             text.unshift({
25401                 tag : 'i',
25402                 cls : 'fa ' + this.icon
25403             })
25404         }
25405         
25406         
25407         var cfg = {
25408             tag : 'div',
25409             cls : 'btn-group',
25410             cn : [
25411                 {
25412                     tag : 'button',
25413                     cls : 'dropdown-button btn btn-' + this.weight,
25414                     cn : text
25415                 },
25416                 {
25417                     tag : 'button',
25418                     cls : 'dropdown-toggle btn btn-' + this.weight,
25419                     cn : [
25420                         {
25421                             tag : 'span',
25422                             cls : 'caret'
25423                         }
25424                     ]
25425                 },
25426                 {
25427                     tag : 'ul',
25428                     cls : 'dropdown-menu'
25429                 }
25430             ]
25431             
25432         };
25433         
25434         if(this.pos == 'top'){
25435             cfg.cls += ' dropup';
25436         }
25437         
25438         if(this.isSubMenu){
25439             cfg = {
25440                 tag : 'ul',
25441                 cls : 'dropdown-menu'
25442             }
25443         }
25444         
25445         return cfg;
25446     },
25447     
25448     onRender : function(ct, position)
25449     {
25450         this.isSubMenu = ct.hasClass('dropdown-submenu');
25451         
25452         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25453     },
25454     
25455     initEvents : function() 
25456     {
25457         if(this.isSubMenu){
25458             return;
25459         }
25460         
25461         this.hidden = true;
25462         
25463         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25464         this.triggerEl.on('click', this.onTriggerPress, this);
25465         
25466         this.buttonEl = this.el.select('button.dropdown-button', true).first();
25467         this.buttonEl.on('click', this.onClick, this);
25468         
25469     },
25470     
25471     list : function()
25472     {
25473         if(this.isSubMenu){
25474             return this.el;
25475         }
25476         
25477         return this.el.select('ul.dropdown-menu', true).first();
25478     },
25479     
25480     onClick : function(e)
25481     {
25482         this.fireEvent("click", this, e);
25483     },
25484     
25485     onTriggerPress  : function(e)
25486     {   
25487         if (this.isVisible()) {
25488             this.hide();
25489         } else {
25490             this.show();
25491         }
25492     },
25493     
25494     isVisible : function(){
25495         return !this.hidden;
25496     },
25497     
25498     show : function()
25499     {
25500         this.fireEvent("beforeshow", this);
25501         
25502         this.hidden = false;
25503         this.el.addClass('open');
25504         
25505         Roo.get(document).on("mouseup", this.onMouseUp, this);
25506         
25507         this.fireEvent("show", this);
25508         
25509         
25510     },
25511     
25512     hide : function()
25513     {
25514         this.fireEvent("beforehide", this);
25515         
25516         this.hidden = true;
25517         this.el.removeClass('open');
25518         
25519         Roo.get(document).un("mouseup", this.onMouseUp);
25520         
25521         this.fireEvent("hide", this);
25522     },
25523     
25524     onMouseUp : function()
25525     {
25526         this.hide();
25527     }
25528     
25529 });
25530
25531  
25532  /*
25533  * - LGPL
25534  *
25535  * menu item
25536  * 
25537  */
25538 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25539
25540 /**
25541  * @class Roo.bootstrap.menu.Item
25542  * @extends Roo.bootstrap.Component
25543  * Bootstrap MenuItem class
25544  * @cfg {Boolean} submenu (true | false) default false
25545  * @cfg {String} html text of the item
25546  * @cfg {String} href the link
25547  * @cfg {Boolean} disable (true | false) default false
25548  * @cfg {Boolean} preventDefault (true | false) default true
25549  * @cfg {String} icon Font awesome icon
25550  * @cfg {String} pos Submenu align to (left | right) default right 
25551  * 
25552  * 
25553  * @constructor
25554  * Create a new Item
25555  * @param {Object} config The config object
25556  */
25557
25558
25559 Roo.bootstrap.menu.Item = function(config){
25560     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25561     this.addEvents({
25562         /**
25563          * @event mouseover
25564          * Fires when the mouse is hovering over this menu
25565          * @param {Roo.bootstrap.menu.Item} this
25566          * @param {Roo.EventObject} e
25567          */
25568         mouseover : true,
25569         /**
25570          * @event mouseout
25571          * Fires when the mouse exits this menu
25572          * @param {Roo.bootstrap.menu.Item} this
25573          * @param {Roo.EventObject} e
25574          */
25575         mouseout : true,
25576         // raw events
25577         /**
25578          * @event click
25579          * The raw click event for the entire grid.
25580          * @param {Roo.EventObject} e
25581          */
25582         click : true
25583     });
25584 };
25585
25586 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
25587     
25588     submenu : false,
25589     href : '',
25590     html : '',
25591     preventDefault: true,
25592     disable : false,
25593     icon : false,
25594     pos : 'right',
25595     
25596     getAutoCreate : function()
25597     {
25598         var text = [
25599             {
25600                 tag : 'span',
25601                 cls : 'roo-menu-item-text',
25602                 html : this.html
25603             }
25604         ];
25605         
25606         if(this.icon){
25607             text.unshift({
25608                 tag : 'i',
25609                 cls : 'fa ' + this.icon
25610             })
25611         }
25612         
25613         var cfg = {
25614             tag : 'li',
25615             cn : [
25616                 {
25617                     tag : 'a',
25618                     href : this.href || '#',
25619                     cn : text
25620                 }
25621             ]
25622         };
25623         
25624         if(this.disable){
25625             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25626         }
25627         
25628         if(this.submenu){
25629             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25630             
25631             if(this.pos == 'left'){
25632                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25633             }
25634         }
25635         
25636         return cfg;
25637     },
25638     
25639     initEvents : function() 
25640     {
25641         this.el.on('mouseover', this.onMouseOver, this);
25642         this.el.on('mouseout', this.onMouseOut, this);
25643         
25644         this.el.select('a', true).first().on('click', this.onClick, this);
25645         
25646     },
25647     
25648     onClick : function(e)
25649     {
25650         if(this.preventDefault){
25651             e.preventDefault();
25652         }
25653         
25654         this.fireEvent("click", this, e);
25655     },
25656     
25657     onMouseOver : function(e)
25658     {
25659         if(this.submenu && this.pos == 'left'){
25660             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25661         }
25662         
25663         this.fireEvent("mouseover", this, e);
25664     },
25665     
25666     onMouseOut : function(e)
25667     {
25668         this.fireEvent("mouseout", this, e);
25669     }
25670 });
25671
25672  
25673
25674  /*
25675  * - LGPL
25676  *
25677  * menu separator
25678  * 
25679  */
25680 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25681
25682 /**
25683  * @class Roo.bootstrap.menu.Separator
25684  * @extends Roo.bootstrap.Component
25685  * Bootstrap Separator class
25686  * 
25687  * @constructor
25688  * Create a new Separator
25689  * @param {Object} config The config object
25690  */
25691
25692
25693 Roo.bootstrap.menu.Separator = function(config){
25694     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25695 };
25696
25697 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
25698     
25699     getAutoCreate : function(){
25700         var cfg = {
25701             tag : 'li',
25702             cls: 'divider'
25703         };
25704         
25705         return cfg;
25706     }
25707    
25708 });
25709
25710  
25711
25712  /*
25713  * - LGPL
25714  *
25715  * Tooltip
25716  * 
25717  */
25718
25719 /**
25720  * @class Roo.bootstrap.Tooltip
25721  * Bootstrap Tooltip class
25722  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25723  * to determine which dom element triggers the tooltip.
25724  * 
25725  * It needs to add support for additional attributes like tooltip-position
25726  * 
25727  * @constructor
25728  * Create a new Toolti
25729  * @param {Object} config The config object
25730  */
25731
25732 Roo.bootstrap.Tooltip = function(config){
25733     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25734     
25735     this.alignment = Roo.bootstrap.Tooltip.alignment;
25736     
25737     if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25738         this.alignment = config.alignment;
25739     }
25740     
25741 };
25742
25743 Roo.apply(Roo.bootstrap.Tooltip, {
25744     /**
25745      * @function init initialize tooltip monitoring.
25746      * @static
25747      */
25748     currentEl : false,
25749     currentTip : false,
25750     currentRegion : false,
25751     
25752     //  init : delay?
25753     
25754     init : function()
25755     {
25756         Roo.get(document).on('mouseover', this.enter ,this);
25757         Roo.get(document).on('mouseout', this.leave, this);
25758          
25759         
25760         this.currentTip = new Roo.bootstrap.Tooltip();
25761     },
25762     
25763     enter : function(ev)
25764     {
25765         var dom = ev.getTarget();
25766         
25767         //Roo.log(['enter',dom]);
25768         var el = Roo.fly(dom);
25769         if (this.currentEl) {
25770             //Roo.log(dom);
25771             //Roo.log(this.currentEl);
25772             //Roo.log(this.currentEl.contains(dom));
25773             if (this.currentEl == el) {
25774                 return;
25775             }
25776             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25777                 return;
25778             }
25779
25780         }
25781         
25782         if (this.currentTip.el) {
25783             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25784         }    
25785         //Roo.log(ev);
25786         
25787         if(!el || el.dom == document){
25788             return;
25789         }
25790         
25791         var bindEl = el;
25792         
25793         // you can not look for children, as if el is the body.. then everythign is the child..
25794         if (!el.attr('tooltip')) { //
25795             if (!el.select("[tooltip]").elements.length) {
25796                 return;
25797             }
25798             // is the mouse over this child...?
25799             bindEl = el.select("[tooltip]").first();
25800             var xy = ev.getXY();
25801             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25802                 //Roo.log("not in region.");
25803                 return;
25804             }
25805             //Roo.log("child element over..");
25806             
25807         }
25808         this.currentEl = bindEl;
25809         this.currentTip.bind(bindEl);
25810         this.currentRegion = Roo.lib.Region.getRegion(dom);
25811         this.currentTip.enter();
25812         
25813     },
25814     leave : function(ev)
25815     {
25816         var dom = ev.getTarget();
25817         //Roo.log(['leave',dom]);
25818         if (!this.currentEl) {
25819             return;
25820         }
25821         
25822         
25823         if (dom != this.currentEl.dom) {
25824             return;
25825         }
25826         var xy = ev.getXY();
25827         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
25828             return;
25829         }
25830         // only activate leave if mouse cursor is outside... bounding box..
25831         
25832         
25833         
25834         
25835         if (this.currentTip) {
25836             this.currentTip.leave();
25837         }
25838         //Roo.log('clear currentEl');
25839         this.currentEl = false;
25840         
25841         
25842     },
25843     alignment : {
25844         'left' : ['r-l', [-2,0], 'right'],
25845         'right' : ['l-r', [2,0], 'left'],
25846         'bottom' : ['t-b', [0,2], 'top'],
25847         'top' : [ 'b-t', [0,-2], 'bottom']
25848     }
25849     
25850 });
25851
25852
25853 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
25854     
25855     
25856     bindEl : false,
25857     
25858     delay : null, // can be { show : 300 , hide: 500}
25859     
25860     timeout : null,
25861     
25862     hoverState : null, //???
25863     
25864     placement : 'bottom', 
25865     
25866     alignment : false,
25867     
25868     getAutoCreate : function(){
25869     
25870         var cfg = {
25871            cls : 'tooltip',
25872            role : 'tooltip',
25873            cn : [
25874                 {
25875                     cls : 'tooltip-arrow'
25876                 },
25877                 {
25878                     cls : 'tooltip-inner'
25879                 }
25880            ]
25881         };
25882         
25883         return cfg;
25884     },
25885     bind : function(el)
25886     {
25887         this.bindEl = el;
25888     },
25889       
25890     
25891     enter : function () {
25892        
25893         if (this.timeout != null) {
25894             clearTimeout(this.timeout);
25895         }
25896         
25897         this.hoverState = 'in';
25898          //Roo.log("enter - show");
25899         if (!this.delay || !this.delay.show) {
25900             this.show();
25901             return;
25902         }
25903         var _t = this;
25904         this.timeout = setTimeout(function () {
25905             if (_t.hoverState == 'in') {
25906                 _t.show();
25907             }
25908         }, this.delay.show);
25909     },
25910     leave : function()
25911     {
25912         clearTimeout(this.timeout);
25913     
25914         this.hoverState = 'out';
25915          if (!this.delay || !this.delay.hide) {
25916             this.hide();
25917             return;
25918         }
25919        
25920         var _t = this;
25921         this.timeout = setTimeout(function () {
25922             //Roo.log("leave - timeout");
25923             
25924             if (_t.hoverState == 'out') {
25925                 _t.hide();
25926                 Roo.bootstrap.Tooltip.currentEl = false;
25927             }
25928         }, delay);
25929     },
25930     
25931     show : function (msg)
25932     {
25933         if (!this.el) {
25934             this.render(document.body);
25935         }
25936         // set content.
25937         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25938         
25939         var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25940         
25941         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25942         
25943         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25944         
25945         var placement = typeof this.placement == 'function' ?
25946             this.placement.call(this, this.el, on_el) :
25947             this.placement;
25948             
25949         var autoToken = /\s?auto?\s?/i;
25950         var autoPlace = autoToken.test(placement);
25951         if (autoPlace) {
25952             placement = placement.replace(autoToken, '') || 'top';
25953         }
25954         
25955         //this.el.detach()
25956         //this.el.setXY([0,0]);
25957         this.el.show();
25958         //this.el.dom.style.display='block';
25959         
25960         //this.el.appendTo(on_el);
25961         
25962         var p = this.getPosition();
25963         var box = this.el.getBox();
25964         
25965         if (autoPlace) {
25966             // fixme..
25967         }
25968         
25969         var align = this.alignment[placement];
25970         
25971         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25972         
25973         if(placement == 'top' || placement == 'bottom'){
25974             if(xy[0] < 0){
25975                 placement = 'right';
25976             }
25977             
25978             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25979                 placement = 'left';
25980             }
25981             
25982             var scroll = Roo.select('body', true).first().getScroll();
25983             
25984             if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25985                 placement = 'top';
25986             }
25987             
25988         }
25989         
25990         this.el.alignTo(this.bindEl, align[0],align[1]);
25991         //var arrow = this.el.select('.arrow',true).first();
25992         //arrow.set(align[2], 
25993         
25994         this.el.addClass(placement);
25995         
25996         this.el.addClass('in fade');
25997         
25998         this.hoverState = null;
25999         
26000         if (this.el.hasClass('fade')) {
26001             // fade it?
26002         }
26003         
26004     },
26005     hide : function()
26006     {
26007          
26008         if (!this.el) {
26009             return;
26010         }
26011         //this.el.setXY([0,0]);
26012         this.el.removeClass('in');
26013         //this.el.hide();
26014         
26015     }
26016     
26017 });
26018  
26019
26020  /*
26021  * - LGPL
26022  *
26023  * Location Picker
26024  * 
26025  */
26026
26027 /**
26028  * @class Roo.bootstrap.LocationPicker
26029  * @extends Roo.bootstrap.Component
26030  * Bootstrap LocationPicker class
26031  * @cfg {Number} latitude Position when init default 0
26032  * @cfg {Number} longitude Position when init default 0
26033  * @cfg {Number} zoom default 15
26034  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26035  * @cfg {Boolean} mapTypeControl default false
26036  * @cfg {Boolean} disableDoubleClickZoom default false
26037  * @cfg {Boolean} scrollwheel default true
26038  * @cfg {Boolean} streetViewControl default false
26039  * @cfg {Number} radius default 0
26040  * @cfg {String} locationName
26041  * @cfg {Boolean} draggable default true
26042  * @cfg {Boolean} enableAutocomplete default false
26043  * @cfg {Boolean} enableReverseGeocode default true
26044  * @cfg {String} markerTitle
26045  * 
26046  * @constructor
26047  * Create a new LocationPicker
26048  * @param {Object} config The config object
26049  */
26050
26051
26052 Roo.bootstrap.LocationPicker = function(config){
26053     
26054     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26055     
26056     this.addEvents({
26057         /**
26058          * @event initial
26059          * Fires when the picker initialized.
26060          * @param {Roo.bootstrap.LocationPicker} this
26061          * @param {Google Location} location
26062          */
26063         initial : true,
26064         /**
26065          * @event positionchanged
26066          * Fires when the picker position changed.
26067          * @param {Roo.bootstrap.LocationPicker} this
26068          * @param {Google Location} location
26069          */
26070         positionchanged : true,
26071         /**
26072          * @event resize
26073          * Fires when the map resize.
26074          * @param {Roo.bootstrap.LocationPicker} this
26075          */
26076         resize : true,
26077         /**
26078          * @event show
26079          * Fires when the map show.
26080          * @param {Roo.bootstrap.LocationPicker} this
26081          */
26082         show : true,
26083         /**
26084          * @event hide
26085          * Fires when the map hide.
26086          * @param {Roo.bootstrap.LocationPicker} this
26087          */
26088         hide : true,
26089         /**
26090          * @event mapClick
26091          * Fires when click the map.
26092          * @param {Roo.bootstrap.LocationPicker} this
26093          * @param {Map event} e
26094          */
26095         mapClick : true,
26096         /**
26097          * @event mapRightClick
26098          * Fires when right click the map.
26099          * @param {Roo.bootstrap.LocationPicker} this
26100          * @param {Map event} e
26101          */
26102         mapRightClick : true,
26103         /**
26104          * @event markerClick
26105          * Fires when click the marker.
26106          * @param {Roo.bootstrap.LocationPicker} this
26107          * @param {Map event} e
26108          */
26109         markerClick : true,
26110         /**
26111          * @event markerRightClick
26112          * Fires when right click the marker.
26113          * @param {Roo.bootstrap.LocationPicker} this
26114          * @param {Map event} e
26115          */
26116         markerRightClick : true,
26117         /**
26118          * @event OverlayViewDraw
26119          * Fires when OverlayView Draw
26120          * @param {Roo.bootstrap.LocationPicker} this
26121          */
26122         OverlayViewDraw : true,
26123         /**
26124          * @event OverlayViewOnAdd
26125          * Fires when OverlayView Draw
26126          * @param {Roo.bootstrap.LocationPicker} this
26127          */
26128         OverlayViewOnAdd : true,
26129         /**
26130          * @event OverlayViewOnRemove
26131          * Fires when OverlayView Draw
26132          * @param {Roo.bootstrap.LocationPicker} this
26133          */
26134         OverlayViewOnRemove : true,
26135         /**
26136          * @event OverlayViewShow
26137          * Fires when OverlayView Draw
26138          * @param {Roo.bootstrap.LocationPicker} this
26139          * @param {Pixel} cpx
26140          */
26141         OverlayViewShow : true,
26142         /**
26143          * @event OverlayViewHide
26144          * Fires when OverlayView Draw
26145          * @param {Roo.bootstrap.LocationPicker} this
26146          */
26147         OverlayViewHide : true,
26148         /**
26149          * @event loadexception
26150          * Fires when load google lib failed.
26151          * @param {Roo.bootstrap.LocationPicker} this
26152          */
26153         loadexception : true
26154     });
26155         
26156 };
26157
26158 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
26159     
26160     gMapContext: false,
26161     
26162     latitude: 0,
26163     longitude: 0,
26164     zoom: 15,
26165     mapTypeId: false,
26166     mapTypeControl: false,
26167     disableDoubleClickZoom: false,
26168     scrollwheel: true,
26169     streetViewControl: false,
26170     radius: 0,
26171     locationName: '',
26172     draggable: true,
26173     enableAutocomplete: false,
26174     enableReverseGeocode: true,
26175     markerTitle: '',
26176     
26177     getAutoCreate: function()
26178     {
26179
26180         var cfg = {
26181             tag: 'div',
26182             cls: 'roo-location-picker'
26183         };
26184         
26185         return cfg
26186     },
26187     
26188     initEvents: function(ct, position)
26189     {       
26190         if(!this.el.getWidth() || this.isApplied()){
26191             return;
26192         }
26193         
26194         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26195         
26196         this.initial();
26197     },
26198     
26199     initial: function()
26200     {
26201         if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26202             this.fireEvent('loadexception', this);
26203             return;
26204         }
26205         
26206         if(!this.mapTypeId){
26207             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26208         }
26209         
26210         this.gMapContext = this.GMapContext();
26211         
26212         this.initOverlayView();
26213         
26214         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26215         
26216         var _this = this;
26217                 
26218         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26219             _this.setPosition(_this.gMapContext.marker.position);
26220         });
26221         
26222         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26223             _this.fireEvent('mapClick', this, event);
26224             
26225         });
26226
26227         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26228             _this.fireEvent('mapRightClick', this, event);
26229             
26230         });
26231         
26232         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26233             _this.fireEvent('markerClick', this, event);
26234             
26235         });
26236
26237         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26238             _this.fireEvent('markerRightClick', this, event);
26239             
26240         });
26241         
26242         this.setPosition(this.gMapContext.location);
26243         
26244         this.fireEvent('initial', this, this.gMapContext.location);
26245     },
26246     
26247     initOverlayView: function()
26248     {
26249         var _this = this;
26250         
26251         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26252             
26253             draw: function()
26254             {
26255                 _this.fireEvent('OverlayViewDraw', _this);
26256             },
26257             
26258             onAdd: function()
26259             {
26260                 _this.fireEvent('OverlayViewOnAdd', _this);
26261             },
26262             
26263             onRemove: function()
26264             {
26265                 _this.fireEvent('OverlayViewOnRemove', _this);
26266             },
26267             
26268             show: function(cpx)
26269             {
26270                 _this.fireEvent('OverlayViewShow', _this, cpx);
26271             },
26272             
26273             hide: function()
26274             {
26275                 _this.fireEvent('OverlayViewHide', _this);
26276             }
26277             
26278         });
26279     },
26280     
26281     fromLatLngToContainerPixel: function(event)
26282     {
26283         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26284     },
26285     
26286     isApplied: function() 
26287     {
26288         return this.getGmapContext() == false ? false : true;
26289     },
26290     
26291     getGmapContext: function() 
26292     {
26293         return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26294     },
26295     
26296     GMapContext: function() 
26297     {
26298         var position = new google.maps.LatLng(this.latitude, this.longitude);
26299         
26300         var _map = new google.maps.Map(this.el.dom, {
26301             center: position,
26302             zoom: this.zoom,
26303             mapTypeId: this.mapTypeId,
26304             mapTypeControl: this.mapTypeControl,
26305             disableDoubleClickZoom: this.disableDoubleClickZoom,
26306             scrollwheel: this.scrollwheel,
26307             streetViewControl: this.streetViewControl,
26308             locationName: this.locationName,
26309             draggable: this.draggable,
26310             enableAutocomplete: this.enableAutocomplete,
26311             enableReverseGeocode: this.enableReverseGeocode
26312         });
26313         
26314         var _marker = new google.maps.Marker({
26315             position: position,
26316             map: _map,
26317             title: this.markerTitle,
26318             draggable: this.draggable
26319         });
26320         
26321         return {
26322             map: _map,
26323             marker: _marker,
26324             circle: null,
26325             location: position,
26326             radius: this.radius,
26327             locationName: this.locationName,
26328             addressComponents: {
26329                 formatted_address: null,
26330                 addressLine1: null,
26331                 addressLine2: null,
26332                 streetName: null,
26333                 streetNumber: null,
26334                 city: null,
26335                 district: null,
26336                 state: null,
26337                 stateOrProvince: null
26338             },
26339             settings: this,
26340             domContainer: this.el.dom,
26341             geodecoder: new google.maps.Geocoder()
26342         };
26343     },
26344     
26345     drawCircle: function(center, radius, options) 
26346     {
26347         if (this.gMapContext.circle != null) {
26348             this.gMapContext.circle.setMap(null);
26349         }
26350         if (radius > 0) {
26351             radius *= 1;
26352             options = Roo.apply({}, options, {
26353                 strokeColor: "#0000FF",
26354                 strokeOpacity: .35,
26355                 strokeWeight: 2,
26356                 fillColor: "#0000FF",
26357                 fillOpacity: .2
26358             });
26359             
26360             options.map = this.gMapContext.map;
26361             options.radius = radius;
26362             options.center = center;
26363             this.gMapContext.circle = new google.maps.Circle(options);
26364             return this.gMapContext.circle;
26365         }
26366         
26367         return null;
26368     },
26369     
26370     setPosition: function(location) 
26371     {
26372         this.gMapContext.location = location;
26373         this.gMapContext.marker.setPosition(location);
26374         this.gMapContext.map.panTo(location);
26375         this.drawCircle(location, this.gMapContext.radius, {});
26376         
26377         var _this = this;
26378         
26379         if (this.gMapContext.settings.enableReverseGeocode) {
26380             this.gMapContext.geodecoder.geocode({
26381                 latLng: this.gMapContext.location
26382             }, function(results, status) {
26383                 
26384                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26385                     _this.gMapContext.locationName = results[0].formatted_address;
26386                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26387                     
26388                     _this.fireEvent('positionchanged', this, location);
26389                 }
26390             });
26391             
26392             return;
26393         }
26394         
26395         this.fireEvent('positionchanged', this, location);
26396     },
26397     
26398     resize: function()
26399     {
26400         google.maps.event.trigger(this.gMapContext.map, "resize");
26401         
26402         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26403         
26404         this.fireEvent('resize', this);
26405     },
26406     
26407     setPositionByLatLng: function(latitude, longitude)
26408     {
26409         this.setPosition(new google.maps.LatLng(latitude, longitude));
26410     },
26411     
26412     getCurrentPosition: function() 
26413     {
26414         return {
26415             latitude: this.gMapContext.location.lat(),
26416             longitude: this.gMapContext.location.lng()
26417         };
26418     },
26419     
26420     getAddressName: function() 
26421     {
26422         return this.gMapContext.locationName;
26423     },
26424     
26425     getAddressComponents: function() 
26426     {
26427         return this.gMapContext.addressComponents;
26428     },
26429     
26430     address_component_from_google_geocode: function(address_components) 
26431     {
26432         var result = {};
26433         
26434         for (var i = 0; i < address_components.length; i++) {
26435             var component = address_components[i];
26436             if (component.types.indexOf("postal_code") >= 0) {
26437                 result.postalCode = component.short_name;
26438             } else if (component.types.indexOf("street_number") >= 0) {
26439                 result.streetNumber = component.short_name;
26440             } else if (component.types.indexOf("route") >= 0) {
26441                 result.streetName = component.short_name;
26442             } else if (component.types.indexOf("neighborhood") >= 0) {
26443                 result.city = component.short_name;
26444             } else if (component.types.indexOf("locality") >= 0) {
26445                 result.city = component.short_name;
26446             } else if (component.types.indexOf("sublocality") >= 0) {
26447                 result.district = component.short_name;
26448             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26449                 result.stateOrProvince = component.short_name;
26450             } else if (component.types.indexOf("country") >= 0) {
26451                 result.country = component.short_name;
26452             }
26453         }
26454         
26455         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26456         result.addressLine2 = "";
26457         return result;
26458     },
26459     
26460     setZoomLevel: function(zoom)
26461     {
26462         this.gMapContext.map.setZoom(zoom);
26463     },
26464     
26465     show: function()
26466     {
26467         if(!this.el){
26468             return;
26469         }
26470         
26471         this.el.show();
26472         
26473         this.resize();
26474         
26475         this.fireEvent('show', this);
26476     },
26477     
26478     hide: function()
26479     {
26480         if(!this.el){
26481             return;
26482         }
26483         
26484         this.el.hide();
26485         
26486         this.fireEvent('hide', this);
26487     }
26488     
26489 });
26490
26491 Roo.apply(Roo.bootstrap.LocationPicker, {
26492     
26493     OverlayView : function(map, options)
26494     {
26495         options = options || {};
26496         
26497         this.setMap(map);
26498     }
26499     
26500     
26501 });/*
26502  * - LGPL
26503  *
26504  * Alert
26505  * 
26506  */
26507
26508 /**
26509  * @class Roo.bootstrap.Alert
26510  * @extends Roo.bootstrap.Component
26511  * Bootstrap Alert class
26512  * @cfg {String} title The title of alert
26513  * @cfg {String} html The content of alert
26514  * @cfg {String} weight (  success | info | warning | danger )
26515  * @cfg {String} faicon font-awesomeicon
26516  * 
26517  * @constructor
26518  * Create a new alert
26519  * @param {Object} config The config object
26520  */
26521
26522
26523 Roo.bootstrap.Alert = function(config){
26524     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26525     
26526 };
26527
26528 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
26529     
26530     title: '',
26531     html: '',
26532     weight: false,
26533     faicon: false,
26534     
26535     getAutoCreate : function()
26536     {
26537         
26538         var cfg = {
26539             tag : 'div',
26540             cls : 'alert',
26541             cn : [
26542                 {
26543                     tag : 'i',
26544                     cls : 'roo-alert-icon'
26545                     
26546                 },
26547                 {
26548                     tag : 'b',
26549                     cls : 'roo-alert-title',
26550                     html : this.title
26551                 },
26552                 {
26553                     tag : 'span',
26554                     cls : 'roo-alert-text',
26555                     html : this.html
26556                 }
26557             ]
26558         };
26559         
26560         if(this.faicon){
26561             cfg.cn[0].cls += ' fa ' + this.faicon;
26562         }
26563         
26564         if(this.weight){
26565             cfg.cls += ' alert-' + this.weight;
26566         }
26567         
26568         return cfg;
26569     },
26570     
26571     initEvents: function() 
26572     {
26573         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26574     },
26575     
26576     setTitle : function(str)
26577     {
26578         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26579     },
26580     
26581     setText : function(str)
26582     {
26583         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26584     },
26585     
26586     setWeight : function(weight)
26587     {
26588         if(this.weight){
26589             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26590         }
26591         
26592         this.weight = weight;
26593         
26594         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26595     },
26596     
26597     setIcon : function(icon)
26598     {
26599         if(this.faicon){
26600             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26601         }
26602         
26603         this.faicon = icon;
26604         
26605         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26606     },
26607     
26608     hide: function() 
26609     {
26610         this.el.hide();   
26611     },
26612     
26613     show: function() 
26614     {  
26615         this.el.show();   
26616     }
26617     
26618 });
26619
26620  
26621 /*
26622 * Licence: LGPL
26623 */
26624
26625 /**
26626  * @class Roo.bootstrap.UploadCropbox
26627  * @extends Roo.bootstrap.Component
26628  * Bootstrap UploadCropbox class
26629  * @cfg {String} emptyText show when image has been loaded
26630  * @cfg {String} rotateNotify show when image too small to rotate
26631  * @cfg {Number} errorTimeout default 3000
26632  * @cfg {Number} minWidth default 300
26633  * @cfg {Number} minHeight default 300
26634  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26635  * @cfg {Boolean} isDocument (true|false) default false
26636  * @cfg {String} url action url
26637  * @cfg {String} paramName default 'imageUpload'
26638  * @cfg {String} method default POST
26639  * @cfg {Boolean} loadMask (true|false) default true
26640  * @cfg {Boolean} loadingText default 'Loading...'
26641  * 
26642  * @constructor
26643  * Create a new UploadCropbox
26644  * @param {Object} config The config object
26645  */
26646
26647 Roo.bootstrap.UploadCropbox = function(config){
26648     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26649     
26650     this.addEvents({
26651         /**
26652          * @event beforeselectfile
26653          * Fire before select file
26654          * @param {Roo.bootstrap.UploadCropbox} this
26655          */
26656         "beforeselectfile" : true,
26657         /**
26658          * @event initial
26659          * Fire after initEvent
26660          * @param {Roo.bootstrap.UploadCropbox} this
26661          */
26662         "initial" : true,
26663         /**
26664          * @event crop
26665          * Fire after initEvent
26666          * @param {Roo.bootstrap.UploadCropbox} this
26667          * @param {String} data
26668          */
26669         "crop" : true,
26670         /**
26671          * @event prepare
26672          * Fire when preparing the file data
26673          * @param {Roo.bootstrap.UploadCropbox} this
26674          * @param {Object} file
26675          */
26676         "prepare" : true,
26677         /**
26678          * @event exception
26679          * Fire when get exception
26680          * @param {Roo.bootstrap.UploadCropbox} this
26681          * @param {XMLHttpRequest} xhr
26682          */
26683         "exception" : true,
26684         /**
26685          * @event beforeloadcanvas
26686          * Fire before load the canvas
26687          * @param {Roo.bootstrap.UploadCropbox} this
26688          * @param {String} src
26689          */
26690         "beforeloadcanvas" : true,
26691         /**
26692          * @event trash
26693          * Fire when trash image
26694          * @param {Roo.bootstrap.UploadCropbox} this
26695          */
26696         "trash" : true,
26697         /**
26698          * @event download
26699          * Fire when download the image
26700          * @param {Roo.bootstrap.UploadCropbox} this
26701          */
26702         "download" : true,
26703         /**
26704          * @event footerbuttonclick
26705          * Fire when footerbuttonclick
26706          * @param {Roo.bootstrap.UploadCropbox} this
26707          * @param {String} type
26708          */
26709         "footerbuttonclick" : true,
26710         /**
26711          * @event resize
26712          * Fire when resize
26713          * @param {Roo.bootstrap.UploadCropbox} this
26714          */
26715         "resize" : true,
26716         /**
26717          * @event rotate
26718          * Fire when rotate the image
26719          * @param {Roo.bootstrap.UploadCropbox} this
26720          * @param {String} pos
26721          */
26722         "rotate" : true,
26723         /**
26724          * @event inspect
26725          * Fire when inspect the file
26726          * @param {Roo.bootstrap.UploadCropbox} this
26727          * @param {Object} file
26728          */
26729         "inspect" : true,
26730         /**
26731          * @event upload
26732          * Fire when xhr upload the file
26733          * @param {Roo.bootstrap.UploadCropbox} this
26734          * @param {Object} data
26735          */
26736         "upload" : true,
26737         /**
26738          * @event arrange
26739          * Fire when arrange the file data
26740          * @param {Roo.bootstrap.UploadCropbox} this
26741          * @param {Object} formData
26742          */
26743         "arrange" : true
26744     });
26745     
26746     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26747 };
26748
26749 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
26750     
26751     emptyText : 'Click to upload image',
26752     rotateNotify : 'Image is too small to rotate',
26753     errorTimeout : 3000,
26754     scale : 0,
26755     baseScale : 1,
26756     rotate : 0,
26757     dragable : false,
26758     pinching : false,
26759     mouseX : 0,
26760     mouseY : 0,
26761     cropData : false,
26762     minWidth : 300,
26763     minHeight : 300,
26764     file : false,
26765     exif : {},
26766     baseRotate : 1,
26767     cropType : 'image/jpeg',
26768     buttons : false,
26769     canvasLoaded : false,
26770     isDocument : false,
26771     method : 'POST',
26772     paramName : 'imageUpload',
26773     loadMask : true,
26774     loadingText : 'Loading...',
26775     maskEl : false,
26776     
26777     getAutoCreate : function()
26778     {
26779         var cfg = {
26780             tag : 'div',
26781             cls : 'roo-upload-cropbox',
26782             cn : [
26783                 {
26784                     tag : 'input',
26785                     cls : 'roo-upload-cropbox-selector',
26786                     type : 'file'
26787                 },
26788                 {
26789                     tag : 'div',
26790                     cls : 'roo-upload-cropbox-body',
26791                     style : 'cursor:pointer',
26792                     cn : [
26793                         {
26794                             tag : 'div',
26795                             cls : 'roo-upload-cropbox-preview'
26796                         },
26797                         {
26798                             tag : 'div',
26799                             cls : 'roo-upload-cropbox-thumb'
26800                         },
26801                         {
26802                             tag : 'div',
26803                             cls : 'roo-upload-cropbox-empty-notify',
26804                             html : this.emptyText
26805                         },
26806                         {
26807                             tag : 'div',
26808                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26809                             html : this.rotateNotify
26810                         }
26811                     ]
26812                 },
26813                 {
26814                     tag : 'div',
26815                     cls : 'roo-upload-cropbox-footer',
26816                     cn : {
26817                         tag : 'div',
26818                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26819                         cn : []
26820                     }
26821                 }
26822             ]
26823         };
26824         
26825         return cfg;
26826     },
26827     
26828     onRender : function(ct, position)
26829     {
26830         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26831         
26832         if (this.buttons.length) {
26833             
26834             Roo.each(this.buttons, function(bb) {
26835                 
26836                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26837                 
26838                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26839                 
26840             }, this);
26841         }
26842         
26843         if(this.loadMask){
26844             this.maskEl = this.el;
26845         }
26846     },
26847     
26848     initEvents : function()
26849     {
26850         this.urlAPI = (window.createObjectURL && window) || 
26851                                 (window.URL && URL.revokeObjectURL && URL) || 
26852                                 (window.webkitURL && webkitURL);
26853                         
26854         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26855         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26856         
26857         this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26858         this.selectorEl.hide();
26859         
26860         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26861         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26862         
26863         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26864         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26865         this.thumbEl.hide();
26866         
26867         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26868         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26869         
26870         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26871         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26872         this.errorEl.hide();
26873         
26874         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26875         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26876         this.footerEl.hide();
26877         
26878         this.setThumbBoxSize();
26879         
26880         this.bind();
26881         
26882         this.resize();
26883         
26884         this.fireEvent('initial', this);
26885     },
26886
26887     bind : function()
26888     {
26889         var _this = this;
26890         
26891         window.addEventListener("resize", function() { _this.resize(); } );
26892         
26893         this.bodyEl.on('click', this.beforeSelectFile, this);
26894         
26895         if(Roo.isTouch){
26896             this.bodyEl.on('touchstart', this.onTouchStart, this);
26897             this.bodyEl.on('touchmove', this.onTouchMove, this);
26898             this.bodyEl.on('touchend', this.onTouchEnd, this);
26899         }
26900         
26901         if(!Roo.isTouch){
26902             this.bodyEl.on('mousedown', this.onMouseDown, this);
26903             this.bodyEl.on('mousemove', this.onMouseMove, this);
26904             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26905             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26906             Roo.get(document).on('mouseup', this.onMouseUp, this);
26907         }
26908         
26909         this.selectorEl.on('change', this.onFileSelected, this);
26910     },
26911     
26912     reset : function()
26913     {    
26914         this.scale = 0;
26915         this.baseScale = 1;
26916         this.rotate = 0;
26917         this.baseRotate = 1;
26918         this.dragable = false;
26919         this.pinching = false;
26920         this.mouseX = 0;
26921         this.mouseY = 0;
26922         this.cropData = false;
26923         this.notifyEl.dom.innerHTML = this.emptyText;
26924         
26925         this.selectorEl.dom.value = '';
26926         
26927     },
26928     
26929     resize : function()
26930     {
26931         if(this.fireEvent('resize', this) != false){
26932             this.setThumbBoxPosition();
26933             this.setCanvasPosition();
26934         }
26935     },
26936     
26937     onFooterButtonClick : function(e, el, o, type)
26938     {
26939         switch (type) {
26940             case 'rotate-left' :
26941                 this.onRotateLeft(e);
26942                 break;
26943             case 'rotate-right' :
26944                 this.onRotateRight(e);
26945                 break;
26946             case 'picture' :
26947                 this.beforeSelectFile(e);
26948                 break;
26949             case 'trash' :
26950                 this.trash(e);
26951                 break;
26952             case 'crop' :
26953                 this.crop(e);
26954                 break;
26955             case 'download' :
26956                 this.download(e);
26957                 break;
26958             default :
26959                 break;
26960         }
26961         
26962         this.fireEvent('footerbuttonclick', this, type);
26963     },
26964     
26965     beforeSelectFile : function(e)
26966     {
26967         e.preventDefault();
26968         
26969         if(this.fireEvent('beforeselectfile', this) != false){
26970             this.selectorEl.dom.click();
26971         }
26972     },
26973     
26974     onFileSelected : function(e)
26975     {
26976         e.preventDefault();
26977         
26978         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26979             return;
26980         }
26981         
26982         var file = this.selectorEl.dom.files[0];
26983         
26984         if(this.fireEvent('inspect', this, file) != false){
26985             this.prepare(file);
26986         }
26987         
26988     },
26989     
26990     trash : function(e)
26991     {
26992         this.fireEvent('trash', this);
26993     },
26994     
26995     download : function(e)
26996     {
26997         this.fireEvent('download', this);
26998     },
26999     
27000     loadCanvas : function(src)
27001     {   
27002         if(this.fireEvent('beforeloadcanvas', this, src) != false){
27003             
27004             this.reset();
27005             
27006             this.imageEl = document.createElement('img');
27007             
27008             var _this = this;
27009             
27010             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27011             
27012             this.imageEl.src = src;
27013         }
27014     },
27015     
27016     onLoadCanvas : function()
27017     {   
27018         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27019         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27020         
27021         this.bodyEl.un('click', this.beforeSelectFile, this);
27022         
27023         this.notifyEl.hide();
27024         this.thumbEl.show();
27025         this.footerEl.show();
27026         
27027         this.baseRotateLevel();
27028         
27029         if(this.isDocument){
27030             this.setThumbBoxSize();
27031         }
27032         
27033         this.setThumbBoxPosition();
27034         
27035         this.baseScaleLevel();
27036         
27037         this.draw();
27038         
27039         this.resize();
27040         
27041         this.canvasLoaded = true;
27042         
27043         if(this.loadMask){
27044             this.maskEl.unmask();
27045         }
27046         
27047     },
27048     
27049     setCanvasPosition : function()
27050     {   
27051         if(!this.canvasEl){
27052             return;
27053         }
27054         
27055         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27056         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27057         
27058         this.previewEl.setLeft(pw);
27059         this.previewEl.setTop(ph);
27060         
27061     },
27062     
27063     onMouseDown : function(e)
27064     {   
27065         e.stopEvent();
27066         
27067         this.dragable = true;
27068         this.pinching = false;
27069         
27070         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27071             this.dragable = false;
27072             return;
27073         }
27074         
27075         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27076         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27077         
27078     },
27079     
27080     onMouseMove : function(e)
27081     {   
27082         e.stopEvent();
27083         
27084         if(!this.canvasLoaded){
27085             return;
27086         }
27087         
27088         if (!this.dragable){
27089             return;
27090         }
27091         
27092         var minX = Math.ceil(this.thumbEl.getLeft(true));
27093         var minY = Math.ceil(this.thumbEl.getTop(true));
27094         
27095         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27096         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27097         
27098         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27099         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27100         
27101         x = x - this.mouseX;
27102         y = y - this.mouseY;
27103         
27104         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27105         var bgY = Math.ceil(y + this.previewEl.getTop(true));
27106         
27107         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27108         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27109         
27110         this.previewEl.setLeft(bgX);
27111         this.previewEl.setTop(bgY);
27112         
27113         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27114         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27115     },
27116     
27117     onMouseUp : function(e)
27118     {   
27119         e.stopEvent();
27120         
27121         this.dragable = false;
27122     },
27123     
27124     onMouseWheel : function(e)
27125     {   
27126         e.stopEvent();
27127         
27128         this.startScale = this.scale;
27129         
27130         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27131         
27132         if(!this.zoomable()){
27133             this.scale = this.startScale;
27134             return;
27135         }
27136         
27137         this.draw();
27138         
27139         return;
27140     },
27141     
27142     zoomable : function()
27143     {
27144         var minScale = this.thumbEl.getWidth() / this.minWidth;
27145         
27146         if(this.minWidth < this.minHeight){
27147             minScale = this.thumbEl.getHeight() / this.minHeight;
27148         }
27149         
27150         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27151         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27152         
27153         if(
27154                 this.isDocument &&
27155                 (this.rotate == 0 || this.rotate == 180) && 
27156                 (
27157                     width > this.imageEl.OriginWidth || 
27158                     height > this.imageEl.OriginHeight ||
27159                     (width < this.minWidth && height < this.minHeight)
27160                 )
27161         ){
27162             return false;
27163         }
27164         
27165         if(
27166                 this.isDocument &&
27167                 (this.rotate == 90 || this.rotate == 270) && 
27168                 (
27169                     width > this.imageEl.OriginWidth || 
27170                     height > this.imageEl.OriginHeight ||
27171                     (width < this.minHeight && height < this.minWidth)
27172                 )
27173         ){
27174             return false;
27175         }
27176         
27177         if(
27178                 !this.isDocument &&
27179                 (this.rotate == 0 || this.rotate == 180) && 
27180                 (
27181                     width < this.minWidth || 
27182                     width > this.imageEl.OriginWidth || 
27183                     height < this.minHeight || 
27184                     height > this.imageEl.OriginHeight
27185                 )
27186         ){
27187             return false;
27188         }
27189         
27190         if(
27191                 !this.isDocument &&
27192                 (this.rotate == 90 || this.rotate == 270) && 
27193                 (
27194                     width < this.minHeight || 
27195                     width > this.imageEl.OriginWidth || 
27196                     height < this.minWidth || 
27197                     height > this.imageEl.OriginHeight
27198                 )
27199         ){
27200             return false;
27201         }
27202         
27203         return true;
27204         
27205     },
27206     
27207     onRotateLeft : function(e)
27208     {   
27209         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27210             
27211             var minScale = this.thumbEl.getWidth() / this.minWidth;
27212             
27213             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27214             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27215             
27216             this.startScale = this.scale;
27217             
27218             while (this.getScaleLevel() < minScale){
27219             
27220                 this.scale = this.scale + 1;
27221                 
27222                 if(!this.zoomable()){
27223                     break;
27224                 }
27225                 
27226                 if(
27227                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27228                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27229                 ){
27230                     continue;
27231                 }
27232                 
27233                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27234
27235                 this.draw();
27236                 
27237                 return;
27238             }
27239             
27240             this.scale = this.startScale;
27241             
27242             this.onRotateFail();
27243             
27244             return false;
27245         }
27246         
27247         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27248
27249         if(this.isDocument){
27250             this.setThumbBoxSize();
27251             this.setThumbBoxPosition();
27252             this.setCanvasPosition();
27253         }
27254         
27255         this.draw();
27256         
27257         this.fireEvent('rotate', this, 'left');
27258         
27259     },
27260     
27261     onRotateRight : function(e)
27262     {
27263         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27264             
27265             var minScale = this.thumbEl.getWidth() / this.minWidth;
27266         
27267             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27268             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27269             
27270             this.startScale = this.scale;
27271             
27272             while (this.getScaleLevel() < minScale){
27273             
27274                 this.scale = this.scale + 1;
27275                 
27276                 if(!this.zoomable()){
27277                     break;
27278                 }
27279                 
27280                 if(
27281                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27282                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27283                 ){
27284                     continue;
27285                 }
27286                 
27287                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27288
27289                 this.draw();
27290                 
27291                 return;
27292             }
27293             
27294             this.scale = this.startScale;
27295             
27296             this.onRotateFail();
27297             
27298             return false;
27299         }
27300         
27301         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27302
27303         if(this.isDocument){
27304             this.setThumbBoxSize();
27305             this.setThumbBoxPosition();
27306             this.setCanvasPosition();
27307         }
27308         
27309         this.draw();
27310         
27311         this.fireEvent('rotate', this, 'right');
27312     },
27313     
27314     onRotateFail : function()
27315     {
27316         this.errorEl.show(true);
27317         
27318         var _this = this;
27319         
27320         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27321     },
27322     
27323     draw : function()
27324     {
27325         this.previewEl.dom.innerHTML = '';
27326         
27327         var canvasEl = document.createElement("canvas");
27328         
27329         var contextEl = canvasEl.getContext("2d");
27330         
27331         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27332         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27333         var center = this.imageEl.OriginWidth / 2;
27334         
27335         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27336             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27337             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27338             center = this.imageEl.OriginHeight / 2;
27339         }
27340         
27341         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27342         
27343         contextEl.translate(center, center);
27344         contextEl.rotate(this.rotate * Math.PI / 180);
27345
27346         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27347         
27348         this.canvasEl = document.createElement("canvas");
27349         
27350         this.contextEl = this.canvasEl.getContext("2d");
27351         
27352         switch (this.rotate) {
27353             case 0 :
27354                 
27355                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27356                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27357                 
27358                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27359                 
27360                 break;
27361             case 90 : 
27362                 
27363                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27364                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27365                 
27366                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27367                     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);
27368                     break;
27369                 }
27370                 
27371                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27372                 
27373                 break;
27374             case 180 :
27375                 
27376                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27377                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27378                 
27379                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27380                     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);
27381                     break;
27382                 }
27383                 
27384                 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);
27385                 
27386                 break;
27387             case 270 :
27388                 
27389                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27390                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27391         
27392                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27393                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27394                     break;
27395                 }
27396                 
27397                 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);
27398                 
27399                 break;
27400             default : 
27401                 break;
27402         }
27403         
27404         this.previewEl.appendChild(this.canvasEl);
27405         
27406         this.setCanvasPosition();
27407     },
27408     
27409     crop : function()
27410     {
27411         if(!this.canvasLoaded){
27412             return;
27413         }
27414         
27415         var imageCanvas = document.createElement("canvas");
27416         
27417         var imageContext = imageCanvas.getContext("2d");
27418         
27419         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27420         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27421         
27422         var center = imageCanvas.width / 2;
27423         
27424         imageContext.translate(center, center);
27425         
27426         imageContext.rotate(this.rotate * Math.PI / 180);
27427         
27428         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27429         
27430         var canvas = document.createElement("canvas");
27431         
27432         var context = canvas.getContext("2d");
27433                 
27434         canvas.width = this.minWidth;
27435         canvas.height = this.minHeight;
27436
27437         switch (this.rotate) {
27438             case 0 :
27439                 
27440                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27441                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27442                 
27443                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27444                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27445                 
27446                 var targetWidth = this.minWidth - 2 * x;
27447                 var targetHeight = this.minHeight - 2 * y;
27448                 
27449                 var scale = 1;
27450                 
27451                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27452                     scale = targetWidth / width;
27453                 }
27454                 
27455                 if(x > 0 && y == 0){
27456                     scale = targetHeight / height;
27457                 }
27458                 
27459                 if(x > 0 && y > 0){
27460                     scale = targetWidth / width;
27461                     
27462                     if(width < height){
27463                         scale = targetHeight / height;
27464                     }
27465                 }
27466                 
27467                 context.scale(scale, scale);
27468                 
27469                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27470                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27471
27472                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27473                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27474
27475                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27476                 
27477                 break;
27478             case 90 : 
27479                 
27480                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27481                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27482                 
27483                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27484                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27485                 
27486                 var targetWidth = this.minWidth - 2 * x;
27487                 var targetHeight = this.minHeight - 2 * y;
27488                 
27489                 var scale = 1;
27490                 
27491                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27492                     scale = targetWidth / width;
27493                 }
27494                 
27495                 if(x > 0 && y == 0){
27496                     scale = targetHeight / height;
27497                 }
27498                 
27499                 if(x > 0 && y > 0){
27500                     scale = targetWidth / width;
27501                     
27502                     if(width < height){
27503                         scale = targetHeight / height;
27504                     }
27505                 }
27506                 
27507                 context.scale(scale, scale);
27508                 
27509                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27510                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27511
27512                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27513                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27514                 
27515                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27516                 
27517                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27518                 
27519                 break;
27520             case 180 :
27521                 
27522                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27523                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27524                 
27525                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27526                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27527                 
27528                 var targetWidth = this.minWidth - 2 * x;
27529                 var targetHeight = this.minHeight - 2 * y;
27530                 
27531                 var scale = 1;
27532                 
27533                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27534                     scale = targetWidth / width;
27535                 }
27536                 
27537                 if(x > 0 && y == 0){
27538                     scale = targetHeight / height;
27539                 }
27540                 
27541                 if(x > 0 && y > 0){
27542                     scale = targetWidth / width;
27543                     
27544                     if(width < height){
27545                         scale = targetHeight / height;
27546                     }
27547                 }
27548                 
27549                 context.scale(scale, scale);
27550                 
27551                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27552                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27553
27554                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27555                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27556
27557                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27558                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27559                 
27560                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27561                 
27562                 break;
27563             case 270 :
27564                 
27565                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27566                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27567                 
27568                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27569                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27570                 
27571                 var targetWidth = this.minWidth - 2 * x;
27572                 var targetHeight = this.minHeight - 2 * y;
27573                 
27574                 var scale = 1;
27575                 
27576                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27577                     scale = targetWidth / width;
27578                 }
27579                 
27580                 if(x > 0 && y == 0){
27581                     scale = targetHeight / height;
27582                 }
27583                 
27584                 if(x > 0 && y > 0){
27585                     scale = targetWidth / width;
27586                     
27587                     if(width < height){
27588                         scale = targetHeight / height;
27589                     }
27590                 }
27591                 
27592                 context.scale(scale, scale);
27593                 
27594                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27595                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27596
27597                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27598                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27599                 
27600                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27601                 
27602                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27603                 
27604                 break;
27605             default : 
27606                 break;
27607         }
27608         
27609         this.cropData = canvas.toDataURL(this.cropType);
27610         
27611         if(this.fireEvent('crop', this, this.cropData) !== false){
27612             this.process(this.file, this.cropData);
27613         }
27614         
27615         return;
27616         
27617     },
27618     
27619     setThumbBoxSize : function()
27620     {
27621         var width, height;
27622         
27623         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27624             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27625             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27626             
27627             this.minWidth = width;
27628             this.minHeight = height;
27629             
27630             if(this.rotate == 90 || this.rotate == 270){
27631                 this.minWidth = height;
27632                 this.minHeight = width;
27633             }
27634         }
27635         
27636         height = 300;
27637         width = Math.ceil(this.minWidth * height / this.minHeight);
27638         
27639         if(this.minWidth > this.minHeight){
27640             width = 300;
27641             height = Math.ceil(this.minHeight * width / this.minWidth);
27642         }
27643         
27644         this.thumbEl.setStyle({
27645             width : width + 'px',
27646             height : height + 'px'
27647         });
27648
27649         return;
27650             
27651     },
27652     
27653     setThumbBoxPosition : function()
27654     {
27655         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27656         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27657         
27658         this.thumbEl.setLeft(x);
27659         this.thumbEl.setTop(y);
27660         
27661     },
27662     
27663     baseRotateLevel : function()
27664     {
27665         this.baseRotate = 1;
27666         
27667         if(
27668                 typeof(this.exif) != 'undefined' &&
27669                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27670                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27671         ){
27672             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27673         }
27674         
27675         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27676         
27677     },
27678     
27679     baseScaleLevel : function()
27680     {
27681         var width, height;
27682         
27683         if(this.isDocument){
27684             
27685             if(this.baseRotate == 6 || this.baseRotate == 8){
27686             
27687                 height = this.thumbEl.getHeight();
27688                 this.baseScale = height / this.imageEl.OriginWidth;
27689
27690                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27691                     width = this.thumbEl.getWidth();
27692                     this.baseScale = width / this.imageEl.OriginHeight;
27693                 }
27694
27695                 return;
27696             }
27697
27698             height = this.thumbEl.getHeight();
27699             this.baseScale = height / this.imageEl.OriginHeight;
27700
27701             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27702                 width = this.thumbEl.getWidth();
27703                 this.baseScale = width / this.imageEl.OriginWidth;
27704             }
27705
27706             return;
27707         }
27708         
27709         if(this.baseRotate == 6 || this.baseRotate == 8){
27710             
27711             width = this.thumbEl.getHeight();
27712             this.baseScale = width / this.imageEl.OriginHeight;
27713             
27714             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27715                 height = this.thumbEl.getWidth();
27716                 this.baseScale = height / this.imageEl.OriginHeight;
27717             }
27718             
27719             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27720                 height = this.thumbEl.getWidth();
27721                 this.baseScale = height / this.imageEl.OriginHeight;
27722                 
27723                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27724                     width = this.thumbEl.getHeight();
27725                     this.baseScale = width / this.imageEl.OriginWidth;
27726                 }
27727             }
27728             
27729             return;
27730         }
27731         
27732         width = this.thumbEl.getWidth();
27733         this.baseScale = width / this.imageEl.OriginWidth;
27734         
27735         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27736             height = this.thumbEl.getHeight();
27737             this.baseScale = height / this.imageEl.OriginHeight;
27738         }
27739         
27740         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27741             
27742             height = this.thumbEl.getHeight();
27743             this.baseScale = height / this.imageEl.OriginHeight;
27744             
27745             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27746                 width = this.thumbEl.getWidth();
27747                 this.baseScale = width / this.imageEl.OriginWidth;
27748             }
27749             
27750         }
27751         
27752         return;
27753     },
27754     
27755     getScaleLevel : function()
27756     {
27757         return this.baseScale * Math.pow(1.1, this.scale);
27758     },
27759     
27760     onTouchStart : function(e)
27761     {
27762         if(!this.canvasLoaded){
27763             this.beforeSelectFile(e);
27764             return;
27765         }
27766         
27767         var touches = e.browserEvent.touches;
27768         
27769         if(!touches){
27770             return;
27771         }
27772         
27773         if(touches.length == 1){
27774             this.onMouseDown(e);
27775             return;
27776         }
27777         
27778         if(touches.length != 2){
27779             return;
27780         }
27781         
27782         var coords = [];
27783         
27784         for(var i = 0, finger; finger = touches[i]; i++){
27785             coords.push(finger.pageX, finger.pageY);
27786         }
27787         
27788         var x = Math.pow(coords[0] - coords[2], 2);
27789         var y = Math.pow(coords[1] - coords[3], 2);
27790         
27791         this.startDistance = Math.sqrt(x + y);
27792         
27793         this.startScale = this.scale;
27794         
27795         this.pinching = true;
27796         this.dragable = false;
27797         
27798     },
27799     
27800     onTouchMove : function(e)
27801     {
27802         if(!this.pinching && !this.dragable){
27803             return;
27804         }
27805         
27806         var touches = e.browserEvent.touches;
27807         
27808         if(!touches){
27809             return;
27810         }
27811         
27812         if(this.dragable){
27813             this.onMouseMove(e);
27814             return;
27815         }
27816         
27817         var coords = [];
27818         
27819         for(var i = 0, finger; finger = touches[i]; i++){
27820             coords.push(finger.pageX, finger.pageY);
27821         }
27822         
27823         var x = Math.pow(coords[0] - coords[2], 2);
27824         var y = Math.pow(coords[1] - coords[3], 2);
27825         
27826         this.endDistance = Math.sqrt(x + y);
27827         
27828         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27829         
27830         if(!this.zoomable()){
27831             this.scale = this.startScale;
27832             return;
27833         }
27834         
27835         this.draw();
27836         
27837     },
27838     
27839     onTouchEnd : function(e)
27840     {
27841         this.pinching = false;
27842         this.dragable = false;
27843         
27844     },
27845     
27846     process : function(file, crop)
27847     {
27848         if(this.loadMask){
27849             this.maskEl.mask(this.loadingText);
27850         }
27851         
27852         this.xhr = new XMLHttpRequest();
27853         
27854         file.xhr = this.xhr;
27855
27856         this.xhr.open(this.method, this.url, true);
27857         
27858         var headers = {
27859             "Accept": "application/json",
27860             "Cache-Control": "no-cache",
27861             "X-Requested-With": "XMLHttpRequest"
27862         };
27863         
27864         for (var headerName in headers) {
27865             var headerValue = headers[headerName];
27866             if (headerValue) {
27867                 this.xhr.setRequestHeader(headerName, headerValue);
27868             }
27869         }
27870         
27871         var _this = this;
27872         
27873         this.xhr.onload = function()
27874         {
27875             _this.xhrOnLoad(_this.xhr);
27876         }
27877         
27878         this.xhr.onerror = function()
27879         {
27880             _this.xhrOnError(_this.xhr);
27881         }
27882         
27883         var formData = new FormData();
27884
27885         formData.append('returnHTML', 'NO');
27886         
27887         if(crop){
27888             formData.append('crop', crop);
27889         }
27890         
27891         if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27892             formData.append(this.paramName, file, file.name);
27893         }
27894         
27895         if(typeof(file.filename) != 'undefined'){
27896             formData.append('filename', file.filename);
27897         }
27898         
27899         if(typeof(file.mimetype) != 'undefined'){
27900             formData.append('mimetype', file.mimetype);
27901         }
27902         
27903         if(this.fireEvent('arrange', this, formData) != false){
27904             this.xhr.send(formData);
27905         };
27906     },
27907     
27908     xhrOnLoad : function(xhr)
27909     {
27910         if(this.loadMask){
27911             this.maskEl.unmask();
27912         }
27913         
27914         if (xhr.readyState !== 4) {
27915             this.fireEvent('exception', this, xhr);
27916             return;
27917         }
27918
27919         var response = Roo.decode(xhr.responseText);
27920         
27921         if(!response.success){
27922             this.fireEvent('exception', this, xhr);
27923             return;
27924         }
27925         
27926         var response = Roo.decode(xhr.responseText);
27927         
27928         this.fireEvent('upload', this, response);
27929         
27930     },
27931     
27932     xhrOnError : function()
27933     {
27934         if(this.loadMask){
27935             this.maskEl.unmask();
27936         }
27937         
27938         Roo.log('xhr on error');
27939         
27940         var response = Roo.decode(xhr.responseText);
27941           
27942         Roo.log(response);
27943         
27944     },
27945     
27946     prepare : function(file)
27947     {   
27948         if(this.loadMask){
27949             this.maskEl.mask(this.loadingText);
27950         }
27951         
27952         this.file = false;
27953         this.exif = {};
27954         
27955         if(typeof(file) === 'string'){
27956             this.loadCanvas(file);
27957             return;
27958         }
27959         
27960         if(!file || !this.urlAPI){
27961             return;
27962         }
27963         
27964         this.file = file;
27965         this.cropType = file.type;
27966         
27967         var _this = this;
27968         
27969         if(this.fireEvent('prepare', this, this.file) != false){
27970             
27971             var reader = new FileReader();
27972             
27973             reader.onload = function (e) {
27974                 if (e.target.error) {
27975                     Roo.log(e.target.error);
27976                     return;
27977                 }
27978                 
27979                 var buffer = e.target.result,
27980                     dataView = new DataView(buffer),
27981                     offset = 2,
27982                     maxOffset = dataView.byteLength - 4,
27983                     markerBytes,
27984                     markerLength;
27985                 
27986                 if (dataView.getUint16(0) === 0xffd8) {
27987                     while (offset < maxOffset) {
27988                         markerBytes = dataView.getUint16(offset);
27989                         
27990                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27991                             markerLength = dataView.getUint16(offset + 2) + 2;
27992                             if (offset + markerLength > dataView.byteLength) {
27993                                 Roo.log('Invalid meta data: Invalid segment size.');
27994                                 break;
27995                             }
27996                             
27997                             if(markerBytes == 0xffe1){
27998                                 _this.parseExifData(
27999                                     dataView,
28000                                     offset,
28001                                     markerLength
28002                                 );
28003                             }
28004                             
28005                             offset += markerLength;
28006                             
28007                             continue;
28008                         }
28009                         
28010                         break;
28011                     }
28012                     
28013                 }
28014                 
28015                 var url = _this.urlAPI.createObjectURL(_this.file);
28016                 
28017                 _this.loadCanvas(url);
28018                 
28019                 return;
28020             }
28021             
28022             reader.readAsArrayBuffer(this.file);
28023             
28024         }
28025         
28026     },
28027     
28028     parseExifData : function(dataView, offset, length)
28029     {
28030         var tiffOffset = offset + 10,
28031             littleEndian,
28032             dirOffset;
28033     
28034         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28035             // No Exif data, might be XMP data instead
28036             return;
28037         }
28038         
28039         // Check for the ASCII code for "Exif" (0x45786966):
28040         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28041             // No Exif data, might be XMP data instead
28042             return;
28043         }
28044         if (tiffOffset + 8 > dataView.byteLength) {
28045             Roo.log('Invalid Exif data: Invalid segment size.');
28046             return;
28047         }
28048         // Check for the two null bytes:
28049         if (dataView.getUint16(offset + 8) !== 0x0000) {
28050             Roo.log('Invalid Exif data: Missing byte alignment offset.');
28051             return;
28052         }
28053         // Check the byte alignment:
28054         switch (dataView.getUint16(tiffOffset)) {
28055         case 0x4949:
28056             littleEndian = true;
28057             break;
28058         case 0x4D4D:
28059             littleEndian = false;
28060             break;
28061         default:
28062             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28063             return;
28064         }
28065         // Check for the TIFF tag marker (0x002A):
28066         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28067             Roo.log('Invalid Exif data: Missing TIFF marker.');
28068             return;
28069         }
28070         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28071         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28072         
28073         this.parseExifTags(
28074             dataView,
28075             tiffOffset,
28076             tiffOffset + dirOffset,
28077             littleEndian
28078         );
28079     },
28080     
28081     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28082     {
28083         var tagsNumber,
28084             dirEndOffset,
28085             i;
28086         if (dirOffset + 6 > dataView.byteLength) {
28087             Roo.log('Invalid Exif data: Invalid directory offset.');
28088             return;
28089         }
28090         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28091         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28092         if (dirEndOffset + 4 > dataView.byteLength) {
28093             Roo.log('Invalid Exif data: Invalid directory size.');
28094             return;
28095         }
28096         for (i = 0; i < tagsNumber; i += 1) {
28097             this.parseExifTag(
28098                 dataView,
28099                 tiffOffset,
28100                 dirOffset + 2 + 12 * i, // tag offset
28101                 littleEndian
28102             );
28103         }
28104         // Return the offset to the next directory:
28105         return dataView.getUint32(dirEndOffset, littleEndian);
28106     },
28107     
28108     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
28109     {
28110         var tag = dataView.getUint16(offset, littleEndian);
28111         
28112         this.exif[tag] = this.getExifValue(
28113             dataView,
28114             tiffOffset,
28115             offset,
28116             dataView.getUint16(offset + 2, littleEndian), // tag type
28117             dataView.getUint32(offset + 4, littleEndian), // tag length
28118             littleEndian
28119         );
28120     },
28121     
28122     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28123     {
28124         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28125             tagSize,
28126             dataOffset,
28127             values,
28128             i,
28129             str,
28130             c;
28131     
28132         if (!tagType) {
28133             Roo.log('Invalid Exif data: Invalid tag type.');
28134             return;
28135         }
28136         
28137         tagSize = tagType.size * length;
28138         // Determine if the value is contained in the dataOffset bytes,
28139         // or if the value at the dataOffset is a pointer to the actual data:
28140         dataOffset = tagSize > 4 ?
28141                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28142         if (dataOffset + tagSize > dataView.byteLength) {
28143             Roo.log('Invalid Exif data: Invalid data offset.');
28144             return;
28145         }
28146         if (length === 1) {
28147             return tagType.getValue(dataView, dataOffset, littleEndian);
28148         }
28149         values = [];
28150         for (i = 0; i < length; i += 1) {
28151             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28152         }
28153         
28154         if (tagType.ascii) {
28155             str = '';
28156             // Concatenate the chars:
28157             for (i = 0; i < values.length; i += 1) {
28158                 c = values[i];
28159                 // Ignore the terminating NULL byte(s):
28160                 if (c === '\u0000') {
28161                     break;
28162                 }
28163                 str += c;
28164             }
28165             return str;
28166         }
28167         return values;
28168     }
28169     
28170 });
28171
28172 Roo.apply(Roo.bootstrap.UploadCropbox, {
28173     tags : {
28174         'Orientation': 0x0112
28175     },
28176     
28177     Orientation: {
28178             1: 0, //'top-left',
28179 //            2: 'top-right',
28180             3: 180, //'bottom-right',
28181 //            4: 'bottom-left',
28182 //            5: 'left-top',
28183             6: 90, //'right-top',
28184 //            7: 'right-bottom',
28185             8: 270 //'left-bottom'
28186     },
28187     
28188     exifTagTypes : {
28189         // byte, 8-bit unsigned int:
28190         1: {
28191             getValue: function (dataView, dataOffset) {
28192                 return dataView.getUint8(dataOffset);
28193             },
28194             size: 1
28195         },
28196         // ascii, 8-bit byte:
28197         2: {
28198             getValue: function (dataView, dataOffset) {
28199                 return String.fromCharCode(dataView.getUint8(dataOffset));
28200             },
28201             size: 1,
28202             ascii: true
28203         },
28204         // short, 16 bit int:
28205         3: {
28206             getValue: function (dataView, dataOffset, littleEndian) {
28207                 return dataView.getUint16(dataOffset, littleEndian);
28208             },
28209             size: 2
28210         },
28211         // long, 32 bit int:
28212         4: {
28213             getValue: function (dataView, dataOffset, littleEndian) {
28214                 return dataView.getUint32(dataOffset, littleEndian);
28215             },
28216             size: 4
28217         },
28218         // rational = two long values, first is numerator, second is denominator:
28219         5: {
28220             getValue: function (dataView, dataOffset, littleEndian) {
28221                 return dataView.getUint32(dataOffset, littleEndian) /
28222                     dataView.getUint32(dataOffset + 4, littleEndian);
28223             },
28224             size: 8
28225         },
28226         // slong, 32 bit signed int:
28227         9: {
28228             getValue: function (dataView, dataOffset, littleEndian) {
28229                 return dataView.getInt32(dataOffset, littleEndian);
28230             },
28231             size: 4
28232         },
28233         // srational, two slongs, first is numerator, second is denominator:
28234         10: {
28235             getValue: function (dataView, dataOffset, littleEndian) {
28236                 return dataView.getInt32(dataOffset, littleEndian) /
28237                     dataView.getInt32(dataOffset + 4, littleEndian);
28238             },
28239             size: 8
28240         }
28241     },
28242     
28243     footer : {
28244         STANDARD : [
28245             {
28246                 tag : 'div',
28247                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28248                 action : 'rotate-left',
28249                 cn : [
28250                     {
28251                         tag : 'button',
28252                         cls : 'btn btn-default',
28253                         html : '<i class="fa fa-undo"></i>'
28254                     }
28255                 ]
28256             },
28257             {
28258                 tag : 'div',
28259                 cls : 'btn-group roo-upload-cropbox-picture',
28260                 action : 'picture',
28261                 cn : [
28262                     {
28263                         tag : 'button',
28264                         cls : 'btn btn-default',
28265                         html : '<i class="fa fa-picture-o"></i>'
28266                     }
28267                 ]
28268             },
28269             {
28270                 tag : 'div',
28271                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28272                 action : 'rotate-right',
28273                 cn : [
28274                     {
28275                         tag : 'button',
28276                         cls : 'btn btn-default',
28277                         html : '<i class="fa fa-repeat"></i>'
28278                     }
28279                 ]
28280             }
28281         ],
28282         DOCUMENT : [
28283             {
28284                 tag : 'div',
28285                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28286                 action : 'rotate-left',
28287                 cn : [
28288                     {
28289                         tag : 'button',
28290                         cls : 'btn btn-default',
28291                         html : '<i class="fa fa-undo"></i>'
28292                     }
28293                 ]
28294             },
28295             {
28296                 tag : 'div',
28297                 cls : 'btn-group roo-upload-cropbox-download',
28298                 action : 'download',
28299                 cn : [
28300                     {
28301                         tag : 'button',
28302                         cls : 'btn btn-default',
28303                         html : '<i class="fa fa-download"></i>'
28304                     }
28305                 ]
28306             },
28307             {
28308                 tag : 'div',
28309                 cls : 'btn-group roo-upload-cropbox-crop',
28310                 action : 'crop',
28311                 cn : [
28312                     {
28313                         tag : 'button',
28314                         cls : 'btn btn-default',
28315                         html : '<i class="fa fa-crop"></i>'
28316                     }
28317                 ]
28318             },
28319             {
28320                 tag : 'div',
28321                 cls : 'btn-group roo-upload-cropbox-trash',
28322                 action : 'trash',
28323                 cn : [
28324                     {
28325                         tag : 'button',
28326                         cls : 'btn btn-default',
28327                         html : '<i class="fa fa-trash"></i>'
28328                     }
28329                 ]
28330             },
28331             {
28332                 tag : 'div',
28333                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28334                 action : 'rotate-right',
28335                 cn : [
28336                     {
28337                         tag : 'button',
28338                         cls : 'btn btn-default',
28339                         html : '<i class="fa fa-repeat"></i>'
28340                     }
28341                 ]
28342             }
28343         ],
28344         ROTATOR : [
28345             {
28346                 tag : 'div',
28347                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28348                 action : 'rotate-left',
28349                 cn : [
28350                     {
28351                         tag : 'button',
28352                         cls : 'btn btn-default',
28353                         html : '<i class="fa fa-undo"></i>'
28354                     }
28355                 ]
28356             },
28357             {
28358                 tag : 'div',
28359                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28360                 action : 'rotate-right',
28361                 cn : [
28362                     {
28363                         tag : 'button',
28364                         cls : 'btn btn-default',
28365                         html : '<i class="fa fa-repeat"></i>'
28366                     }
28367                 ]
28368             }
28369         ]
28370     }
28371 });
28372
28373 /*
28374 * Licence: LGPL
28375 */
28376
28377 /**
28378  * @class Roo.bootstrap.DocumentManager
28379  * @extends Roo.bootstrap.Component
28380  * Bootstrap DocumentManager class
28381  * @cfg {String} paramName default 'imageUpload'
28382  * @cfg {String} toolTipName default 'filename'
28383  * @cfg {String} method default POST
28384  * @cfg {String} url action url
28385  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28386  * @cfg {Boolean} multiple multiple upload default true
28387  * @cfg {Number} thumbSize default 300
28388  * @cfg {String} fieldLabel
28389  * @cfg {Number} labelWidth default 4
28390  * @cfg {String} labelAlign (left|top) default left
28391  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28392 * @cfg {Number} labellg set the width of label (1-12)
28393  * @cfg {Number} labelmd set the width of label (1-12)
28394  * @cfg {Number} labelsm set the width of label (1-12)
28395  * @cfg {Number} labelxs set the width of label (1-12)
28396  * 
28397  * @constructor
28398  * Create a new DocumentManager
28399  * @param {Object} config The config object
28400  */
28401
28402 Roo.bootstrap.DocumentManager = function(config){
28403     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28404     
28405     this.files = [];
28406     this.delegates = [];
28407     
28408     this.addEvents({
28409         /**
28410          * @event initial
28411          * Fire when initial the DocumentManager
28412          * @param {Roo.bootstrap.DocumentManager} this
28413          */
28414         "initial" : true,
28415         /**
28416          * @event inspect
28417          * inspect selected file
28418          * @param {Roo.bootstrap.DocumentManager} this
28419          * @param {File} file
28420          */
28421         "inspect" : true,
28422         /**
28423          * @event exception
28424          * Fire when xhr load exception
28425          * @param {Roo.bootstrap.DocumentManager} this
28426          * @param {XMLHttpRequest} xhr
28427          */
28428         "exception" : true,
28429         /**
28430          * @event afterupload
28431          * Fire when xhr load exception
28432          * @param {Roo.bootstrap.DocumentManager} this
28433          * @param {XMLHttpRequest} xhr
28434          */
28435         "afterupload" : true,
28436         /**
28437          * @event prepare
28438          * prepare the form data
28439          * @param {Roo.bootstrap.DocumentManager} this
28440          * @param {Object} formData
28441          */
28442         "prepare" : true,
28443         /**
28444          * @event remove
28445          * Fire when remove the file
28446          * @param {Roo.bootstrap.DocumentManager} this
28447          * @param {Object} file
28448          */
28449         "remove" : true,
28450         /**
28451          * @event refresh
28452          * Fire after refresh the file
28453          * @param {Roo.bootstrap.DocumentManager} this
28454          */
28455         "refresh" : true,
28456         /**
28457          * @event click
28458          * Fire after click the image
28459          * @param {Roo.bootstrap.DocumentManager} this
28460          * @param {Object} file
28461          */
28462         "click" : true,
28463         /**
28464          * @event edit
28465          * Fire when upload a image and editable set to true
28466          * @param {Roo.bootstrap.DocumentManager} this
28467          * @param {Object} file
28468          */
28469         "edit" : true,
28470         /**
28471          * @event beforeselectfile
28472          * Fire before select file
28473          * @param {Roo.bootstrap.DocumentManager} this
28474          */
28475         "beforeselectfile" : true,
28476         /**
28477          * @event process
28478          * Fire before process file
28479          * @param {Roo.bootstrap.DocumentManager} this
28480          * @param {Object} file
28481          */
28482         "process" : true,
28483         /**
28484          * @event previewrendered
28485          * Fire when preview rendered
28486          * @param {Roo.bootstrap.DocumentManager} this
28487          * @param {Object} file
28488          */
28489         "previewrendered" : true
28490         
28491     });
28492 };
28493
28494 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
28495     
28496     boxes : 0,
28497     inputName : '',
28498     thumbSize : 300,
28499     multiple : true,
28500     files : false,
28501     method : 'POST',
28502     url : '',
28503     paramName : 'imageUpload',
28504     toolTipName : 'filename',
28505     fieldLabel : '',
28506     labelWidth : 4,
28507     labelAlign : 'left',
28508     editable : true,
28509     delegates : false,
28510     xhr : false, 
28511     
28512     labellg : 0,
28513     labelmd : 0,
28514     labelsm : 0,
28515     labelxs : 0,
28516     
28517     getAutoCreate : function()
28518     {   
28519         var managerWidget = {
28520             tag : 'div',
28521             cls : 'roo-document-manager',
28522             cn : [
28523                 {
28524                     tag : 'input',
28525                     cls : 'roo-document-manager-selector',
28526                     type : 'file'
28527                 },
28528                 {
28529                     tag : 'div',
28530                     cls : 'roo-document-manager-uploader',
28531                     cn : [
28532                         {
28533                             tag : 'div',
28534                             cls : 'roo-document-manager-upload-btn',
28535                             html : '<i class="fa fa-plus"></i>'
28536                         }
28537                     ]
28538                     
28539                 }
28540             ]
28541         };
28542         
28543         var content = [
28544             {
28545                 tag : 'div',
28546                 cls : 'column col-md-12',
28547                 cn : managerWidget
28548             }
28549         ];
28550         
28551         if(this.fieldLabel.length){
28552             
28553             content = [
28554                 {
28555                     tag : 'div',
28556                     cls : 'column col-md-12',
28557                     html : this.fieldLabel
28558                 },
28559                 {
28560                     tag : 'div',
28561                     cls : 'column col-md-12',
28562                     cn : managerWidget
28563                 }
28564             ];
28565
28566             if(this.labelAlign == 'left'){
28567                 content = [
28568                     {
28569                         tag : 'div',
28570                         cls : 'column',
28571                         html : this.fieldLabel
28572                     },
28573                     {
28574                         tag : 'div',
28575                         cls : 'column',
28576                         cn : managerWidget
28577                     }
28578                 ];
28579                 
28580                 if(this.labelWidth > 12){
28581                     content[0].style = "width: " + this.labelWidth + 'px';
28582                 }
28583
28584                 if(this.labelWidth < 13 && this.labelmd == 0){
28585                     this.labelmd = this.labelWidth;
28586                 }
28587
28588                 if(this.labellg > 0){
28589                     content[0].cls += ' col-lg-' + this.labellg;
28590                     content[1].cls += ' col-lg-' + (12 - this.labellg);
28591                 }
28592
28593                 if(this.labelmd > 0){
28594                     content[0].cls += ' col-md-' + this.labelmd;
28595                     content[1].cls += ' col-md-' + (12 - this.labelmd);
28596                 }
28597
28598                 if(this.labelsm > 0){
28599                     content[0].cls += ' col-sm-' + this.labelsm;
28600                     content[1].cls += ' col-sm-' + (12 - this.labelsm);
28601                 }
28602
28603                 if(this.labelxs > 0){
28604                     content[0].cls += ' col-xs-' + this.labelxs;
28605                     content[1].cls += ' col-xs-' + (12 - this.labelxs);
28606                 }
28607                 
28608             }
28609         }
28610         
28611         var cfg = {
28612             tag : 'div',
28613             cls : 'row clearfix',
28614             cn : content
28615         };
28616         
28617         return cfg;
28618         
28619     },
28620     
28621     initEvents : function()
28622     {
28623         this.managerEl = this.el.select('.roo-document-manager', true).first();
28624         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28625         
28626         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28627         this.selectorEl.hide();
28628         
28629         if(this.multiple){
28630             this.selectorEl.attr('multiple', 'multiple');
28631         }
28632         
28633         this.selectorEl.on('change', this.onFileSelected, this);
28634         
28635         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28636         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28637         
28638         this.uploader.on('click', this.onUploaderClick, this);
28639         
28640         this.renderProgressDialog();
28641         
28642         var _this = this;
28643         
28644         window.addEventListener("resize", function() { _this.refresh(); } );
28645         
28646         this.fireEvent('initial', this);
28647     },
28648     
28649     renderProgressDialog : function()
28650     {
28651         var _this = this;
28652         
28653         this.progressDialog = new Roo.bootstrap.Modal({
28654             cls : 'roo-document-manager-progress-dialog',
28655             allow_close : false,
28656             title : '',
28657             buttons : [
28658                 {
28659                     name  :'cancel',
28660                     weight : 'danger',
28661                     html : 'Cancel'
28662                 }
28663             ], 
28664             listeners : { 
28665                 btnclick : function() {
28666                     _this.uploadCancel();
28667                     this.hide();
28668                 }
28669             }
28670         });
28671          
28672         this.progressDialog.render(Roo.get(document.body));
28673          
28674         this.progress = new Roo.bootstrap.Progress({
28675             cls : 'roo-document-manager-progress',
28676             active : true,
28677             striped : true
28678         });
28679         
28680         this.progress.render(this.progressDialog.getChildContainer());
28681         
28682         this.progressBar = new Roo.bootstrap.ProgressBar({
28683             cls : 'roo-document-manager-progress-bar',
28684             aria_valuenow : 0,
28685             aria_valuemin : 0,
28686             aria_valuemax : 12,
28687             panel : 'success'
28688         });
28689         
28690         this.progressBar.render(this.progress.getChildContainer());
28691     },
28692     
28693     onUploaderClick : function(e)
28694     {
28695         e.preventDefault();
28696      
28697         if(this.fireEvent('beforeselectfile', this) != false){
28698             this.selectorEl.dom.click();
28699         }
28700         
28701     },
28702     
28703     onFileSelected : function(e)
28704     {
28705         e.preventDefault();
28706         
28707         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28708             return;
28709         }
28710         
28711         Roo.each(this.selectorEl.dom.files, function(file){
28712             if(this.fireEvent('inspect', this, file) != false){
28713                 this.files.push(file);
28714             }
28715         }, this);
28716         
28717         this.queue();
28718         
28719     },
28720     
28721     queue : function()
28722     {
28723         this.selectorEl.dom.value = '';
28724         
28725         if(!this.files || !this.files.length){
28726             return;
28727         }
28728         
28729         if(this.boxes > 0 && this.files.length > this.boxes){
28730             this.files = this.files.slice(0, this.boxes);
28731         }
28732         
28733         this.uploader.show();
28734         
28735         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28736             this.uploader.hide();
28737         }
28738         
28739         var _this = this;
28740         
28741         var files = [];
28742         
28743         var docs = [];
28744         
28745         Roo.each(this.files, function(file){
28746             
28747             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28748                 var f = this.renderPreview(file);
28749                 files.push(f);
28750                 return;
28751             }
28752             
28753             if(file.type.indexOf('image') != -1){
28754                 this.delegates.push(
28755                     (function(){
28756                         _this.process(file);
28757                     }).createDelegate(this)
28758                 );
28759         
28760                 return;
28761             }
28762             
28763             docs.push(
28764                 (function(){
28765                     _this.process(file);
28766                 }).createDelegate(this)
28767             );
28768             
28769         }, this);
28770         
28771         this.files = files;
28772         
28773         this.delegates = this.delegates.concat(docs);
28774         
28775         if(!this.delegates.length){
28776             this.refresh();
28777             return;
28778         }
28779         
28780         this.progressBar.aria_valuemax = this.delegates.length;
28781         
28782         this.arrange();
28783         
28784         return;
28785     },
28786     
28787     arrange : function()
28788     {
28789         if(!this.delegates.length){
28790             this.progressDialog.hide();
28791             this.refresh();
28792             return;
28793         }
28794         
28795         var delegate = this.delegates.shift();
28796         
28797         this.progressDialog.show();
28798         
28799         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28800         
28801         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28802         
28803         delegate();
28804     },
28805     
28806     refresh : function()
28807     {
28808         this.uploader.show();
28809         
28810         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28811             this.uploader.hide();
28812         }
28813         
28814         Roo.isTouch ? this.closable(false) : this.closable(true);
28815         
28816         this.fireEvent('refresh', this);
28817     },
28818     
28819     onRemove : function(e, el, o)
28820     {
28821         e.preventDefault();
28822         
28823         this.fireEvent('remove', this, o);
28824         
28825     },
28826     
28827     remove : function(o)
28828     {
28829         var files = [];
28830         
28831         Roo.each(this.files, function(file){
28832             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28833                 files.push(file);
28834                 return;
28835             }
28836
28837             o.target.remove();
28838
28839         }, this);
28840         
28841         this.files = files;
28842         
28843         this.refresh();
28844     },
28845     
28846     clear : function()
28847     {
28848         Roo.each(this.files, function(file){
28849             if(!file.target){
28850                 return;
28851             }
28852             
28853             file.target.remove();
28854
28855         }, this);
28856         
28857         this.files = [];
28858         
28859         this.refresh();
28860     },
28861     
28862     onClick : function(e, el, o)
28863     {
28864         e.preventDefault();
28865         
28866         this.fireEvent('click', this, o);
28867         
28868     },
28869     
28870     closable : function(closable)
28871     {
28872         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28873             
28874             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28875             
28876             if(closable){
28877                 el.show();
28878                 return;
28879             }
28880             
28881             el.hide();
28882             
28883         }, this);
28884     },
28885     
28886     xhrOnLoad : function(xhr)
28887     {
28888         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28889             el.remove();
28890         }, this);
28891         
28892         if (xhr.readyState !== 4) {
28893             this.arrange();
28894             this.fireEvent('exception', this, xhr);
28895             return;
28896         }
28897
28898         var response = Roo.decode(xhr.responseText);
28899         
28900         if(!response.success){
28901             this.arrange();
28902             this.fireEvent('exception', this, xhr);
28903             return;
28904         }
28905         
28906         var file = this.renderPreview(response.data);
28907         
28908         this.files.push(file);
28909         
28910         this.arrange();
28911         
28912         this.fireEvent('afterupload', this, xhr);
28913         
28914     },
28915     
28916     xhrOnError : function(xhr)
28917     {
28918         Roo.log('xhr on error');
28919         
28920         var response = Roo.decode(xhr.responseText);
28921           
28922         Roo.log(response);
28923         
28924         this.arrange();
28925     },
28926     
28927     process : function(file)
28928     {
28929         if(this.fireEvent('process', this, file) !== false){
28930             if(this.editable && file.type.indexOf('image') != -1){
28931                 this.fireEvent('edit', this, file);
28932                 return;
28933             }
28934
28935             this.uploadStart(file, false);
28936
28937             return;
28938         }
28939         
28940     },
28941     
28942     uploadStart : function(file, crop)
28943     {
28944         this.xhr = new XMLHttpRequest();
28945         
28946         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28947             this.arrange();
28948             return;
28949         }
28950         
28951         file.xhr = this.xhr;
28952             
28953         this.managerEl.createChild({
28954             tag : 'div',
28955             cls : 'roo-document-manager-loading',
28956             cn : [
28957                 {
28958                     tag : 'div',
28959                     tooltip : file.name,
28960                     cls : 'roo-document-manager-thumb',
28961                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28962                 }
28963             ]
28964
28965         });
28966
28967         this.xhr.open(this.method, this.url, true);
28968         
28969         var headers = {
28970             "Accept": "application/json",
28971             "Cache-Control": "no-cache",
28972             "X-Requested-With": "XMLHttpRequest"
28973         };
28974         
28975         for (var headerName in headers) {
28976             var headerValue = headers[headerName];
28977             if (headerValue) {
28978                 this.xhr.setRequestHeader(headerName, headerValue);
28979             }
28980         }
28981         
28982         var _this = this;
28983         
28984         this.xhr.onload = function()
28985         {
28986             _this.xhrOnLoad(_this.xhr);
28987         }
28988         
28989         this.xhr.onerror = function()
28990         {
28991             _this.xhrOnError(_this.xhr);
28992         }
28993         
28994         var formData = new FormData();
28995
28996         formData.append('returnHTML', 'NO');
28997         
28998         if(crop){
28999             formData.append('crop', crop);
29000         }
29001         
29002         formData.append(this.paramName, file, file.name);
29003         
29004         var options = {
29005             file : file, 
29006             manually : false
29007         };
29008         
29009         if(this.fireEvent('prepare', this, formData, options) != false){
29010             
29011             if(options.manually){
29012                 return;
29013             }
29014             
29015             this.xhr.send(formData);
29016             return;
29017         };
29018         
29019         this.uploadCancel();
29020     },
29021     
29022     uploadCancel : function()
29023     {
29024         if (this.xhr) {
29025             this.xhr.abort();
29026         }
29027         
29028         this.delegates = [];
29029         
29030         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29031             el.remove();
29032         }, this);
29033         
29034         this.arrange();
29035     },
29036     
29037     renderPreview : function(file)
29038     {
29039         if(typeof(file.target) != 'undefined' && file.target){
29040             return file;
29041         }
29042         
29043         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29044         
29045         var previewEl = this.managerEl.createChild({
29046             tag : 'div',
29047             cls : 'roo-document-manager-preview',
29048             cn : [
29049                 {
29050                     tag : 'div',
29051                     tooltip : file[this.toolTipName],
29052                     cls : 'roo-document-manager-thumb',
29053                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29054                 },
29055                 {
29056                     tag : 'button',
29057                     cls : 'close',
29058                     html : '<i class="fa fa-times-circle"></i>'
29059                 }
29060             ]
29061         });
29062
29063         var close = previewEl.select('button.close', true).first();
29064
29065         close.on('click', this.onRemove, this, file);
29066
29067         file.target = previewEl;
29068
29069         var image = previewEl.select('img', true).first();
29070         
29071         var _this = this;
29072         
29073         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29074         
29075         image.on('click', this.onClick, this, file);
29076         
29077         this.fireEvent('previewrendered', this, file);
29078         
29079         return file;
29080         
29081     },
29082     
29083     onPreviewLoad : function(file, image)
29084     {
29085         if(typeof(file.target) == 'undefined' || !file.target){
29086             return;
29087         }
29088         
29089         var width = image.dom.naturalWidth || image.dom.width;
29090         var height = image.dom.naturalHeight || image.dom.height;
29091         
29092         if(width > height){
29093             file.target.addClass('wide');
29094             return;
29095         }
29096         
29097         file.target.addClass('tall');
29098         return;
29099         
29100     },
29101     
29102     uploadFromSource : function(file, crop)
29103     {
29104         this.xhr = new XMLHttpRequest();
29105         
29106         this.managerEl.createChild({
29107             tag : 'div',
29108             cls : 'roo-document-manager-loading',
29109             cn : [
29110                 {
29111                     tag : 'div',
29112                     tooltip : file.name,
29113                     cls : 'roo-document-manager-thumb',
29114                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29115                 }
29116             ]
29117
29118         });
29119
29120         this.xhr.open(this.method, this.url, true);
29121         
29122         var headers = {
29123             "Accept": "application/json",
29124             "Cache-Control": "no-cache",
29125             "X-Requested-With": "XMLHttpRequest"
29126         };
29127         
29128         for (var headerName in headers) {
29129             var headerValue = headers[headerName];
29130             if (headerValue) {
29131                 this.xhr.setRequestHeader(headerName, headerValue);
29132             }
29133         }
29134         
29135         var _this = this;
29136         
29137         this.xhr.onload = function()
29138         {
29139             _this.xhrOnLoad(_this.xhr);
29140         }
29141         
29142         this.xhr.onerror = function()
29143         {
29144             _this.xhrOnError(_this.xhr);
29145         }
29146         
29147         var formData = new FormData();
29148
29149         formData.append('returnHTML', 'NO');
29150         
29151         formData.append('crop', crop);
29152         
29153         if(typeof(file.filename) != 'undefined'){
29154             formData.append('filename', file.filename);
29155         }
29156         
29157         if(typeof(file.mimetype) != 'undefined'){
29158             formData.append('mimetype', file.mimetype);
29159         }
29160         
29161         Roo.log(formData);
29162         
29163         if(this.fireEvent('prepare', this, formData) != false){
29164             this.xhr.send(formData);
29165         };
29166     }
29167 });
29168
29169 /*
29170 * Licence: LGPL
29171 */
29172
29173 /**
29174  * @class Roo.bootstrap.DocumentViewer
29175  * @extends Roo.bootstrap.Component
29176  * Bootstrap DocumentViewer class
29177  * @cfg {Boolean} showDownload (true|false) show download button (default true)
29178  * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29179  * 
29180  * @constructor
29181  * Create a new DocumentViewer
29182  * @param {Object} config The config object
29183  */
29184
29185 Roo.bootstrap.DocumentViewer = function(config){
29186     Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29187     
29188     this.addEvents({
29189         /**
29190          * @event initial
29191          * Fire after initEvent
29192          * @param {Roo.bootstrap.DocumentViewer} this
29193          */
29194         "initial" : true,
29195         /**
29196          * @event click
29197          * Fire after click
29198          * @param {Roo.bootstrap.DocumentViewer} this
29199          */
29200         "click" : true,
29201         /**
29202          * @event download
29203          * Fire after download button
29204          * @param {Roo.bootstrap.DocumentViewer} this
29205          */
29206         "download" : true,
29207         /**
29208          * @event trash
29209          * Fire after trash button
29210          * @param {Roo.bootstrap.DocumentViewer} this
29211          */
29212         "trash" : true
29213         
29214     });
29215 };
29216
29217 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
29218     
29219     showDownload : true,
29220     
29221     showTrash : true,
29222     
29223     getAutoCreate : function()
29224     {
29225         var cfg = {
29226             tag : 'div',
29227             cls : 'roo-document-viewer',
29228             cn : [
29229                 {
29230                     tag : 'div',
29231                     cls : 'roo-document-viewer-body',
29232                     cn : [
29233                         {
29234                             tag : 'div',
29235                             cls : 'roo-document-viewer-thumb',
29236                             cn : [
29237                                 {
29238                                     tag : 'img',
29239                                     cls : 'roo-document-viewer-image'
29240                                 }
29241                             ]
29242                         }
29243                     ]
29244                 },
29245                 {
29246                     tag : 'div',
29247                     cls : 'roo-document-viewer-footer',
29248                     cn : {
29249                         tag : 'div',
29250                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29251                         cn : [
29252                             {
29253                                 tag : 'div',
29254                                 cls : 'btn-group roo-document-viewer-download',
29255                                 cn : [
29256                                     {
29257                                         tag : 'button',
29258                                         cls : 'btn btn-default',
29259                                         html : '<i class="fa fa-download"></i>'
29260                                     }
29261                                 ]
29262                             },
29263                             {
29264                                 tag : 'div',
29265                                 cls : 'btn-group roo-document-viewer-trash',
29266                                 cn : [
29267                                     {
29268                                         tag : 'button',
29269                                         cls : 'btn btn-default',
29270                                         html : '<i class="fa fa-trash"></i>'
29271                                     }
29272                                 ]
29273                             }
29274                         ]
29275                     }
29276                 }
29277             ]
29278         };
29279         
29280         return cfg;
29281     },
29282     
29283     initEvents : function()
29284     {
29285         this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29286         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29287         
29288         this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29289         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29290         
29291         this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29292         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29293         
29294         this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29295         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29296         
29297         this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29298         this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29299         
29300         this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29301         this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29302         
29303         this.bodyEl.on('click', this.onClick, this);
29304         this.downloadBtn.on('click', this.onDownload, this);
29305         this.trashBtn.on('click', this.onTrash, this);
29306         
29307         this.downloadBtn.hide();
29308         this.trashBtn.hide();
29309         
29310         if(this.showDownload){
29311             this.downloadBtn.show();
29312         }
29313         
29314         if(this.showTrash){
29315             this.trashBtn.show();
29316         }
29317         
29318         if(!this.showDownload && !this.showTrash) {
29319             this.footerEl.hide();
29320         }
29321         
29322     },
29323     
29324     initial : function()
29325     {
29326         this.fireEvent('initial', this);
29327         
29328     },
29329     
29330     onClick : function(e)
29331     {
29332         e.preventDefault();
29333         
29334         this.fireEvent('click', this);
29335     },
29336     
29337     onDownload : function(e)
29338     {
29339         e.preventDefault();
29340         
29341         this.fireEvent('download', this);
29342     },
29343     
29344     onTrash : function(e)
29345     {
29346         e.preventDefault();
29347         
29348         this.fireEvent('trash', this);
29349     }
29350     
29351 });
29352 /*
29353  * - LGPL
29354  *
29355  * nav progress bar
29356  * 
29357  */
29358
29359 /**
29360  * @class Roo.bootstrap.NavProgressBar
29361  * @extends Roo.bootstrap.Component
29362  * Bootstrap NavProgressBar class
29363  * 
29364  * @constructor
29365  * Create a new nav progress bar
29366  * @param {Object} config The config object
29367  */
29368
29369 Roo.bootstrap.NavProgressBar = function(config){
29370     Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29371
29372     this.bullets = this.bullets || [];
29373    
29374 //    Roo.bootstrap.NavProgressBar.register(this);
29375      this.addEvents({
29376         /**
29377              * @event changed
29378              * Fires when the active item changes
29379              * @param {Roo.bootstrap.NavProgressBar} this
29380              * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29381              * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
29382          */
29383         'changed': true
29384      });
29385     
29386 };
29387
29388 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
29389     
29390     bullets : [],
29391     barItems : [],
29392     
29393     getAutoCreate : function()
29394     {
29395         var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29396         
29397         cfg = {
29398             tag : 'div',
29399             cls : 'roo-navigation-bar-group',
29400             cn : [
29401                 {
29402                     tag : 'div',
29403                     cls : 'roo-navigation-top-bar'
29404                 },
29405                 {
29406                     tag : 'div',
29407                     cls : 'roo-navigation-bullets-bar',
29408                     cn : [
29409                         {
29410                             tag : 'ul',
29411                             cls : 'roo-navigation-bar'
29412                         }
29413                     ]
29414                 },
29415                 
29416                 {
29417                     tag : 'div',
29418                     cls : 'roo-navigation-bottom-bar'
29419                 }
29420             ]
29421             
29422         };
29423         
29424         return cfg;
29425         
29426     },
29427     
29428     initEvents: function() 
29429     {
29430         
29431     },
29432     
29433     onRender : function(ct, position) 
29434     {
29435         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29436         
29437         if(this.bullets.length){
29438             Roo.each(this.bullets, function(b){
29439                this.addItem(b);
29440             }, this);
29441         }
29442         
29443         this.format();
29444         
29445     },
29446     
29447     addItem : function(cfg)
29448     {
29449         var item = new Roo.bootstrap.NavProgressItem(cfg);
29450         
29451         item.parentId = this.id;
29452         item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29453         
29454         if(cfg.html){
29455             var top = new Roo.bootstrap.Element({
29456                 tag : 'div',
29457                 cls : 'roo-navigation-bar-text'
29458             });
29459             
29460             var bottom = new Roo.bootstrap.Element({
29461                 tag : 'div',
29462                 cls : 'roo-navigation-bar-text'
29463             });
29464             
29465             top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29466             bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29467             
29468             var topText = new Roo.bootstrap.Element({
29469                 tag : 'span',
29470                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29471             });
29472             
29473             var bottomText = new Roo.bootstrap.Element({
29474                 tag : 'span',
29475                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29476             });
29477             
29478             topText.onRender(top.el, null);
29479             bottomText.onRender(bottom.el, null);
29480             
29481             item.topEl = top;
29482             item.bottomEl = bottom;
29483         }
29484         
29485         this.barItems.push(item);
29486         
29487         return item;
29488     },
29489     
29490     getActive : function()
29491     {
29492         var active = false;
29493         
29494         Roo.each(this.barItems, function(v){
29495             
29496             if (!v.isActive()) {
29497                 return;
29498             }
29499             
29500             active = v;
29501             return false;
29502             
29503         });
29504         
29505         return active;
29506     },
29507     
29508     setActiveItem : function(item)
29509     {
29510         var prev = false;
29511         
29512         Roo.each(this.barItems, function(v){
29513             if (v.rid == item.rid) {
29514                 return ;
29515             }
29516             
29517             if (v.isActive()) {
29518                 v.setActive(false);
29519                 prev = v;
29520             }
29521         });
29522
29523         item.setActive(true);
29524         
29525         this.fireEvent('changed', this, item, prev);
29526     },
29527     
29528     getBarItem: function(rid)
29529     {
29530         var ret = false;
29531         
29532         Roo.each(this.barItems, function(e) {
29533             if (e.rid != rid) {
29534                 return;
29535             }
29536             
29537             ret =  e;
29538             return false;
29539         });
29540         
29541         return ret;
29542     },
29543     
29544     indexOfItem : function(item)
29545     {
29546         var index = false;
29547         
29548         Roo.each(this.barItems, function(v, i){
29549             
29550             if (v.rid != item.rid) {
29551                 return;
29552             }
29553             
29554             index = i;
29555             return false
29556         });
29557         
29558         return index;
29559     },
29560     
29561     setActiveNext : function()
29562     {
29563         var i = this.indexOfItem(this.getActive());
29564         
29565         if (i > this.barItems.length) {
29566             return;
29567         }
29568         
29569         this.setActiveItem(this.barItems[i+1]);
29570     },
29571     
29572     setActivePrev : function()
29573     {
29574         var i = this.indexOfItem(this.getActive());
29575         
29576         if (i  < 1) {
29577             return;
29578         }
29579         
29580         this.setActiveItem(this.barItems[i-1]);
29581     },
29582     
29583     format : function()
29584     {
29585         if(!this.barItems.length){
29586             return;
29587         }
29588      
29589         var width = 100 / this.barItems.length;
29590         
29591         Roo.each(this.barItems, function(i){
29592             i.el.setStyle('width', width + '%');
29593             i.topEl.el.setStyle('width', width + '%');
29594             i.bottomEl.el.setStyle('width', width + '%');
29595         }, this);
29596         
29597     }
29598     
29599 });
29600 /*
29601  * - LGPL
29602  *
29603  * Nav Progress Item
29604  * 
29605  */
29606
29607 /**
29608  * @class Roo.bootstrap.NavProgressItem
29609  * @extends Roo.bootstrap.Component
29610  * Bootstrap NavProgressItem class
29611  * @cfg {String} rid the reference id
29612  * @cfg {Boolean} active (true|false) Is item active default false
29613  * @cfg {Boolean} disabled (true|false) Is item active default false
29614  * @cfg {String} html
29615  * @cfg {String} position (top|bottom) text position default bottom
29616  * @cfg {String} icon show icon instead of number
29617  * 
29618  * @constructor
29619  * Create a new NavProgressItem
29620  * @param {Object} config The config object
29621  */
29622 Roo.bootstrap.NavProgressItem = function(config){
29623     Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29624     this.addEvents({
29625         // raw events
29626         /**
29627          * @event click
29628          * The raw click event for the entire grid.
29629          * @param {Roo.bootstrap.NavProgressItem} this
29630          * @param {Roo.EventObject} e
29631          */
29632         "click" : true
29633     });
29634    
29635 };
29636
29637 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
29638     
29639     rid : '',
29640     active : false,
29641     disabled : false,
29642     html : '',
29643     position : 'bottom',
29644     icon : false,
29645     
29646     getAutoCreate : function()
29647     {
29648         var iconCls = 'roo-navigation-bar-item-icon';
29649         
29650         iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29651         
29652         var cfg = {
29653             tag: 'li',
29654             cls: 'roo-navigation-bar-item',
29655             cn : [
29656                 {
29657                     tag : 'i',
29658                     cls : iconCls
29659                 }
29660             ]
29661         };
29662         
29663         if(this.active){
29664             cfg.cls += ' active';
29665         }
29666         if(this.disabled){
29667             cfg.cls += ' disabled';
29668         }
29669         
29670         return cfg;
29671     },
29672     
29673     disable : function()
29674     {
29675         this.setDisabled(true);
29676     },
29677     
29678     enable : function()
29679     {
29680         this.setDisabled(false);
29681     },
29682     
29683     initEvents: function() 
29684     {
29685         this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29686         
29687         this.iconEl.on('click', this.onClick, this);
29688     },
29689     
29690     onClick : function(e)
29691     {
29692         e.preventDefault();
29693         
29694         if(this.disabled){
29695             return;
29696         }
29697         
29698         if(this.fireEvent('click', this, e) === false){
29699             return;
29700         };
29701         
29702         this.parent().setActiveItem(this);
29703     },
29704     
29705     isActive: function () 
29706     {
29707         return this.active;
29708     },
29709     
29710     setActive : function(state)
29711     {
29712         if(this.active == state){
29713             return;
29714         }
29715         
29716         this.active = state;
29717         
29718         if (state) {
29719             this.el.addClass('active');
29720             return;
29721         }
29722         
29723         this.el.removeClass('active');
29724         
29725         return;
29726     },
29727     
29728     setDisabled : function(state)
29729     {
29730         if(this.disabled == state){
29731             return;
29732         }
29733         
29734         this.disabled = state;
29735         
29736         if (state) {
29737             this.el.addClass('disabled');
29738             return;
29739         }
29740         
29741         this.el.removeClass('disabled');
29742     },
29743     
29744     tooltipEl : function()
29745     {
29746         return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29747     }
29748 });
29749  
29750
29751  /*
29752  * - LGPL
29753  *
29754  * FieldLabel
29755  * 
29756  */
29757
29758 /**
29759  * @class Roo.bootstrap.FieldLabel
29760  * @extends Roo.bootstrap.Component
29761  * Bootstrap FieldLabel class
29762  * @cfg {String} html contents of the element
29763  * @cfg {String} tag tag of the element default label
29764  * @cfg {String} cls class of the element
29765  * @cfg {String} target label target 
29766  * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29767  * @cfg {String} invalidClass default "text-warning"
29768  * @cfg {String} validClass default "text-success"
29769  * @cfg {String} iconTooltip default "This field is required"
29770  * @cfg {String} indicatorpos (left|right) default left
29771  * 
29772  * @constructor
29773  * Create a new FieldLabel
29774  * @param {Object} config The config object
29775  */
29776
29777 Roo.bootstrap.FieldLabel = function(config){
29778     Roo.bootstrap.Element.superclass.constructor.call(this, config);
29779     
29780     this.addEvents({
29781             /**
29782              * @event invalid
29783              * Fires after the field has been marked as invalid.
29784              * @param {Roo.form.FieldLabel} this
29785              * @param {String} msg The validation message
29786              */
29787             invalid : true,
29788             /**
29789              * @event valid
29790              * Fires after the field has been validated with no errors.
29791              * @param {Roo.form.FieldLabel} this
29792              */
29793             valid : true
29794         });
29795 };
29796
29797 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
29798     
29799     tag: 'label',
29800     cls: '',
29801     html: '',
29802     target: '',
29803     allowBlank : true,
29804     invalidClass : 'has-warning',
29805     validClass : 'has-success',
29806     iconTooltip : 'This field is required',
29807     indicatorpos : 'left',
29808     
29809     getAutoCreate : function(){
29810         
29811         var cfg = {
29812             tag : this.tag,
29813             cls : 'roo-bootstrap-field-label ' + this.cls,
29814             for : this.target,
29815             cn : [
29816                 {
29817                     tag : 'i',
29818                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29819                     tooltip : this.iconTooltip
29820                 },
29821                 {
29822                     tag : 'span',
29823                     html : this.html
29824                 }
29825             ] 
29826         };
29827         
29828         if(this.indicatorpos == 'right'){
29829             var cfg = {
29830                 tag : this.tag,
29831                 cls : 'roo-bootstrap-field-label ' + this.cls,
29832                 for : this.target,
29833                 cn : [
29834                     {
29835                         tag : 'span',
29836                         html : this.html
29837                     },
29838                     {
29839                         tag : 'i',
29840                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29841                         tooltip : this.iconTooltip
29842                     }
29843                 ] 
29844             };
29845         }
29846         
29847         return cfg;
29848     },
29849     
29850     initEvents: function() 
29851     {
29852         Roo.bootstrap.Element.superclass.initEvents.call(this);
29853         
29854         this.indicator = this.indicatorEl();
29855         
29856         if(this.indicator){
29857             this.indicator.removeClass('visible');
29858             this.indicator.addClass('invisible');
29859         }
29860         
29861         Roo.bootstrap.FieldLabel.register(this);
29862     },
29863     
29864     indicatorEl : function()
29865     {
29866         var indicator = this.el.select('i.roo-required-indicator',true).first();
29867         
29868         if(!indicator){
29869             return false;
29870         }
29871         
29872         return indicator;
29873         
29874     },
29875     
29876     /**
29877      * Mark this field as valid
29878      */
29879     markValid : function()
29880     {
29881         if(this.indicator){
29882             this.indicator.removeClass('visible');
29883             this.indicator.addClass('invisible');
29884         }
29885         
29886         this.el.removeClass(this.invalidClass);
29887         
29888         this.el.addClass(this.validClass);
29889         
29890         this.fireEvent('valid', this);
29891     },
29892     
29893     /**
29894      * Mark this field as invalid
29895      * @param {String} msg The validation message
29896      */
29897     markInvalid : function(msg)
29898     {
29899         if(this.indicator){
29900             this.indicator.removeClass('invisible');
29901             this.indicator.addClass('visible');
29902         }
29903         
29904         this.el.removeClass(this.validClass);
29905         
29906         this.el.addClass(this.invalidClass);
29907         
29908         this.fireEvent('invalid', this, msg);
29909     }
29910     
29911    
29912 });
29913
29914 Roo.apply(Roo.bootstrap.FieldLabel, {
29915     
29916     groups: {},
29917     
29918      /**
29919     * register a FieldLabel Group
29920     * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29921     */
29922     register : function(label)
29923     {
29924         if(this.groups.hasOwnProperty(label.target)){
29925             return;
29926         }
29927      
29928         this.groups[label.target] = label;
29929         
29930     },
29931     /**
29932     * fetch a FieldLabel Group based on the target
29933     * @param {string} target
29934     * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29935     */
29936     get: function(target) {
29937         if (typeof(this.groups[target]) == 'undefined') {
29938             return false;
29939         }
29940         
29941         return this.groups[target] ;
29942     }
29943 });
29944
29945  
29946
29947  /*
29948  * - LGPL
29949  *
29950  * page DateSplitField.
29951  * 
29952  */
29953
29954
29955 /**
29956  * @class Roo.bootstrap.DateSplitField
29957  * @extends Roo.bootstrap.Component
29958  * Bootstrap DateSplitField class
29959  * @cfg {string} fieldLabel - the label associated
29960  * @cfg {Number} labelWidth set the width of label (0-12)
29961  * @cfg {String} labelAlign (top|left)
29962  * @cfg {Boolean} dayAllowBlank (true|false) default false
29963  * @cfg {Boolean} monthAllowBlank (true|false) default false
29964  * @cfg {Boolean} yearAllowBlank (true|false) default false
29965  * @cfg {string} dayPlaceholder 
29966  * @cfg {string} monthPlaceholder
29967  * @cfg {string} yearPlaceholder
29968  * @cfg {string} dayFormat default 'd'
29969  * @cfg {string} monthFormat default 'm'
29970  * @cfg {string} yearFormat default 'Y'
29971  * @cfg {Number} labellg set the width of label (1-12)
29972  * @cfg {Number} labelmd set the width of label (1-12)
29973  * @cfg {Number} labelsm set the width of label (1-12)
29974  * @cfg {Number} labelxs set the width of label (1-12)
29975
29976  *     
29977  * @constructor
29978  * Create a new DateSplitField
29979  * @param {Object} config The config object
29980  */
29981
29982 Roo.bootstrap.DateSplitField = function(config){
29983     Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29984     
29985     this.addEvents({
29986         // raw events
29987          /**
29988          * @event years
29989          * getting the data of years
29990          * @param {Roo.bootstrap.DateSplitField} this
29991          * @param {Object} years
29992          */
29993         "years" : true,
29994         /**
29995          * @event days
29996          * getting the data of days
29997          * @param {Roo.bootstrap.DateSplitField} this
29998          * @param {Object} days
29999          */
30000         "days" : true,
30001         /**
30002          * @event invalid
30003          * Fires after the field has been marked as invalid.
30004          * @param {Roo.form.Field} this
30005          * @param {String} msg The validation message
30006          */
30007         invalid : true,
30008        /**
30009          * @event valid
30010          * Fires after the field has been validated with no errors.
30011          * @param {Roo.form.Field} this
30012          */
30013         valid : true
30014     });
30015 };
30016
30017 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
30018     
30019     fieldLabel : '',
30020     labelAlign : 'top',
30021     labelWidth : 3,
30022     dayAllowBlank : false,
30023     monthAllowBlank : false,
30024     yearAllowBlank : false,
30025     dayPlaceholder : '',
30026     monthPlaceholder : '',
30027     yearPlaceholder : '',
30028     dayFormat : 'd',
30029     monthFormat : 'm',
30030     yearFormat : 'Y',
30031     isFormField : true,
30032     labellg : 0,
30033     labelmd : 0,
30034     labelsm : 0,
30035     labelxs : 0,
30036     
30037     getAutoCreate : function()
30038     {
30039         var cfg = {
30040             tag : 'div',
30041             cls : 'row roo-date-split-field-group',
30042             cn : [
30043                 {
30044                     tag : 'input',
30045                     type : 'hidden',
30046                     cls : 'form-hidden-field roo-date-split-field-group-value',
30047                     name : this.name
30048                 }
30049             ]
30050         };
30051         
30052         var labelCls = 'col-md-12';
30053         var contentCls = 'col-md-4';
30054         
30055         if(this.fieldLabel){
30056             
30057             var label = {
30058                 tag : 'div',
30059                 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30060                 cn : [
30061                     {
30062                         tag : 'label',
30063                         html : this.fieldLabel
30064                     }
30065                 ]
30066             };
30067             
30068             if(this.labelAlign == 'left'){
30069             
30070                 if(this.labelWidth > 12){
30071                     label.style = "width: " + this.labelWidth + 'px';
30072                 }
30073
30074                 if(this.labelWidth < 13 && this.labelmd == 0){
30075                     this.labelmd = this.labelWidth;
30076                 }
30077
30078                 if(this.labellg > 0){
30079                     labelCls = ' col-lg-' + this.labellg;
30080                     contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30081                 }
30082
30083                 if(this.labelmd > 0){
30084                     labelCls = ' col-md-' + this.labelmd;
30085                     contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30086                 }
30087
30088                 if(this.labelsm > 0){
30089                     labelCls = ' col-sm-' + this.labelsm;
30090                     contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30091                 }
30092
30093                 if(this.labelxs > 0){
30094                     labelCls = ' col-xs-' + this.labelxs;
30095                     contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30096                 }
30097             }
30098             
30099             label.cls += ' ' + labelCls;
30100             
30101             cfg.cn.push(label);
30102         }
30103         
30104         Roo.each(['day', 'month', 'year'], function(t){
30105             cfg.cn.push({
30106                 tag : 'div',
30107                 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30108             });
30109         }, this);
30110         
30111         return cfg;
30112     },
30113     
30114     inputEl: function ()
30115     {
30116         return this.el.select('.roo-date-split-field-group-value', true).first();
30117     },
30118     
30119     onRender : function(ct, position) 
30120     {
30121         var _this = this;
30122         
30123         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30124         
30125         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30126         
30127         this.dayField = new Roo.bootstrap.ComboBox({
30128             allowBlank : this.dayAllowBlank,
30129             alwaysQuery : true,
30130             displayField : 'value',
30131             editable : false,
30132             fieldLabel : '',
30133             forceSelection : true,
30134             mode : 'local',
30135             placeholder : this.dayPlaceholder,
30136             selectOnFocus : true,
30137             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30138             triggerAction : 'all',
30139             typeAhead : true,
30140             valueField : 'value',
30141             store : new Roo.data.SimpleStore({
30142                 data : (function() {    
30143                     var days = [];
30144                     _this.fireEvent('days', _this, days);
30145                     return days;
30146                 })(),
30147                 fields : [ 'value' ]
30148             }),
30149             listeners : {
30150                 select : function (_self, record, index)
30151                 {
30152                     _this.setValue(_this.getValue());
30153                 }
30154             }
30155         });
30156
30157         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30158         
30159         this.monthField = new Roo.bootstrap.MonthField({
30160             after : '<i class=\"fa fa-calendar\"></i>',
30161             allowBlank : this.monthAllowBlank,
30162             placeholder : this.monthPlaceholder,
30163             readOnly : true,
30164             listeners : {
30165                 render : function (_self)
30166                 {
30167                     this.el.select('span.input-group-addon', true).first().on('click', function(e){
30168                         e.preventDefault();
30169                         _self.focus();
30170                     });
30171                 },
30172                 select : function (_self, oldvalue, newvalue)
30173                 {
30174                     _this.setValue(_this.getValue());
30175                 }
30176             }
30177         });
30178         
30179         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30180         
30181         this.yearField = new Roo.bootstrap.ComboBox({
30182             allowBlank : this.yearAllowBlank,
30183             alwaysQuery : true,
30184             displayField : 'value',
30185             editable : false,
30186             fieldLabel : '',
30187             forceSelection : true,
30188             mode : 'local',
30189             placeholder : this.yearPlaceholder,
30190             selectOnFocus : true,
30191             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30192             triggerAction : 'all',
30193             typeAhead : true,
30194             valueField : 'value',
30195             store : new Roo.data.SimpleStore({
30196                 data : (function() {
30197                     var years = [];
30198                     _this.fireEvent('years', _this, years);
30199                     return years;
30200                 })(),
30201                 fields : [ 'value' ]
30202             }),
30203             listeners : {
30204                 select : function (_self, record, index)
30205                 {
30206                     _this.setValue(_this.getValue());
30207                 }
30208             }
30209         });
30210
30211         this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30212     },
30213     
30214     setValue : function(v, format)
30215     {
30216         this.inputEl.dom.value = v;
30217         
30218         var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30219         
30220         var d = Date.parseDate(v, f);
30221         
30222         if(!d){
30223             this.validate();
30224             return;
30225         }
30226         
30227         this.setDay(d.format(this.dayFormat));
30228         this.setMonth(d.format(this.monthFormat));
30229         this.setYear(d.format(this.yearFormat));
30230         
30231         this.validate();
30232         
30233         return;
30234     },
30235     
30236     setDay : function(v)
30237     {
30238         this.dayField.setValue(v);
30239         this.inputEl.dom.value = this.getValue();
30240         this.validate();
30241         return;
30242     },
30243     
30244     setMonth : function(v)
30245     {
30246         this.monthField.setValue(v, true);
30247         this.inputEl.dom.value = this.getValue();
30248         this.validate();
30249         return;
30250     },
30251     
30252     setYear : function(v)
30253     {
30254         this.yearField.setValue(v);
30255         this.inputEl.dom.value = this.getValue();
30256         this.validate();
30257         return;
30258     },
30259     
30260     getDay : function()
30261     {
30262         return this.dayField.getValue();
30263     },
30264     
30265     getMonth : function()
30266     {
30267         return this.monthField.getValue();
30268     },
30269     
30270     getYear : function()
30271     {
30272         return this.yearField.getValue();
30273     },
30274     
30275     getValue : function()
30276     {
30277         var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30278         
30279         var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30280         
30281         return date;
30282     },
30283     
30284     reset : function()
30285     {
30286         this.setDay('');
30287         this.setMonth('');
30288         this.setYear('');
30289         this.inputEl.dom.value = '';
30290         this.validate();
30291         return;
30292     },
30293     
30294     validate : function()
30295     {
30296         var d = this.dayField.validate();
30297         var m = this.monthField.validate();
30298         var y = this.yearField.validate();
30299         
30300         var valid = true;
30301         
30302         if(
30303                 (!this.dayAllowBlank && !d) ||
30304                 (!this.monthAllowBlank && !m) ||
30305                 (!this.yearAllowBlank && !y)
30306         ){
30307             valid = false;
30308         }
30309         
30310         if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30311             return valid;
30312         }
30313         
30314         if(valid){
30315             this.markValid();
30316             return valid;
30317         }
30318         
30319         this.markInvalid();
30320         
30321         return valid;
30322     },
30323     
30324     markValid : function()
30325     {
30326         
30327         var label = this.el.select('label', true).first();
30328         var icon = this.el.select('i.fa-star', true).first();
30329
30330         if(label && icon){
30331             icon.remove();
30332         }
30333         
30334         this.fireEvent('valid', this);
30335     },
30336     
30337      /**
30338      * Mark this field as invalid
30339      * @param {String} msg The validation message
30340      */
30341     markInvalid : function(msg)
30342     {
30343         
30344         var label = this.el.select('label', true).first();
30345         var icon = this.el.select('i.fa-star', true).first();
30346
30347         if(label && !icon){
30348             this.el.select('.roo-date-split-field-label', true).createChild({
30349                 tag : 'i',
30350                 cls : 'text-danger fa fa-lg fa-star',
30351                 tooltip : 'This field is required',
30352                 style : 'margin-right:5px;'
30353             }, label, true);
30354         }
30355         
30356         this.fireEvent('invalid', this, msg);
30357     },
30358     
30359     clearInvalid : function()
30360     {
30361         var label = this.el.select('label', true).first();
30362         var icon = this.el.select('i.fa-star', true).first();
30363
30364         if(label && icon){
30365             icon.remove();
30366         }
30367         
30368         this.fireEvent('valid', this);
30369     },
30370     
30371     getName: function()
30372     {
30373         return this.name;
30374     }
30375     
30376 });
30377
30378  /**
30379  *
30380  * This is based on 
30381  * http://masonry.desandro.com
30382  *
30383  * The idea is to render all the bricks based on vertical width...
30384  *
30385  * The original code extends 'outlayer' - we might need to use that....
30386  * 
30387  */
30388
30389
30390 /**
30391  * @class Roo.bootstrap.LayoutMasonry
30392  * @extends Roo.bootstrap.Component
30393  * Bootstrap Layout Masonry class
30394  * 
30395  * @constructor
30396  * Create a new Element
30397  * @param {Object} config The config object
30398  */
30399
30400 Roo.bootstrap.LayoutMasonry = function(config){
30401     
30402     Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30403     
30404     this.bricks = [];
30405     
30406     Roo.bootstrap.LayoutMasonry.register(this);
30407     
30408     this.addEvents({
30409         // raw events
30410         /**
30411          * @event layout
30412          * Fire after layout the items
30413          * @param {Roo.bootstrap.LayoutMasonry} this
30414          * @param {Roo.EventObject} e
30415          */
30416         "layout" : true
30417     });
30418     
30419 };
30420
30421 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component,  {
30422     
30423     /**
30424      * @cfg {Boolean} isLayoutInstant = no animation?
30425      */   
30426     isLayoutInstant : false, // needed?
30427    
30428     /**
30429      * @cfg {Number} boxWidth  width of the columns
30430      */   
30431     boxWidth : 450,
30432     
30433       /**
30434      * @cfg {Number} boxHeight  - 0 for square, or fix it at a certian height
30435      */   
30436     boxHeight : 0,
30437     
30438     /**
30439      * @cfg {Number} padWidth padding below box..
30440      */   
30441     padWidth : 10, 
30442     
30443     /**
30444      * @cfg {Number} gutter gutter width..
30445      */   
30446     gutter : 10,
30447     
30448      /**
30449      * @cfg {Number} maxCols maximum number of columns
30450      */   
30451     
30452     maxCols: 0,
30453     
30454     /**
30455      * @cfg {Boolean} isAutoInitial defalut true
30456      */   
30457     isAutoInitial : true, 
30458     
30459     containerWidth: 0,
30460     
30461     /**
30462      * @cfg {Boolean} isHorizontal defalut false
30463      */   
30464     isHorizontal : false, 
30465
30466     currentSize : null,
30467     
30468     tag: 'div',
30469     
30470     cls: '',
30471     
30472     bricks: null, //CompositeElement
30473     
30474     cols : 1,
30475     
30476     _isLayoutInited : false,
30477     
30478 //    isAlternative : false, // only use for vertical layout...
30479     
30480     /**
30481      * @cfg {Number} alternativePadWidth padding below box..
30482      */   
30483     alternativePadWidth : 50,
30484     
30485     selectedBrick : [],
30486     
30487     getAutoCreate : function(){
30488         
30489         var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30490         
30491         var cfg = {
30492             tag: this.tag,
30493             cls: 'blog-masonary-wrapper ' + this.cls,
30494             cn : {
30495                 cls : 'mas-boxes masonary'
30496             }
30497         };
30498         
30499         return cfg;
30500     },
30501     
30502     getChildContainer: function( )
30503     {
30504         if (this.boxesEl) {
30505             return this.boxesEl;
30506         }
30507         
30508         this.boxesEl = this.el.select('.mas-boxes').first();
30509         
30510         return this.boxesEl;
30511     },
30512     
30513     
30514     initEvents : function()
30515     {
30516         var _this = this;
30517         
30518         if(this.isAutoInitial){
30519             Roo.log('hook children rendered');
30520             this.on('childrenrendered', function() {
30521                 Roo.log('children rendered');
30522                 _this.initial();
30523             } ,this);
30524         }
30525     },
30526     
30527     initial : function()
30528     {
30529         this.selectedBrick = [];
30530         
30531         this.currentSize = this.el.getBox(true);
30532         
30533         Roo.EventManager.onWindowResize(this.resize, this); 
30534
30535         if(!this.isAutoInitial){
30536             this.layout();
30537             return;
30538         }
30539         
30540         this.layout();
30541         
30542         return;
30543         //this.layout.defer(500,this);
30544         
30545     },
30546     
30547     resize : function()
30548     {
30549         var cs = this.el.getBox(true);
30550         
30551         if (
30552                 this.currentSize.width == cs.width && 
30553                 this.currentSize.x == cs.x && 
30554                 this.currentSize.height == cs.height && 
30555                 this.currentSize.y == cs.y 
30556         ) {
30557             Roo.log("no change in with or X or Y");
30558             return;
30559         }
30560         
30561         this.currentSize = cs;
30562         
30563         this.layout();
30564         
30565     },
30566     
30567     layout : function()
30568     {   
30569         this._resetLayout();
30570         
30571         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30572         
30573         this.layoutItems( isInstant );
30574       
30575         this._isLayoutInited = true;
30576         
30577         this.fireEvent('layout', this);
30578         
30579     },
30580     
30581     _resetLayout : function()
30582     {
30583         if(this.isHorizontal){
30584             this.horizontalMeasureColumns();
30585             return;
30586         }
30587         
30588         this.verticalMeasureColumns();
30589         
30590     },
30591     
30592     verticalMeasureColumns : function()
30593     {
30594         this.getContainerWidth();
30595         
30596 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30597 //            this.colWidth = Math.floor(this.containerWidth * 0.8);
30598 //            return;
30599 //        }
30600         
30601         var boxWidth = this.boxWidth + this.padWidth;
30602         
30603         if(this.containerWidth < this.boxWidth){
30604             boxWidth = this.containerWidth
30605         }
30606         
30607         var containerWidth = this.containerWidth;
30608         
30609         var cols = Math.floor(containerWidth / boxWidth);
30610         
30611         this.cols = Math.max( cols, 1 );
30612         
30613         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30614         
30615         var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30616         
30617         var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30618         
30619         this.colWidth = boxWidth + avail - this.padWidth;
30620         
30621         this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30622         this.unitHeight = this.boxHeight > 0 ? this.boxHeight  : this.unitWidth;
30623     },
30624     
30625     horizontalMeasureColumns : function()
30626     {
30627         this.getContainerWidth();
30628         
30629         var boxWidth = this.boxWidth;
30630         
30631         if(this.containerWidth < boxWidth){
30632             boxWidth = this.containerWidth;
30633         }
30634         
30635         this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30636         
30637         this.el.setHeight(boxWidth);
30638         
30639     },
30640     
30641     getContainerWidth : function()
30642     {
30643         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
30644     },
30645     
30646     layoutItems : function( isInstant )
30647     {
30648         Roo.log(this.bricks);
30649         
30650         var items = Roo.apply([], this.bricks);
30651         
30652         if(this.isHorizontal){
30653             this._horizontalLayoutItems( items , isInstant );
30654             return;
30655         }
30656         
30657 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30658 //            this._verticalAlternativeLayoutItems( items , isInstant );
30659 //            return;
30660 //        }
30661         
30662         this._verticalLayoutItems( items , isInstant );
30663         
30664     },
30665     
30666     _verticalLayoutItems : function ( items , isInstant)
30667     {
30668         if ( !items || !items.length ) {
30669             return;
30670         }
30671         
30672         var standard = [
30673             ['xs', 'xs', 'xs', 'tall'],
30674             ['xs', 'xs', 'tall'],
30675             ['xs', 'xs', 'sm'],
30676             ['xs', 'xs', 'xs'],
30677             ['xs', 'tall'],
30678             ['xs', 'sm'],
30679             ['xs', 'xs'],
30680             ['xs'],
30681             
30682             ['sm', 'xs', 'xs'],
30683             ['sm', 'xs'],
30684             ['sm'],
30685             
30686             ['tall', 'xs', 'xs', 'xs'],
30687             ['tall', 'xs', 'xs'],
30688             ['tall', 'xs'],
30689             ['tall']
30690             
30691         ];
30692         
30693         var queue = [];
30694         
30695         var boxes = [];
30696         
30697         var box = [];
30698         
30699         Roo.each(items, function(item, k){
30700             
30701             switch (item.size) {
30702                 // these layouts take up a full box,
30703                 case 'md' :
30704                 case 'md-left' :
30705                 case 'md-right' :
30706                 case 'wide' :
30707                     
30708                     if(box.length){
30709                         boxes.push(box);
30710                         box = [];
30711                     }
30712                     
30713                     boxes.push([item]);
30714                     
30715                     break;
30716                     
30717                 case 'xs' :
30718                 case 'sm' :
30719                 case 'tall' :
30720                     
30721                     box.push(item);
30722                     
30723                     break;
30724                 default :
30725                     break;
30726                     
30727             }
30728             
30729         }, this);
30730         
30731         if(box.length){
30732             boxes.push(box);
30733             box = [];
30734         }
30735         
30736         var filterPattern = function(box, length)
30737         {
30738             if(!box.length){
30739                 return;
30740             }
30741             
30742             var match = false;
30743             
30744             var pattern = box.slice(0, length);
30745             
30746             var format = [];
30747             
30748             Roo.each(pattern, function(i){
30749                 format.push(i.size);
30750             }, this);
30751             
30752             Roo.each(standard, function(s){
30753                 
30754                 if(String(s) != String(format)){
30755                     return;
30756                 }
30757                 
30758                 match = true;
30759                 return false;
30760                 
30761             }, this);
30762             
30763             if(!match && length == 1){
30764                 return;
30765             }
30766             
30767             if(!match){
30768                 filterPattern(box, length - 1);
30769                 return;
30770             }
30771                 
30772             queue.push(pattern);
30773
30774             box = box.slice(length, box.length);
30775
30776             filterPattern(box, 4);
30777
30778             return;
30779             
30780         }
30781         
30782         Roo.each(boxes, function(box, k){
30783             
30784             if(!box.length){
30785                 return;
30786             }
30787             
30788             if(box.length == 1){
30789                 queue.push(box);
30790                 return;
30791             }
30792             
30793             filterPattern(box, 4);
30794             
30795         }, this);
30796         
30797         this._processVerticalLayoutQueue( queue, isInstant );
30798         
30799     },
30800     
30801 //    _verticalAlternativeLayoutItems : function( items , isInstant )
30802 //    {
30803 //        if ( !items || !items.length ) {
30804 //            return;
30805 //        }
30806 //
30807 //        this._processVerticalAlternativeLayoutQueue( items, isInstant );
30808 //        
30809 //    },
30810     
30811     _horizontalLayoutItems : function ( items , isInstant)
30812     {
30813         if ( !items || !items.length || items.length < 3) {
30814             return;
30815         }
30816         
30817         items.reverse();
30818         
30819         var eItems = items.slice(0, 3);
30820         
30821         items = items.slice(3, items.length);
30822         
30823         var standard = [
30824             ['xs', 'xs', 'xs', 'wide'],
30825             ['xs', 'xs', 'wide'],
30826             ['xs', 'xs', 'sm'],
30827             ['xs', 'xs', 'xs'],
30828             ['xs', 'wide'],
30829             ['xs', 'sm'],
30830             ['xs', 'xs'],
30831             ['xs'],
30832             
30833             ['sm', 'xs', 'xs'],
30834             ['sm', 'xs'],
30835             ['sm'],
30836             
30837             ['wide', 'xs', 'xs', 'xs'],
30838             ['wide', 'xs', 'xs'],
30839             ['wide', 'xs'],
30840             ['wide'],
30841             
30842             ['wide-thin']
30843         ];
30844         
30845         var queue = [];
30846         
30847         var boxes = [];
30848         
30849         var box = [];
30850         
30851         Roo.each(items, function(item, k){
30852             
30853             switch (item.size) {
30854                 case 'md' :
30855                 case 'md-left' :
30856                 case 'md-right' :
30857                 case 'tall' :
30858                     
30859                     if(box.length){
30860                         boxes.push(box);
30861                         box = [];
30862                     }
30863                     
30864                     boxes.push([item]);
30865                     
30866                     break;
30867                     
30868                 case 'xs' :
30869                 case 'sm' :
30870                 case 'wide' :
30871                 case 'wide-thin' :
30872                     
30873                     box.push(item);
30874                     
30875                     break;
30876                 default :
30877                     break;
30878                     
30879             }
30880             
30881         }, this);
30882         
30883         if(box.length){
30884             boxes.push(box);
30885             box = [];
30886         }
30887         
30888         var filterPattern = function(box, length)
30889         {
30890             if(!box.length){
30891                 return;
30892             }
30893             
30894             var match = false;
30895             
30896             var pattern = box.slice(0, length);
30897             
30898             var format = [];
30899             
30900             Roo.each(pattern, function(i){
30901                 format.push(i.size);
30902             }, this);
30903             
30904             Roo.each(standard, function(s){
30905                 
30906                 if(String(s) != String(format)){
30907                     return;
30908                 }
30909                 
30910                 match = true;
30911                 return false;
30912                 
30913             }, this);
30914             
30915             if(!match && length == 1){
30916                 return;
30917             }
30918             
30919             if(!match){
30920                 filterPattern(box, length - 1);
30921                 return;
30922             }
30923                 
30924             queue.push(pattern);
30925
30926             box = box.slice(length, box.length);
30927
30928             filterPattern(box, 4);
30929
30930             return;
30931             
30932         }
30933         
30934         Roo.each(boxes, function(box, k){
30935             
30936             if(!box.length){
30937                 return;
30938             }
30939             
30940             if(box.length == 1){
30941                 queue.push(box);
30942                 return;
30943             }
30944             
30945             filterPattern(box, 4);
30946             
30947         }, this);
30948         
30949         
30950         var prune = [];
30951         
30952         var pos = this.el.getBox(true);
30953         
30954         var minX = pos.x;
30955         
30956         var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30957         
30958         var hit_end = false;
30959         
30960         Roo.each(queue, function(box){
30961             
30962             if(hit_end){
30963                 
30964                 Roo.each(box, function(b){
30965                 
30966                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
30967                     b.el.hide();
30968
30969                 }, this);
30970
30971                 return;
30972             }
30973             
30974             var mx = 0;
30975             
30976             Roo.each(box, function(b){
30977                 
30978                 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30979                 b.el.show();
30980
30981                 mx = Math.max(mx, b.x);
30982                 
30983             }, this);
30984             
30985             maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30986             
30987             if(maxX < minX){
30988                 
30989                 Roo.each(box, function(b){
30990                 
30991                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
30992                     b.el.hide();
30993                     
30994                 }, this);
30995                 
30996                 hit_end = true;
30997                 
30998                 return;
30999             }
31000             
31001             prune.push(box);
31002             
31003         }, this);
31004         
31005         this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31006     },
31007     
31008     /** Sets position of item in DOM
31009     * @param {Element} item
31010     * @param {Number} x - horizontal position
31011     * @param {Number} y - vertical position
31012     * @param {Boolean} isInstant - disables transitions
31013     */
31014     _processVerticalLayoutQueue : function( queue, isInstant )
31015     {
31016         var pos = this.el.getBox(true);
31017         var x = pos.x;
31018         var y = pos.y;
31019         var maxY = [];
31020         
31021         for (var i = 0; i < this.cols; i++){
31022             maxY[i] = pos.y;
31023         }
31024         
31025         Roo.each(queue, function(box, k){
31026             
31027             var col = k % this.cols;
31028             
31029             Roo.each(box, function(b,kk){
31030                 
31031                 b.el.position('absolute');
31032                 
31033                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31034                 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31035                 
31036                 if(b.size == 'md-left' || b.size == 'md-right'){
31037                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31038                     height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31039                 }
31040                 
31041                 b.el.setWidth(width);
31042                 b.el.setHeight(height);
31043                 // iframe?
31044                 b.el.select('iframe',true).setSize(width,height);
31045                 
31046             }, this);
31047             
31048             for (var i = 0; i < this.cols; i++){
31049                 
31050                 if(maxY[i] < maxY[col]){
31051                     col = i;
31052                     continue;
31053                 }
31054                 
31055                 col = Math.min(col, i);
31056                 
31057             }
31058             
31059             x = pos.x + col * (this.colWidth + this.padWidth);
31060             
31061             y = maxY[col];
31062             
31063             var positions = [];
31064             
31065             switch (box.length){
31066                 case 1 :
31067                     positions = this.getVerticalOneBoxColPositions(x, y, box);
31068                     break;
31069                 case 2 :
31070                     positions = this.getVerticalTwoBoxColPositions(x, y, box);
31071                     break;
31072                 case 3 :
31073                     positions = this.getVerticalThreeBoxColPositions(x, y, box);
31074                     break;
31075                 case 4 :
31076                     positions = this.getVerticalFourBoxColPositions(x, y, box);
31077                     break;
31078                 default :
31079                     break;
31080             }
31081             
31082             Roo.each(box, function(b,kk){
31083                 
31084                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31085                 
31086                 var sz = b.el.getSize();
31087                 
31088                 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31089                 
31090             }, this);
31091             
31092         }, this);
31093         
31094         var mY = 0;
31095         
31096         for (var i = 0; i < this.cols; i++){
31097             mY = Math.max(mY, maxY[i]);
31098         }
31099         
31100         this.el.setHeight(mY - pos.y);
31101         
31102     },
31103     
31104 //    _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31105 //    {
31106 //        var pos = this.el.getBox(true);
31107 //        var x = pos.x;
31108 //        var y = pos.y;
31109 //        var maxX = pos.right;
31110 //        
31111 //        var maxHeight = 0;
31112 //        
31113 //        Roo.each(items, function(item, k){
31114 //            
31115 //            var c = k % 2;
31116 //            
31117 //            item.el.position('absolute');
31118 //                
31119 //            var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31120 //
31121 //            item.el.setWidth(width);
31122 //
31123 //            var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31124 //
31125 //            item.el.setHeight(height);
31126 //            
31127 //            if(c == 0){
31128 //                item.el.setXY([x, y], isInstant ? false : true);
31129 //            } else {
31130 //                item.el.setXY([maxX - width, y], isInstant ? false : true);
31131 //            }
31132 //            
31133 //            y = y + height + this.alternativePadWidth;
31134 //            
31135 //            maxHeight = maxHeight + height + this.alternativePadWidth;
31136 //            
31137 //        }, this);
31138 //        
31139 //        this.el.setHeight(maxHeight);
31140 //        
31141 //    },
31142     
31143     _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31144     {
31145         var pos = this.el.getBox(true);
31146         
31147         var minX = pos.x;
31148         var minY = pos.y;
31149         
31150         var maxX = pos.right;
31151         
31152         this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31153         
31154         var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31155         
31156         Roo.each(queue, function(box, k){
31157             
31158             Roo.each(box, function(b, kk){
31159                 
31160                 b.el.position('absolute');
31161                 
31162                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31163                 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31164                 
31165                 if(b.size == 'md-left' || b.size == 'md-right'){
31166                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31167                     height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31168                 }
31169                 
31170                 b.el.setWidth(width);
31171                 b.el.setHeight(height);
31172                 
31173             }, this);
31174             
31175             if(!box.length){
31176                 return;
31177             }
31178             
31179             var positions = [];
31180             
31181             switch (box.length){
31182                 case 1 :
31183                     positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31184                     break;
31185                 case 2 :
31186                     positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31187                     break;
31188                 case 3 :
31189                     positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31190                     break;
31191                 case 4 :
31192                     positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31193                     break;
31194                 default :
31195                     break;
31196             }
31197             
31198             Roo.each(box, function(b,kk){
31199                 
31200                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31201                 
31202                 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31203                 
31204             }, this);
31205             
31206         }, this);
31207         
31208     },
31209     
31210     _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31211     {
31212         Roo.each(eItems, function(b,k){
31213             
31214             b.size = (k == 0) ? 'sm' : 'xs';
31215             b.x = (k == 0) ? 2 : 1;
31216             b.y = (k == 0) ? 2 : 1;
31217             
31218             b.el.position('absolute');
31219             
31220             var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31221                 
31222             b.el.setWidth(width);
31223             
31224             var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31225             
31226             b.el.setHeight(height);
31227             
31228         }, this);
31229
31230         var positions = [];
31231         
31232         positions.push({
31233             x : maxX - this.unitWidth * 2 - this.gutter,
31234             y : minY
31235         });
31236         
31237         positions.push({
31238             x : maxX - this.unitWidth,
31239             y : minY + (this.unitWidth + this.gutter) * 2
31240         });
31241         
31242         positions.push({
31243             x : maxX - this.unitWidth * 3 - this.gutter * 2,
31244             y : minY
31245         });
31246         
31247         Roo.each(eItems, function(b,k){
31248             
31249             b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31250
31251         }, this);
31252         
31253     },
31254     
31255     getVerticalOneBoxColPositions : function(x, y, box)
31256     {
31257         var pos = [];
31258         
31259         var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31260         
31261         if(box[0].size == 'md-left'){
31262             rand = 0;
31263         }
31264         
31265         if(box[0].size == 'md-right'){
31266             rand = 1;
31267         }
31268         
31269         pos.push({
31270             x : x + (this.unitWidth + this.gutter) * rand,
31271             y : y
31272         });
31273         
31274         return pos;
31275     },
31276     
31277     getVerticalTwoBoxColPositions : function(x, y, box)
31278     {
31279         var pos = [];
31280         
31281         if(box[0].size == 'xs'){
31282             
31283             pos.push({
31284                 x : x,
31285                 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31286             });
31287
31288             pos.push({
31289                 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31290                 y : y
31291             });
31292             
31293             return pos;
31294             
31295         }
31296         
31297         pos.push({
31298             x : x,
31299             y : y
31300         });
31301
31302         pos.push({
31303             x : x + (this.unitWidth + this.gutter) * 2,
31304             y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31305         });
31306         
31307         return pos;
31308         
31309     },
31310     
31311     getVerticalThreeBoxColPositions : function(x, y, box)
31312     {
31313         var pos = [];
31314         
31315         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31316             
31317             pos.push({
31318                 x : x,
31319                 y : y
31320             });
31321
31322             pos.push({
31323                 x : x + (this.unitWidth + this.gutter) * 1,
31324                 y : y
31325             });
31326             
31327             pos.push({
31328                 x : x + (this.unitWidth + this.gutter) * 2,
31329                 y : y
31330             });
31331             
31332             return pos;
31333             
31334         }
31335         
31336         if(box[0].size == 'xs' && box[1].size == 'xs'){
31337             
31338             pos.push({
31339                 x : x,
31340                 y : y
31341             });
31342
31343             pos.push({
31344                 x : x,
31345                 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31346             });
31347             
31348             pos.push({
31349                 x : x + (this.unitWidth + this.gutter) * 1,
31350                 y : y
31351             });
31352             
31353             return pos;
31354             
31355         }
31356         
31357         pos.push({
31358             x : x,
31359             y : y
31360         });
31361
31362         pos.push({
31363             x : x + (this.unitWidth + this.gutter) * 2,
31364             y : y
31365         });
31366
31367         pos.push({
31368             x : x + (this.unitWidth + this.gutter) * 2,
31369             y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31370         });
31371             
31372         return pos;
31373         
31374     },
31375     
31376     getVerticalFourBoxColPositions : function(x, y, box)
31377     {
31378         var pos = [];
31379         
31380         if(box[0].size == 'xs'){
31381             
31382             pos.push({
31383                 x : x,
31384                 y : y
31385             });
31386
31387             pos.push({
31388                 x : x,
31389                 y : y + (this.unitHeight + this.gutter) * 1
31390             });
31391             
31392             pos.push({
31393                 x : x,
31394                 y : y + (this.unitHeight + this.gutter) * 2
31395             });
31396             
31397             pos.push({
31398                 x : x + (this.unitWidth + this.gutter) * 1,
31399                 y : y
31400             });
31401             
31402             return pos;
31403             
31404         }
31405         
31406         pos.push({
31407             x : x,
31408             y : y
31409         });
31410
31411         pos.push({
31412             x : x + (this.unitWidth + this.gutter) * 2,
31413             y : y
31414         });
31415
31416         pos.push({
31417             x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31418             y : y + (this.unitHeight + this.gutter) * 1
31419         });
31420
31421         pos.push({
31422             x : x + (this.unitWidth + this.gutter) * 2,
31423             y : y + (this.unitWidth + this.gutter) * 2
31424         });
31425
31426         return pos;
31427         
31428     },
31429     
31430     getHorizontalOneBoxColPositions : function(maxX, minY, box)
31431     {
31432         var pos = [];
31433         
31434         if(box[0].size == 'md-left'){
31435             pos.push({
31436                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31437                 y : minY
31438             });
31439             
31440             return pos;
31441         }
31442         
31443         if(box[0].size == 'md-right'){
31444             pos.push({
31445                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31446                 y : minY + (this.unitWidth + this.gutter) * 1
31447             });
31448             
31449             return pos;
31450         }
31451         
31452         var rand = Math.floor(Math.random() * (4 - box[0].y));
31453         
31454         pos.push({
31455             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31456             y : minY + (this.unitWidth + this.gutter) * rand
31457         });
31458         
31459         return pos;
31460         
31461     },
31462     
31463     getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31464     {
31465         var pos = [];
31466         
31467         if(box[0].size == 'xs'){
31468             
31469             pos.push({
31470                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31471                 y : minY
31472             });
31473
31474             pos.push({
31475                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31476                 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31477             });
31478             
31479             return pos;
31480             
31481         }
31482         
31483         pos.push({
31484             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31485             y : minY
31486         });
31487
31488         pos.push({
31489             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31490             y : minY + (this.unitWidth + this.gutter) * 2
31491         });
31492         
31493         return pos;
31494         
31495     },
31496     
31497     getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31498     {
31499         var pos = [];
31500         
31501         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31502             
31503             pos.push({
31504                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31505                 y : minY
31506             });
31507
31508             pos.push({
31509                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31510                 y : minY + (this.unitWidth + this.gutter) * 1
31511             });
31512             
31513             pos.push({
31514                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31515                 y : minY + (this.unitWidth + this.gutter) * 2
31516             });
31517             
31518             return pos;
31519             
31520         }
31521         
31522         if(box[0].size == 'xs' && box[1].size == 'xs'){
31523             
31524             pos.push({
31525                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31526                 y : minY
31527             });
31528
31529             pos.push({
31530                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31531                 y : minY
31532             });
31533             
31534             pos.push({
31535                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31536                 y : minY + (this.unitWidth + this.gutter) * 1
31537             });
31538             
31539             return pos;
31540             
31541         }
31542         
31543         pos.push({
31544             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31545             y : minY
31546         });
31547
31548         pos.push({
31549             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31550             y : minY + (this.unitWidth + this.gutter) * 2
31551         });
31552
31553         pos.push({
31554             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31555             y : minY + (this.unitWidth + this.gutter) * 2
31556         });
31557             
31558         return pos;
31559         
31560     },
31561     
31562     getHorizontalFourBoxColPositions : function(maxX, minY, box)
31563     {
31564         var pos = [];
31565         
31566         if(box[0].size == 'xs'){
31567             
31568             pos.push({
31569                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31570                 y : minY
31571             });
31572
31573             pos.push({
31574                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31575                 y : minY
31576             });
31577             
31578             pos.push({
31579                 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),
31580                 y : minY
31581             });
31582             
31583             pos.push({
31584                 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31585                 y : minY + (this.unitWidth + this.gutter) * 1
31586             });
31587             
31588             return pos;
31589             
31590         }
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) * 2
31600         });
31601         
31602         pos.push({
31603             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31604             y : minY + (this.unitWidth + this.gutter) * 2
31605         });
31606         
31607         pos.push({
31608             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),
31609             y : minY + (this.unitWidth + this.gutter) * 2
31610         });
31611
31612         return pos;
31613         
31614     },
31615     
31616     /**
31617     * remove a Masonry Brick
31618     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31619     */
31620     removeBrick : function(brick_id)
31621     {
31622         if (!brick_id) {
31623             return;
31624         }
31625         
31626         for (var i = 0; i<this.bricks.length; i++) {
31627             if (this.bricks[i].id == brick_id) {
31628                 this.bricks.splice(i,1);
31629                 this.el.dom.removeChild(Roo.get(brick_id).dom);
31630                 this.initial();
31631             }
31632         }
31633     },
31634     
31635     /**
31636     * adds a Masonry Brick
31637     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31638     */
31639     addBrick : function(cfg)
31640     {
31641         var cn = new Roo.bootstrap.MasonryBrick(cfg);
31642         //this.register(cn);
31643         cn.parentId = this.id;
31644         cn.onRender(this.el, null);
31645         return cn;
31646     },
31647     
31648     /**
31649     * register a Masonry Brick
31650     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31651     */
31652     
31653     register : function(brick)
31654     {
31655         this.bricks.push(brick);
31656         brick.masonryId = this.id;
31657     },
31658     
31659     /**
31660     * clear all the Masonry Brick
31661     */
31662     clearAll : function()
31663     {
31664         this.bricks = [];
31665         //this.getChildContainer().dom.innerHTML = "";
31666         this.el.dom.innerHTML = '';
31667     },
31668     
31669     getSelected : function()
31670     {
31671         if (!this.selectedBrick) {
31672             return false;
31673         }
31674         
31675         return this.selectedBrick;
31676     }
31677 });
31678
31679 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31680     
31681     groups: {},
31682      /**
31683     * register a Masonry Layout
31684     * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31685     */
31686     
31687     register : function(layout)
31688     {
31689         this.groups[layout.id] = layout;
31690     },
31691     /**
31692     * fetch a  Masonry Layout based on the masonry layout ID
31693     * @param {string} the masonry layout to add
31694     * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31695     */
31696     
31697     get: function(layout_id) {
31698         if (typeof(this.groups[layout_id]) == 'undefined') {
31699             return false;
31700         }
31701         return this.groups[layout_id] ;
31702     }
31703     
31704     
31705     
31706 });
31707
31708  
31709
31710  /**
31711  *
31712  * This is based on 
31713  * http://masonry.desandro.com
31714  *
31715  * The idea is to render all the bricks based on vertical width...
31716  *
31717  * The original code extends 'outlayer' - we might need to use that....
31718  * 
31719  */
31720
31721
31722 /**
31723  * @class Roo.bootstrap.LayoutMasonryAuto
31724  * @extends Roo.bootstrap.Component
31725  * Bootstrap Layout Masonry class
31726  * 
31727  * @constructor
31728  * Create a new Element
31729  * @param {Object} config The config object
31730  */
31731
31732 Roo.bootstrap.LayoutMasonryAuto = function(config){
31733     Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31734 };
31735
31736 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component,  {
31737     
31738       /**
31739      * @cfg {Boolean} isFitWidth  - resize the width..
31740      */   
31741     isFitWidth : false,  // options..
31742     /**
31743      * @cfg {Boolean} isOriginLeft = left align?
31744      */   
31745     isOriginLeft : true,
31746     /**
31747      * @cfg {Boolean} isOriginTop = top align?
31748      */   
31749     isOriginTop : false,
31750     /**
31751      * @cfg {Boolean} isLayoutInstant = no animation?
31752      */   
31753     isLayoutInstant : false, // needed?
31754     /**
31755      * @cfg {Boolean} isResizingContainer = not sure if this is used..
31756      */   
31757     isResizingContainer : true,
31758     /**
31759      * @cfg {Number} columnWidth  width of the columns 
31760      */   
31761     
31762     columnWidth : 0,
31763     
31764     /**
31765      * @cfg {Number} maxCols maximum number of columns
31766      */   
31767     
31768     maxCols: 0,
31769     /**
31770      * @cfg {Number} padHeight padding below box..
31771      */   
31772     
31773     padHeight : 10, 
31774     
31775     /**
31776      * @cfg {Boolean} isAutoInitial defalut true
31777      */   
31778     
31779     isAutoInitial : true, 
31780     
31781     // private?
31782     gutter : 0,
31783     
31784     containerWidth: 0,
31785     initialColumnWidth : 0,
31786     currentSize : null,
31787     
31788     colYs : null, // array.
31789     maxY : 0,
31790     padWidth: 10,
31791     
31792     
31793     tag: 'div',
31794     cls: '',
31795     bricks: null, //CompositeElement
31796     cols : 0, // array?
31797     // element : null, // wrapped now this.el
31798     _isLayoutInited : null, 
31799     
31800     
31801     getAutoCreate : function(){
31802         
31803         var cfg = {
31804             tag: this.tag,
31805             cls: 'blog-masonary-wrapper ' + this.cls,
31806             cn : {
31807                 cls : 'mas-boxes masonary'
31808             }
31809         };
31810         
31811         return cfg;
31812     },
31813     
31814     getChildContainer: function( )
31815     {
31816         if (this.boxesEl) {
31817             return this.boxesEl;
31818         }
31819         
31820         this.boxesEl = this.el.select('.mas-boxes').first();
31821         
31822         return this.boxesEl;
31823     },
31824     
31825     
31826     initEvents : function()
31827     {
31828         var _this = this;
31829         
31830         if(this.isAutoInitial){
31831             Roo.log('hook children rendered');
31832             this.on('childrenrendered', function() {
31833                 Roo.log('children rendered');
31834                 _this.initial();
31835             } ,this);
31836         }
31837         
31838     },
31839     
31840     initial : function()
31841     {
31842         this.reloadItems();
31843
31844         this.currentSize = this.el.getBox(true);
31845
31846         /// was window resize... - let's see if this works..
31847         Roo.EventManager.onWindowResize(this.resize, this); 
31848
31849         if(!this.isAutoInitial){
31850             this.layout();
31851             return;
31852         }
31853         
31854         this.layout.defer(500,this);
31855     },
31856     
31857     reloadItems: function()
31858     {
31859         this.bricks = this.el.select('.masonry-brick', true);
31860         
31861         this.bricks.each(function(b) {
31862             //Roo.log(b.getSize());
31863             if (!b.attr('originalwidth')) {
31864                 b.attr('originalwidth',  b.getSize().width);
31865             }
31866             
31867         });
31868         
31869         Roo.log(this.bricks.elements.length);
31870     },
31871     
31872     resize : function()
31873     {
31874         Roo.log('resize');
31875         var cs = this.el.getBox(true);
31876         
31877         if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31878             Roo.log("no change in with or X");
31879             return;
31880         }
31881         this.currentSize = cs;
31882         this.layout();
31883     },
31884     
31885     layout : function()
31886     {
31887          Roo.log('layout');
31888         this._resetLayout();
31889         //this._manageStamps();
31890       
31891         // don't animate first layout
31892         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31893         this.layoutItems( isInstant );
31894       
31895         // flag for initalized
31896         this._isLayoutInited = true;
31897     },
31898     
31899     layoutItems : function( isInstant )
31900     {
31901         //var items = this._getItemsForLayout( this.items );
31902         // original code supports filtering layout items.. we just ignore it..
31903         
31904         this._layoutItems( this.bricks , isInstant );
31905       
31906         this._postLayout();
31907     },
31908     _layoutItems : function ( items , isInstant)
31909     {
31910        //this.fireEvent( 'layout', this, items );
31911     
31912
31913         if ( !items || !items.elements.length ) {
31914           // no items, emit event with empty array
31915             return;
31916         }
31917
31918         var queue = [];
31919         items.each(function(item) {
31920             Roo.log("layout item");
31921             Roo.log(item);
31922             // get x/y object from method
31923             var position = this._getItemLayoutPosition( item );
31924             // enqueue
31925             position.item = item;
31926             position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31927             queue.push( position );
31928         }, this);
31929       
31930         this._processLayoutQueue( queue );
31931     },
31932     /** Sets position of item in DOM
31933     * @param {Element} item
31934     * @param {Number} x - horizontal position
31935     * @param {Number} y - vertical position
31936     * @param {Boolean} isInstant - disables transitions
31937     */
31938     _processLayoutQueue : function( queue )
31939     {
31940         for ( var i=0, len = queue.length; i < len; i++ ) {
31941             var obj = queue[i];
31942             obj.item.position('absolute');
31943             obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31944         }
31945     },
31946       
31947     
31948     /**
31949     * Any logic you want to do after each layout,
31950     * i.e. size the container
31951     */
31952     _postLayout : function()
31953     {
31954         this.resizeContainer();
31955     },
31956     
31957     resizeContainer : function()
31958     {
31959         if ( !this.isResizingContainer ) {
31960             return;
31961         }
31962         var size = this._getContainerSize();
31963         if ( size ) {
31964             this.el.setSize(size.width,size.height);
31965             this.boxesEl.setSize(size.width,size.height);
31966         }
31967     },
31968     
31969     
31970     
31971     _resetLayout : function()
31972     {
31973         //this.getSize();  // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31974         this.colWidth = this.el.getWidth();
31975         //this.gutter = this.el.getWidth(); 
31976         
31977         this.measureColumns();
31978
31979         // reset column Y
31980         var i = this.cols;
31981         this.colYs = [];
31982         while (i--) {
31983             this.colYs.push( 0 );
31984         }
31985     
31986         this.maxY = 0;
31987     },
31988
31989     measureColumns : function()
31990     {
31991         this.getContainerWidth();
31992       // if columnWidth is 0, default to outerWidth of first item
31993         if ( !this.columnWidth ) {
31994             var firstItem = this.bricks.first();
31995             Roo.log(firstItem);
31996             this.columnWidth  = this.containerWidth;
31997             if (firstItem && firstItem.attr('originalwidth') ) {
31998                 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31999             }
32000             // columnWidth fall back to item of first element
32001             Roo.log("set column width?");
32002                         this.initialColumnWidth = this.columnWidth  ;
32003
32004             // if first elem has no width, default to size of container
32005             
32006         }
32007         
32008         
32009         if (this.initialColumnWidth) {
32010             this.columnWidth = this.initialColumnWidth;
32011         }
32012         
32013         
32014             
32015         // column width is fixed at the top - however if container width get's smaller we should
32016         // reduce it...
32017         
32018         // this bit calcs how man columns..
32019             
32020         var columnWidth = this.columnWidth += this.gutter;
32021       
32022         // calculate columns
32023         var containerWidth = this.containerWidth + this.gutter;
32024         
32025         var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32026         // fix rounding errors, typically with gutters
32027         var excess = columnWidth - containerWidth % columnWidth;
32028         
32029         
32030         // if overshoot is less than a pixel, round up, otherwise floor it
32031         var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32032         cols = Math[ mathMethod ]( cols );
32033         this.cols = Math.max( cols, 1 );
32034         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32035         
32036          // padding positioning..
32037         var totalColWidth = this.cols * this.columnWidth;
32038         var padavail = this.containerWidth - totalColWidth;
32039         // so for 2 columns - we need 3 'pads'
32040         
32041         var padNeeded = (1+this.cols) * this.padWidth;
32042         
32043         var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32044         
32045         this.columnWidth += padExtra
32046         //this.padWidth = Math.floor(padavail /  ( this.cols));
32047         
32048         // adjust colum width so that padding is fixed??
32049         
32050         // we have 3 columns ... total = width * 3
32051         // we have X left over... that should be used by 
32052         
32053         //if (this.expandC) {
32054             
32055         //}
32056         
32057         
32058         
32059     },
32060     
32061     getContainerWidth : function()
32062     {
32063        /* // container is parent if fit width
32064         var container = this.isFitWidth ? this.element.parentNode : this.element;
32065         // check that this.size and size are there
32066         // IE8 triggers resize on body size change, so they might not be
32067         
32068         var size = getSize( container );  //FIXME
32069         this.containerWidth = size && size.innerWidth; //FIXME
32070         */
32071          
32072         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
32073         
32074     },
32075     
32076     _getItemLayoutPosition : function( item )  // what is item?
32077     {
32078         // we resize the item to our columnWidth..
32079       
32080         item.setWidth(this.columnWidth);
32081         item.autoBoxAdjust  = false;
32082         
32083         var sz = item.getSize();
32084  
32085         // how many columns does this brick span
32086         var remainder = this.containerWidth % this.columnWidth;
32087         
32088         var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32089         // round if off by 1 pixel, otherwise use ceil
32090         var colSpan = Math[ mathMethod ]( sz.width  / this.columnWidth );
32091         colSpan = Math.min( colSpan, this.cols );
32092         
32093         // normally this should be '1' as we dont' currently allow multi width columns..
32094         
32095         var colGroup = this._getColGroup( colSpan );
32096         // get the minimum Y value from the columns
32097         var minimumY = Math.min.apply( Math, colGroup );
32098         Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32099         
32100         var shortColIndex = colGroup.indexOf(  minimumY ); // broken on ie8..?? probably...
32101          
32102         // position the brick
32103         var position = {
32104             x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32105             y: this.currentSize.y + minimumY + this.padHeight
32106         };
32107         
32108         Roo.log(position);
32109         // apply setHeight to necessary columns
32110         var setHeight = minimumY + sz.height + this.padHeight;
32111         //Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32112         
32113         var setSpan = this.cols + 1 - colGroup.length;
32114         for ( var i = 0; i < setSpan; i++ ) {
32115           this.colYs[ shortColIndex + i ] = setHeight ;
32116         }
32117       
32118         return position;
32119     },
32120     
32121     /**
32122      * @param {Number} colSpan - number of columns the element spans
32123      * @returns {Array} colGroup
32124      */
32125     _getColGroup : function( colSpan )
32126     {
32127         if ( colSpan < 2 ) {
32128           // if brick spans only one column, use all the column Ys
32129           return this.colYs;
32130         }
32131       
32132         var colGroup = [];
32133         // how many different places could this brick fit horizontally
32134         var groupCount = this.cols + 1 - colSpan;
32135         // for each group potential horizontal position
32136         for ( var i = 0; i < groupCount; i++ ) {
32137           // make an array of colY values for that one group
32138           var groupColYs = this.colYs.slice( i, i + colSpan );
32139           // and get the max value of the array
32140           colGroup[i] = Math.max.apply( Math, groupColYs );
32141         }
32142         return colGroup;
32143     },
32144     /*
32145     _manageStamp : function( stamp )
32146     {
32147         var stampSize =  stamp.getSize();
32148         var offset = stamp.getBox();
32149         // get the columns that this stamp affects
32150         var firstX = this.isOriginLeft ? offset.x : offset.right;
32151         var lastX = firstX + stampSize.width;
32152         var firstCol = Math.floor( firstX / this.columnWidth );
32153         firstCol = Math.max( 0, firstCol );
32154         
32155         var lastCol = Math.floor( lastX / this.columnWidth );
32156         // lastCol should not go over if multiple of columnWidth #425
32157         lastCol -= lastX % this.columnWidth ? 0 : 1;
32158         lastCol = Math.min( this.cols - 1, lastCol );
32159         
32160         // set colYs to bottom of the stamp
32161         var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32162             stampSize.height;
32163             
32164         for ( var i = firstCol; i <= lastCol; i++ ) {
32165           this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32166         }
32167     },
32168     */
32169     
32170     _getContainerSize : function()
32171     {
32172         this.maxY = Math.max.apply( Math, this.colYs );
32173         var size = {
32174             height: this.maxY
32175         };
32176       
32177         if ( this.isFitWidth ) {
32178             size.width = this._getContainerFitWidth();
32179         }
32180       
32181         return size;
32182     },
32183     
32184     _getContainerFitWidth : function()
32185     {
32186         var unusedCols = 0;
32187         // count unused columns
32188         var i = this.cols;
32189         while ( --i ) {
32190           if ( this.colYs[i] !== 0 ) {
32191             break;
32192           }
32193           unusedCols++;
32194         }
32195         // fit container to columns that have been used
32196         return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32197     },
32198     
32199     needsResizeLayout : function()
32200     {
32201         var previousWidth = this.containerWidth;
32202         this.getContainerWidth();
32203         return previousWidth !== this.containerWidth;
32204     }
32205  
32206 });
32207
32208  
32209
32210  /*
32211  * - LGPL
32212  *
32213  * element
32214  * 
32215  */
32216
32217 /**
32218  * @class Roo.bootstrap.MasonryBrick
32219  * @extends Roo.bootstrap.Component
32220  * Bootstrap MasonryBrick class
32221  * 
32222  * @constructor
32223  * Create a new MasonryBrick
32224  * @param {Object} config The config object
32225  */
32226
32227 Roo.bootstrap.MasonryBrick = function(config){
32228     
32229     Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32230     
32231     Roo.bootstrap.MasonryBrick.register(this);
32232     
32233     this.addEvents({
32234         // raw events
32235         /**
32236          * @event click
32237          * When a MasonryBrick is clcik
32238          * @param {Roo.bootstrap.MasonryBrick} this
32239          * @param {Roo.EventObject} e
32240          */
32241         "click" : true
32242     });
32243 };
32244
32245 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component,  {
32246     
32247     /**
32248      * @cfg {String} title
32249      */   
32250     title : '',
32251     /**
32252      * @cfg {String} html
32253      */   
32254     html : '',
32255     /**
32256      * @cfg {String} bgimage
32257      */   
32258     bgimage : '',
32259     /**
32260      * @cfg {String} videourl
32261      */   
32262     videourl : '',
32263     /**
32264      * @cfg {String} cls
32265      */   
32266     cls : '',
32267     /**
32268      * @cfg {String} href
32269      */   
32270     href : '',
32271     /**
32272      * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32273      */   
32274     size : 'xs',
32275     
32276     /**
32277      * @cfg {String} placetitle (center|bottom)
32278      */   
32279     placetitle : '',
32280     
32281     /**
32282      * @cfg {Boolean} isFitContainer defalut true
32283      */   
32284     isFitContainer : true, 
32285     
32286     /**
32287      * @cfg {Boolean} preventDefault defalut false
32288      */   
32289     preventDefault : false, 
32290     
32291     /**
32292      * @cfg {Boolean} inverse defalut false
32293      */   
32294     maskInverse : false, 
32295     
32296     getAutoCreate : function()
32297     {
32298         if(!this.isFitContainer){
32299             return this.getSplitAutoCreate();
32300         }
32301         
32302         var cls = 'masonry-brick masonry-brick-full';
32303         
32304         if(this.href.length){
32305             cls += ' masonry-brick-link';
32306         }
32307         
32308         if(this.bgimage.length){
32309             cls += ' masonry-brick-image';
32310         }
32311         
32312         if(this.maskInverse){
32313             cls += ' mask-inverse';
32314         }
32315         
32316         if(!this.html.length && !this.maskInverse && !this.videourl.length){
32317             cls += ' enable-mask';
32318         }
32319         
32320         if(this.size){
32321             cls += ' masonry-' + this.size + '-brick';
32322         }
32323         
32324         if(this.placetitle.length){
32325             
32326             switch (this.placetitle) {
32327                 case 'center' :
32328                     cls += ' masonry-center-title';
32329                     break;
32330                 case 'bottom' :
32331                     cls += ' masonry-bottom-title';
32332                     break;
32333                 default:
32334                     break;
32335             }
32336             
32337         } else {
32338             if(!this.html.length && !this.bgimage.length){
32339                 cls += ' masonry-center-title';
32340             }
32341
32342             if(!this.html.length && this.bgimage.length){
32343                 cls += ' masonry-bottom-title';
32344             }
32345         }
32346         
32347         if(this.cls){
32348             cls += ' ' + this.cls;
32349         }
32350         
32351         var cfg = {
32352             tag: (this.href.length) ? 'a' : 'div',
32353             cls: cls,
32354             cn: [
32355                 {
32356                     tag: 'div',
32357                     cls: 'masonry-brick-mask'
32358                 },
32359                 {
32360                     tag: 'div',
32361                     cls: 'masonry-brick-paragraph',
32362                     cn: []
32363                 }
32364             ]
32365         };
32366         
32367         if(this.href.length){
32368             cfg.href = this.href;
32369         }
32370         
32371         var cn = cfg.cn[1].cn;
32372         
32373         if(this.title.length){
32374             cn.push({
32375                 tag: 'h4',
32376                 cls: 'masonry-brick-title',
32377                 html: this.title
32378             });
32379         }
32380         
32381         if(this.html.length){
32382             cn.push({
32383                 tag: 'p',
32384                 cls: 'masonry-brick-text',
32385                 html: this.html
32386             });
32387         }
32388         
32389         if (!this.title.length && !this.html.length) {
32390             cfg.cn[1].cls += ' hide';
32391         }
32392         
32393         if(this.bgimage.length){
32394             cfg.cn.push({
32395                 tag: 'img',
32396                 cls: 'masonry-brick-image-view',
32397                 src: this.bgimage
32398             });
32399         }
32400         
32401         if(this.videourl.length){
32402             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32403             // youtube support only?
32404             cfg.cn.push({
32405                 tag: 'iframe',
32406                 cls: 'masonry-brick-image-view',
32407                 src: vurl,
32408                 frameborder : 0,
32409                 allowfullscreen : true
32410             });
32411         }
32412         
32413         return cfg;
32414         
32415     },
32416     
32417     getSplitAutoCreate : function()
32418     {
32419         var cls = 'masonry-brick masonry-brick-split';
32420         
32421         if(this.href.length){
32422             cls += ' masonry-brick-link';
32423         }
32424         
32425         if(this.bgimage.length){
32426             cls += ' masonry-brick-image';
32427         }
32428         
32429         if(this.size){
32430             cls += ' masonry-' + this.size + '-brick';
32431         }
32432         
32433         switch (this.placetitle) {
32434             case 'center' :
32435                 cls += ' masonry-center-title';
32436                 break;
32437             case 'bottom' :
32438                 cls += ' masonry-bottom-title';
32439                 break;
32440             default:
32441                 if(!this.bgimage.length){
32442                     cls += ' masonry-center-title';
32443                 }
32444
32445                 if(this.bgimage.length){
32446                     cls += ' masonry-bottom-title';
32447                 }
32448                 break;
32449         }
32450         
32451         if(this.cls){
32452             cls += ' ' + this.cls;
32453         }
32454         
32455         var cfg = {
32456             tag: (this.href.length) ? 'a' : 'div',
32457             cls: cls,
32458             cn: [
32459                 {
32460                     tag: 'div',
32461                     cls: 'masonry-brick-split-head',
32462                     cn: [
32463                         {
32464                             tag: 'div',
32465                             cls: 'masonry-brick-paragraph',
32466                             cn: []
32467                         }
32468                     ]
32469                 },
32470                 {
32471                     tag: 'div',
32472                     cls: 'masonry-brick-split-body',
32473                     cn: []
32474                 }
32475             ]
32476         };
32477         
32478         if(this.href.length){
32479             cfg.href = this.href;
32480         }
32481         
32482         if(this.title.length){
32483             cfg.cn[0].cn[0].cn.push({
32484                 tag: 'h4',
32485                 cls: 'masonry-brick-title',
32486                 html: this.title
32487             });
32488         }
32489         
32490         if(this.html.length){
32491             cfg.cn[1].cn.push({
32492                 tag: 'p',
32493                 cls: 'masonry-brick-text',
32494                 html: this.html
32495             });
32496         }
32497
32498         if(this.bgimage.length){
32499             cfg.cn[0].cn.push({
32500                 tag: 'img',
32501                 cls: 'masonry-brick-image-view',
32502                 src: this.bgimage
32503             });
32504         }
32505         
32506         if(this.videourl.length){
32507             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32508             // youtube support only?
32509             cfg.cn[0].cn.cn.push({
32510                 tag: 'iframe',
32511                 cls: 'masonry-brick-image-view',
32512                 src: vurl,
32513                 frameborder : 0,
32514                 allowfullscreen : true
32515             });
32516         }
32517         
32518         return cfg;
32519     },
32520     
32521     initEvents: function() 
32522     {
32523         switch (this.size) {
32524             case 'xs' :
32525                 this.x = 1;
32526                 this.y = 1;
32527                 break;
32528             case 'sm' :
32529                 this.x = 2;
32530                 this.y = 2;
32531                 break;
32532             case 'md' :
32533             case 'md-left' :
32534             case 'md-right' :
32535                 this.x = 3;
32536                 this.y = 3;
32537                 break;
32538             case 'tall' :
32539                 this.x = 2;
32540                 this.y = 3;
32541                 break;
32542             case 'wide' :
32543                 this.x = 3;
32544                 this.y = 2;
32545                 break;
32546             case 'wide-thin' :
32547                 this.x = 3;
32548                 this.y = 1;
32549                 break;
32550                         
32551             default :
32552                 break;
32553         }
32554         
32555         if(Roo.isTouch){
32556             this.el.on('touchstart', this.onTouchStart, this);
32557             this.el.on('touchmove', this.onTouchMove, this);
32558             this.el.on('touchend', this.onTouchEnd, this);
32559             this.el.on('contextmenu', this.onContextMenu, this);
32560         } else {
32561             this.el.on('mouseenter'  ,this.enter, this);
32562             this.el.on('mouseleave', this.leave, this);
32563             this.el.on('click', this.onClick, this);
32564         }
32565         
32566         if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32567             this.parent().bricks.push(this);   
32568         }
32569         
32570     },
32571     
32572     onClick: function(e, el)
32573     {
32574         var time = this.endTimer - this.startTimer;
32575         // Roo.log(e.preventDefault());
32576         if(Roo.isTouch){
32577             if(time > 1000){
32578                 e.preventDefault();
32579                 return;
32580             }
32581         }
32582         
32583         if(!this.preventDefault){
32584             return;
32585         }
32586         
32587         e.preventDefault();
32588         
32589         if (this.activcClass != '') {
32590             this.selectBrick();
32591         }
32592         
32593         this.fireEvent('click', this);
32594     },
32595     
32596     enter: function(e, el)
32597     {
32598         e.preventDefault();
32599         
32600         if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32601             return;
32602         }
32603         
32604         if(this.bgimage.length && this.html.length){
32605             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32606         }
32607     },
32608     
32609     leave: function(e, el)
32610     {
32611         e.preventDefault();
32612         
32613         if(!this.isFitContainer || this.maskInverse  || this.videourl.length){
32614             return;
32615         }
32616         
32617         if(this.bgimage.length && this.html.length){
32618             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32619         }
32620     },
32621     
32622     onTouchStart: function(e, el)
32623     {
32624 //        e.preventDefault();
32625         
32626         this.touchmoved = false;
32627         
32628         if(!this.isFitContainer){
32629             return;
32630         }
32631         
32632         if(!this.bgimage.length || !this.html.length){
32633             return;
32634         }
32635         
32636         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32637         
32638         this.timer = new Date().getTime();
32639         
32640     },
32641     
32642     onTouchMove: function(e, el)
32643     {
32644         this.touchmoved = true;
32645     },
32646     
32647     onContextMenu : function(e,el)
32648     {
32649         e.preventDefault();
32650         e.stopPropagation();
32651         return false;
32652     },
32653     
32654     onTouchEnd: function(e, el)
32655     {
32656 //        e.preventDefault();
32657         
32658         if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32659         
32660             this.leave(e,el);
32661             
32662             return;
32663         }
32664         
32665         if(!this.bgimage.length || !this.html.length){
32666             
32667             if(this.href.length){
32668                 window.location.href = this.href;
32669             }
32670             
32671             return;
32672         }
32673         
32674         if(!this.isFitContainer){
32675             return;
32676         }
32677         
32678         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32679         
32680         window.location.href = this.href;
32681     },
32682     
32683     //selection on single brick only
32684     selectBrick : function() {
32685         
32686         if (!this.parentId) {
32687             return;
32688         }
32689         
32690         var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32691         var index = m.selectedBrick.indexOf(this.id);
32692         
32693         if ( index > -1) {
32694             m.selectedBrick.splice(index,1);
32695             this.el.removeClass(this.activeClass);
32696             return;
32697         }
32698         
32699         for(var i = 0; i < m.selectedBrick.length; i++) {
32700             var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32701             b.el.removeClass(b.activeClass);
32702         }
32703         
32704         m.selectedBrick = [];
32705         
32706         m.selectedBrick.push(this.id);
32707         this.el.addClass(this.activeClass);
32708         return;
32709     }
32710     
32711 });
32712
32713 Roo.apply(Roo.bootstrap.MasonryBrick, {
32714     
32715     //groups: {},
32716     groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32717      /**
32718     * register a Masonry Brick
32719     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32720     */
32721     
32722     register : function(brick)
32723     {
32724         //this.groups[brick.id] = brick;
32725         this.groups.add(brick.id, brick);
32726     },
32727     /**
32728     * fetch a  masonry brick based on the masonry brick ID
32729     * @param {string} the masonry brick to add
32730     * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32731     */
32732     
32733     get: function(brick_id) 
32734     {
32735         // if (typeof(this.groups[brick_id]) == 'undefined') {
32736         //     return false;
32737         // }
32738         // return this.groups[brick_id] ;
32739         
32740         if(this.groups.key(brick_id)) {
32741             return this.groups.key(brick_id);
32742         }
32743         
32744         return false;
32745     }
32746     
32747     
32748     
32749 });
32750
32751  /*
32752  * - LGPL
32753  *
32754  * element
32755  * 
32756  */
32757
32758 /**
32759  * @class Roo.bootstrap.Brick
32760  * @extends Roo.bootstrap.Component
32761  * Bootstrap Brick class
32762  * 
32763  * @constructor
32764  * Create a new Brick
32765  * @param {Object} config The config object
32766  */
32767
32768 Roo.bootstrap.Brick = function(config){
32769     Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32770     
32771     this.addEvents({
32772         // raw events
32773         /**
32774          * @event click
32775          * When a Brick is click
32776          * @param {Roo.bootstrap.Brick} this
32777          * @param {Roo.EventObject} e
32778          */
32779         "click" : true
32780     });
32781 };
32782
32783 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
32784     
32785     /**
32786      * @cfg {String} title
32787      */   
32788     title : '',
32789     /**
32790      * @cfg {String} html
32791      */   
32792     html : '',
32793     /**
32794      * @cfg {String} bgimage
32795      */   
32796     bgimage : '',
32797     /**
32798      * @cfg {String} cls
32799      */   
32800     cls : '',
32801     /**
32802      * @cfg {String} href
32803      */   
32804     href : '',
32805     /**
32806      * @cfg {String} video
32807      */   
32808     video : '',
32809     /**
32810      * @cfg {Boolean} square
32811      */   
32812     square : true,
32813     
32814     getAutoCreate : function()
32815     {
32816         var cls = 'roo-brick';
32817         
32818         if(this.href.length){
32819             cls += ' roo-brick-link';
32820         }
32821         
32822         if(this.bgimage.length){
32823             cls += ' roo-brick-image';
32824         }
32825         
32826         if(!this.html.length && !this.bgimage.length){
32827             cls += ' roo-brick-center-title';
32828         }
32829         
32830         if(!this.html.length && this.bgimage.length){
32831             cls += ' roo-brick-bottom-title';
32832         }
32833         
32834         if(this.cls){
32835             cls += ' ' + this.cls;
32836         }
32837         
32838         var cfg = {
32839             tag: (this.href.length) ? 'a' : 'div',
32840             cls: cls,
32841             cn: [
32842                 {
32843                     tag: 'div',
32844                     cls: 'roo-brick-paragraph',
32845                     cn: []
32846                 }
32847             ]
32848         };
32849         
32850         if(this.href.length){
32851             cfg.href = this.href;
32852         }
32853         
32854         var cn = cfg.cn[0].cn;
32855         
32856         if(this.title.length){
32857             cn.push({
32858                 tag: 'h4',
32859                 cls: 'roo-brick-title',
32860                 html: this.title
32861             });
32862         }
32863         
32864         if(this.html.length){
32865             cn.push({
32866                 tag: 'p',
32867                 cls: 'roo-brick-text',
32868                 html: this.html
32869             });
32870         } else {
32871             cn.cls += ' hide';
32872         }
32873         
32874         if(this.bgimage.length){
32875             cfg.cn.push({
32876                 tag: 'img',
32877                 cls: 'roo-brick-image-view',
32878                 src: this.bgimage
32879             });
32880         }
32881         
32882         return cfg;
32883     },
32884     
32885     initEvents: function() 
32886     {
32887         if(this.title.length || this.html.length){
32888             this.el.on('mouseenter'  ,this.enter, this);
32889             this.el.on('mouseleave', this.leave, this);
32890         }
32891         
32892         Roo.EventManager.onWindowResize(this.resize, this); 
32893         
32894         if(this.bgimage.length){
32895             this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32896             this.imageEl.on('load', this.onImageLoad, this);
32897             return;
32898         }
32899         
32900         this.resize();
32901     },
32902     
32903     onImageLoad : function()
32904     {
32905         this.resize();
32906     },
32907     
32908     resize : function()
32909     {
32910         var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32911         
32912         paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32913         
32914         if(this.bgimage.length){
32915             var image = this.el.select('.roo-brick-image-view', true).first();
32916             
32917             image.setWidth(paragraph.getWidth());
32918             
32919             if(this.square){
32920                 image.setHeight(paragraph.getWidth());
32921             }
32922             
32923             this.el.setHeight(image.getHeight());
32924             paragraph.setHeight(image.getHeight());
32925             
32926         }
32927         
32928     },
32929     
32930     enter: function(e, el)
32931     {
32932         e.preventDefault();
32933         
32934         if(this.bgimage.length){
32935             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32936             this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32937         }
32938     },
32939     
32940     leave: function(e, el)
32941     {
32942         e.preventDefault();
32943         
32944         if(this.bgimage.length){
32945             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32946             this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32947         }
32948     }
32949     
32950 });
32951
32952  
32953
32954  /*
32955  * - LGPL
32956  *
32957  * Input
32958  * 
32959  */
32960
32961 /**
32962  * @class Roo.bootstrap.NumberField
32963  * @extends Roo.bootstrap.Input
32964  * Bootstrap NumberField class
32965  * 
32966  * 
32967  * 
32968  * 
32969  * @constructor
32970  * Create a new NumberField
32971  * @param {Object} config The config object
32972  */
32973
32974 Roo.bootstrap.NumberField = function(config){
32975     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32976 };
32977
32978 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32979     
32980     /**
32981      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32982      */
32983     allowDecimals : true,
32984     /**
32985      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32986      */
32987     decimalSeparator : ".",
32988     /**
32989      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32990      */
32991     decimalPrecision : 2,
32992     /**
32993      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32994      */
32995     allowNegative : true,
32996     /**
32997      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32998      */
32999     minValue : Number.NEGATIVE_INFINITY,
33000     /**
33001      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33002      */
33003     maxValue : Number.MAX_VALUE,
33004     /**
33005      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33006      */
33007     minText : "The minimum value for this field is {0}",
33008     /**
33009      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33010      */
33011     maxText : "The maximum value for this field is {0}",
33012     /**
33013      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
33014      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33015      */
33016     nanText : "{0} is not a valid number",
33017     /**
33018      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33019      */
33020     castInt : true,
33021
33022     // private
33023     initEvents : function()
33024     {   
33025         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33026         
33027         var allowed = "0123456789";
33028         
33029         if(this.allowDecimals){
33030             allowed += this.decimalSeparator;
33031         }
33032         
33033         if(this.allowNegative){
33034             allowed += "-";
33035         }
33036         
33037         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33038         
33039         var keyPress = function(e){
33040             
33041             var k = e.getKey();
33042             
33043             var c = e.getCharCode();
33044             
33045             if(
33046                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33047                     allowed.indexOf(String.fromCharCode(c)) === -1
33048             ){
33049                 e.stopEvent();
33050                 return;
33051             }
33052             
33053             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33054                 return;
33055             }
33056             
33057             if(allowed.indexOf(String.fromCharCode(c)) === -1){
33058                 e.stopEvent();
33059             }
33060         };
33061         
33062         this.el.on("keypress", keyPress, this);
33063     },
33064     
33065     validateValue : function(value)
33066     {
33067         
33068         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33069             return false;
33070         }
33071         
33072         var num = this.parseValue(value);
33073         
33074         if(isNaN(num)){
33075             this.markInvalid(String.format(this.nanText, value));
33076             return false;
33077         }
33078         
33079         if(num < this.minValue){
33080             this.markInvalid(String.format(this.minText, this.minValue));
33081             return false;
33082         }
33083         
33084         if(num > this.maxValue){
33085             this.markInvalid(String.format(this.maxText, this.maxValue));
33086             return false;
33087         }
33088         
33089         return true;
33090     },
33091
33092     getValue : function()
33093     {
33094         return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
33095     },
33096
33097     parseValue : function(value)
33098     {
33099         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33100         return isNaN(value) ? '' : value;
33101     },
33102
33103     fixPrecision : function(value)
33104     {
33105         var nan = isNaN(value);
33106         
33107         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33108             return nan ? '' : value;
33109         }
33110         return parseFloat(value).toFixed(this.decimalPrecision);
33111     },
33112
33113     setValue : function(v)
33114     {
33115         v = this.fixPrecision(v);
33116         Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
33117     },
33118
33119     decimalPrecisionFcn : function(v)
33120     {
33121         return Math.floor(v);
33122     },
33123
33124     beforeBlur : function()
33125     {
33126         if(!this.castInt){
33127             return;
33128         }
33129         
33130         var v = this.parseValue(this.getRawValue());
33131         if(v){
33132             this.setValue(v);
33133         }
33134     }
33135     
33136 });
33137
33138  
33139
33140 /*
33141 * Licence: LGPL
33142 */
33143
33144 /**
33145  * @class Roo.bootstrap.DocumentSlider
33146  * @extends Roo.bootstrap.Component
33147  * Bootstrap DocumentSlider class
33148  * 
33149  * @constructor
33150  * Create a new DocumentViewer
33151  * @param {Object} config The config object
33152  */
33153
33154 Roo.bootstrap.DocumentSlider = function(config){
33155     Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33156     
33157     this.files = [];
33158     
33159     this.addEvents({
33160         /**
33161          * @event initial
33162          * Fire after initEvent
33163          * @param {Roo.bootstrap.DocumentSlider} this
33164          */
33165         "initial" : true,
33166         /**
33167          * @event update
33168          * Fire after update
33169          * @param {Roo.bootstrap.DocumentSlider} this
33170          */
33171         "update" : true,
33172         /**
33173          * @event click
33174          * Fire after click
33175          * @param {Roo.bootstrap.DocumentSlider} this
33176          */
33177         "click" : true
33178     });
33179 };
33180
33181 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
33182     
33183     files : false,
33184     
33185     indicator : 0,
33186     
33187     getAutoCreate : function()
33188     {
33189         var cfg = {
33190             tag : 'div',
33191             cls : 'roo-document-slider',
33192             cn : [
33193                 {
33194                     tag : 'div',
33195                     cls : 'roo-document-slider-header',
33196                     cn : [
33197                         {
33198                             tag : 'div',
33199                             cls : 'roo-document-slider-header-title'
33200                         }
33201                     ]
33202                 },
33203                 {
33204                     tag : 'div',
33205                     cls : 'roo-document-slider-body',
33206                     cn : [
33207                         {
33208                             tag : 'div',
33209                             cls : 'roo-document-slider-prev',
33210                             cn : [
33211                                 {
33212                                     tag : 'i',
33213                                     cls : 'fa fa-chevron-left'
33214                                 }
33215                             ]
33216                         },
33217                         {
33218                             tag : 'div',
33219                             cls : 'roo-document-slider-thumb',
33220                             cn : [
33221                                 {
33222                                     tag : 'img',
33223                                     cls : 'roo-document-slider-image'
33224                                 }
33225                             ]
33226                         },
33227                         {
33228                             tag : 'div',
33229                             cls : 'roo-document-slider-next',
33230                             cn : [
33231                                 {
33232                                     tag : 'i',
33233                                     cls : 'fa fa-chevron-right'
33234                                 }
33235                             ]
33236                         }
33237                     ]
33238                 }
33239             ]
33240         };
33241         
33242         return cfg;
33243     },
33244     
33245     initEvents : function()
33246     {
33247         this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33248         this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33249         
33250         this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33251         this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33252         
33253         this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33254         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33255         
33256         this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33257         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33258         
33259         this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33260         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33261         
33262         this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33263         this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33264         
33265         this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33266         this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33267         
33268         this.thumbEl.on('click', this.onClick, this);
33269         
33270         this.prevIndicator.on('click', this.prev, this);
33271         
33272         this.nextIndicator.on('click', this.next, this);
33273         
33274     },
33275     
33276     initial : function()
33277     {
33278         if(this.files.length){
33279             this.indicator = 1;
33280             this.update()
33281         }
33282         
33283         this.fireEvent('initial', this);
33284     },
33285     
33286     update : function()
33287     {
33288         this.imageEl.attr('src', this.files[this.indicator - 1]);
33289         
33290         this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33291         
33292         this.prevIndicator.show();
33293         
33294         if(this.indicator == 1){
33295             this.prevIndicator.hide();
33296         }
33297         
33298         this.nextIndicator.show();
33299         
33300         if(this.indicator == this.files.length){
33301             this.nextIndicator.hide();
33302         }
33303         
33304         this.thumbEl.scrollTo('top');
33305         
33306         this.fireEvent('update', this);
33307     },
33308     
33309     onClick : function(e)
33310     {
33311         e.preventDefault();
33312         
33313         this.fireEvent('click', this);
33314     },
33315     
33316     prev : function(e)
33317     {
33318         e.preventDefault();
33319         
33320         this.indicator = Math.max(1, this.indicator - 1);
33321         
33322         this.update();
33323     },
33324     
33325     next : function(e)
33326     {
33327         e.preventDefault();
33328         
33329         this.indicator = Math.min(this.files.length, this.indicator + 1);
33330         
33331         this.update();
33332     }
33333 });
33334 /*
33335  * - LGPL
33336  *
33337  * RadioSet
33338  *
33339  *
33340  */
33341
33342 /**
33343  * @class Roo.bootstrap.RadioSet
33344  * @extends Roo.bootstrap.Input
33345  * Bootstrap RadioSet class
33346  * @cfg {String} indicatorpos (left|right) default left
33347  * @cfg {Boolean} inline (true|false) inline the element (default true)
33348  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33349  * @constructor
33350  * Create a new RadioSet
33351  * @param {Object} config The config object
33352  */
33353
33354 Roo.bootstrap.RadioSet = function(config){
33355     
33356     Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33357     
33358     this.radioes = [];
33359     
33360     Roo.bootstrap.RadioSet.register(this);
33361     
33362     this.addEvents({
33363         /**
33364         * @event check
33365         * Fires when the element is checked or unchecked.
33366         * @param {Roo.bootstrap.RadioSet} this This radio
33367         * @param {Roo.bootstrap.Radio} item The checked item
33368         */
33369        check : true
33370     });
33371     
33372 };
33373
33374 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
33375
33376     radioes : false,
33377     
33378     inline : true,
33379     
33380     weight : '',
33381     
33382     indicatorpos : 'left',
33383     
33384     getAutoCreate : function()
33385     {
33386         var label = {
33387             tag : 'label',
33388             cls : 'roo-radio-set-label',
33389             cn : [
33390                 {
33391                     tag : 'span',
33392                     html : this.fieldLabel
33393                 }
33394             ]
33395         };
33396         
33397         if(this.indicatorpos == 'left'){
33398             label.cn.unshift({
33399                 tag : 'i',
33400                 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33401                 tooltip : 'This field is required'
33402             });
33403         } else {
33404             label.cn.push({
33405                 tag : 'i',
33406                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33407                 tooltip : 'This field is required'
33408             });
33409         }
33410         
33411         var items = {
33412             tag : 'div',
33413             cls : 'roo-radio-set-items'
33414         };
33415         
33416         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33417         
33418         if (align === 'left' && this.fieldLabel.length) {
33419             
33420             items = {
33421                 cls : "roo-radio-set-right", 
33422                 cn: [
33423                     items
33424                 ]
33425             };
33426             
33427             if(this.labelWidth > 12){
33428                 label.style = "width: " + this.labelWidth + 'px';
33429             }
33430             
33431             if(this.labelWidth < 13 && this.labelmd == 0){
33432                 this.labelmd = this.labelWidth;
33433             }
33434             
33435             if(this.labellg > 0){
33436                 label.cls += ' col-lg-' + this.labellg;
33437                 items.cls += ' col-lg-' + (12 - this.labellg);
33438             }
33439             
33440             if(this.labelmd > 0){
33441                 label.cls += ' col-md-' + this.labelmd;
33442                 items.cls += ' col-md-' + (12 - this.labelmd);
33443             }
33444             
33445             if(this.labelsm > 0){
33446                 label.cls += ' col-sm-' + this.labelsm;
33447                 items.cls += ' col-sm-' + (12 - this.labelsm);
33448             }
33449             
33450             if(this.labelxs > 0){
33451                 label.cls += ' col-xs-' + this.labelxs;
33452                 items.cls += ' col-xs-' + (12 - this.labelxs);
33453             }
33454         }
33455         
33456         var cfg = {
33457             tag : 'div',
33458             cls : 'roo-radio-set',
33459             cn : [
33460                 {
33461                     tag : 'input',
33462                     cls : 'roo-radio-set-input',
33463                     type : 'hidden',
33464                     name : this.name,
33465                     value : this.value ? this.value :  ''
33466                 },
33467                 label,
33468                 items
33469             ]
33470         };
33471         
33472         if(this.weight.length){
33473             cfg.cls += ' roo-radio-' + this.weight;
33474         }
33475         
33476         if(this.inline) {
33477             cfg.cls += ' roo-radio-set-inline';
33478         }
33479         
33480         var settings=this;
33481         ['xs','sm','md','lg'].map(function(size){
33482             if (settings[size]) {
33483                 cfg.cls += ' col-' + size + '-' + settings[size];
33484             }
33485         });
33486         
33487         return cfg;
33488         
33489     },
33490
33491     initEvents : function()
33492     {
33493         this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33494         this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33495         
33496         if(!this.fieldLabel.length){
33497             this.labelEl.hide();
33498         }
33499         
33500         this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33501         this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33502         
33503         this.indicatorEl().addClass('invisible');
33504         
33505         this.originalValue = this.getValue();
33506         
33507     },
33508     
33509     inputEl: function ()
33510     {
33511         return this.el.select('.roo-radio-set-input', true).first();
33512     },
33513     
33514     getChildContainer : function()
33515     {
33516         return this.itemsEl;
33517     },
33518     
33519     register : function(item)
33520     {
33521         this.radioes.push(item);
33522         
33523     },
33524     
33525     validate : function()
33526     {   
33527         var valid = false;
33528         
33529         Roo.each(this.radioes, function(i){
33530             if(!i.checked){
33531                 return;
33532             }
33533             
33534             valid = true;
33535             return false;
33536         });
33537         
33538         if(this.allowBlank) {
33539             return true;
33540         }
33541         
33542         if(this.disabled || valid){
33543             this.markValid();
33544             return true;
33545         }
33546         
33547         this.markInvalid();
33548         return false;
33549         
33550     },
33551     
33552     markValid : function()
33553     {
33554         if(this.labelEl.isVisible(true)){
33555             this.indicatorEl().removeClass('visible');
33556             this.indicatorEl().addClass('invisible');
33557         }
33558         
33559         this.el.removeClass([this.invalidClass, this.validClass]);
33560         this.el.addClass(this.validClass);
33561         
33562         this.fireEvent('valid', this);
33563     },
33564     
33565     markInvalid : function(msg)
33566     {
33567         if(this.allowBlank || this.disabled){
33568             return;
33569         }
33570         
33571         if(this.labelEl.isVisible(true)){
33572             this.indicatorEl().removeClass('invisible');
33573             this.indicatorEl().addClass('visible');
33574         }
33575         
33576         this.el.removeClass([this.invalidClass, this.validClass]);
33577         this.el.addClass(this.invalidClass);
33578         
33579         this.fireEvent('invalid', this, msg);
33580         
33581     },
33582     
33583     setValue : function(v, suppressEvent)
33584     {   
33585         if(this.value === v){
33586             return;
33587         }
33588         
33589         this.value = v;
33590         
33591         if(this.rendered){
33592             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33593         }
33594         
33595         Roo.each(this.radioes, function(i){
33596             
33597             i.checked = false;
33598             i.el.removeClass('checked');
33599             
33600             if(i.value === v || i.value.toString() === v.toString()){
33601                 i.checked = true;
33602                 i.el.addClass('checked');
33603                 
33604                 if(suppressEvent !== true){
33605                     this.fireEvent('check', this, i);
33606                 }
33607             }
33608             
33609         }, this);
33610         
33611         this.validate();
33612     },
33613     
33614     clearInvalid : function(){
33615         
33616         if(!this.el || this.preventMark){
33617             return;
33618         }
33619         
33620         this.el.removeClass([this.invalidClass]);
33621         
33622         this.fireEvent('valid', this);
33623     }
33624     
33625 });
33626
33627 Roo.apply(Roo.bootstrap.RadioSet, {
33628     
33629     groups: {},
33630     
33631     register : function(set)
33632     {
33633         this.groups[set.name] = set;
33634     },
33635     
33636     get: function(name) 
33637     {
33638         if (typeof(this.groups[name]) == 'undefined') {
33639             return false;
33640         }
33641         
33642         return this.groups[name] ;
33643     }
33644     
33645 });
33646 /*
33647  * Based on:
33648  * Ext JS Library 1.1.1
33649  * Copyright(c) 2006-2007, Ext JS, LLC.
33650  *
33651  * Originally Released Under LGPL - original licence link has changed is not relivant.
33652  *
33653  * Fork - LGPL
33654  * <script type="text/javascript">
33655  */
33656
33657
33658 /**
33659  * @class Roo.bootstrap.SplitBar
33660  * @extends Roo.util.Observable
33661  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33662  * <br><br>
33663  * Usage:
33664  * <pre><code>
33665 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33666                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33667 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33668 split.minSize = 100;
33669 split.maxSize = 600;
33670 split.animate = true;
33671 split.on('moved', splitterMoved);
33672 </code></pre>
33673  * @constructor
33674  * Create a new SplitBar
33675  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
33676  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
33677  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33678  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
33679                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33680                         position of the SplitBar).
33681  */
33682 Roo.bootstrap.SplitBar = function(cfg){
33683     
33684     /** @private */
33685     
33686     //{
33687     //  dragElement : elm
33688     //  resizingElement: el,
33689         // optional..
33690     //    orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33691     //    placement : Roo.bootstrap.SplitBar.LEFT  ,
33692         // existingProxy ???
33693     //}
33694     
33695     this.el = Roo.get(cfg.dragElement, true);
33696     this.el.dom.unselectable = "on";
33697     /** @private */
33698     this.resizingEl = Roo.get(cfg.resizingElement, true);
33699
33700     /**
33701      * @private
33702      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33703      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33704      * @type Number
33705      */
33706     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33707     
33708     /**
33709      * The minimum size of the resizing element. (Defaults to 0)
33710      * @type Number
33711      */
33712     this.minSize = 0;
33713     
33714     /**
33715      * The maximum size of the resizing element. (Defaults to 2000)
33716      * @type Number
33717      */
33718     this.maxSize = 2000;
33719     
33720     /**
33721      * Whether to animate the transition to the new size
33722      * @type Boolean
33723      */
33724     this.animate = false;
33725     
33726     /**
33727      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33728      * @type Boolean
33729      */
33730     this.useShim = false;
33731     
33732     /** @private */
33733     this.shim = null;
33734     
33735     if(!cfg.existingProxy){
33736         /** @private */
33737         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33738     }else{
33739         this.proxy = Roo.get(cfg.existingProxy).dom;
33740     }
33741     /** @private */
33742     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33743     
33744     /** @private */
33745     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33746     
33747     /** @private */
33748     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33749     
33750     /** @private */
33751     this.dragSpecs = {};
33752     
33753     /**
33754      * @private The adapter to use to positon and resize elements
33755      */
33756     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33757     this.adapter.init(this);
33758     
33759     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33760         /** @private */
33761         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33762         this.el.addClass("roo-splitbar-h");
33763     }else{
33764         /** @private */
33765         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33766         this.el.addClass("roo-splitbar-v");
33767     }
33768     
33769     this.addEvents({
33770         /**
33771          * @event resize
33772          * Fires when the splitter is moved (alias for {@link #event-moved})
33773          * @param {Roo.bootstrap.SplitBar} this
33774          * @param {Number} newSize the new width or height
33775          */
33776         "resize" : true,
33777         /**
33778          * @event moved
33779          * Fires when the splitter is moved
33780          * @param {Roo.bootstrap.SplitBar} this
33781          * @param {Number} newSize the new width or height
33782          */
33783         "moved" : true,
33784         /**
33785          * @event beforeresize
33786          * Fires before the splitter is dragged
33787          * @param {Roo.bootstrap.SplitBar} this
33788          */
33789         "beforeresize" : true,
33790
33791         "beforeapply" : true
33792     });
33793
33794     Roo.util.Observable.call(this);
33795 };
33796
33797 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33798     onStartProxyDrag : function(x, y){
33799         this.fireEvent("beforeresize", this);
33800         if(!this.overlay){
33801             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "roo-drag-overlay", html: "&#160;"}, true);
33802             o.unselectable();
33803             o.enableDisplayMode("block");
33804             // all splitbars share the same overlay
33805             Roo.bootstrap.SplitBar.prototype.overlay = o;
33806         }
33807         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33808         this.overlay.show();
33809         Roo.get(this.proxy).setDisplayed("block");
33810         var size = this.adapter.getElementSize(this);
33811         this.activeMinSize = this.getMinimumSize();;
33812         this.activeMaxSize = this.getMaximumSize();;
33813         var c1 = size - this.activeMinSize;
33814         var c2 = Math.max(this.activeMaxSize - size, 0);
33815         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33816             this.dd.resetConstraints();
33817             this.dd.setXConstraint(
33818                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
33819                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33820             );
33821             this.dd.setYConstraint(0, 0);
33822         }else{
33823             this.dd.resetConstraints();
33824             this.dd.setXConstraint(0, 0);
33825             this.dd.setYConstraint(
33826                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
33827                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33828             );
33829          }
33830         this.dragSpecs.startSize = size;
33831         this.dragSpecs.startPoint = [x, y];
33832         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33833     },
33834     
33835     /** 
33836      * @private Called after the drag operation by the DDProxy
33837      */
33838     onEndProxyDrag : function(e){
33839         Roo.get(this.proxy).setDisplayed(false);
33840         var endPoint = Roo.lib.Event.getXY(e);
33841         if(this.overlay){
33842             this.overlay.hide();
33843         }
33844         var newSize;
33845         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33846             newSize = this.dragSpecs.startSize + 
33847                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33848                     endPoint[0] - this.dragSpecs.startPoint[0] :
33849                     this.dragSpecs.startPoint[0] - endPoint[0]
33850                 );
33851         }else{
33852             newSize = this.dragSpecs.startSize + 
33853                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33854                     endPoint[1] - this.dragSpecs.startPoint[1] :
33855                     this.dragSpecs.startPoint[1] - endPoint[1]
33856                 );
33857         }
33858         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33859         if(newSize != this.dragSpecs.startSize){
33860             if(this.fireEvent('beforeapply', this, newSize) !== false){
33861                 this.adapter.setElementSize(this, newSize);
33862                 this.fireEvent("moved", this, newSize);
33863                 this.fireEvent("resize", this, newSize);
33864             }
33865         }
33866     },
33867     
33868     /**
33869      * Get the adapter this SplitBar uses
33870      * @return The adapter object
33871      */
33872     getAdapter : function(){
33873         return this.adapter;
33874     },
33875     
33876     /**
33877      * Set the adapter this SplitBar uses
33878      * @param {Object} adapter A SplitBar adapter object
33879      */
33880     setAdapter : function(adapter){
33881         this.adapter = adapter;
33882         this.adapter.init(this);
33883     },
33884     
33885     /**
33886      * Gets the minimum size for the resizing element
33887      * @return {Number} The minimum size
33888      */
33889     getMinimumSize : function(){
33890         return this.minSize;
33891     },
33892     
33893     /**
33894      * Sets the minimum size for the resizing element
33895      * @param {Number} minSize The minimum size
33896      */
33897     setMinimumSize : function(minSize){
33898         this.minSize = minSize;
33899     },
33900     
33901     /**
33902      * Gets the maximum size for the resizing element
33903      * @return {Number} The maximum size
33904      */
33905     getMaximumSize : function(){
33906         return this.maxSize;
33907     },
33908     
33909     /**
33910      * Sets the maximum size for the resizing element
33911      * @param {Number} maxSize The maximum size
33912      */
33913     setMaximumSize : function(maxSize){
33914         this.maxSize = maxSize;
33915     },
33916     
33917     /**
33918      * Sets the initialize size for the resizing element
33919      * @param {Number} size The initial size
33920      */
33921     setCurrentSize : function(size){
33922         var oldAnimate = this.animate;
33923         this.animate = false;
33924         this.adapter.setElementSize(this, size);
33925         this.animate = oldAnimate;
33926     },
33927     
33928     /**
33929      * Destroy this splitbar. 
33930      * @param {Boolean} removeEl True to remove the element
33931      */
33932     destroy : function(removeEl){
33933         if(this.shim){
33934             this.shim.remove();
33935         }
33936         this.dd.unreg();
33937         this.proxy.parentNode.removeChild(this.proxy);
33938         if(removeEl){
33939             this.el.remove();
33940         }
33941     }
33942 });
33943
33944 /**
33945  * @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.
33946  */
33947 Roo.bootstrap.SplitBar.createProxy = function(dir){
33948     var proxy = new Roo.Element(document.createElement("div"));
33949     proxy.unselectable();
33950     var cls = 'roo-splitbar-proxy';
33951     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33952     document.body.appendChild(proxy.dom);
33953     return proxy.dom;
33954 };
33955
33956 /** 
33957  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33958  * Default Adapter. It assumes the splitter and resizing element are not positioned
33959  * elements and only gets/sets the width of the element. Generally used for table based layouts.
33960  */
33961 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33962 };
33963
33964 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33965     // do nothing for now
33966     init : function(s){
33967     
33968     },
33969     /**
33970      * Called before drag operations to get the current size of the resizing element. 
33971      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33972      */
33973      getElementSize : function(s){
33974         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33975             return s.resizingEl.getWidth();
33976         }else{
33977             return s.resizingEl.getHeight();
33978         }
33979     },
33980     
33981     /**
33982      * Called after drag operations to set the size of the resizing element.
33983      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33984      * @param {Number} newSize The new size to set
33985      * @param {Function} onComplete A function to be invoked when resizing is complete
33986      */
33987     setElementSize : function(s, newSize, onComplete){
33988         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33989             if(!s.animate){
33990                 s.resizingEl.setWidth(newSize);
33991                 if(onComplete){
33992                     onComplete(s, newSize);
33993                 }
33994             }else{
33995                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33996             }
33997         }else{
33998             
33999             if(!s.animate){
34000                 s.resizingEl.setHeight(newSize);
34001                 if(onComplete){
34002                     onComplete(s, newSize);
34003                 }
34004             }else{
34005                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34006             }
34007         }
34008     }
34009 };
34010
34011 /** 
34012  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34013  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34014  * Adapter that  moves the splitter element to align with the resized sizing element. 
34015  * Used with an absolute positioned SplitBar.
34016  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34017  * document.body, make sure you assign an id to the body element.
34018  */
34019 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34020     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34021     this.container = Roo.get(container);
34022 };
34023
34024 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34025     init : function(s){
34026         this.basic.init(s);
34027     },
34028     
34029     getElementSize : function(s){
34030         return this.basic.getElementSize(s);
34031     },
34032     
34033     setElementSize : function(s, newSize, onComplete){
34034         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34035     },
34036     
34037     moveSplitter : function(s){
34038         var yes = Roo.bootstrap.SplitBar;
34039         switch(s.placement){
34040             case yes.LEFT:
34041                 s.el.setX(s.resizingEl.getRight());
34042                 break;
34043             case yes.RIGHT:
34044                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34045                 break;
34046             case yes.TOP:
34047                 s.el.setY(s.resizingEl.getBottom());
34048                 break;
34049             case yes.BOTTOM:
34050                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34051                 break;
34052         }
34053     }
34054 };
34055
34056 /**
34057  * Orientation constant - Create a vertical SplitBar
34058  * @static
34059  * @type Number
34060  */
34061 Roo.bootstrap.SplitBar.VERTICAL = 1;
34062
34063 /**
34064  * Orientation constant - Create a horizontal SplitBar
34065  * @static
34066  * @type Number
34067  */
34068 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34069
34070 /**
34071  * Placement constant - The resizing element is to the left of the splitter element
34072  * @static
34073  * @type Number
34074  */
34075 Roo.bootstrap.SplitBar.LEFT = 1;
34076
34077 /**
34078  * Placement constant - The resizing element is to the right of the splitter element
34079  * @static
34080  * @type Number
34081  */
34082 Roo.bootstrap.SplitBar.RIGHT = 2;
34083
34084 /**
34085  * Placement constant - The resizing element is positioned above the splitter element
34086  * @static
34087  * @type Number
34088  */
34089 Roo.bootstrap.SplitBar.TOP = 3;
34090
34091 /**
34092  * Placement constant - The resizing element is positioned under splitter element
34093  * @static
34094  * @type Number
34095  */
34096 Roo.bootstrap.SplitBar.BOTTOM = 4;
34097 Roo.namespace("Roo.bootstrap.layout");/*
34098  * Based on:
34099  * Ext JS Library 1.1.1
34100  * Copyright(c) 2006-2007, Ext JS, LLC.
34101  *
34102  * Originally Released Under LGPL - original licence link has changed is not relivant.
34103  *
34104  * Fork - LGPL
34105  * <script type="text/javascript">
34106  */
34107
34108 /**
34109  * @class Roo.bootstrap.layout.Manager
34110  * @extends Roo.bootstrap.Component
34111  * Base class for layout managers.
34112  */
34113 Roo.bootstrap.layout.Manager = function(config)
34114 {
34115     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34116
34117
34118
34119
34120
34121     /** false to disable window resize monitoring @type Boolean */
34122     this.monitorWindowResize = true;
34123     this.regions = {};
34124     this.addEvents({
34125         /**
34126          * @event layout
34127          * Fires when a layout is performed.
34128          * @param {Roo.LayoutManager} this
34129          */
34130         "layout" : true,
34131         /**
34132          * @event regionresized
34133          * Fires when the user resizes a region.
34134          * @param {Roo.LayoutRegion} region The resized region
34135          * @param {Number} newSize The new size (width for east/west, height for north/south)
34136          */
34137         "regionresized" : true,
34138         /**
34139          * @event regioncollapsed
34140          * Fires when a region is collapsed.
34141          * @param {Roo.LayoutRegion} region The collapsed region
34142          */
34143         "regioncollapsed" : true,
34144         /**
34145          * @event regionexpanded
34146          * Fires when a region is expanded.
34147          * @param {Roo.LayoutRegion} region The expanded region
34148          */
34149         "regionexpanded" : true
34150     });
34151     this.updating = false;
34152
34153     if (config.el) {
34154         this.el = Roo.get(config.el);
34155         this.initEvents();
34156     }
34157
34158 };
34159
34160 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34161
34162
34163     regions : null,
34164
34165     monitorWindowResize : true,
34166
34167
34168     updating : false,
34169
34170
34171     onRender : function(ct, position)
34172     {
34173         if(!this.el){
34174             this.el = Roo.get(ct);
34175             this.initEvents();
34176         }
34177         //this.fireEvent('render',this);
34178     },
34179
34180
34181     initEvents: function()
34182     {
34183
34184
34185         // ie scrollbar fix
34186         if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34187             document.body.scroll = "no";
34188         }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34189             this.el.position('relative');
34190         }
34191         this.id = this.el.id;
34192         this.el.addClass("roo-layout-container");
34193         Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34194         if(this.el.dom != document.body ) {
34195             this.el.on('resize', this.layout,this);
34196             this.el.on('show', this.layout,this);
34197         }
34198
34199     },
34200
34201     /**
34202      * Returns true if this layout is currently being updated
34203      * @return {Boolean}
34204      */
34205     isUpdating : function(){
34206         return this.updating;
34207     },
34208
34209     /**
34210      * Suspend the LayoutManager from doing auto-layouts while
34211      * making multiple add or remove calls
34212      */
34213     beginUpdate : function(){
34214         this.updating = true;
34215     },
34216
34217     /**
34218      * Restore auto-layouts and optionally disable the manager from performing a layout
34219      * @param {Boolean} noLayout true to disable a layout update
34220      */
34221     endUpdate : function(noLayout){
34222         this.updating = false;
34223         if(!noLayout){
34224             this.layout();
34225         }
34226     },
34227
34228     layout: function(){
34229         // abstract...
34230     },
34231
34232     onRegionResized : function(region, newSize){
34233         this.fireEvent("regionresized", region, newSize);
34234         this.layout();
34235     },
34236
34237     onRegionCollapsed : function(region){
34238         this.fireEvent("regioncollapsed", region);
34239     },
34240
34241     onRegionExpanded : function(region){
34242         this.fireEvent("regionexpanded", region);
34243     },
34244
34245     /**
34246      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34247      * performs box-model adjustments.
34248      * @return {Object} The size as an object {width: (the width), height: (the height)}
34249      */
34250     getViewSize : function()
34251     {
34252         var size;
34253         if(this.el.dom != document.body){
34254             size = this.el.getSize();
34255         }else{
34256             size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34257         }
34258         size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34259         size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34260         return size;
34261     },
34262
34263     /**
34264      * Returns the Element this layout is bound to.
34265      * @return {Roo.Element}
34266      */
34267     getEl : function(){
34268         return this.el;
34269     },
34270
34271     /**
34272      * Returns the specified region.
34273      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34274      * @return {Roo.LayoutRegion}
34275      */
34276     getRegion : function(target){
34277         return this.regions[target.toLowerCase()];
34278     },
34279
34280     onWindowResize : function(){
34281         if(this.monitorWindowResize){
34282             this.layout();
34283         }
34284     }
34285 });
34286 /*
34287  * Based on:
34288  * Ext JS Library 1.1.1
34289  * Copyright(c) 2006-2007, Ext JS, LLC.
34290  *
34291  * Originally Released Under LGPL - original licence link has changed is not relivant.
34292  *
34293  * Fork - LGPL
34294  * <script type="text/javascript">
34295  */
34296 /**
34297  * @class Roo.bootstrap.layout.Border
34298  * @extends Roo.bootstrap.layout.Manager
34299  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34300  * please see: examples/bootstrap/nested.html<br><br>
34301  
34302 <b>The container the layout is rendered into can be either the body element or any other element.
34303 If it is not the body element, the container needs to either be an absolute positioned element,
34304 or you will need to add "position:relative" to the css of the container.  You will also need to specify
34305 the container size if it is not the body element.</b>
34306
34307 * @constructor
34308 * Create a new Border
34309 * @param {Object} config Configuration options
34310  */
34311 Roo.bootstrap.layout.Border = function(config){
34312     config = config || {};
34313     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34314     
34315     
34316     
34317     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34318         if(config[region]){
34319             config[region].region = region;
34320             this.addRegion(config[region]);
34321         }
34322     },this);
34323     
34324 };
34325
34326 Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
34327
34328 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34329     /**
34330      * Creates and adds a new region if it doesn't already exist.
34331      * @param {String} target The target region key (north, south, east, west or center).
34332      * @param {Object} config The regions config object
34333      * @return {BorderLayoutRegion} The new region
34334      */
34335     addRegion : function(config)
34336     {
34337         if(!this.regions[config.region]){
34338             var r = this.factory(config);
34339             this.bindRegion(r);
34340         }
34341         return this.regions[config.region];
34342     },
34343
34344     // private (kinda)
34345     bindRegion : function(r){
34346         this.regions[r.config.region] = r;
34347         
34348         r.on("visibilitychange",    this.layout, this);
34349         r.on("paneladded",          this.layout, this);
34350         r.on("panelremoved",        this.layout, this);
34351         r.on("invalidated",         this.layout, this);
34352         r.on("resized",             this.onRegionResized, this);
34353         r.on("collapsed",           this.onRegionCollapsed, this);
34354         r.on("expanded",            this.onRegionExpanded, this);
34355     },
34356
34357     /**
34358      * Performs a layout update.
34359      */
34360     layout : function()
34361     {
34362         if(this.updating) {
34363             return;
34364         }
34365         
34366         // render all the rebions if they have not been done alreayd?
34367         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34368             if(this.regions[region] && !this.regions[region].bodyEl){
34369                 this.regions[region].onRender(this.el)
34370             }
34371         },this);
34372         
34373         var size = this.getViewSize();
34374         var w = size.width;
34375         var h = size.height;
34376         var centerW = w;
34377         var centerH = h;
34378         var centerY = 0;
34379         var centerX = 0;
34380         //var x = 0, y = 0;
34381
34382         var rs = this.regions;
34383         var north = rs["north"];
34384         var south = rs["south"]; 
34385         var west = rs["west"];
34386         var east = rs["east"];
34387         var center = rs["center"];
34388         //if(this.hideOnLayout){ // not supported anymore
34389             //c.el.setStyle("display", "none");
34390         //}
34391         if(north && north.isVisible()){
34392             var b = north.getBox();
34393             var m = north.getMargins();
34394             b.width = w - (m.left+m.right);
34395             b.x = m.left;
34396             b.y = m.top;
34397             centerY = b.height + b.y + m.bottom;
34398             centerH -= centerY;
34399             north.updateBox(this.safeBox(b));
34400         }
34401         if(south && south.isVisible()){
34402             var b = south.getBox();
34403             var m = south.getMargins();
34404             b.width = w - (m.left+m.right);
34405             b.x = m.left;
34406             var totalHeight = (b.height + m.top + m.bottom);
34407             b.y = h - totalHeight + m.top;
34408             centerH -= totalHeight;
34409             south.updateBox(this.safeBox(b));
34410         }
34411         if(west && west.isVisible()){
34412             var b = west.getBox();
34413             var m = west.getMargins();
34414             b.height = centerH - (m.top+m.bottom);
34415             b.x = m.left;
34416             b.y = centerY + m.top;
34417             var totalWidth = (b.width + m.left + m.right);
34418             centerX += totalWidth;
34419             centerW -= totalWidth;
34420             west.updateBox(this.safeBox(b));
34421         }
34422         if(east && east.isVisible()){
34423             var b = east.getBox();
34424             var m = east.getMargins();
34425             b.height = centerH - (m.top+m.bottom);
34426             var totalWidth = (b.width + m.left + m.right);
34427             b.x = w - totalWidth + m.left;
34428             b.y = centerY + m.top;
34429             centerW -= totalWidth;
34430             east.updateBox(this.safeBox(b));
34431         }
34432         if(center){
34433             var m = center.getMargins();
34434             var centerBox = {
34435                 x: centerX + m.left,
34436                 y: centerY + m.top,
34437                 width: centerW - (m.left+m.right),
34438                 height: centerH - (m.top+m.bottom)
34439             };
34440             //if(this.hideOnLayout){
34441                 //center.el.setStyle("display", "block");
34442             //}
34443             center.updateBox(this.safeBox(centerBox));
34444         }
34445         this.el.repaint();
34446         this.fireEvent("layout", this);
34447     },
34448
34449     // private
34450     safeBox : function(box){
34451         box.width = Math.max(0, box.width);
34452         box.height = Math.max(0, box.height);
34453         return box;
34454     },
34455
34456     /**
34457      * Adds a ContentPanel (or subclass) to this layout.
34458      * @param {String} target The target region key (north, south, east, west or center).
34459      * @param {Roo.ContentPanel} panel The panel to add
34460      * @return {Roo.ContentPanel} The added panel
34461      */
34462     add : function(target, panel){
34463          
34464         target = target.toLowerCase();
34465         return this.regions[target].add(panel);
34466     },
34467
34468     /**
34469      * Remove a ContentPanel (or subclass) to this layout.
34470      * @param {String} target The target region key (north, south, east, west or center).
34471      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34472      * @return {Roo.ContentPanel} The removed panel
34473      */
34474     remove : function(target, panel){
34475         target = target.toLowerCase();
34476         return this.regions[target].remove(panel);
34477     },
34478
34479     /**
34480      * Searches all regions for a panel with the specified id
34481      * @param {String} panelId
34482      * @return {Roo.ContentPanel} The panel or null if it wasn't found
34483      */
34484     findPanel : function(panelId){
34485         var rs = this.regions;
34486         for(var target in rs){
34487             if(typeof rs[target] != "function"){
34488                 var p = rs[target].getPanel(panelId);
34489                 if(p){
34490                     return p;
34491                 }
34492             }
34493         }
34494         return null;
34495     },
34496
34497     /**
34498      * Searches all regions for a panel with the specified id and activates (shows) it.
34499      * @param {String/ContentPanel} panelId The panels id or the panel itself
34500      * @return {Roo.ContentPanel} The shown panel or null
34501      */
34502     showPanel : function(panelId) {
34503       var rs = this.regions;
34504       for(var target in rs){
34505          var r = rs[target];
34506          if(typeof r != "function"){
34507             if(r.hasPanel(panelId)){
34508                return r.showPanel(panelId);
34509             }
34510          }
34511       }
34512       return null;
34513    },
34514
34515    /**
34516      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34517      * @param {Roo.state.Provider} provider (optional) An alternate state provider
34518      */
34519    /*
34520     restoreState : function(provider){
34521         if(!provider){
34522             provider = Roo.state.Manager;
34523         }
34524         var sm = new Roo.LayoutStateManager();
34525         sm.init(this, provider);
34526     },
34527 */
34528  
34529  
34530     /**
34531      * Adds a xtype elements to the layout.
34532      * <pre><code>
34533
34534 layout.addxtype({
34535        xtype : 'ContentPanel',
34536        region: 'west',
34537        items: [ .... ]
34538    }
34539 );
34540
34541 layout.addxtype({
34542         xtype : 'NestedLayoutPanel',
34543         region: 'west',
34544         layout: {
34545            center: { },
34546            west: { }   
34547         },
34548         items : [ ... list of content panels or nested layout panels.. ]
34549    }
34550 );
34551 </code></pre>
34552      * @param {Object} cfg Xtype definition of item to add.
34553      */
34554     addxtype : function(cfg)
34555     {
34556         // basically accepts a pannel...
34557         // can accept a layout region..!?!?
34558         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34559         
34560         
34561         // theory?  children can only be panels??
34562         
34563         //if (!cfg.xtype.match(/Panel$/)) {
34564         //    return false;
34565         //}
34566         var ret = false;
34567         
34568         if (typeof(cfg.region) == 'undefined') {
34569             Roo.log("Failed to add Panel, region was not set");
34570             Roo.log(cfg);
34571             return false;
34572         }
34573         var region = cfg.region;
34574         delete cfg.region;
34575         
34576           
34577         var xitems = [];
34578         if (cfg.items) {
34579             xitems = cfg.items;
34580             delete cfg.items;
34581         }
34582         var nb = false;
34583         
34584         switch(cfg.xtype) 
34585         {
34586             case 'Content':  // ContentPanel (el, cfg)
34587             case 'Scroll':  // ContentPanel (el, cfg)
34588             case 'View': 
34589                 cfg.autoCreate = true;
34590                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34591                 //} else {
34592                 //    var el = this.el.createChild();
34593                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34594                 //}
34595                 
34596                 this.add(region, ret);
34597                 break;
34598             
34599             /*
34600             case 'TreePanel': // our new panel!
34601                 cfg.el = this.el.createChild();
34602                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34603                 this.add(region, ret);
34604                 break;
34605             */
34606             
34607             case 'Nest': 
34608                 // create a new Layout (which is  a Border Layout...
34609                 
34610                 var clayout = cfg.layout;
34611                 clayout.el  = this.el.createChild();
34612                 clayout.items   = clayout.items  || [];
34613                 
34614                 delete cfg.layout;
34615                 
34616                 // replace this exitems with the clayout ones..
34617                 xitems = clayout.items;
34618                  
34619                 // force background off if it's in center...
34620                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34621                     cfg.background = false;
34622                 }
34623                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
34624                 
34625                 
34626                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34627                 //console.log('adding nested layout panel '  + cfg.toSource());
34628                 this.add(region, ret);
34629                 nb = {}; /// find first...
34630                 break;
34631             
34632             case 'Grid':
34633                 
34634                 // needs grid and region
34635                 
34636                 //var el = this.getRegion(region).el.createChild();
34637                 /*
34638                  *var el = this.el.createChild();
34639                 // create the grid first...
34640                 cfg.grid.container = el;
34641                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34642                 */
34643                 
34644                 if (region == 'center' && this.active ) {
34645                     cfg.background = false;
34646                 }
34647                 
34648                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34649                 
34650                 this.add(region, ret);
34651                 /*
34652                 if (cfg.background) {
34653                     // render grid on panel activation (if panel background)
34654                     ret.on('activate', function(gp) {
34655                         if (!gp.grid.rendered) {
34656                     //        gp.grid.render(el);
34657                         }
34658                     });
34659                 } else {
34660                   //  cfg.grid.render(el);
34661                 }
34662                 */
34663                 break;
34664            
34665            
34666             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34667                 // it was the old xcomponent building that caused this before.
34668                 // espeically if border is the top element in the tree.
34669                 ret = this;
34670                 break; 
34671                 
34672                     
34673                 
34674                 
34675                 
34676             default:
34677                 /*
34678                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34679                     
34680                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34681                     this.add(region, ret);
34682                 } else {
34683                 */
34684                     Roo.log(cfg);
34685                     throw "Can not add '" + cfg.xtype + "' to Border";
34686                     return null;
34687              
34688                                 
34689              
34690         }
34691         this.beginUpdate();
34692         // add children..
34693         var region = '';
34694         var abn = {};
34695         Roo.each(xitems, function(i)  {
34696             region = nb && i.region ? i.region : false;
34697             
34698             var add = ret.addxtype(i);
34699            
34700             if (region) {
34701                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34702                 if (!i.background) {
34703                     abn[region] = nb[region] ;
34704                 }
34705             }
34706             
34707         });
34708         this.endUpdate();
34709
34710         // make the last non-background panel active..
34711         //if (nb) { Roo.log(abn); }
34712         if (nb) {
34713             
34714             for(var r in abn) {
34715                 region = this.getRegion(r);
34716                 if (region) {
34717                     // tried using nb[r], but it does not work..
34718                      
34719                     region.showPanel(abn[r]);
34720                    
34721                 }
34722             }
34723         }
34724         return ret;
34725         
34726     },
34727     
34728     
34729 // private
34730     factory : function(cfg)
34731     {
34732         
34733         var validRegions = Roo.bootstrap.layout.Border.regions;
34734
34735         var target = cfg.region;
34736         cfg.mgr = this;
34737         
34738         var r = Roo.bootstrap.layout;
34739         Roo.log(target);
34740         switch(target){
34741             case "north":
34742                 return new r.North(cfg);
34743             case "south":
34744                 return new r.South(cfg);
34745             case "east":
34746                 return new r.East(cfg);
34747             case "west":
34748                 return new r.West(cfg);
34749             case "center":
34750                 return new r.Center(cfg);
34751         }
34752         throw 'Layout region "'+target+'" not supported.';
34753     }
34754     
34755     
34756 });
34757  /*
34758  * Based on:
34759  * Ext JS Library 1.1.1
34760  * Copyright(c) 2006-2007, Ext JS, LLC.
34761  *
34762  * Originally Released Under LGPL - original licence link has changed is not relivant.
34763  *
34764  * Fork - LGPL
34765  * <script type="text/javascript">
34766  */
34767  
34768 /**
34769  * @class Roo.bootstrap.layout.Basic
34770  * @extends Roo.util.Observable
34771  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34772  * and does not have a titlebar, tabs or any other features. All it does is size and position 
34773  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34774  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
34775  * @cfg {string}   region  the region that it inhabits..
34776  * @cfg {bool}   skipConfig skip config?
34777  * 
34778
34779  */
34780 Roo.bootstrap.layout.Basic = function(config){
34781     
34782     this.mgr = config.mgr;
34783     
34784     this.position = config.region;
34785     
34786     var skipConfig = config.skipConfig;
34787     
34788     this.events = {
34789         /**
34790          * @scope Roo.BasicLayoutRegion
34791          */
34792         
34793         /**
34794          * @event beforeremove
34795          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34796          * @param {Roo.LayoutRegion} this
34797          * @param {Roo.ContentPanel} panel The panel
34798          * @param {Object} e The cancel event object
34799          */
34800         "beforeremove" : true,
34801         /**
34802          * @event invalidated
34803          * Fires when the layout for this region is changed.
34804          * @param {Roo.LayoutRegion} this
34805          */
34806         "invalidated" : true,
34807         /**
34808          * @event visibilitychange
34809          * Fires when this region is shown or hidden 
34810          * @param {Roo.LayoutRegion} this
34811          * @param {Boolean} visibility true or false
34812          */
34813         "visibilitychange" : true,
34814         /**
34815          * @event paneladded
34816          * Fires when a panel is added. 
34817          * @param {Roo.LayoutRegion} this
34818          * @param {Roo.ContentPanel} panel The panel
34819          */
34820         "paneladded" : true,
34821         /**
34822          * @event panelremoved
34823          * Fires when a panel is removed. 
34824          * @param {Roo.LayoutRegion} this
34825          * @param {Roo.ContentPanel} panel The panel
34826          */
34827         "panelremoved" : true,
34828         /**
34829          * @event beforecollapse
34830          * Fires when this region before collapse.
34831          * @param {Roo.LayoutRegion} this
34832          */
34833         "beforecollapse" : true,
34834         /**
34835          * @event collapsed
34836          * Fires when this region is collapsed.
34837          * @param {Roo.LayoutRegion} this
34838          */
34839         "collapsed" : true,
34840         /**
34841          * @event expanded
34842          * Fires when this region is expanded.
34843          * @param {Roo.LayoutRegion} this
34844          */
34845         "expanded" : true,
34846         /**
34847          * @event slideshow
34848          * Fires when this region is slid into view.
34849          * @param {Roo.LayoutRegion} this
34850          */
34851         "slideshow" : true,
34852         /**
34853          * @event slidehide
34854          * Fires when this region slides out of view. 
34855          * @param {Roo.LayoutRegion} this
34856          */
34857         "slidehide" : true,
34858         /**
34859          * @event panelactivated
34860          * Fires when a panel is activated. 
34861          * @param {Roo.LayoutRegion} this
34862          * @param {Roo.ContentPanel} panel The activated panel
34863          */
34864         "panelactivated" : true,
34865         /**
34866          * @event resized
34867          * Fires when the user resizes this region. 
34868          * @param {Roo.LayoutRegion} this
34869          * @param {Number} newSize The new size (width for east/west, height for north/south)
34870          */
34871         "resized" : true
34872     };
34873     /** A collection of panels in this region. @type Roo.util.MixedCollection */
34874     this.panels = new Roo.util.MixedCollection();
34875     this.panels.getKey = this.getPanelId.createDelegate(this);
34876     this.box = null;
34877     this.activePanel = null;
34878     // ensure listeners are added...
34879     
34880     if (config.listeners || config.events) {
34881         Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34882             listeners : config.listeners || {},
34883             events : config.events || {}
34884         });
34885     }
34886     
34887     if(skipConfig !== true){
34888         this.applyConfig(config);
34889     }
34890 };
34891
34892 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34893 {
34894     getPanelId : function(p){
34895         return p.getId();
34896     },
34897     
34898     applyConfig : function(config){
34899         this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34900         this.config = config;
34901         
34902     },
34903     
34904     /**
34905      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
34906      * the width, for horizontal (north, south) the height.
34907      * @param {Number} newSize The new width or height
34908      */
34909     resizeTo : function(newSize){
34910         var el = this.el ? this.el :
34911                  (this.activePanel ? this.activePanel.getEl() : null);
34912         if(el){
34913             switch(this.position){
34914                 case "east":
34915                 case "west":
34916                     el.setWidth(newSize);
34917                     this.fireEvent("resized", this, newSize);
34918                 break;
34919                 case "north":
34920                 case "south":
34921                     el.setHeight(newSize);
34922                     this.fireEvent("resized", this, newSize);
34923                 break;                
34924             }
34925         }
34926     },
34927     
34928     getBox : function(){
34929         return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34930     },
34931     
34932     getMargins : function(){
34933         return this.margins;
34934     },
34935     
34936     updateBox : function(box){
34937         this.box = box;
34938         var el = this.activePanel.getEl();
34939         el.dom.style.left = box.x + "px";
34940         el.dom.style.top = box.y + "px";
34941         this.activePanel.setSize(box.width, box.height);
34942     },
34943     
34944     /**
34945      * Returns the container element for this region.
34946      * @return {Roo.Element}
34947      */
34948     getEl : function(){
34949         return this.activePanel;
34950     },
34951     
34952     /**
34953      * Returns true if this region is currently visible.
34954      * @return {Boolean}
34955      */
34956     isVisible : function(){
34957         return this.activePanel ? true : false;
34958     },
34959     
34960     setActivePanel : function(panel){
34961         panel = this.getPanel(panel);
34962         if(this.activePanel && this.activePanel != panel){
34963             this.activePanel.setActiveState(false);
34964             this.activePanel.getEl().setLeftTop(-10000,-10000);
34965         }
34966         this.activePanel = panel;
34967         panel.setActiveState(true);
34968         if(this.box){
34969             panel.setSize(this.box.width, this.box.height);
34970         }
34971         this.fireEvent("panelactivated", this, panel);
34972         this.fireEvent("invalidated");
34973     },
34974     
34975     /**
34976      * Show the specified panel.
34977      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34978      * @return {Roo.ContentPanel} The shown panel or null
34979      */
34980     showPanel : function(panel){
34981         panel = this.getPanel(panel);
34982         if(panel){
34983             this.setActivePanel(panel);
34984         }
34985         return panel;
34986     },
34987     
34988     /**
34989      * Get the active panel for this region.
34990      * @return {Roo.ContentPanel} The active panel or null
34991      */
34992     getActivePanel : function(){
34993         return this.activePanel;
34994     },
34995     
34996     /**
34997      * Add the passed ContentPanel(s)
34998      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34999      * @return {Roo.ContentPanel} The panel added (if only one was added)
35000      */
35001     add : function(panel){
35002         if(arguments.length > 1){
35003             for(var i = 0, len = arguments.length; i < len; i++) {
35004                 this.add(arguments[i]);
35005             }
35006             return null;
35007         }
35008         if(this.hasPanel(panel)){
35009             this.showPanel(panel);
35010             return panel;
35011         }
35012         var el = panel.getEl();
35013         if(el.dom.parentNode != this.mgr.el.dom){
35014             this.mgr.el.dom.appendChild(el.dom);
35015         }
35016         if(panel.setRegion){
35017             panel.setRegion(this);
35018         }
35019         this.panels.add(panel);
35020         el.setStyle("position", "absolute");
35021         if(!panel.background){
35022             this.setActivePanel(panel);
35023             if(this.config.initialSize && this.panels.getCount()==1){
35024                 this.resizeTo(this.config.initialSize);
35025             }
35026         }
35027         this.fireEvent("paneladded", this, panel);
35028         return panel;
35029     },
35030     
35031     /**
35032      * Returns true if the panel is in this region.
35033      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35034      * @return {Boolean}
35035      */
35036     hasPanel : function(panel){
35037         if(typeof panel == "object"){ // must be panel obj
35038             panel = panel.getId();
35039         }
35040         return this.getPanel(panel) ? true : false;
35041     },
35042     
35043     /**
35044      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35045      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35046      * @param {Boolean} preservePanel Overrides the config preservePanel option
35047      * @return {Roo.ContentPanel} The panel that was removed
35048      */
35049     remove : function(panel, preservePanel){
35050         panel = this.getPanel(panel);
35051         if(!panel){
35052             return null;
35053         }
35054         var e = {};
35055         this.fireEvent("beforeremove", this, panel, e);
35056         if(e.cancel === true){
35057             return null;
35058         }
35059         var panelId = panel.getId();
35060         this.panels.removeKey(panelId);
35061         return panel;
35062     },
35063     
35064     /**
35065      * Returns the panel specified or null if it's not in this region.
35066      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35067      * @return {Roo.ContentPanel}
35068      */
35069     getPanel : function(id){
35070         if(typeof id == "object"){ // must be panel obj
35071             return id;
35072         }
35073         return this.panels.get(id);
35074     },
35075     
35076     /**
35077      * Returns this regions position (north/south/east/west/center).
35078      * @return {String} 
35079      */
35080     getPosition: function(){
35081         return this.position;    
35082     }
35083 });/*
35084  * Based on:
35085  * Ext JS Library 1.1.1
35086  * Copyright(c) 2006-2007, Ext JS, LLC.
35087  *
35088  * Originally Released Under LGPL - original licence link has changed is not relivant.
35089  *
35090  * Fork - LGPL
35091  * <script type="text/javascript">
35092  */
35093  
35094 /**
35095  * @class Roo.bootstrap.layout.Region
35096  * @extends Roo.bootstrap.layout.Basic
35097  * This class represents a region in a layout manager.
35098  
35099  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35100  * @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})
35101  * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
35102  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
35103  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
35104  * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
35105  * @cfg {String}    title           The title for the region (overrides panel titles)
35106  * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
35107  * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35108  * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
35109  * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35110  * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
35111  * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35112  *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
35113  * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
35114  * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
35115  * @cfg {String}    overflow       (hidden|visible) if you have menus in the region, then you need to set this to visible.
35116
35117  * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
35118  * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
35119  * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
35120  * @cfg {Number}    width           For East/West panels
35121  * @cfg {Number}    height          For North/South panels
35122  * @cfg {Boolean}   split           To show the splitter
35123  * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
35124  * 
35125  * @cfg {string}   cls             Extra CSS classes to add to region
35126  * 
35127  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35128  * @cfg {string}   region  the region that it inhabits..
35129  *
35130
35131  * @xxxcfg {Boolean}   collapsible     DISABLED False to disable collapsing (defaults to true)
35132  * @xxxcfg {Boolean}   collapsed       DISABLED True to set the initial display to collapsed (defaults to false)
35133
35134  * @xxxcfg {String}    collapsedTitle  DISABLED Optional string message to display in the collapsed block of a north or south region
35135  * @xxxxcfg {Boolean}   floatable       DISABLED False to disable floating (defaults to true)
35136  * @xxxxcfg {Boolean}   showPin         True to show a pin button NOT SUPPORTED YET
35137  */
35138 Roo.bootstrap.layout.Region = function(config)
35139 {
35140     this.applyConfig(config);
35141
35142     var mgr = config.mgr;
35143     var pos = config.region;
35144     config.skipConfig = true;
35145     Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35146     
35147     if (mgr.el) {
35148         this.onRender(mgr.el);   
35149     }
35150      
35151     this.visible = true;
35152     this.collapsed = false;
35153     this.unrendered_panels = [];
35154 };
35155
35156 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35157
35158     position: '', // set by wrapper (eg. north/south etc..)
35159     unrendered_panels : null,  // unrendered panels.
35160     createBody : function(){
35161         /** This region's body element 
35162         * @type Roo.Element */
35163         this.bodyEl = this.el.createChild({
35164                 tag: "div",
35165                 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35166         });
35167     },
35168
35169     onRender: function(ctr, pos)
35170     {
35171         var dh = Roo.DomHelper;
35172         /** This region's container element 
35173         * @type Roo.Element */
35174         this.el = dh.append(ctr.dom, {
35175                 tag: "div",
35176                 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35177             }, true);
35178         /** This region's title element 
35179         * @type Roo.Element */
35180     
35181         this.titleEl = dh.append(this.el.dom,
35182             {
35183                     tag: "div",
35184                     unselectable: "on",
35185                     cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35186                     children:[
35187                         {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
35188                         {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35189                     ]}, true);
35190         
35191         this.titleEl.enableDisplayMode();
35192         /** This region's title text element 
35193         * @type HTMLElement */
35194         this.titleTextEl = this.titleEl.dom.firstChild;
35195         this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35196         /*
35197         this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35198         this.closeBtn.enableDisplayMode();
35199         this.closeBtn.on("click", this.closeClicked, this);
35200         this.closeBtn.hide();
35201     */
35202         this.createBody(this.config);
35203         if(this.config.hideWhenEmpty){
35204             this.hide();
35205             this.on("paneladded", this.validateVisibility, this);
35206             this.on("panelremoved", this.validateVisibility, this);
35207         }
35208         if(this.autoScroll){
35209             this.bodyEl.setStyle("overflow", "auto");
35210         }else{
35211             this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35212         }
35213         //if(c.titlebar !== false){
35214             if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35215                 this.titleEl.hide();
35216             }else{
35217                 this.titleEl.show();
35218                 if(this.config.title){
35219                     this.titleTextEl.innerHTML = this.config.title;
35220                 }
35221             }
35222         //}
35223         if(this.config.collapsed){
35224             this.collapse(true);
35225         }
35226         if(this.config.hidden){
35227             this.hide();
35228         }
35229         
35230         if (this.unrendered_panels && this.unrendered_panels.length) {
35231             for (var i =0;i< this.unrendered_panels.length; i++) {
35232                 this.add(this.unrendered_panels[i]);
35233             }
35234             this.unrendered_panels = null;
35235             
35236         }
35237         
35238     },
35239     
35240     applyConfig : function(c)
35241     {
35242         /*
35243          *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35244             var dh = Roo.DomHelper;
35245             if(c.titlebar !== false){
35246                 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35247                 this.collapseBtn.on("click", this.collapse, this);
35248                 this.collapseBtn.enableDisplayMode();
35249                 /*
35250                 if(c.showPin === true || this.showPin){
35251                     this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35252                     this.stickBtn.enableDisplayMode();
35253                     this.stickBtn.on("click", this.expand, this);
35254                     this.stickBtn.hide();
35255                 }
35256                 
35257             }
35258             */
35259             /** This region's collapsed element
35260             * @type Roo.Element */
35261             /*
35262              *
35263             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35264                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35265             ]}, true);
35266             
35267             if(c.floatable !== false){
35268                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35269                this.collapsedEl.on("click", this.collapseClick, this);
35270             }
35271
35272             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35273                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35274                    id: "message", unselectable: "on", style:{"float":"left"}});
35275                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35276              }
35277             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35278             this.expandBtn.on("click", this.expand, this);
35279             
35280         }
35281         
35282         if(this.collapseBtn){
35283             this.collapseBtn.setVisible(c.collapsible == true);
35284         }
35285         
35286         this.cmargins = c.cmargins || this.cmargins ||
35287                          (this.position == "west" || this.position == "east" ?
35288                              {top: 0, left: 2, right:2, bottom: 0} :
35289                              {top: 2, left: 0, right:0, bottom: 2});
35290         */
35291         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35292         
35293         
35294         this.bottomTabs = c.tabPosition != "top";
35295         
35296         this.autoScroll = c.autoScroll || false;
35297         
35298         
35299        
35300         
35301         this.duration = c.duration || .30;
35302         this.slideDuration = c.slideDuration || .45;
35303         this.config = c;
35304        
35305     },
35306     /**
35307      * Returns true if this region is currently visible.
35308      * @return {Boolean}
35309      */
35310     isVisible : function(){
35311         return this.visible;
35312     },
35313
35314     /**
35315      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35316      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
35317      */
35318     //setCollapsedTitle : function(title){
35319     //    title = title || "&#160;";
35320      //   if(this.collapsedTitleTextEl){
35321       //      this.collapsedTitleTextEl.innerHTML = title;
35322        // }
35323     //},
35324
35325     getBox : function(){
35326         var b;
35327       //  if(!this.collapsed){
35328             b = this.el.getBox(false, true);
35329        // }else{
35330           //  b = this.collapsedEl.getBox(false, true);
35331         //}
35332         return b;
35333     },
35334
35335     getMargins : function(){
35336         return this.margins;
35337         //return this.collapsed ? this.cmargins : this.margins;
35338     },
35339 /*
35340     highlight : function(){
35341         this.el.addClass("x-layout-panel-dragover");
35342     },
35343
35344     unhighlight : function(){
35345         this.el.removeClass("x-layout-panel-dragover");
35346     },
35347 */
35348     updateBox : function(box)
35349     {
35350         if (!this.bodyEl) {
35351             return; // not rendered yet..
35352         }
35353         
35354         this.box = box;
35355         if(!this.collapsed){
35356             this.el.dom.style.left = box.x + "px";
35357             this.el.dom.style.top = box.y + "px";
35358             this.updateBody(box.width, box.height);
35359         }else{
35360             this.collapsedEl.dom.style.left = box.x + "px";
35361             this.collapsedEl.dom.style.top = box.y + "px";
35362             this.collapsedEl.setSize(box.width, box.height);
35363         }
35364         if(this.tabs){
35365             this.tabs.autoSizeTabs();
35366         }
35367     },
35368
35369     updateBody : function(w, h)
35370     {
35371         if(w !== null){
35372             this.el.setWidth(w);
35373             w -= this.el.getBorderWidth("rl");
35374             if(this.config.adjustments){
35375                 w += this.config.adjustments[0];
35376             }
35377         }
35378         if(h !== null && h > 0){
35379             this.el.setHeight(h);
35380             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35381             h -= this.el.getBorderWidth("tb");
35382             if(this.config.adjustments){
35383                 h += this.config.adjustments[1];
35384             }
35385             this.bodyEl.setHeight(h);
35386             if(this.tabs){
35387                 h = this.tabs.syncHeight(h);
35388             }
35389         }
35390         if(this.panelSize){
35391             w = w !== null ? w : this.panelSize.width;
35392             h = h !== null ? h : this.panelSize.height;
35393         }
35394         if(this.activePanel){
35395             var el = this.activePanel.getEl();
35396             w = w !== null ? w : el.getWidth();
35397             h = h !== null ? h : el.getHeight();
35398             this.panelSize = {width: w, height: h};
35399             this.activePanel.setSize(w, h);
35400         }
35401         if(Roo.isIE && this.tabs){
35402             this.tabs.el.repaint();
35403         }
35404     },
35405
35406     /**
35407      * Returns the container element for this region.
35408      * @return {Roo.Element}
35409      */
35410     getEl : function(){
35411         return this.el;
35412     },
35413
35414     /**
35415      * Hides this region.
35416      */
35417     hide : function(){
35418         //if(!this.collapsed){
35419             this.el.dom.style.left = "-2000px";
35420             this.el.hide();
35421         //}else{
35422          //   this.collapsedEl.dom.style.left = "-2000px";
35423          //   this.collapsedEl.hide();
35424        // }
35425         this.visible = false;
35426         this.fireEvent("visibilitychange", this, false);
35427     },
35428
35429     /**
35430      * Shows this region if it was previously hidden.
35431      */
35432     show : function(){
35433         //if(!this.collapsed){
35434             this.el.show();
35435         //}else{
35436         //    this.collapsedEl.show();
35437        // }
35438         this.visible = true;
35439         this.fireEvent("visibilitychange", this, true);
35440     },
35441 /*
35442     closeClicked : function(){
35443         if(this.activePanel){
35444             this.remove(this.activePanel);
35445         }
35446     },
35447
35448     collapseClick : function(e){
35449         if(this.isSlid){
35450            e.stopPropagation();
35451            this.slideIn();
35452         }else{
35453            e.stopPropagation();
35454            this.slideOut();
35455         }
35456     },
35457 */
35458     /**
35459      * Collapses this region.
35460      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35461      */
35462     /*
35463     collapse : function(skipAnim, skipCheck = false){
35464         if(this.collapsed) {
35465             return;
35466         }
35467         
35468         if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35469             
35470             this.collapsed = true;
35471             if(this.split){
35472                 this.split.el.hide();
35473             }
35474             if(this.config.animate && skipAnim !== true){
35475                 this.fireEvent("invalidated", this);
35476                 this.animateCollapse();
35477             }else{
35478                 this.el.setLocation(-20000,-20000);
35479                 this.el.hide();
35480                 this.collapsedEl.show();
35481                 this.fireEvent("collapsed", this);
35482                 this.fireEvent("invalidated", this);
35483             }
35484         }
35485         
35486     },
35487 */
35488     animateCollapse : function(){
35489         // overridden
35490     },
35491
35492     /**
35493      * Expands this region if it was previously collapsed.
35494      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35495      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35496      */
35497     /*
35498     expand : function(e, skipAnim){
35499         if(e) {
35500             e.stopPropagation();
35501         }
35502         if(!this.collapsed || this.el.hasActiveFx()) {
35503             return;
35504         }
35505         if(this.isSlid){
35506             this.afterSlideIn();
35507             skipAnim = true;
35508         }
35509         this.collapsed = false;
35510         if(this.config.animate && skipAnim !== true){
35511             this.animateExpand();
35512         }else{
35513             this.el.show();
35514             if(this.split){
35515                 this.split.el.show();
35516             }
35517             this.collapsedEl.setLocation(-2000,-2000);
35518             this.collapsedEl.hide();
35519             this.fireEvent("invalidated", this);
35520             this.fireEvent("expanded", this);
35521         }
35522     },
35523 */
35524     animateExpand : function(){
35525         // overridden
35526     },
35527
35528     initTabs : function()
35529     {
35530         //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35531         
35532         var ts = new Roo.bootstrap.panel.Tabs({
35533                 el: this.bodyEl.dom,
35534                 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35535                 disableTooltips: this.config.disableTabTips,
35536                 toolbar : this.config.toolbar
35537             });
35538         
35539         if(this.config.hideTabs){
35540             ts.stripWrap.setDisplayed(false);
35541         }
35542         this.tabs = ts;
35543         ts.resizeTabs = this.config.resizeTabs === true;
35544         ts.minTabWidth = this.config.minTabWidth || 40;
35545         ts.maxTabWidth = this.config.maxTabWidth || 250;
35546         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35547         ts.monitorResize = false;
35548         //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35549         ts.bodyEl.addClass('roo-layout-tabs-body');
35550         this.panels.each(this.initPanelAsTab, this);
35551     },
35552
35553     initPanelAsTab : function(panel){
35554         var ti = this.tabs.addTab(
35555             panel.getEl().id,
35556             panel.getTitle(),
35557             null,
35558             this.config.closeOnTab && panel.isClosable(),
35559             panel.tpl
35560         );
35561         if(panel.tabTip !== undefined){
35562             ti.setTooltip(panel.tabTip);
35563         }
35564         ti.on("activate", function(){
35565               this.setActivePanel(panel);
35566         }, this);
35567         
35568         if(this.config.closeOnTab){
35569             ti.on("beforeclose", function(t, e){
35570                 e.cancel = true;
35571                 this.remove(panel);
35572             }, this);
35573         }
35574         
35575         panel.tabItem = ti;
35576         
35577         return ti;
35578     },
35579
35580     updatePanelTitle : function(panel, title)
35581     {
35582         if(this.activePanel == panel){
35583             this.updateTitle(title);
35584         }
35585         if(this.tabs){
35586             var ti = this.tabs.getTab(panel.getEl().id);
35587             ti.setText(title);
35588             if(panel.tabTip !== undefined){
35589                 ti.setTooltip(panel.tabTip);
35590             }
35591         }
35592     },
35593
35594     updateTitle : function(title){
35595         if(this.titleTextEl && !this.config.title){
35596             this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
35597         }
35598     },
35599
35600     setActivePanel : function(panel)
35601     {
35602         panel = this.getPanel(panel);
35603         if(this.activePanel && this.activePanel != panel){
35604             if(this.activePanel.setActiveState(false) === false){
35605                 return;
35606             }
35607         }
35608         this.activePanel = panel;
35609         panel.setActiveState(true);
35610         if(this.panelSize){
35611             panel.setSize(this.panelSize.width, this.panelSize.height);
35612         }
35613         if(this.closeBtn){
35614             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35615         }
35616         this.updateTitle(panel.getTitle());
35617         if(this.tabs){
35618             this.fireEvent("invalidated", this);
35619         }
35620         this.fireEvent("panelactivated", this, panel);
35621     },
35622
35623     /**
35624      * Shows the specified panel.
35625      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35626      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35627      */
35628     showPanel : function(panel)
35629     {
35630         panel = this.getPanel(panel);
35631         if(panel){
35632             if(this.tabs){
35633                 var tab = this.tabs.getTab(panel.getEl().id);
35634                 if(tab.isHidden()){
35635                     this.tabs.unhideTab(tab.id);
35636                 }
35637                 tab.activate();
35638             }else{
35639                 this.setActivePanel(panel);
35640             }
35641         }
35642         return panel;
35643     },
35644
35645     /**
35646      * Get the active panel for this region.
35647      * @return {Roo.ContentPanel} The active panel or null
35648      */
35649     getActivePanel : function(){
35650         return this.activePanel;
35651     },
35652
35653     validateVisibility : function(){
35654         if(this.panels.getCount() < 1){
35655             this.updateTitle("&#160;");
35656             this.closeBtn.hide();
35657             this.hide();
35658         }else{
35659             if(!this.isVisible()){
35660                 this.show();
35661             }
35662         }
35663     },
35664
35665     /**
35666      * Adds the passed ContentPanel(s) to this region.
35667      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35668      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35669      */
35670     add : function(panel)
35671     {
35672         if(arguments.length > 1){
35673             for(var i = 0, len = arguments.length; i < len; i++) {
35674                 this.add(arguments[i]);
35675             }
35676             return null;
35677         }
35678         
35679         // if we have not been rendered yet, then we can not really do much of this..
35680         if (!this.bodyEl) {
35681             this.unrendered_panels.push(panel);
35682             return panel;
35683         }
35684         
35685         
35686         
35687         
35688         if(this.hasPanel(panel)){
35689             this.showPanel(panel);
35690             return panel;
35691         }
35692         panel.setRegion(this);
35693         this.panels.add(panel);
35694        /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35695             // sinle panel - no tab...?? would it not be better to render it with the tabs,
35696             // and hide them... ???
35697             this.bodyEl.dom.appendChild(panel.getEl().dom);
35698             if(panel.background !== true){
35699                 this.setActivePanel(panel);
35700             }
35701             this.fireEvent("paneladded", this, panel);
35702             return panel;
35703         }
35704         */
35705         if(!this.tabs){
35706             this.initTabs();
35707         }else{
35708             this.initPanelAsTab(panel);
35709         }
35710         
35711         
35712         if(panel.background !== true){
35713             this.tabs.activate(panel.getEl().id);
35714         }
35715         this.fireEvent("paneladded", this, panel);
35716         return panel;
35717     },
35718
35719     /**
35720      * Hides the tab for the specified panel.
35721      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35722      */
35723     hidePanel : function(panel){
35724         if(this.tabs && (panel = this.getPanel(panel))){
35725             this.tabs.hideTab(panel.getEl().id);
35726         }
35727     },
35728
35729     /**
35730      * Unhides the tab for a previously hidden panel.
35731      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35732      */
35733     unhidePanel : function(panel){
35734         if(this.tabs && (panel = this.getPanel(panel))){
35735             this.tabs.unhideTab(panel.getEl().id);
35736         }
35737     },
35738
35739     clearPanels : function(){
35740         while(this.panels.getCount() > 0){
35741              this.remove(this.panels.first());
35742         }
35743     },
35744
35745     /**
35746      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35747      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35748      * @param {Boolean} preservePanel Overrides the config preservePanel option
35749      * @return {Roo.ContentPanel} The panel that was removed
35750      */
35751     remove : function(panel, preservePanel)
35752     {
35753         panel = this.getPanel(panel);
35754         if(!panel){
35755             return null;
35756         }
35757         var e = {};
35758         this.fireEvent("beforeremove", this, panel, e);
35759         if(e.cancel === true){
35760             return null;
35761         }
35762         preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35763         var panelId = panel.getId();
35764         this.panels.removeKey(panelId);
35765         if(preservePanel){
35766             document.body.appendChild(panel.getEl().dom);
35767         }
35768         if(this.tabs){
35769             this.tabs.removeTab(panel.getEl().id);
35770         }else if (!preservePanel){
35771             this.bodyEl.dom.removeChild(panel.getEl().dom);
35772         }
35773         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35774             var p = this.panels.first();
35775             var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35776             tempEl.appendChild(p.getEl().dom);
35777             this.bodyEl.update("");
35778             this.bodyEl.dom.appendChild(p.getEl().dom);
35779             tempEl = null;
35780             this.updateTitle(p.getTitle());
35781             this.tabs = null;
35782             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35783             this.setActivePanel(p);
35784         }
35785         panel.setRegion(null);
35786         if(this.activePanel == panel){
35787             this.activePanel = null;
35788         }
35789         if(this.config.autoDestroy !== false && preservePanel !== true){
35790             try{panel.destroy();}catch(e){}
35791         }
35792         this.fireEvent("panelremoved", this, panel);
35793         return panel;
35794     },
35795
35796     /**
35797      * Returns the TabPanel component used by this region
35798      * @return {Roo.TabPanel}
35799      */
35800     getTabs : function(){
35801         return this.tabs;
35802     },
35803
35804     createTool : function(parentEl, className){
35805         var btn = Roo.DomHelper.append(parentEl, {
35806             tag: "div",
35807             cls: "x-layout-tools-button",
35808             children: [ {
35809                 tag: "div",
35810                 cls: "roo-layout-tools-button-inner " + className,
35811                 html: "&#160;"
35812             }]
35813         }, true);
35814         btn.addClassOnOver("roo-layout-tools-button-over");
35815         return btn;
35816     }
35817 });/*
35818  * Based on:
35819  * Ext JS Library 1.1.1
35820  * Copyright(c) 2006-2007, Ext JS, LLC.
35821  *
35822  * Originally Released Under LGPL - original licence link has changed is not relivant.
35823  *
35824  * Fork - LGPL
35825  * <script type="text/javascript">
35826  */
35827  
35828
35829
35830 /**
35831  * @class Roo.SplitLayoutRegion
35832  * @extends Roo.LayoutRegion
35833  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35834  */
35835 Roo.bootstrap.layout.Split = function(config){
35836     this.cursor = config.cursor;
35837     Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35838 };
35839
35840 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35841 {
35842     splitTip : "Drag to resize.",
35843     collapsibleSplitTip : "Drag to resize. Double click to hide.",
35844     useSplitTips : false,
35845
35846     applyConfig : function(config){
35847         Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35848     },
35849     
35850     onRender : function(ctr,pos) {
35851         
35852         Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35853         if(!this.config.split){
35854             return;
35855         }
35856         if(!this.split){
35857             
35858             var splitEl = Roo.DomHelper.append(ctr.dom,  {
35859                             tag: "div",
35860                             id: this.el.id + "-split",
35861                             cls: "roo-layout-split roo-layout-split-"+this.position,
35862                             html: "&#160;"
35863             });
35864             /** The SplitBar for this region 
35865             * @type Roo.SplitBar */
35866             // does not exist yet...
35867             Roo.log([this.position, this.orientation]);
35868             
35869             this.split = new Roo.bootstrap.SplitBar({
35870                 dragElement : splitEl,
35871                 resizingElement: this.el,
35872                 orientation : this.orientation
35873             });
35874             
35875             this.split.on("moved", this.onSplitMove, this);
35876             this.split.useShim = this.config.useShim === true;
35877             this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35878             if(this.useSplitTips){
35879                 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35880             }
35881             //if(config.collapsible){
35882             //    this.split.el.on("dblclick", this.collapse,  this);
35883             //}
35884         }
35885         if(typeof this.config.minSize != "undefined"){
35886             this.split.minSize = this.config.minSize;
35887         }
35888         if(typeof this.config.maxSize != "undefined"){
35889             this.split.maxSize = this.config.maxSize;
35890         }
35891         if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35892             this.hideSplitter();
35893         }
35894         
35895     },
35896
35897     getHMaxSize : function(){
35898          var cmax = this.config.maxSize || 10000;
35899          var center = this.mgr.getRegion("center");
35900          return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35901     },
35902
35903     getVMaxSize : function(){
35904          var cmax = this.config.maxSize || 10000;
35905          var center = this.mgr.getRegion("center");
35906          return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35907     },
35908
35909     onSplitMove : function(split, newSize){
35910         this.fireEvent("resized", this, newSize);
35911     },
35912     
35913     /** 
35914      * Returns the {@link Roo.SplitBar} for this region.
35915      * @return {Roo.SplitBar}
35916      */
35917     getSplitBar : function(){
35918         return this.split;
35919     },
35920     
35921     hide : function(){
35922         this.hideSplitter();
35923         Roo.bootstrap.layout.Split.superclass.hide.call(this);
35924     },
35925
35926     hideSplitter : function(){
35927         if(this.split){
35928             this.split.el.setLocation(-2000,-2000);
35929             this.split.el.hide();
35930         }
35931     },
35932
35933     show : function(){
35934         if(this.split){
35935             this.split.el.show();
35936         }
35937         Roo.bootstrap.layout.Split.superclass.show.call(this);
35938     },
35939     
35940     beforeSlide: function(){
35941         if(Roo.isGecko){// firefox overflow auto bug workaround
35942             this.bodyEl.clip();
35943             if(this.tabs) {
35944                 this.tabs.bodyEl.clip();
35945             }
35946             if(this.activePanel){
35947                 this.activePanel.getEl().clip();
35948                 
35949                 if(this.activePanel.beforeSlide){
35950                     this.activePanel.beforeSlide();
35951                 }
35952             }
35953         }
35954     },
35955     
35956     afterSlide : function(){
35957         if(Roo.isGecko){// firefox overflow auto bug workaround
35958             this.bodyEl.unclip();
35959             if(this.tabs) {
35960                 this.tabs.bodyEl.unclip();
35961             }
35962             if(this.activePanel){
35963                 this.activePanel.getEl().unclip();
35964                 if(this.activePanel.afterSlide){
35965                     this.activePanel.afterSlide();
35966                 }
35967             }
35968         }
35969     },
35970
35971     initAutoHide : function(){
35972         if(this.autoHide !== false){
35973             if(!this.autoHideHd){
35974                 var st = new Roo.util.DelayedTask(this.slideIn, this);
35975                 this.autoHideHd = {
35976                     "mouseout": function(e){
35977                         if(!e.within(this.el, true)){
35978                             st.delay(500);
35979                         }
35980                     },
35981                     "mouseover" : function(e){
35982                         st.cancel();
35983                     },
35984                     scope : this
35985                 };
35986             }
35987             this.el.on(this.autoHideHd);
35988         }
35989     },
35990
35991     clearAutoHide : function(){
35992         if(this.autoHide !== false){
35993             this.el.un("mouseout", this.autoHideHd.mouseout);
35994             this.el.un("mouseover", this.autoHideHd.mouseover);
35995         }
35996     },
35997
35998     clearMonitor : function(){
35999         Roo.get(document).un("click", this.slideInIf, this);
36000     },
36001
36002     // these names are backwards but not changed for compat
36003     slideOut : function(){
36004         if(this.isSlid || this.el.hasActiveFx()){
36005             return;
36006         }
36007         this.isSlid = true;
36008         if(this.collapseBtn){
36009             this.collapseBtn.hide();
36010         }
36011         this.closeBtnState = this.closeBtn.getStyle('display');
36012         this.closeBtn.hide();
36013         if(this.stickBtn){
36014             this.stickBtn.show();
36015         }
36016         this.el.show();
36017         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36018         this.beforeSlide();
36019         this.el.setStyle("z-index", 10001);
36020         this.el.slideIn(this.getSlideAnchor(), {
36021             callback: function(){
36022                 this.afterSlide();
36023                 this.initAutoHide();
36024                 Roo.get(document).on("click", this.slideInIf, this);
36025                 this.fireEvent("slideshow", this);
36026             },
36027             scope: this,
36028             block: true
36029         });
36030     },
36031
36032     afterSlideIn : function(){
36033         this.clearAutoHide();
36034         this.isSlid = false;
36035         this.clearMonitor();
36036         this.el.setStyle("z-index", "");
36037         if(this.collapseBtn){
36038             this.collapseBtn.show();
36039         }
36040         this.closeBtn.setStyle('display', this.closeBtnState);
36041         if(this.stickBtn){
36042             this.stickBtn.hide();
36043         }
36044         this.fireEvent("slidehide", this);
36045     },
36046
36047     slideIn : function(cb){
36048         if(!this.isSlid || this.el.hasActiveFx()){
36049             Roo.callback(cb);
36050             return;
36051         }
36052         this.isSlid = false;
36053         this.beforeSlide();
36054         this.el.slideOut(this.getSlideAnchor(), {
36055             callback: function(){
36056                 this.el.setLeftTop(-10000, -10000);
36057                 this.afterSlide();
36058                 this.afterSlideIn();
36059                 Roo.callback(cb);
36060             },
36061             scope: this,
36062             block: true
36063         });
36064     },
36065     
36066     slideInIf : function(e){
36067         if(!e.within(this.el)){
36068             this.slideIn();
36069         }
36070     },
36071
36072     animateCollapse : function(){
36073         this.beforeSlide();
36074         this.el.setStyle("z-index", 20000);
36075         var anchor = this.getSlideAnchor();
36076         this.el.slideOut(anchor, {
36077             callback : function(){
36078                 this.el.setStyle("z-index", "");
36079                 this.collapsedEl.slideIn(anchor, {duration:.3});
36080                 this.afterSlide();
36081                 this.el.setLocation(-10000,-10000);
36082                 this.el.hide();
36083                 this.fireEvent("collapsed", this);
36084             },
36085             scope: this,
36086             block: true
36087         });
36088     },
36089
36090     animateExpand : function(){
36091         this.beforeSlide();
36092         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36093         this.el.setStyle("z-index", 20000);
36094         this.collapsedEl.hide({
36095             duration:.1
36096         });
36097         this.el.slideIn(this.getSlideAnchor(), {
36098             callback : function(){
36099                 this.el.setStyle("z-index", "");
36100                 this.afterSlide();
36101                 if(this.split){
36102                     this.split.el.show();
36103                 }
36104                 this.fireEvent("invalidated", this);
36105                 this.fireEvent("expanded", this);
36106             },
36107             scope: this,
36108             block: true
36109         });
36110     },
36111
36112     anchors : {
36113         "west" : "left",
36114         "east" : "right",
36115         "north" : "top",
36116         "south" : "bottom"
36117     },
36118
36119     sanchors : {
36120         "west" : "l",
36121         "east" : "r",
36122         "north" : "t",
36123         "south" : "b"
36124     },
36125
36126     canchors : {
36127         "west" : "tl-tr",
36128         "east" : "tr-tl",
36129         "north" : "tl-bl",
36130         "south" : "bl-tl"
36131     },
36132
36133     getAnchor : function(){
36134         return this.anchors[this.position];
36135     },
36136
36137     getCollapseAnchor : function(){
36138         return this.canchors[this.position];
36139     },
36140
36141     getSlideAnchor : function(){
36142         return this.sanchors[this.position];
36143     },
36144
36145     getAlignAdj : function(){
36146         var cm = this.cmargins;
36147         switch(this.position){
36148             case "west":
36149                 return [0, 0];
36150             break;
36151             case "east":
36152                 return [0, 0];
36153             break;
36154             case "north":
36155                 return [0, 0];
36156             break;
36157             case "south":
36158                 return [0, 0];
36159             break;
36160         }
36161     },
36162
36163     getExpandAdj : function(){
36164         var c = this.collapsedEl, cm = this.cmargins;
36165         switch(this.position){
36166             case "west":
36167                 return [-(cm.right+c.getWidth()+cm.left), 0];
36168             break;
36169             case "east":
36170                 return [cm.right+c.getWidth()+cm.left, 0];
36171             break;
36172             case "north":
36173                 return [0, -(cm.top+cm.bottom+c.getHeight())];
36174             break;
36175             case "south":
36176                 return [0, cm.top+cm.bottom+c.getHeight()];
36177             break;
36178         }
36179     }
36180 });/*
36181  * Based on:
36182  * Ext JS Library 1.1.1
36183  * Copyright(c) 2006-2007, Ext JS, LLC.
36184  *
36185  * Originally Released Under LGPL - original licence link has changed is not relivant.
36186  *
36187  * Fork - LGPL
36188  * <script type="text/javascript">
36189  */
36190 /*
36191  * These classes are private internal classes
36192  */
36193 Roo.bootstrap.layout.Center = function(config){
36194     config.region = "center";
36195     Roo.bootstrap.layout.Region.call(this, config);
36196     this.visible = true;
36197     this.minWidth = config.minWidth || 20;
36198     this.minHeight = config.minHeight || 20;
36199 };
36200
36201 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36202     hide : function(){
36203         // center panel can't be hidden
36204     },
36205     
36206     show : function(){
36207         // center panel can't be hidden
36208     },
36209     
36210     getMinWidth: function(){
36211         return this.minWidth;
36212     },
36213     
36214     getMinHeight: function(){
36215         return this.minHeight;
36216     }
36217 });
36218
36219
36220
36221
36222  
36223
36224
36225
36226
36227
36228 Roo.bootstrap.layout.North = function(config)
36229 {
36230     config.region = 'north';
36231     config.cursor = 'n-resize';
36232     
36233     Roo.bootstrap.layout.Split.call(this, config);
36234     
36235     
36236     if(this.split){
36237         this.split.placement = Roo.bootstrap.SplitBar.TOP;
36238         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36239         this.split.el.addClass("roo-layout-split-v");
36240     }
36241     var size = config.initialSize || config.height;
36242     if(typeof size != "undefined"){
36243         this.el.setHeight(size);
36244     }
36245 };
36246 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36247 {
36248     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36249     
36250     
36251     
36252     getBox : function(){
36253         if(this.collapsed){
36254             return this.collapsedEl.getBox();
36255         }
36256         var box = this.el.getBox();
36257         if(this.split){
36258             box.height += this.split.el.getHeight();
36259         }
36260         return box;
36261     },
36262     
36263     updateBox : function(box){
36264         if(this.split && !this.collapsed){
36265             box.height -= this.split.el.getHeight();
36266             this.split.el.setLeft(box.x);
36267             this.split.el.setTop(box.y+box.height);
36268             this.split.el.setWidth(box.width);
36269         }
36270         if(this.collapsed){
36271             this.updateBody(box.width, null);
36272         }
36273         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36274     }
36275 });
36276
36277
36278
36279
36280
36281 Roo.bootstrap.layout.South = function(config){
36282     config.region = 'south';
36283     config.cursor = 's-resize';
36284     Roo.bootstrap.layout.Split.call(this, config);
36285     if(this.split){
36286         this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36287         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36288         this.split.el.addClass("roo-layout-split-v");
36289     }
36290     var size = config.initialSize || config.height;
36291     if(typeof size != "undefined"){
36292         this.el.setHeight(size);
36293     }
36294 };
36295
36296 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36297     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36298     getBox : function(){
36299         if(this.collapsed){
36300             return this.collapsedEl.getBox();
36301         }
36302         var box = this.el.getBox();
36303         if(this.split){
36304             var sh = this.split.el.getHeight();
36305             box.height += sh;
36306             box.y -= sh;
36307         }
36308         return box;
36309     },
36310     
36311     updateBox : function(box){
36312         if(this.split && !this.collapsed){
36313             var sh = this.split.el.getHeight();
36314             box.height -= sh;
36315             box.y += sh;
36316             this.split.el.setLeft(box.x);
36317             this.split.el.setTop(box.y-sh);
36318             this.split.el.setWidth(box.width);
36319         }
36320         if(this.collapsed){
36321             this.updateBody(box.width, null);
36322         }
36323         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36324     }
36325 });
36326
36327 Roo.bootstrap.layout.East = function(config){
36328     config.region = "east";
36329     config.cursor = "e-resize";
36330     Roo.bootstrap.layout.Split.call(this, config);
36331     if(this.split){
36332         this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36333         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36334         this.split.el.addClass("roo-layout-split-h");
36335     }
36336     var size = config.initialSize || config.width;
36337     if(typeof size != "undefined"){
36338         this.el.setWidth(size);
36339     }
36340 };
36341 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36342     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36343     getBox : function(){
36344         if(this.collapsed){
36345             return this.collapsedEl.getBox();
36346         }
36347         var box = this.el.getBox();
36348         if(this.split){
36349             var sw = this.split.el.getWidth();
36350             box.width += sw;
36351             box.x -= sw;
36352         }
36353         return box;
36354     },
36355
36356     updateBox : function(box){
36357         if(this.split && !this.collapsed){
36358             var sw = this.split.el.getWidth();
36359             box.width -= sw;
36360             this.split.el.setLeft(box.x);
36361             this.split.el.setTop(box.y);
36362             this.split.el.setHeight(box.height);
36363             box.x += sw;
36364         }
36365         if(this.collapsed){
36366             this.updateBody(null, box.height);
36367         }
36368         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36369     }
36370 });
36371
36372 Roo.bootstrap.layout.West = function(config){
36373     config.region = "west";
36374     config.cursor = "w-resize";
36375     
36376     Roo.bootstrap.layout.Split.call(this, config);
36377     if(this.split){
36378         this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36379         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36380         this.split.el.addClass("roo-layout-split-h");
36381     }
36382     
36383 };
36384 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36385     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36386     
36387     onRender: function(ctr, pos)
36388     {
36389         Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36390         var size = this.config.initialSize || this.config.width;
36391         if(typeof size != "undefined"){
36392             this.el.setWidth(size);
36393         }
36394     },
36395     
36396     getBox : function(){
36397         if(this.collapsed){
36398             return this.collapsedEl.getBox();
36399         }
36400         var box = this.el.getBox();
36401         if(this.split){
36402             box.width += this.split.el.getWidth();
36403         }
36404         return box;
36405     },
36406     
36407     updateBox : function(box){
36408         if(this.split && !this.collapsed){
36409             var sw = this.split.el.getWidth();
36410             box.width -= sw;
36411             this.split.el.setLeft(box.x+box.width);
36412             this.split.el.setTop(box.y);
36413             this.split.el.setHeight(box.height);
36414         }
36415         if(this.collapsed){
36416             this.updateBody(null, box.height);
36417         }
36418         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36419     }
36420 });
36421 Roo.namespace("Roo.bootstrap.panel");/*
36422  * Based on:
36423  * Ext JS Library 1.1.1
36424  * Copyright(c) 2006-2007, Ext JS, LLC.
36425  *
36426  * Originally Released Under LGPL - original licence link has changed is not relivant.
36427  *
36428  * Fork - LGPL
36429  * <script type="text/javascript">
36430  */
36431 /**
36432  * @class Roo.ContentPanel
36433  * @extends Roo.util.Observable
36434  * A basic ContentPanel element.
36435  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
36436  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
36437  * @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
36438  * @cfg {Boolean}   closable      True if the panel can be closed/removed
36439  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
36440  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36441  * @cfg {Toolbar}   toolbar       A toolbar for this panel
36442  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
36443  * @cfg {String} title          The title for this panel
36444  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36445  * @cfg {String} url            Calls {@link #setUrl} with this value
36446  * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36447  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
36448  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
36449  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
36450  * @cfg {Boolean} badges render the badges
36451
36452  * @constructor
36453  * Create a new ContentPanel.
36454  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36455  * @param {String/Object} config A string to set only the title or a config object
36456  * @param {String} content (optional) Set the HTML content for this panel
36457  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36458  */
36459 Roo.bootstrap.panel.Content = function( config){
36460     
36461     this.tpl = config.tpl || false;
36462     
36463     var el = config.el;
36464     var content = config.content;
36465
36466     if(config.autoCreate){ // xtype is available if this is called from factory
36467         el = Roo.id();
36468     }
36469     this.el = Roo.get(el);
36470     if(!this.el && config && config.autoCreate){
36471         if(typeof config.autoCreate == "object"){
36472             if(!config.autoCreate.id){
36473                 config.autoCreate.id = config.id||el;
36474             }
36475             this.el = Roo.DomHelper.append(document.body,
36476                         config.autoCreate, true);
36477         }else{
36478             var elcfg =  {   tag: "div",
36479                             cls: "roo-layout-inactive-content",
36480                             id: config.id||el
36481                             };
36482             if (config.html) {
36483                 elcfg.html = config.html;
36484                 
36485             }
36486                         
36487             this.el = Roo.DomHelper.append(document.body, elcfg , true);
36488         }
36489     } 
36490     this.closable = false;
36491     this.loaded = false;
36492     this.active = false;
36493    
36494       
36495     if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36496         
36497         this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36498         
36499         this.wrapEl = this.el; //this.el.wrap();
36500         var ti = [];
36501         if (config.toolbar.items) {
36502             ti = config.toolbar.items ;
36503             delete config.toolbar.items ;
36504         }
36505         
36506         var nitems = [];
36507         this.toolbar.render(this.wrapEl, 'before');
36508         for(var i =0;i < ti.length;i++) {
36509           //  Roo.log(['add child', items[i]]);
36510             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36511         }
36512         this.toolbar.items = nitems;
36513         this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36514         delete config.toolbar;
36515         
36516     }
36517     /*
36518     // xtype created footer. - not sure if will work as we normally have to render first..
36519     if (this.footer && !this.footer.el && this.footer.xtype) {
36520         if (!this.wrapEl) {
36521             this.wrapEl = this.el.wrap();
36522         }
36523     
36524         this.footer.container = this.wrapEl.createChild();
36525          
36526         this.footer = Roo.factory(this.footer, Roo);
36527         
36528     }
36529     */
36530     
36531      if(typeof config == "string"){
36532         this.title = config;
36533     }else{
36534         Roo.apply(this, config);
36535     }
36536     
36537     if(this.resizeEl){
36538         this.resizeEl = Roo.get(this.resizeEl, true);
36539     }else{
36540         this.resizeEl = this.el;
36541     }
36542     // handle view.xtype
36543     
36544  
36545     
36546     
36547     this.addEvents({
36548         /**
36549          * @event activate
36550          * Fires when this panel is activated. 
36551          * @param {Roo.ContentPanel} this
36552          */
36553         "activate" : true,
36554         /**
36555          * @event deactivate
36556          * Fires when this panel is activated. 
36557          * @param {Roo.ContentPanel} this
36558          */
36559         "deactivate" : true,
36560
36561         /**
36562          * @event resize
36563          * Fires when this panel is resized if fitToFrame is true.
36564          * @param {Roo.ContentPanel} this
36565          * @param {Number} width The width after any component adjustments
36566          * @param {Number} height The height after any component adjustments
36567          */
36568         "resize" : true,
36569         
36570          /**
36571          * @event render
36572          * Fires when this tab is created
36573          * @param {Roo.ContentPanel} this
36574          */
36575         "render" : true
36576         
36577         
36578         
36579     });
36580     
36581
36582     
36583     
36584     if(this.autoScroll){
36585         this.resizeEl.setStyle("overflow", "auto");
36586     } else {
36587         // fix randome scrolling
36588         //this.el.on('scroll', function() {
36589         //    Roo.log('fix random scolling');
36590         //    this.scrollTo('top',0); 
36591         //});
36592     }
36593     content = content || this.content;
36594     if(content){
36595         this.setContent(content);
36596     }
36597     if(config && config.url){
36598         this.setUrl(this.url, this.params, this.loadOnce);
36599     }
36600     
36601     
36602     
36603     Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36604     
36605     if (this.view && typeof(this.view.xtype) != 'undefined') {
36606         this.view.el = this.el.appendChild(document.createElement("div"));
36607         this.view = Roo.factory(this.view); 
36608         this.view.render  &&  this.view.render(false, '');  
36609     }
36610     
36611     
36612     this.fireEvent('render', this);
36613 };
36614
36615 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36616     
36617     tabTip : '',
36618     
36619     setRegion : function(region){
36620         this.region = region;
36621         this.setActiveClass(region && !this.background);
36622     },
36623     
36624     
36625     setActiveClass: function(state)
36626     {
36627         if(state){
36628            this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36629            this.el.setStyle('position','relative');
36630         }else{
36631            this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36632            this.el.setStyle('position', 'absolute');
36633         } 
36634     },
36635     
36636     /**
36637      * Returns the toolbar for this Panel if one was configured. 
36638      * @return {Roo.Toolbar} 
36639      */
36640     getToolbar : function(){
36641         return this.toolbar;
36642     },
36643     
36644     setActiveState : function(active)
36645     {
36646         this.active = active;
36647         this.setActiveClass(active);
36648         if(!active){
36649             if(this.fireEvent("deactivate", this) === false){
36650                 return false;
36651             }
36652             return true;
36653         }
36654         this.fireEvent("activate", this);
36655         return true;
36656     },
36657     /**
36658      * Updates this panel's element
36659      * @param {String} content The new content
36660      * @param {Boolean} loadScripts (optional) true to look for and process scripts
36661     */
36662     setContent : function(content, loadScripts){
36663         this.el.update(content, loadScripts);
36664     },
36665
36666     ignoreResize : function(w, h){
36667         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36668             return true;
36669         }else{
36670             this.lastSize = {width: w, height: h};
36671             return false;
36672         }
36673     },
36674     /**
36675      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36676      * @return {Roo.UpdateManager} The UpdateManager
36677      */
36678     getUpdateManager : function(){
36679         return this.el.getUpdateManager();
36680     },
36681      /**
36682      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36683      * @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:
36684 <pre><code>
36685 panel.load({
36686     url: "your-url.php",
36687     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36688     callback: yourFunction,
36689     scope: yourObject, //(optional scope)
36690     discardUrl: false,
36691     nocache: false,
36692     text: "Loading...",
36693     timeout: 30,
36694     scripts: false
36695 });
36696 </code></pre>
36697      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36698      * 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.
36699      * @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}
36700      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36701      * @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.
36702      * @return {Roo.ContentPanel} this
36703      */
36704     load : function(){
36705         var um = this.el.getUpdateManager();
36706         um.update.apply(um, arguments);
36707         return this;
36708     },
36709
36710
36711     /**
36712      * 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.
36713      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36714      * @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)
36715      * @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)
36716      * @return {Roo.UpdateManager} The UpdateManager
36717      */
36718     setUrl : function(url, params, loadOnce){
36719         if(this.refreshDelegate){
36720             this.removeListener("activate", this.refreshDelegate);
36721         }
36722         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36723         this.on("activate", this.refreshDelegate);
36724         return this.el.getUpdateManager();
36725     },
36726     
36727     _handleRefresh : function(url, params, loadOnce){
36728         if(!loadOnce || !this.loaded){
36729             var updater = this.el.getUpdateManager();
36730             updater.update(url, params, this._setLoaded.createDelegate(this));
36731         }
36732     },
36733     
36734     _setLoaded : function(){
36735         this.loaded = true;
36736     }, 
36737     
36738     /**
36739      * Returns this panel's id
36740      * @return {String} 
36741      */
36742     getId : function(){
36743         return this.el.id;
36744     },
36745     
36746     /** 
36747      * Returns this panel's element - used by regiosn to add.
36748      * @return {Roo.Element} 
36749      */
36750     getEl : function(){
36751         return this.wrapEl || this.el;
36752     },
36753     
36754    
36755     
36756     adjustForComponents : function(width, height)
36757     {
36758         //Roo.log('adjustForComponents ');
36759         if(this.resizeEl != this.el){
36760             width -= this.el.getFrameWidth('lr');
36761             height -= this.el.getFrameWidth('tb');
36762         }
36763         if(this.toolbar){
36764             var te = this.toolbar.getEl();
36765             te.setWidth(width);
36766             height -= te.getHeight();
36767         }
36768         if(this.footer){
36769             var te = this.footer.getEl();
36770             te.setWidth(width);
36771             height -= te.getHeight();
36772         }
36773         
36774         
36775         if(this.adjustments){
36776             width += this.adjustments[0];
36777             height += this.adjustments[1];
36778         }
36779         return {"width": width, "height": height};
36780     },
36781     
36782     setSize : function(width, height){
36783         if(this.fitToFrame && !this.ignoreResize(width, height)){
36784             if(this.fitContainer && this.resizeEl != this.el){
36785                 this.el.setSize(width, height);
36786             }
36787             var size = this.adjustForComponents(width, height);
36788             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36789             this.fireEvent('resize', this, size.width, size.height);
36790         }
36791     },
36792     
36793     /**
36794      * Returns this panel's title
36795      * @return {String} 
36796      */
36797     getTitle : function(){
36798         
36799         if (typeof(this.title) != 'object') {
36800             return this.title;
36801         }
36802         
36803         var t = '';
36804         for (var k in this.title) {
36805             if (!this.title.hasOwnProperty(k)) {
36806                 continue;
36807             }
36808             
36809             if (k.indexOf('-') >= 0) {
36810                 var s = k.split('-');
36811                 for (var i = 0; i<s.length; i++) {
36812                     t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36813                 }
36814             } else {
36815                 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36816             }
36817         }
36818         return t;
36819     },
36820     
36821     /**
36822      * Set this panel's title
36823      * @param {String} title
36824      */
36825     setTitle : function(title){
36826         this.title = title;
36827         if(this.region){
36828             this.region.updatePanelTitle(this, title);
36829         }
36830     },
36831     
36832     /**
36833      * Returns true is this panel was configured to be closable
36834      * @return {Boolean} 
36835      */
36836     isClosable : function(){
36837         return this.closable;
36838     },
36839     
36840     beforeSlide : function(){
36841         this.el.clip();
36842         this.resizeEl.clip();
36843     },
36844     
36845     afterSlide : function(){
36846         this.el.unclip();
36847         this.resizeEl.unclip();
36848     },
36849     
36850     /**
36851      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
36852      *   Will fail silently if the {@link #setUrl} method has not been called.
36853      *   This does not activate the panel, just updates its content.
36854      */
36855     refresh : function(){
36856         if(this.refreshDelegate){
36857            this.loaded = false;
36858            this.refreshDelegate();
36859         }
36860     },
36861     
36862     /**
36863      * Destroys this panel
36864      */
36865     destroy : function(){
36866         this.el.removeAllListeners();
36867         var tempEl = document.createElement("span");
36868         tempEl.appendChild(this.el.dom);
36869         tempEl.innerHTML = "";
36870         this.el.remove();
36871         this.el = null;
36872     },
36873     
36874     /**
36875      * form - if the content panel contains a form - this is a reference to it.
36876      * @type {Roo.form.Form}
36877      */
36878     form : false,
36879     /**
36880      * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36881      *    This contains a reference to it.
36882      * @type {Roo.View}
36883      */
36884     view : false,
36885     
36886       /**
36887      * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36888      * <pre><code>
36889
36890 layout.addxtype({
36891        xtype : 'Form',
36892        items: [ .... ]
36893    }
36894 );
36895
36896 </code></pre>
36897      * @param {Object} cfg Xtype definition of item to add.
36898      */
36899     
36900     
36901     getChildContainer: function () {
36902         return this.getEl();
36903     }
36904     
36905     
36906     /*
36907         var  ret = new Roo.factory(cfg);
36908         return ret;
36909         
36910         
36911         // add form..
36912         if (cfg.xtype.match(/^Form$/)) {
36913             
36914             var el;
36915             //if (this.footer) {
36916             //    el = this.footer.container.insertSibling(false, 'before');
36917             //} else {
36918                 el = this.el.createChild();
36919             //}
36920
36921             this.form = new  Roo.form.Form(cfg);
36922             
36923             
36924             if ( this.form.allItems.length) {
36925                 this.form.render(el.dom);
36926             }
36927             return this.form;
36928         }
36929         // should only have one of theses..
36930         if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36931             // views.. should not be just added - used named prop 'view''
36932             
36933             cfg.el = this.el.appendChild(document.createElement("div"));
36934             // factory?
36935             
36936             var ret = new Roo.factory(cfg);
36937              
36938              ret.render && ret.render(false, ''); // render blank..
36939             this.view = ret;
36940             return ret;
36941         }
36942         return false;
36943     }
36944     \*/
36945 });
36946  
36947 /**
36948  * @class Roo.bootstrap.panel.Grid
36949  * @extends Roo.bootstrap.panel.Content
36950  * @constructor
36951  * Create a new GridPanel.
36952  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36953  * @param {Object} config A the config object
36954   
36955  */
36956
36957
36958
36959 Roo.bootstrap.panel.Grid = function(config)
36960 {
36961     
36962       
36963     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36964         {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36965
36966     config.el = this.wrapper;
36967     //this.el = this.wrapper;
36968     
36969       if (config.container) {
36970         // ctor'ed from a Border/panel.grid
36971         
36972         
36973         this.wrapper.setStyle("overflow", "hidden");
36974         this.wrapper.addClass('roo-grid-container');
36975
36976     }
36977     
36978     
36979     if(config.toolbar){
36980         var tool_el = this.wrapper.createChild();    
36981         this.toolbar = Roo.factory(config.toolbar);
36982         var ti = [];
36983         if (config.toolbar.items) {
36984             ti = config.toolbar.items ;
36985             delete config.toolbar.items ;
36986         }
36987         
36988         var nitems = [];
36989         this.toolbar.render(tool_el);
36990         for(var i =0;i < ti.length;i++) {
36991           //  Roo.log(['add child', items[i]]);
36992             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36993         }
36994         this.toolbar.items = nitems;
36995         
36996         delete config.toolbar;
36997     }
36998     
36999     Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37000     config.grid.scrollBody = true;;
37001     config.grid.monitorWindowResize = false; // turn off autosizing
37002     config.grid.autoHeight = false;
37003     config.grid.autoWidth = false;
37004     
37005     this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37006     
37007     if (config.background) {
37008         // render grid on panel activation (if panel background)
37009         this.on('activate', function(gp) {
37010             if (!gp.grid.rendered) {
37011                 gp.grid.render(this.wrapper);
37012                 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");   
37013             }
37014         });
37015             
37016     } else {
37017         this.grid.render(this.wrapper);
37018         this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");               
37019
37020     }
37021     //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37022     // ??? needed ??? config.el = this.wrapper;
37023     
37024     
37025     
37026   
37027     // xtype created footer. - not sure if will work as we normally have to render first..
37028     if (this.footer && !this.footer.el && this.footer.xtype) {
37029         
37030         var ctr = this.grid.getView().getFooterPanel(true);
37031         this.footer.dataSource = this.grid.dataSource;
37032         this.footer = Roo.factory(this.footer, Roo);
37033         this.footer.render(ctr);
37034         
37035     }
37036     
37037     
37038     
37039     
37040      
37041 };
37042
37043 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37044     getId : function(){
37045         return this.grid.id;
37046     },
37047     
37048     /**
37049      * Returns the grid for this panel
37050      * @return {Roo.bootstrap.Table} 
37051      */
37052     getGrid : function(){
37053         return this.grid;    
37054     },
37055     
37056     setSize : function(width, height){
37057         if(!this.ignoreResize(width, height)){
37058             var grid = this.grid;
37059             var size = this.adjustForComponents(width, height);
37060             var gridel = grid.getGridEl();
37061             gridel.setSize(size.width, size.height);
37062             /*
37063             var thd = grid.getGridEl().select('thead',true).first();
37064             var tbd = grid.getGridEl().select('tbody', true).first();
37065             if (tbd) {
37066                 tbd.setSize(width, height - thd.getHeight());
37067             }
37068             */
37069             grid.autoSize();
37070         }
37071     },
37072      
37073     
37074     
37075     beforeSlide : function(){
37076         this.grid.getView().scroller.clip();
37077     },
37078     
37079     afterSlide : function(){
37080         this.grid.getView().scroller.unclip();
37081     },
37082     
37083     destroy : function(){
37084         this.grid.destroy();
37085         delete this.grid;
37086         Roo.bootstrap.panel.Grid.superclass.destroy.call(this); 
37087     }
37088 });
37089
37090 /**
37091  * @class Roo.bootstrap.panel.Nest
37092  * @extends Roo.bootstrap.panel.Content
37093  * @constructor
37094  * Create a new Panel, that can contain a layout.Border.
37095  * 
37096  * 
37097  * @param {Roo.BorderLayout} layout The layout for this panel
37098  * @param {String/Object} config A string to set only the title or a config object
37099  */
37100 Roo.bootstrap.panel.Nest = function(config)
37101 {
37102     // construct with only one argument..
37103     /* FIXME - implement nicer consturctors
37104     if (layout.layout) {
37105         config = layout;
37106         layout = config.layout;
37107         delete config.layout;
37108     }
37109     if (layout.xtype && !layout.getEl) {
37110         // then layout needs constructing..
37111         layout = Roo.factory(layout, Roo);
37112     }
37113     */
37114     
37115     config.el =  config.layout.getEl();
37116     
37117     Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37118     
37119     config.layout.monitorWindowResize = false; // turn off autosizing
37120     this.layout = config.layout;
37121     this.layout.getEl().addClass("roo-layout-nested-layout");
37122     
37123     
37124     
37125     
37126 };
37127
37128 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37129
37130     setSize : function(width, height){
37131         if(!this.ignoreResize(width, height)){
37132             var size = this.adjustForComponents(width, height);
37133             var el = this.layout.getEl();
37134             if (size.height < 1) {
37135                 el.setWidth(size.width);   
37136             } else {
37137                 el.setSize(size.width, size.height);
37138             }
37139             var touch = el.dom.offsetWidth;
37140             this.layout.layout();
37141             // ie requires a double layout on the first pass
37142             if(Roo.isIE && !this.initialized){
37143                 this.initialized = true;
37144                 this.layout.layout();
37145             }
37146         }
37147     },
37148     
37149     // activate all subpanels if not currently active..
37150     
37151     setActiveState : function(active){
37152         this.active = active;
37153         this.setActiveClass(active);
37154         
37155         if(!active){
37156             this.fireEvent("deactivate", this);
37157             return;
37158         }
37159         
37160         this.fireEvent("activate", this);
37161         // not sure if this should happen before or after..
37162         if (!this.layout) {
37163             return; // should not happen..
37164         }
37165         var reg = false;
37166         for (var r in this.layout.regions) {
37167             reg = this.layout.getRegion(r);
37168             if (reg.getActivePanel()) {
37169                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
37170                 reg.setActivePanel(reg.getActivePanel());
37171                 continue;
37172             }
37173             if (!reg.panels.length) {
37174                 continue;
37175             }
37176             reg.showPanel(reg.getPanel(0));
37177         }
37178         
37179         
37180         
37181         
37182     },
37183     
37184     /**
37185      * Returns the nested BorderLayout for this panel
37186      * @return {Roo.BorderLayout} 
37187      */
37188     getLayout : function(){
37189         return this.layout;
37190     },
37191     
37192      /**
37193      * Adds a xtype elements to the layout of the nested panel
37194      * <pre><code>
37195
37196 panel.addxtype({
37197        xtype : 'ContentPanel',
37198        region: 'west',
37199        items: [ .... ]
37200    }
37201 );
37202
37203 panel.addxtype({
37204         xtype : 'NestedLayoutPanel',
37205         region: 'west',
37206         layout: {
37207            center: { },
37208            west: { }   
37209         },
37210         items : [ ... list of content panels or nested layout panels.. ]
37211    }
37212 );
37213 </code></pre>
37214      * @param {Object} cfg Xtype definition of item to add.
37215      */
37216     addxtype : function(cfg) {
37217         return this.layout.addxtype(cfg);
37218     
37219     }
37220 });        /*
37221  * Based on:
37222  * Ext JS Library 1.1.1
37223  * Copyright(c) 2006-2007, Ext JS, LLC.
37224  *
37225  * Originally Released Under LGPL - original licence link has changed is not relivant.
37226  *
37227  * Fork - LGPL
37228  * <script type="text/javascript">
37229  */
37230 /**
37231  * @class Roo.TabPanel
37232  * @extends Roo.util.Observable
37233  * A lightweight tab container.
37234  * <br><br>
37235  * Usage:
37236  * <pre><code>
37237 // basic tabs 1, built from existing content
37238 var tabs = new Roo.TabPanel("tabs1");
37239 tabs.addTab("script", "View Script");
37240 tabs.addTab("markup", "View Markup");
37241 tabs.activate("script");
37242
37243 // more advanced tabs, built from javascript
37244 var jtabs = new Roo.TabPanel("jtabs");
37245 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37246
37247 // set up the UpdateManager
37248 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37249 var updater = tab2.getUpdateManager();
37250 updater.setDefaultUrl("ajax1.htm");
37251 tab2.on('activate', updater.refresh, updater, true);
37252
37253 // Use setUrl for Ajax loading
37254 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37255 tab3.setUrl("ajax2.htm", null, true);
37256
37257 // Disabled tab
37258 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37259 tab4.disable();
37260
37261 jtabs.activate("jtabs-1");
37262  * </code></pre>
37263  * @constructor
37264  * Create a new TabPanel.
37265  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37266  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37267  */
37268 Roo.bootstrap.panel.Tabs = function(config){
37269     /**
37270     * The container element for this TabPanel.
37271     * @type Roo.Element
37272     */
37273     this.el = Roo.get(config.el);
37274     delete config.el;
37275     if(config){
37276         if(typeof config == "boolean"){
37277             this.tabPosition = config ? "bottom" : "top";
37278         }else{
37279             Roo.apply(this, config);
37280         }
37281     }
37282     
37283     if(this.tabPosition == "bottom"){
37284         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37285         this.el.addClass("roo-tabs-bottom");
37286     }
37287     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37288     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37289     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37290     if(Roo.isIE){
37291         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37292     }
37293     if(this.tabPosition != "bottom"){
37294         /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37295          * @type Roo.Element
37296          */
37297         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37298         this.el.addClass("roo-tabs-top");
37299     }
37300     this.items = [];
37301
37302     this.bodyEl.setStyle("position", "relative");
37303
37304     this.active = null;
37305     this.activateDelegate = this.activate.createDelegate(this);
37306
37307     this.addEvents({
37308         /**
37309          * @event tabchange
37310          * Fires when the active tab changes
37311          * @param {Roo.TabPanel} this
37312          * @param {Roo.TabPanelItem} activePanel The new active tab
37313          */
37314         "tabchange": true,
37315         /**
37316          * @event beforetabchange
37317          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37318          * @param {Roo.TabPanel} this
37319          * @param {Object} e Set cancel to true on this object to cancel the tab change
37320          * @param {Roo.TabPanelItem} tab The tab being changed to
37321          */
37322         "beforetabchange" : true
37323     });
37324
37325     Roo.EventManager.onWindowResize(this.onResize, this);
37326     this.cpad = this.el.getPadding("lr");
37327     this.hiddenCount = 0;
37328
37329
37330     // toolbar on the tabbar support...
37331     if (this.toolbar) {
37332         alert("no toolbar support yet");
37333         this.toolbar  = false;
37334         /*
37335         var tcfg = this.toolbar;
37336         tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
37337         this.toolbar = new Roo.Toolbar(tcfg);
37338         if (Roo.isSafari) {
37339             var tbl = tcfg.container.child('table', true);
37340             tbl.setAttribute('width', '100%');
37341         }
37342         */
37343         
37344     }
37345    
37346
37347
37348     Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37349 };
37350
37351 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37352     /*
37353      *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37354      */
37355     tabPosition : "top",
37356     /*
37357      *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37358      */
37359     currentTabWidth : 0,
37360     /*
37361      *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37362      */
37363     minTabWidth : 40,
37364     /*
37365      *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37366      */
37367     maxTabWidth : 250,
37368     /*
37369      *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37370      */
37371     preferredTabWidth : 175,
37372     /*
37373      *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37374      */
37375     resizeTabs : false,
37376     /*
37377      *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37378      */
37379     monitorResize : true,
37380     /*
37381      *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
37382      */
37383     toolbar : false,
37384
37385     /**
37386      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37387      * @param {String} id The id of the div to use <b>or create</b>
37388      * @param {String} text The text for the tab
37389      * @param {String} content (optional) Content to put in the TabPanelItem body
37390      * @param {Boolean} closable (optional) True to create a close icon on the tab
37391      * @return {Roo.TabPanelItem} The created TabPanelItem
37392      */
37393     addTab : function(id, text, content, closable, tpl)
37394     {
37395         var item = new Roo.bootstrap.panel.TabItem({
37396             panel: this,
37397             id : id,
37398             text : text,
37399             closable : closable,
37400             tpl : tpl
37401         });
37402         this.addTabItem(item);
37403         if(content){
37404             item.setContent(content);
37405         }
37406         return item;
37407     },
37408
37409     /**
37410      * Returns the {@link Roo.TabPanelItem} with the specified id/index
37411      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37412      * @return {Roo.TabPanelItem}
37413      */
37414     getTab : function(id){
37415         return this.items[id];
37416     },
37417
37418     /**
37419      * Hides the {@link Roo.TabPanelItem} with the specified id/index
37420      * @param {String/Number} id The id or index of the TabPanelItem to hide.
37421      */
37422     hideTab : function(id){
37423         var t = this.items[id];
37424         if(!t.isHidden()){
37425            t.setHidden(true);
37426            this.hiddenCount++;
37427            this.autoSizeTabs();
37428         }
37429     },
37430
37431     /**
37432      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37433      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37434      */
37435     unhideTab : function(id){
37436         var t = this.items[id];
37437         if(t.isHidden()){
37438            t.setHidden(false);
37439            this.hiddenCount--;
37440            this.autoSizeTabs();
37441         }
37442     },
37443
37444     /**
37445      * Adds an existing {@link Roo.TabPanelItem}.
37446      * @param {Roo.TabPanelItem} item The TabPanelItem to add
37447      */
37448     addTabItem : function(item){
37449         this.items[item.id] = item;
37450         this.items.push(item);
37451       //  if(this.resizeTabs){
37452     //       item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37453   //         this.autoSizeTabs();
37454 //        }else{
37455 //            item.autoSize();
37456        // }
37457     },
37458
37459     /**
37460      * Removes a {@link Roo.TabPanelItem}.
37461      * @param {String/Number} id The id or index of the TabPanelItem to remove.
37462      */
37463     removeTab : function(id){
37464         var items = this.items;
37465         var tab = items[id];
37466         if(!tab) { return; }
37467         var index = items.indexOf(tab);
37468         if(this.active == tab && items.length > 1){
37469             var newTab = this.getNextAvailable(index);
37470             if(newTab) {
37471                 newTab.activate();
37472             }
37473         }
37474         this.stripEl.dom.removeChild(tab.pnode.dom);
37475         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37476             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37477         }
37478         items.splice(index, 1);
37479         delete this.items[tab.id];
37480         tab.fireEvent("close", tab);
37481         tab.purgeListeners();
37482         this.autoSizeTabs();
37483     },
37484
37485     getNextAvailable : function(start){
37486         var items = this.items;
37487         var index = start;
37488         // look for a next tab that will slide over to
37489         // replace the one being removed
37490         while(index < items.length){
37491             var item = items[++index];
37492             if(item && !item.isHidden()){
37493                 return item;
37494             }
37495         }
37496         // if one isn't found select the previous tab (on the left)
37497         index = start;
37498         while(index >= 0){
37499             var item = items[--index];
37500             if(item && !item.isHidden()){
37501                 return item;
37502             }
37503         }
37504         return null;
37505     },
37506
37507     /**
37508      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37509      * @param {String/Number} id The id or index of the TabPanelItem to disable.
37510      */
37511     disableTab : function(id){
37512         var tab = this.items[id];
37513         if(tab && this.active != tab){
37514             tab.disable();
37515         }
37516     },
37517
37518     /**
37519      * Enables a {@link Roo.TabPanelItem} that is disabled.
37520      * @param {String/Number} id The id or index of the TabPanelItem to enable.
37521      */
37522     enableTab : function(id){
37523         var tab = this.items[id];
37524         tab.enable();
37525     },
37526
37527     /**
37528      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37529      * @param {String/Number} id The id or index of the TabPanelItem to activate.
37530      * @return {Roo.TabPanelItem} The TabPanelItem.
37531      */
37532     activate : function(id){
37533         var tab = this.items[id];
37534         if(!tab){
37535             return null;
37536         }
37537         if(tab == this.active || tab.disabled){
37538             return tab;
37539         }
37540         var e = {};
37541         this.fireEvent("beforetabchange", this, e, tab);
37542         if(e.cancel !== true && !tab.disabled){
37543             if(this.active){
37544                 this.active.hide();
37545             }
37546             this.active = this.items[id];
37547             this.active.show();
37548             this.fireEvent("tabchange", this, this.active);
37549         }
37550         return tab;
37551     },
37552
37553     /**
37554      * Gets the active {@link Roo.TabPanelItem}.
37555      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37556      */
37557     getActiveTab : function(){
37558         return this.active;
37559     },
37560
37561     /**
37562      * Updates the tab body element to fit the height of the container element
37563      * for overflow scrolling
37564      * @param {Number} targetHeight (optional) Override the starting height from the elements height
37565      */
37566     syncHeight : function(targetHeight){
37567         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37568         var bm = this.bodyEl.getMargins();
37569         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37570         this.bodyEl.setHeight(newHeight);
37571         return newHeight;
37572     },
37573
37574     onResize : function(){
37575         if(this.monitorResize){
37576             this.autoSizeTabs();
37577         }
37578     },
37579
37580     /**
37581      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37582      */
37583     beginUpdate : function(){
37584         this.updating = true;
37585     },
37586
37587     /**
37588      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37589      */
37590     endUpdate : function(){
37591         this.updating = false;
37592         this.autoSizeTabs();
37593     },
37594
37595     /**
37596      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37597      */
37598     autoSizeTabs : function(){
37599         var count = this.items.length;
37600         var vcount = count - this.hiddenCount;
37601         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37602             return;
37603         }
37604         var w = Math.max(this.el.getWidth() - this.cpad, 10);
37605         var availWidth = Math.floor(w / vcount);
37606         var b = this.stripBody;
37607         if(b.getWidth() > w){
37608             var tabs = this.items;
37609             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37610             if(availWidth < this.minTabWidth){
37611                 /*if(!this.sleft){    // incomplete scrolling code
37612                     this.createScrollButtons();
37613                 }
37614                 this.showScroll();
37615                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37616             }
37617         }else{
37618             if(this.currentTabWidth < this.preferredTabWidth){
37619                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37620             }
37621         }
37622     },
37623
37624     /**
37625      * Returns the number of tabs in this TabPanel.
37626      * @return {Number}
37627      */
37628      getCount : function(){
37629          return this.items.length;
37630      },
37631
37632     /**
37633      * Resizes all the tabs to the passed width
37634      * @param {Number} The new width
37635      */
37636     setTabWidth : function(width){
37637         this.currentTabWidth = width;
37638         for(var i = 0, len = this.items.length; i < len; i++) {
37639                 if(!this.items[i].isHidden()) {
37640                 this.items[i].setWidth(width);
37641             }
37642         }
37643     },
37644
37645     /**
37646      * Destroys this TabPanel
37647      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37648      */
37649     destroy : function(removeEl){
37650         Roo.EventManager.removeResizeListener(this.onResize, this);
37651         for(var i = 0, len = this.items.length; i < len; i++){
37652             this.items[i].purgeListeners();
37653         }
37654         if(removeEl === true){
37655             this.el.update("");
37656             this.el.remove();
37657         }
37658     },
37659     
37660     createStrip : function(container)
37661     {
37662         var strip = document.createElement("nav");
37663         strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37664         container.appendChild(strip);
37665         return strip;
37666     },
37667     
37668     createStripList : function(strip)
37669     {
37670         // div wrapper for retard IE
37671         // returns the "tr" element.
37672         strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37673         //'<div class="x-tabs-strip-wrap">'+
37674           //  '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37675           //  '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37676         return strip.firstChild; //.firstChild.firstChild.firstChild;
37677     },
37678     createBody : function(container)
37679     {
37680         var body = document.createElement("div");
37681         Roo.id(body, "tab-body");
37682         //Roo.fly(body).addClass("x-tabs-body");
37683         Roo.fly(body).addClass("tab-content");
37684         container.appendChild(body);
37685         return body;
37686     },
37687     createItemBody :function(bodyEl, id){
37688         var body = Roo.getDom(id);
37689         if(!body){
37690             body = document.createElement("div");
37691             body.id = id;
37692         }
37693         //Roo.fly(body).addClass("x-tabs-item-body");
37694         Roo.fly(body).addClass("tab-pane");
37695          bodyEl.insertBefore(body, bodyEl.firstChild);
37696         return body;
37697     },
37698     /** @private */
37699     createStripElements :  function(stripEl, text, closable, tpl)
37700     {
37701         var td = document.createElement("li"); // was td..
37702         
37703         
37704         //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37705         
37706         
37707         stripEl.appendChild(td);
37708         /*if(closable){
37709             td.className = "x-tabs-closable";
37710             if(!this.closeTpl){
37711                 this.closeTpl = new Roo.Template(
37712                    '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37713                    '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37714                    '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
37715                 );
37716             }
37717             var el = this.closeTpl.overwrite(td, {"text": text});
37718             var close = el.getElementsByTagName("div")[0];
37719             var inner = el.getElementsByTagName("em")[0];
37720             return {"el": el, "close": close, "inner": inner};
37721         } else {
37722         */
37723         // not sure what this is..
37724 //            if(!this.tabTpl){
37725                 //this.tabTpl = new Roo.Template(
37726                 //   '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37727                 //   '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37728                 //);
37729 //                this.tabTpl = new Roo.Template(
37730 //                   '<a href="#">' +
37731 //                   '<span unselectable="on"' +
37732 //                            (this.disableTooltips ? '' : ' title="{text}"') +
37733 //                            ' >{text}</span></a>'
37734 //                );
37735 //                
37736 //            }
37737
37738
37739             var template = tpl || this.tabTpl || false;
37740             
37741             if(!template){
37742                 
37743                 template = new Roo.Template(
37744                    '<a href="#">' +
37745                    '<span unselectable="on"' +
37746                             (this.disableTooltips ? '' : ' title="{text}"') +
37747                             ' >{text}</span></a>'
37748                 );
37749             }
37750             
37751             switch (typeof(template)) {
37752                 case 'object' :
37753                     break;
37754                 case 'string' :
37755                     template = new Roo.Template(template);
37756                     break;
37757                 default :
37758                     break;
37759             }
37760             
37761             var el = template.overwrite(td, {"text": text});
37762             
37763             var inner = el.getElementsByTagName("span")[0];
37764             
37765             return {"el": el, "inner": inner};
37766             
37767     }
37768         
37769     
37770 });
37771
37772 /**
37773  * @class Roo.TabPanelItem
37774  * @extends Roo.util.Observable
37775  * Represents an individual item (tab plus body) in a TabPanel.
37776  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37777  * @param {String} id The id of this TabPanelItem
37778  * @param {String} text The text for the tab of this TabPanelItem
37779  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37780  */
37781 Roo.bootstrap.panel.TabItem = function(config){
37782     /**
37783      * The {@link Roo.TabPanel} this TabPanelItem belongs to
37784      * @type Roo.TabPanel
37785      */
37786     this.tabPanel = config.panel;
37787     /**
37788      * The id for this TabPanelItem
37789      * @type String
37790      */
37791     this.id = config.id;
37792     /** @private */
37793     this.disabled = false;
37794     /** @private */
37795     this.text = config.text;
37796     /** @private */
37797     this.loaded = false;
37798     this.closable = config.closable;
37799
37800     /**
37801      * The body element for this TabPanelItem.
37802      * @type Roo.Element
37803      */
37804     this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37805     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37806     this.bodyEl.setStyle("display", "block");
37807     this.bodyEl.setStyle("zoom", "1");
37808     //this.hideAction();
37809
37810     var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37811     /** @private */
37812     this.el = Roo.get(els.el);
37813     this.inner = Roo.get(els.inner, true);
37814     this.textEl = Roo.get(this.el.dom.firstChild, true);
37815     this.pnode = Roo.get(els.el.parentNode, true);
37816 //    this.el.on("mousedown", this.onTabMouseDown, this);
37817     this.el.on("click", this.onTabClick, this);
37818     /** @private */
37819     if(config.closable){
37820         var c = Roo.get(els.close, true);
37821         c.dom.title = this.closeText;
37822         c.addClassOnOver("close-over");
37823         c.on("click", this.closeClick, this);
37824      }
37825
37826     this.addEvents({
37827          /**
37828          * @event activate
37829          * Fires when this tab becomes the active tab.
37830          * @param {Roo.TabPanel} tabPanel The parent TabPanel
37831          * @param {Roo.TabPanelItem} this
37832          */
37833         "activate": true,
37834         /**
37835          * @event beforeclose
37836          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37837          * @param {Roo.TabPanelItem} this
37838          * @param {Object} e Set cancel to true on this object to cancel the close.
37839          */
37840         "beforeclose": true,
37841         /**
37842          * @event close
37843          * Fires when this tab is closed.
37844          * @param {Roo.TabPanelItem} this
37845          */
37846          "close": true,
37847         /**
37848          * @event deactivate
37849          * Fires when this tab is no longer the active tab.
37850          * @param {Roo.TabPanel} tabPanel The parent TabPanel
37851          * @param {Roo.TabPanelItem} this
37852          */
37853          "deactivate" : true
37854     });
37855     this.hidden = false;
37856
37857     Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37858 };
37859
37860 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37861            {
37862     purgeListeners : function(){
37863        Roo.util.Observable.prototype.purgeListeners.call(this);
37864        this.el.removeAllListeners();
37865     },
37866     /**
37867      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37868      */
37869     show : function(){
37870         this.pnode.addClass("active");
37871         this.showAction();
37872         if(Roo.isOpera){
37873             this.tabPanel.stripWrap.repaint();
37874         }
37875         this.fireEvent("activate", this.tabPanel, this);
37876     },
37877
37878     /**
37879      * Returns true if this tab is the active tab.
37880      * @return {Boolean}
37881      */
37882     isActive : function(){
37883         return this.tabPanel.getActiveTab() == this;
37884     },
37885
37886     /**
37887      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37888      */
37889     hide : function(){
37890         this.pnode.removeClass("active");
37891         this.hideAction();
37892         this.fireEvent("deactivate", this.tabPanel, this);
37893     },
37894
37895     hideAction : function(){
37896         this.bodyEl.hide();
37897         this.bodyEl.setStyle("position", "absolute");
37898         this.bodyEl.setLeft("-20000px");
37899         this.bodyEl.setTop("-20000px");
37900     },
37901
37902     showAction : function(){
37903         this.bodyEl.setStyle("position", "relative");
37904         this.bodyEl.setTop("");
37905         this.bodyEl.setLeft("");
37906         this.bodyEl.show();
37907     },
37908
37909     /**
37910      * Set the tooltip for the tab.
37911      * @param {String} tooltip The tab's tooltip
37912      */
37913     setTooltip : function(text){
37914         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37915             this.textEl.dom.qtip = text;
37916             this.textEl.dom.removeAttribute('title');
37917         }else{
37918             this.textEl.dom.title = text;
37919         }
37920     },
37921
37922     onTabClick : function(e){
37923         e.preventDefault();
37924         this.tabPanel.activate(this.id);
37925     },
37926
37927     onTabMouseDown : function(e){
37928         e.preventDefault();
37929         this.tabPanel.activate(this.id);
37930     },
37931 /*
37932     getWidth : function(){
37933         return this.inner.getWidth();
37934     },
37935
37936     setWidth : function(width){
37937         var iwidth = width - this.pnode.getPadding("lr");
37938         this.inner.setWidth(iwidth);
37939         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37940         this.pnode.setWidth(width);
37941     },
37942 */
37943     /**
37944      * Show or hide the tab
37945      * @param {Boolean} hidden True to hide or false to show.
37946      */
37947     setHidden : function(hidden){
37948         this.hidden = hidden;
37949         this.pnode.setStyle("display", hidden ? "none" : "");
37950     },
37951
37952     /**
37953      * Returns true if this tab is "hidden"
37954      * @return {Boolean}
37955      */
37956     isHidden : function(){
37957         return this.hidden;
37958     },
37959
37960     /**
37961      * Returns the text for this tab
37962      * @return {String}
37963      */
37964     getText : function(){
37965         return this.text;
37966     },
37967     /*
37968     autoSize : function(){
37969         //this.el.beginMeasure();
37970         this.textEl.setWidth(1);
37971         /*
37972          *  #2804 [new] Tabs in Roojs
37973          *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37974          */
37975         //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37976         //this.el.endMeasure();
37977     //},
37978
37979     /**
37980      * Sets the text for the tab (Note: this also sets the tooltip text)
37981      * @param {String} text The tab's text and tooltip
37982      */
37983     setText : function(text){
37984         this.text = text;
37985         this.textEl.update(text);
37986         this.setTooltip(text);
37987         //if(!this.tabPanel.resizeTabs){
37988         //    this.autoSize();
37989         //}
37990     },
37991     /**
37992      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37993      */
37994     activate : function(){
37995         this.tabPanel.activate(this.id);
37996     },
37997
37998     /**
37999      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38000      */
38001     disable : function(){
38002         if(this.tabPanel.active != this){
38003             this.disabled = true;
38004             this.pnode.addClass("disabled");
38005         }
38006     },
38007
38008     /**
38009      * Enables this TabPanelItem if it was previously disabled.
38010      */
38011     enable : function(){
38012         this.disabled = false;
38013         this.pnode.removeClass("disabled");
38014     },
38015
38016     /**
38017      * Sets the content for this TabPanelItem.
38018      * @param {String} content The content
38019      * @param {Boolean} loadScripts true to look for and load scripts
38020      */
38021     setContent : function(content, loadScripts){
38022         this.bodyEl.update(content, loadScripts);
38023     },
38024
38025     /**
38026      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38027      * @return {Roo.UpdateManager} The UpdateManager
38028      */
38029     getUpdateManager : function(){
38030         return this.bodyEl.getUpdateManager();
38031     },
38032
38033     /**
38034      * Set a URL to be used to load the content for this TabPanelItem.
38035      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38036      * @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)
38037      * @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)
38038      * @return {Roo.UpdateManager} The UpdateManager
38039      */
38040     setUrl : function(url, params, loadOnce){
38041         if(this.refreshDelegate){
38042             this.un('activate', this.refreshDelegate);
38043         }
38044         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38045         this.on("activate", this.refreshDelegate);
38046         return this.bodyEl.getUpdateManager();
38047     },
38048
38049     /** @private */
38050     _handleRefresh : function(url, params, loadOnce){
38051         if(!loadOnce || !this.loaded){
38052             var updater = this.bodyEl.getUpdateManager();
38053             updater.update(url, params, this._setLoaded.createDelegate(this));
38054         }
38055     },
38056
38057     /**
38058      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
38059      *   Will fail silently if the setUrl method has not been called.
38060      *   This does not activate the panel, just updates its content.
38061      */
38062     refresh : function(){
38063         if(this.refreshDelegate){
38064            this.loaded = false;
38065            this.refreshDelegate();
38066         }
38067     },
38068
38069     /** @private */
38070     _setLoaded : function(){
38071         this.loaded = true;
38072     },
38073
38074     /** @private */
38075     closeClick : function(e){
38076         var o = {};
38077         e.stopEvent();
38078         this.fireEvent("beforeclose", this, o);
38079         if(o.cancel !== true){
38080             this.tabPanel.removeTab(this.id);
38081         }
38082     },
38083     /**
38084      * The text displayed in the tooltip for the close icon.
38085      * @type String
38086      */
38087     closeText : "Close this tab"
38088 });
38089 /**
38090 *    This script refer to:
38091 *    Title: International Telephone Input
38092 *    Author: Jack O'Connor
38093 *    Code version:  v12.1.12
38094 *    Availability: https://github.com/jackocnr/intl-tel-input.git
38095 **/
38096
38097 Roo.bootstrap.PhoneInputData = function() {
38098     var d = [
38099       [
38100         "Afghanistan (‫افغانستان‬‎)",
38101         "af",
38102         "93"
38103       ],
38104       [
38105         "Albania (Shqipëri)",
38106         "al",
38107         "355"
38108       ],
38109       [
38110         "Algeria (‫الجزائر‬‎)",
38111         "dz",
38112         "213"
38113       ],
38114       [
38115         "American Samoa",
38116         "as",
38117         "1684"
38118       ],
38119       [
38120         "Andorra",
38121         "ad",
38122         "376"
38123       ],
38124       [
38125         "Angola",
38126         "ao",
38127         "244"
38128       ],
38129       [
38130         "Anguilla",
38131         "ai",
38132         "1264"
38133       ],
38134       [
38135         "Antigua and Barbuda",
38136         "ag",
38137         "1268"
38138       ],
38139       [
38140         "Argentina",
38141         "ar",
38142         "54"
38143       ],
38144       [
38145         "Armenia (Հայաստան)",
38146         "am",
38147         "374"
38148       ],
38149       [
38150         "Aruba",
38151         "aw",
38152         "297"
38153       ],
38154       [
38155         "Australia",
38156         "au",
38157         "61",
38158         0
38159       ],
38160       [
38161         "Austria (Österreich)",
38162         "at",
38163         "43"
38164       ],
38165       [
38166         "Azerbaijan (Azərbaycan)",
38167         "az",
38168         "994"
38169       ],
38170       [
38171         "Bahamas",
38172         "bs",
38173         "1242"
38174       ],
38175       [
38176         "Bahrain (‫البحرين‬‎)",
38177         "bh",
38178         "973"
38179       ],
38180       [
38181         "Bangladesh (বাংলাদেশ)",
38182         "bd",
38183         "880"
38184       ],
38185       [
38186         "Barbados",
38187         "bb",
38188         "1246"
38189       ],
38190       [
38191         "Belarus (Беларусь)",
38192         "by",
38193         "375"
38194       ],
38195       [
38196         "Belgium (België)",
38197         "be",
38198         "32"
38199       ],
38200       [
38201         "Belize",
38202         "bz",
38203         "501"
38204       ],
38205       [
38206         "Benin (Bénin)",
38207         "bj",
38208         "229"
38209       ],
38210       [
38211         "Bermuda",
38212         "bm",
38213         "1441"
38214       ],
38215       [
38216         "Bhutan (འབྲུག)",
38217         "bt",
38218         "975"
38219       ],
38220       [
38221         "Bolivia",
38222         "bo",
38223         "591"
38224       ],
38225       [
38226         "Bosnia and Herzegovina (Босна и Херцеговина)",
38227         "ba",
38228         "387"
38229       ],
38230       [
38231         "Botswana",
38232         "bw",
38233         "267"
38234       ],
38235       [
38236         "Brazil (Brasil)",
38237         "br",
38238         "55"
38239       ],
38240       [
38241         "British Indian Ocean Territory",
38242         "io",
38243         "246"
38244       ],
38245       [
38246         "British Virgin Islands",
38247         "vg",
38248         "1284"
38249       ],
38250       [
38251         "Brunei",
38252         "bn",
38253         "673"
38254       ],
38255       [
38256         "Bulgaria (България)",
38257         "bg",
38258         "359"
38259       ],
38260       [
38261         "Burkina Faso",
38262         "bf",
38263         "226"
38264       ],
38265       [
38266         "Burundi (Uburundi)",
38267         "bi",
38268         "257"
38269       ],
38270       [
38271         "Cambodia (កម្ពុជា)",
38272         "kh",
38273         "855"
38274       ],
38275       [
38276         "Cameroon (Cameroun)",
38277         "cm",
38278         "237"
38279       ],
38280       [
38281         "Canada",
38282         "ca",
38283         "1",
38284         1,
38285         ["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"]
38286       ],
38287       [
38288         "Cape Verde (Kabu Verdi)",
38289         "cv",
38290         "238"
38291       ],
38292       [
38293         "Caribbean Netherlands",
38294         "bq",
38295         "599",
38296         1
38297       ],
38298       [
38299         "Cayman Islands",
38300         "ky",
38301         "1345"
38302       ],
38303       [
38304         "Central African Republic (République centrafricaine)",
38305         "cf",
38306         "236"
38307       ],
38308       [
38309         "Chad (Tchad)",
38310         "td",
38311         "235"
38312       ],
38313       [
38314         "Chile",
38315         "cl",
38316         "56"
38317       ],
38318       [
38319         "China (中国)",
38320         "cn",
38321         "86"
38322       ],
38323       [
38324         "Christmas Island",
38325         "cx",
38326         "61",
38327         2
38328       ],
38329       [
38330         "Cocos (Keeling) Islands",
38331         "cc",
38332         "61",
38333         1
38334       ],
38335       [
38336         "Colombia",
38337         "co",
38338         "57"
38339       ],
38340       [
38341         "Comoros (‫جزر القمر‬‎)",
38342         "km",
38343         "269"
38344       ],
38345       [
38346         "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38347         "cd",
38348         "243"
38349       ],
38350       [
38351         "Congo (Republic) (Congo-Brazzaville)",
38352         "cg",
38353         "242"
38354       ],
38355       [
38356         "Cook Islands",
38357         "ck",
38358         "682"
38359       ],
38360       [
38361         "Costa Rica",
38362         "cr",
38363         "506"
38364       ],
38365       [
38366         "Côte d’Ivoire",
38367         "ci",
38368         "225"
38369       ],
38370       [
38371         "Croatia (Hrvatska)",
38372         "hr",
38373         "385"
38374       ],
38375       [
38376         "Cuba",
38377         "cu",
38378         "53"
38379       ],
38380       [
38381         "Curaçao",
38382         "cw",
38383         "599",
38384         0
38385       ],
38386       [
38387         "Cyprus (Κύπρος)",
38388         "cy",
38389         "357"
38390       ],
38391       [
38392         "Czech Republic (Česká republika)",
38393         "cz",
38394         "420"
38395       ],
38396       [
38397         "Denmark (Danmark)",
38398         "dk",
38399         "45"
38400       ],
38401       [
38402         "Djibouti",
38403         "dj",
38404         "253"
38405       ],
38406       [
38407         "Dominica",
38408         "dm",
38409         "1767"
38410       ],
38411       [
38412         "Dominican Republic (República Dominicana)",
38413         "do",
38414         "1",
38415         2,
38416         ["809", "829", "849"]
38417       ],
38418       [
38419         "Ecuador",
38420         "ec",
38421         "593"
38422       ],
38423       [
38424         "Egypt (‫مصر‬‎)",
38425         "eg",
38426         "20"
38427       ],
38428       [
38429         "El Salvador",
38430         "sv",
38431         "503"
38432       ],
38433       [
38434         "Equatorial Guinea (Guinea Ecuatorial)",
38435         "gq",
38436         "240"
38437       ],
38438       [
38439         "Eritrea",
38440         "er",
38441         "291"
38442       ],
38443       [
38444         "Estonia (Eesti)",
38445         "ee",
38446         "372"
38447       ],
38448       [
38449         "Ethiopia",
38450         "et",
38451         "251"
38452       ],
38453       [
38454         "Falkland Islands (Islas Malvinas)",
38455         "fk",
38456         "500"
38457       ],
38458       [
38459         "Faroe Islands (Føroyar)",
38460         "fo",
38461         "298"
38462       ],
38463       [
38464         "Fiji",
38465         "fj",
38466         "679"
38467       ],
38468       [
38469         "Finland (Suomi)",
38470         "fi",
38471         "358",
38472         0
38473       ],
38474       [
38475         "France",
38476         "fr",
38477         "33"
38478       ],
38479       [
38480         "French Guiana (Guyane française)",
38481         "gf",
38482         "594"
38483       ],
38484       [
38485         "French Polynesia (Polynésie française)",
38486         "pf",
38487         "689"
38488       ],
38489       [
38490         "Gabon",
38491         "ga",
38492         "241"
38493       ],
38494       [
38495         "Gambia",
38496         "gm",
38497         "220"
38498       ],
38499       [
38500         "Georgia (საქართველო)",
38501         "ge",
38502         "995"
38503       ],
38504       [
38505         "Germany (Deutschland)",
38506         "de",
38507         "49"
38508       ],
38509       [
38510         "Ghana (Gaana)",
38511         "gh",
38512         "233"
38513       ],
38514       [
38515         "Gibraltar",
38516         "gi",
38517         "350"
38518       ],
38519       [
38520         "Greece (Ελλάδα)",
38521         "gr",
38522         "30"
38523       ],
38524       [
38525         "Greenland (Kalaallit Nunaat)",
38526         "gl",
38527         "299"
38528       ],
38529       [
38530         "Grenada",
38531         "gd",
38532         "1473"
38533       ],
38534       [
38535         "Guadeloupe",
38536         "gp",
38537         "590",
38538         0
38539       ],
38540       [
38541         "Guam",
38542         "gu",
38543         "1671"
38544       ],
38545       [
38546         "Guatemala",
38547         "gt",
38548         "502"
38549       ],
38550       [
38551         "Guernsey",
38552         "gg",
38553         "44",
38554         1
38555       ],
38556       [
38557         "Guinea (Guinée)",
38558         "gn",
38559         "224"
38560       ],
38561       [
38562         "Guinea-Bissau (Guiné Bissau)",
38563         "gw",
38564         "245"
38565       ],
38566       [
38567         "Guyana",
38568         "gy",
38569         "592"
38570       ],
38571       [
38572         "Haiti",
38573         "ht",
38574         "509"
38575       ],
38576       [
38577         "Honduras",
38578         "hn",
38579         "504"
38580       ],
38581       [
38582         "Hong Kong (香港)",
38583         "hk",
38584         "852"
38585       ],
38586       [
38587         "Hungary (Magyarország)",
38588         "hu",
38589         "36"
38590       ],
38591       [
38592         "Iceland (Ísland)",
38593         "is",
38594         "354"
38595       ],
38596       [
38597         "India (भारत)",
38598         "in",
38599         "91"
38600       ],
38601       [
38602         "Indonesia",
38603         "id",
38604         "62"
38605       ],
38606       [
38607         "Iran (‫ایران‬‎)",
38608         "ir",
38609         "98"
38610       ],
38611       [
38612         "Iraq (‫العراق‬‎)",
38613         "iq",
38614         "964"
38615       ],
38616       [
38617         "Ireland",
38618         "ie",
38619         "353"
38620       ],
38621       [
38622         "Isle of Man",
38623         "im",
38624         "44",
38625         2
38626       ],
38627       [
38628         "Israel (‫ישראל‬‎)",
38629         "il",
38630         "972"
38631       ],
38632       [
38633         "Italy (Italia)",
38634         "it",
38635         "39",
38636         0
38637       ],
38638       [
38639         "Jamaica",
38640         "jm",
38641         "1876"
38642       ],
38643       [
38644         "Japan (日本)",
38645         "jp",
38646         "81"
38647       ],
38648       [
38649         "Jersey",
38650         "je",
38651         "44",
38652         3
38653       ],
38654       [
38655         "Jordan (‫الأردن‬‎)",
38656         "jo",
38657         "962"
38658       ],
38659       [
38660         "Kazakhstan (Казахстан)",
38661         "kz",
38662         "7",
38663         1
38664       ],
38665       [
38666         "Kenya",
38667         "ke",
38668         "254"
38669       ],
38670       [
38671         "Kiribati",
38672         "ki",
38673         "686"
38674       ],
38675       [
38676         "Kosovo",
38677         "xk",
38678         "383"
38679       ],
38680       [
38681         "Kuwait (‫الكويت‬‎)",
38682         "kw",
38683         "965"
38684       ],
38685       [
38686         "Kyrgyzstan (Кыргызстан)",
38687         "kg",
38688         "996"
38689       ],
38690       [
38691         "Laos (ລາວ)",
38692         "la",
38693         "856"
38694       ],
38695       [
38696         "Latvia (Latvija)",
38697         "lv",
38698         "371"
38699       ],
38700       [
38701         "Lebanon (‫لبنان‬‎)",
38702         "lb",
38703         "961"
38704       ],
38705       [
38706         "Lesotho",
38707         "ls",
38708         "266"
38709       ],
38710       [
38711         "Liberia",
38712         "lr",
38713         "231"
38714       ],
38715       [
38716         "Libya (‫ليبيا‬‎)",
38717         "ly",
38718         "218"
38719       ],
38720       [
38721         "Liechtenstein",
38722         "li",
38723         "423"
38724       ],
38725       [
38726         "Lithuania (Lietuva)",
38727         "lt",
38728         "370"
38729       ],
38730       [
38731         "Luxembourg",
38732         "lu",
38733         "352"
38734       ],
38735       [
38736         "Macau (澳門)",
38737         "mo",
38738         "853"
38739       ],
38740       [
38741         "Macedonia (FYROM) (Македонија)",
38742         "mk",
38743         "389"
38744       ],
38745       [
38746         "Madagascar (Madagasikara)",
38747         "mg",
38748         "261"
38749       ],
38750       [
38751         "Malawi",
38752         "mw",
38753         "265"
38754       ],
38755       [
38756         "Malaysia",
38757         "my",
38758         "60"
38759       ],
38760       [
38761         "Maldives",
38762         "mv",
38763         "960"
38764       ],
38765       [
38766         "Mali",
38767         "ml",
38768         "223"
38769       ],
38770       [
38771         "Malta",
38772         "mt",
38773         "356"
38774       ],
38775       [
38776         "Marshall Islands",
38777         "mh",
38778         "692"
38779       ],
38780       [
38781         "Martinique",
38782         "mq",
38783         "596"
38784       ],
38785       [
38786         "Mauritania (‫موريتانيا‬‎)",
38787         "mr",
38788         "222"
38789       ],
38790       [
38791         "Mauritius (Moris)",
38792         "mu",
38793         "230"
38794       ],
38795       [
38796         "Mayotte",
38797         "yt",
38798         "262",
38799         1
38800       ],
38801       [
38802         "Mexico (México)",
38803         "mx",
38804         "52"
38805       ],
38806       [
38807         "Micronesia",
38808         "fm",
38809         "691"
38810       ],
38811       [
38812         "Moldova (Republica Moldova)",
38813         "md",
38814         "373"
38815       ],
38816       [
38817         "Monaco",
38818         "mc",
38819         "377"
38820       ],
38821       [
38822         "Mongolia (Монгол)",
38823         "mn",
38824         "976"
38825       ],
38826       [
38827         "Montenegro (Crna Gora)",
38828         "me",
38829         "382"
38830       ],
38831       [
38832         "Montserrat",
38833         "ms",
38834         "1664"
38835       ],
38836       [
38837         "Morocco (‫المغرب‬‎)",
38838         "ma",
38839         "212",
38840         0
38841       ],
38842       [
38843         "Mozambique (Moçambique)",
38844         "mz",
38845         "258"
38846       ],
38847       [
38848         "Myanmar (Burma) (မြန်မာ)",
38849         "mm",
38850         "95"
38851       ],
38852       [
38853         "Namibia (Namibië)",
38854         "na",
38855         "264"
38856       ],
38857       [
38858         "Nauru",
38859         "nr",
38860         "674"
38861       ],
38862       [
38863         "Nepal (नेपाल)",
38864         "np",
38865         "977"
38866       ],
38867       [
38868         "Netherlands (Nederland)",
38869         "nl",
38870         "31"
38871       ],
38872       [
38873         "New Caledonia (Nouvelle-Calédonie)",
38874         "nc",
38875         "687"
38876       ],
38877       [
38878         "New Zealand",
38879         "nz",
38880         "64"
38881       ],
38882       [
38883         "Nicaragua",
38884         "ni",
38885         "505"
38886       ],
38887       [
38888         "Niger (Nijar)",
38889         "ne",
38890         "227"
38891       ],
38892       [
38893         "Nigeria",
38894         "ng",
38895         "234"
38896       ],
38897       [
38898         "Niue",
38899         "nu",
38900         "683"
38901       ],
38902       [
38903         "Norfolk Island",
38904         "nf",
38905         "672"
38906       ],
38907       [
38908         "North Korea (조선 민주주의 인민 공화국)",
38909         "kp",
38910         "850"
38911       ],
38912       [
38913         "Northern Mariana Islands",
38914         "mp",
38915         "1670"
38916       ],
38917       [
38918         "Norway (Norge)",
38919         "no",
38920         "47",
38921         0
38922       ],
38923       [
38924         "Oman (‫عُمان‬‎)",
38925         "om",
38926         "968"
38927       ],
38928       [
38929         "Pakistan (‫پاکستان‬‎)",
38930         "pk",
38931         "92"
38932       ],
38933       [
38934         "Palau",
38935         "pw",
38936         "680"
38937       ],
38938       [
38939         "Palestine (‫فلسطين‬‎)",
38940         "ps",
38941         "970"
38942       ],
38943       [
38944         "Panama (Panamá)",
38945         "pa",
38946         "507"
38947       ],
38948       [
38949         "Papua New Guinea",
38950         "pg",
38951         "675"
38952       ],
38953       [
38954         "Paraguay",
38955         "py",
38956         "595"
38957       ],
38958       [
38959         "Peru (Perú)",
38960         "pe",
38961         "51"
38962       ],
38963       [
38964         "Philippines",
38965         "ph",
38966         "63"
38967       ],
38968       [
38969         "Poland (Polska)",
38970         "pl",
38971         "48"
38972       ],
38973       [
38974         "Portugal",
38975         "pt",
38976         "351"
38977       ],
38978       [
38979         "Puerto Rico",
38980         "pr",
38981         "1",
38982         3,
38983         ["787", "939"]
38984       ],
38985       [
38986         "Qatar (‫قطر‬‎)",
38987         "qa",
38988         "974"
38989       ],
38990       [
38991         "Réunion (La Réunion)",
38992         "re",
38993         "262",
38994         0
38995       ],
38996       [
38997         "Romania (România)",
38998         "ro",
38999         "40"
39000       ],
39001       [
39002         "Russia (Россия)",
39003         "ru",
39004         "7",
39005         0
39006       ],
39007       [
39008         "Rwanda",
39009         "rw",
39010         "250"
39011       ],
39012       [
39013         "Saint Barthélemy",
39014         "bl",
39015         "590",
39016         1
39017       ],
39018       [
39019         "Saint Helena",
39020         "sh",
39021         "290"
39022       ],
39023       [
39024         "Saint Kitts and Nevis",
39025         "kn",
39026         "1869"
39027       ],
39028       [
39029         "Saint Lucia",
39030         "lc",
39031         "1758"
39032       ],
39033       [
39034         "Saint Martin (Saint-Martin (partie française))",
39035         "mf",
39036         "590",
39037         2
39038       ],
39039       [
39040         "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39041         "pm",
39042         "508"
39043       ],
39044       [
39045         "Saint Vincent and the Grenadines",
39046         "vc",
39047         "1784"
39048       ],
39049       [
39050         "Samoa",
39051         "ws",
39052         "685"
39053       ],
39054       [
39055         "San Marino",
39056         "sm",
39057         "378"
39058       ],
39059       [
39060         "São Tomé and Príncipe (São Tomé e Príncipe)",
39061         "st",
39062         "239"
39063       ],
39064       [
39065         "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
39066         "sa",
39067         "966"
39068       ],
39069       [
39070         "Senegal (Sénégal)",
39071         "sn",
39072         "221"
39073       ],
39074       [
39075         "Serbia (Србија)",
39076         "rs",
39077         "381"
39078       ],
39079       [
39080         "Seychelles",
39081         "sc",
39082         "248"
39083       ],
39084       [
39085         "Sierra Leone",
39086         "sl",
39087         "232"
39088       ],
39089       [
39090         "Singapore",
39091         "sg",
39092         "65"
39093       ],
39094       [
39095         "Sint Maarten",
39096         "sx",
39097         "1721"
39098       ],
39099       [
39100         "Slovakia (Slovensko)",
39101         "sk",
39102         "421"
39103       ],
39104       [
39105         "Slovenia (Slovenija)",
39106         "si",
39107         "386"
39108       ],
39109       [
39110         "Solomon Islands",
39111         "sb",
39112         "677"
39113       ],
39114       [
39115         "Somalia (Soomaaliya)",
39116         "so",
39117         "252"
39118       ],
39119       [
39120         "South Africa",
39121         "za",
39122         "27"
39123       ],
39124       [
39125         "South Korea (대한민국)",
39126         "kr",
39127         "82"
39128       ],
39129       [
39130         "South Sudan (‫جنوب السودان‬‎)",
39131         "ss",
39132         "211"
39133       ],
39134       [
39135         "Spain (España)",
39136         "es",
39137         "34"
39138       ],
39139       [
39140         "Sri Lanka (ශ්‍රී ලංකාව)",
39141         "lk",
39142         "94"
39143       ],
39144       [
39145         "Sudan (‫السودان‬‎)",
39146         "sd",
39147         "249"
39148       ],
39149       [
39150         "Suriname",
39151         "sr",
39152         "597"
39153       ],
39154       [
39155         "Svalbard and Jan Mayen",
39156         "sj",
39157         "47",
39158         1
39159       ],
39160       [
39161         "Swaziland",
39162         "sz",
39163         "268"
39164       ],
39165       [
39166         "Sweden (Sverige)",
39167         "se",
39168         "46"
39169       ],
39170       [
39171         "Switzerland (Schweiz)",
39172         "ch",
39173         "41"
39174       ],
39175       [
39176         "Syria (‫سوريا‬‎)",
39177         "sy",
39178         "963"
39179       ],
39180       [
39181         "Taiwan (台灣)",
39182         "tw",
39183         "886"
39184       ],
39185       [
39186         "Tajikistan",
39187         "tj",
39188         "992"
39189       ],
39190       [
39191         "Tanzania",
39192         "tz",
39193         "255"
39194       ],
39195       [
39196         "Thailand (ไทย)",
39197         "th",
39198         "66"
39199       ],
39200       [
39201         "Timor-Leste",
39202         "tl",
39203         "670"
39204       ],
39205       [
39206         "Togo",
39207         "tg",
39208         "228"
39209       ],
39210       [
39211         "Tokelau",
39212         "tk",
39213         "690"
39214       ],
39215       [
39216         "Tonga",
39217         "to",
39218         "676"
39219       ],
39220       [
39221         "Trinidad and Tobago",
39222         "tt",
39223         "1868"
39224       ],
39225       [
39226         "Tunisia (‫تونس‬‎)",
39227         "tn",
39228         "216"
39229       ],
39230       [
39231         "Turkey (Türkiye)",
39232         "tr",
39233         "90"
39234       ],
39235       [
39236         "Turkmenistan",
39237         "tm",
39238         "993"
39239       ],
39240       [
39241         "Turks and Caicos Islands",
39242         "tc",
39243         "1649"
39244       ],
39245       [
39246         "Tuvalu",
39247         "tv",
39248         "688"
39249       ],
39250       [
39251         "U.S. Virgin Islands",
39252         "vi",
39253         "1340"
39254       ],
39255       [
39256         "Uganda",
39257         "ug",
39258         "256"
39259       ],
39260       [
39261         "Ukraine (Україна)",
39262         "ua",
39263         "380"
39264       ],
39265       [
39266         "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
39267         "ae",
39268         "971"
39269       ],
39270       [
39271         "United Kingdom",
39272         "gb",
39273         "44",
39274         0
39275       ],
39276       [
39277         "United States",
39278         "us",
39279         "1",
39280         0
39281       ],
39282       [
39283         "Uruguay",
39284         "uy",
39285         "598"
39286       ],
39287       [
39288         "Uzbekistan (Oʻzbekiston)",
39289         "uz",
39290         "998"
39291       ],
39292       [
39293         "Vanuatu",
39294         "vu",
39295         "678"
39296       ],
39297       [
39298         "Vatican City (Città del Vaticano)",
39299         "va",
39300         "39",
39301         1
39302       ],
39303       [
39304         "Venezuela",
39305         "ve",
39306         "58"
39307       ],
39308       [
39309         "Vietnam (Việt Nam)",
39310         "vn",
39311         "84"
39312       ],
39313       [
39314         "Wallis and Futuna (Wallis-et-Futuna)",
39315         "wf",
39316         "681"
39317       ],
39318       [
39319         "Western Sahara (‫الصحراء الغربية‬‎)",
39320         "eh",
39321         "212",
39322         1
39323       ],
39324       [
39325         "Yemen (‫اليمن‬‎)",
39326         "ye",
39327         "967"
39328       ],
39329       [
39330         "Zambia",
39331         "zm",
39332         "260"
39333       ],
39334       [
39335         "Zimbabwe",
39336         "zw",
39337         "263"
39338       ],
39339       [
39340         "Åland Islands",
39341         "ax",
39342         "358",
39343         1
39344       ]
39345   ];
39346   
39347   return d;
39348 }/**
39349 *    This script refer to:
39350 *    Title: International Telephone Input
39351 *    Author: Jack O'Connor
39352 *    Code version:  v12.1.12
39353 *    Availability: https://github.com/jackocnr/intl-tel-input.git
39354 **/
39355
39356 /**
39357  * @class Roo.bootstrap.PhoneInput
39358  * @extends Roo.bootstrap.TriggerField
39359  * An input with International dial-code selection
39360  
39361  * @cfg {String} defaultDialCode default '+852'
39362  * @cfg {Array} preferedCountries default []
39363   
39364  * @constructor
39365  * Create a new PhoneInput.
39366  * @param {Object} config Configuration options
39367  */
39368
39369 Roo.bootstrap.PhoneInput = function(config) {
39370     Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39371 };
39372
39373 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39374         
39375         listWidth: undefined,
39376         
39377         selectedClass: 'active',
39378         
39379         invalidClass : "has-warning",
39380         
39381         validClass: 'has-success',
39382         
39383         allowed: '0123456789',
39384         
39385         /**
39386          * @cfg {String} defaultDialCode The default dial code when initializing the input
39387          */
39388         defaultDialCode: '+852',
39389         
39390         /**
39391          * @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
39392          */
39393         preferedCountries: false,
39394         
39395         getAutoCreate : function()
39396         {
39397             var data = Roo.bootstrap.PhoneInputData();
39398             var align = this.labelAlign || this.parentLabelAlign();
39399             var id = Roo.id();
39400             
39401             this.allCountries = [];
39402             this.dialCodeMapping = [];
39403             
39404             for (var i = 0; i < data.length; i++) {
39405               var c = data[i];
39406               this.allCountries[i] = {
39407                 name: c[0],
39408                 iso2: c[1],
39409                 dialCode: c[2],
39410                 priority: c[3] || 0,
39411                 areaCodes: c[4] || null
39412               };
39413               this.dialCodeMapping[c[2]] = {
39414                   name: c[0],
39415                   iso2: c[1],
39416                   priority: c[3] || 0,
39417                   areaCodes: c[4] || null
39418               };
39419             }
39420             
39421             var cfg = {
39422                 cls: 'form-group',
39423                 cn: []
39424             };
39425             
39426             var input =  {
39427                 tag: 'input',
39428                 id : id,
39429                 cls : 'form-control tel-input',
39430                 autocomplete: 'new-password'
39431             };
39432             
39433             var hiddenInput = {
39434                 tag: 'input',
39435                 type: 'hidden',
39436                 cls: 'hidden-tel-input'
39437             };
39438             
39439             if (this.name) {
39440                 hiddenInput.name = this.name;
39441             }
39442             
39443             if (this.disabled) {
39444                 input.disabled = true;
39445             }
39446             
39447             var flag_container = {
39448                 tag: 'div',
39449                 cls: 'flag-box',
39450                 cn: [
39451                     {
39452                         tag: 'div',
39453                         cls: 'flag'
39454                     },
39455                     {
39456                         tag: 'div',
39457                         cls: 'caret'
39458                     }
39459                 ]
39460             };
39461             
39462             var box = {
39463                 tag: 'div',
39464                 cls: this.hasFeedback ? 'has-feedback' : '',
39465                 cn: [
39466                     hiddenInput,
39467                     input,
39468                     {
39469                         tag: 'input',
39470                         cls: 'dial-code-holder',
39471                         disabled: true
39472                     }
39473                 ]
39474             };
39475             
39476             var container = {
39477                 cls: 'roo-select2-container input-group',
39478                 cn: [
39479                     flag_container,
39480                     box
39481                 ]
39482             };
39483             
39484             if (this.fieldLabel.length) {
39485                 var indicator = {
39486                     tag: 'i',
39487                     tooltip: 'This field is required'
39488                 };
39489                 
39490                 var label = {
39491                     tag: 'label',
39492                     'for':  id,
39493                     cls: 'control-label',
39494                     cn: []
39495                 };
39496                 
39497                 var label_text = {
39498                     tag: 'span',
39499                     html: this.fieldLabel
39500                 };
39501                 
39502                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39503                 label.cn = [
39504                     indicator,
39505                     label_text
39506                 ];
39507                 
39508                 if(this.indicatorpos == 'right') {
39509                     indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39510                     label.cn = [
39511                         label_text,
39512                         indicator
39513                     ];
39514                 }
39515                 
39516                 if(align == 'left') {
39517                     container = {
39518                         tag: 'div',
39519                         cn: [
39520                             container
39521                         ]
39522                     };
39523                     
39524                     if(this.labelWidth > 12){
39525                         label.style = "width: " + this.labelWidth + 'px';
39526                     }
39527                     if(this.labelWidth < 13 && this.labelmd == 0){
39528                         this.labelmd = this.labelWidth;
39529                     }
39530                     if(this.labellg > 0){
39531                         label.cls += ' col-lg-' + this.labellg;
39532                         input.cls += ' col-lg-' + (12 - this.labellg);
39533                     }
39534                     if(this.labelmd > 0){
39535                         label.cls += ' col-md-' + this.labelmd;
39536                         container.cls += ' col-md-' + (12 - this.labelmd);
39537                     }
39538                     if(this.labelsm > 0){
39539                         label.cls += ' col-sm-' + this.labelsm;
39540                         container.cls += ' col-sm-' + (12 - this.labelsm);
39541                     }
39542                     if(this.labelxs > 0){
39543                         label.cls += ' col-xs-' + this.labelxs;
39544                         container.cls += ' col-xs-' + (12 - this.labelxs);
39545                     }
39546                 }
39547             }
39548             
39549             cfg.cn = [
39550                 label,
39551                 container
39552             ];
39553             
39554             var settings = this;
39555             
39556             ['xs','sm','md','lg'].map(function(size){
39557                 if (settings[size]) {
39558                     cfg.cls += ' col-' + size + '-' + settings[size];
39559                 }
39560             });
39561             
39562             this.store = new Roo.data.Store({
39563                 proxy : new Roo.data.MemoryProxy({}),
39564                 reader : new Roo.data.JsonReader({
39565                     fields : [
39566                         {
39567                             'name' : 'name',
39568                             'type' : 'string'
39569                         },
39570                         {
39571                             'name' : 'iso2',
39572                             'type' : 'string'
39573                         },
39574                         {
39575                             'name' : 'dialCode',
39576                             'type' : 'string'
39577                         },
39578                         {
39579                             'name' : 'priority',
39580                             'type' : 'string'
39581                         },
39582                         {
39583                             'name' : 'areaCodes',
39584                             'type' : 'string'
39585                         }
39586                     ]
39587                 })
39588             });
39589             
39590             if(!this.preferedCountries) {
39591                 this.preferedCountries = [
39592                     'hk',
39593                     'gb',
39594                     'us'
39595                 ];
39596             }
39597             
39598             var p = this.preferedCountries.reverse();
39599             
39600             if(p) {
39601                 for (var i = 0; i < p.length; i++) {
39602                     for (var j = 0; j < this.allCountries.length; j++) {
39603                         if(this.allCountries[j].iso2 == p[i]) {
39604                             var t = this.allCountries[j];
39605                             this.allCountries.splice(j,1);
39606                             this.allCountries.unshift(t);
39607                         }
39608                     } 
39609                 }
39610             }
39611             
39612             this.store.proxy.data = {
39613                 success: true,
39614                 data: this.allCountries
39615             };
39616             
39617             return cfg;
39618         },
39619         
39620         initEvents : function()
39621         {
39622             this.createList();
39623             Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39624             
39625             this.indicator = this.indicatorEl();
39626             this.flag = this.flagEl();
39627             this.dialCodeHolder = this.dialCodeHolderEl();
39628             
39629             this.trigger = this.el.select('div.flag-box',true).first();
39630             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39631             
39632             var _this = this;
39633             
39634             (function(){
39635                 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39636                 _this.list.setWidth(lw);
39637             }).defer(100);
39638             
39639             this.list.on('mouseover', this.onViewOver, this);
39640             this.list.on('mousemove', this.onViewMove, this);
39641             this.inputEl().on("keyup", this.onKeyUp, this);
39642             
39643             this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39644
39645             this.view = new Roo.View(this.list, this.tpl, {
39646                 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39647             });
39648             
39649             this.view.on('click', this.onViewClick, this);
39650             this.setValue(this.defaultDialCode);
39651         },
39652         
39653         onTriggerClick : function(e)
39654         {
39655             Roo.log('trigger click');
39656             if(this.disabled){
39657                 return;
39658             }
39659             
39660             if(this.isExpanded()){
39661                 this.collapse();
39662                 this.hasFocus = false;
39663             }else {
39664                 this.store.load({});
39665                 this.hasFocus = true;
39666                 this.expand();
39667             }
39668         },
39669         
39670         isExpanded : function()
39671         {
39672             return this.list.isVisible();
39673         },
39674         
39675         collapse : function()
39676         {
39677             if(!this.isExpanded()){
39678                 return;
39679             }
39680             this.list.hide();
39681             Roo.get(document).un('mousedown', this.collapseIf, this);
39682             Roo.get(document).un('mousewheel', this.collapseIf, this);
39683             this.fireEvent('collapse', this);
39684             this.validate();
39685         },
39686         
39687         expand : function()
39688         {
39689             Roo.log('expand');
39690
39691             if(this.isExpanded() || !this.hasFocus){
39692                 return;
39693             }
39694             
39695             var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39696             this.list.setWidth(lw);
39697             
39698             this.list.show();
39699             this.restrictHeight();
39700             
39701             Roo.get(document).on('mousedown', this.collapseIf, this);
39702             Roo.get(document).on('mousewheel', this.collapseIf, this);
39703             
39704             this.fireEvent('expand', this);
39705         },
39706         
39707         restrictHeight : function()
39708         {
39709             this.list.alignTo(this.inputEl(), this.listAlign);
39710             this.list.alignTo(this.inputEl(), this.listAlign);
39711         },
39712         
39713         onViewOver : function(e, t)
39714         {
39715             if(this.inKeyMode){
39716                 return;
39717             }
39718             var item = this.view.findItemFromChild(t);
39719             
39720             if(item){
39721                 var index = this.view.indexOf(item);
39722                 this.select(index, false);
39723             }
39724         },
39725
39726         // private
39727         onViewClick : function(view, doFocus, el, e)
39728         {
39729             var index = this.view.getSelectedIndexes()[0];
39730             
39731             var r = this.store.getAt(index);
39732             
39733             if(r){
39734                 this.onSelect(r, index);
39735             }
39736             if(doFocus !== false && !this.blockFocus){
39737                 this.inputEl().focus();
39738             }
39739         },
39740         
39741         onViewMove : function(e, t)
39742         {
39743             this.inKeyMode = false;
39744         },
39745         
39746         select : function(index, scrollIntoView)
39747         {
39748             this.selectedIndex = index;
39749             this.view.select(index);
39750             if(scrollIntoView !== false){
39751                 var el = this.view.getNode(index);
39752                 if(el){
39753                     this.list.scrollChildIntoView(el, false);
39754                 }
39755             }
39756         },
39757         
39758         createList : function()
39759         {
39760             this.list = Roo.get(document.body).createChild({
39761                 tag: 'ul',
39762                 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39763                 style: 'display:none'
39764             });
39765             this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39766         },
39767         
39768         collapseIf : function(e)
39769         {
39770             var in_combo  = e.within(this.el);
39771             var in_list =  e.within(this.list);
39772             var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39773             
39774             if (in_combo || in_list || is_list) {
39775                 return;
39776             }
39777             this.collapse();
39778         },
39779         
39780         onSelect : function(record, index)
39781         {
39782             if(this.fireEvent('beforeselect', this, record, index) !== false){
39783                 
39784                 this.setFlagClass(record.data.iso2);
39785                 this.setDialCode(record.data.dialCode);
39786                 this.hasFocus = false;
39787                 this.collapse();
39788                 this.fireEvent('select', this, record, index);
39789             }
39790         },
39791         
39792         flagEl : function()
39793         {
39794             var flag = this.el.select('div.flag',true).first();
39795             if(!flag){
39796                 return false;
39797             }
39798             return flag;
39799         },
39800         
39801         dialCodeHolderEl : function()
39802         {
39803             var d = this.el.select('input.dial-code-holder',true).first();
39804             if(!d){
39805                 return false;
39806             }
39807             return d;
39808         },
39809         
39810         setDialCode : function(v)
39811         {
39812             this.dialCodeHolder.dom.value = '+'+v;
39813         },
39814         
39815         setFlagClass : function(n)
39816         {
39817             this.flag.dom.className = 'flag '+n;
39818         },
39819         
39820         getValue : function()
39821         {
39822             var v = this.inputEl().getValue();
39823             if(this.dialCodeHolder) {
39824                 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
39825             }
39826             return v;
39827         },
39828         
39829         setValue : function(v)
39830         {
39831             var d = this.getDialCode(v);
39832             
39833             //invalid dial code
39834             if(v.length == 0 || !d || d.length == 0) {
39835                 if(this.rendered){
39836                     this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
39837                     this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
39838                 }
39839                 return;
39840             }
39841             
39842             //valid dial code
39843             this.setFlagClass(this.dialCodeMapping[d].iso2);
39844             this.setDialCode(d);
39845             this.inputEl().dom.value = v.replace('+'+d,'');
39846             this.hiddenEl().dom.value = this.getValue();
39847             
39848             this.validate();
39849         },
39850         
39851         getDialCode : function(v = '')
39852         {
39853             if (v.length == 0) {
39854                 return this.dialCodeHolder.dom.value;
39855             }
39856             
39857             var dialCode = "";
39858             if (v.charAt(0) != "+") {
39859                 return false;
39860             }
39861             var numericChars = "";
39862             for (var i = 1; i < v.length; i++) {
39863               var c = v.charAt(i);
39864               if (!isNaN(c)) {
39865                 numericChars += c;
39866                 if (this.dialCodeMapping[numericChars]) {
39867                   dialCode = v.substr(1, i);
39868                 }
39869                 if (numericChars.length == 4) {
39870                   break;
39871                 }
39872               }
39873             }
39874             return dialCode;
39875         },
39876         
39877         reset : function()
39878         {
39879             this.setValue(this.defaultDialCode);
39880             this.validate();
39881         },
39882         
39883         hiddenEl : function()
39884         {
39885             return this.el.select('input.hidden-tel-input',true).first();
39886         },
39887         
39888         onKeyUp : function(e){
39889             
39890             var k = e.getKey();
39891             var c = e.getCharCode();
39892             
39893             if(
39894                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
39895                     this.allowed.indexOf(String.fromCharCode(c)) === -1
39896             ){
39897                 e.stopEvent();
39898             }
39899             
39900             // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39901             //     return;
39902             // }
39903             if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
39904                 e.stopEvent();
39905             }
39906             
39907             this.setValue(this.getValue());
39908         }
39909         
39910 });
39911 /**
39912  * @class Roo.bootstrap.MoneyField
39913  * @extends Roo.bootstrap.ComboBox
39914  * Bootstrap MoneyField class
39915  * 
39916  * @constructor
39917  * Create a new MoneyField.
39918  * @param {Object} config Configuration options
39919  */
39920
39921 Roo.bootstrap.MoneyField = function(config) {
39922     
39923     Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
39924     
39925 };
39926
39927 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
39928     
39929     /**
39930      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39931      */
39932     allowDecimals : true,
39933     /**
39934      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39935      */
39936     decimalSeparator : ".",
39937     /**
39938      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39939      */
39940     decimalPrecision : 2,
39941     /**
39942      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39943      */
39944     allowNegative : true,
39945     /**
39946      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39947      */
39948     minValue : Number.NEGATIVE_INFINITY,
39949     /**
39950      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39951      */
39952     maxValue : Number.MAX_VALUE,
39953     /**
39954      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39955      */
39956     minText : "The minimum value for this field is {0}",
39957     /**
39958      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39959      */
39960     maxText : "The maximum value for this field is {0}",
39961     /**
39962      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
39963      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39964      */
39965     nanText : "{0} is not a valid number",
39966     /**
39967      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
39968      */
39969     castInt : true,
39970     /**
39971      * @cfg {String} defaults currency of the MoneyField
39972      * value should be in lkey
39973      */
39974     defaultCurrency : false,
39975     
39976     
39977     inputlg : 9,
39978     inputmd : 9,
39979     inputsm : 9,
39980     inputxs : 6,
39981     
39982     store : false,
39983     
39984     getAutoCreate : function()
39985     {
39986         var align = this.labelAlign || this.parentLabelAlign();
39987         
39988         var id = Roo.id();
39989
39990         var cfg = {
39991             cls: 'form-group',
39992             cn: []
39993         };
39994
39995         var input =  {
39996             tag: 'input',
39997             id : id,
39998             cls : 'form-control roo-money-amount-input',
39999             autocomplete: 'new-password'
40000         };
40001         
40002         if (this.name) {
40003             input.name = this.name;
40004         }
40005
40006         if (this.disabled) {
40007             input.disabled = true;
40008         }
40009
40010         var clg = 12 - this.inputlg;
40011         var cmd = 12 - this.inputmd;
40012         var csm = 12 - this.inputsm;
40013         var cxs = 12 - this.inputxs;
40014         
40015         var container = {
40016             tag : 'div',
40017             cls : 'row roo-money-field',
40018             cn : [
40019                 {
40020                     tag : 'div',
40021                     cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40022                     cn : [
40023                         {
40024                             tag : 'div',
40025                             cls: 'roo-select2-container input-group',
40026                             cn: [
40027                                 {
40028                                     tag : 'input',
40029                                     cls : 'form-control roo-money-currency-input',
40030                                     autocomplete: 'new-password',
40031                                     readOnly : 1,
40032                                     name : this.currencyName
40033                                 },
40034                                 {
40035                                     tag :'span',
40036                                     cls : 'input-group-addon',
40037                                     cn : [
40038                                         {
40039                                             tag: 'span',
40040                                             cls: 'caret'
40041                                         }
40042                                     ]
40043                                 }
40044                             ]
40045                         }
40046                     ]
40047                 },
40048                 {
40049                     tag : 'div',
40050                     cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40051                     cn : [
40052                         {
40053                             tag: 'div',
40054                             cls: this.hasFeedback ? 'has-feedback' : '',
40055                             cn: [
40056                                 input
40057                             ]
40058                         }
40059                     ]
40060                 }
40061             ]
40062             
40063         };
40064         
40065         if (this.fieldLabel.length) {
40066             var indicator = {
40067                 tag: 'i',
40068                 tooltip: 'This field is required'
40069             };
40070
40071             var label = {
40072                 tag: 'label',
40073                 'for':  id,
40074                 cls: 'control-label',
40075                 cn: []
40076             };
40077
40078             var label_text = {
40079                 tag: 'span',
40080                 html: this.fieldLabel
40081             };
40082
40083             indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40084             label.cn = [
40085                 indicator,
40086                 label_text
40087             ];
40088
40089             if(this.indicatorpos == 'right') {
40090                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40091                 label.cn = [
40092                     label_text,
40093                     indicator
40094                 ];
40095             }
40096
40097             if(align == 'left') {
40098                 container = {
40099                     tag: 'div',
40100                     cn: [
40101                         container
40102                     ]
40103                 };
40104
40105                 if(this.labelWidth > 12){
40106                     label.style = "width: " + this.labelWidth + 'px';
40107                 }
40108                 if(this.labelWidth < 13 && this.labelmd == 0){
40109                     this.labelmd = this.labelWidth;
40110                 }
40111                 if(this.labellg > 0){
40112                     label.cls += ' col-lg-' + this.labellg;
40113                     input.cls += ' col-lg-' + (12 - this.labellg);
40114                 }
40115                 if(this.labelmd > 0){
40116                     label.cls += ' col-md-' + this.labelmd;
40117                     container.cls += ' col-md-' + (12 - this.labelmd);
40118                 }
40119                 if(this.labelsm > 0){
40120                     label.cls += ' col-sm-' + this.labelsm;
40121                     container.cls += ' col-sm-' + (12 - this.labelsm);
40122                 }
40123                 if(this.labelxs > 0){
40124                     label.cls += ' col-xs-' + this.labelxs;
40125                     container.cls += ' col-xs-' + (12 - this.labelxs);
40126                 }
40127             }
40128         }
40129
40130         cfg.cn = [
40131             label,
40132             container
40133         ];
40134
40135         var settings = this;
40136
40137         ['xs','sm','md','lg'].map(function(size){
40138             if (settings[size]) {
40139                 cfg.cls += ' col-' + size + '-' + settings[size];
40140             }
40141         });
40142         
40143         return cfg;
40144         
40145     },
40146     
40147     initEvents : function()
40148     {
40149         this.indicator = this.indicatorEl();
40150         
40151         this.initCurrencyEvent();
40152         
40153         this.initNumberEvent();
40154         
40155     },
40156     
40157     initCurrencyEvent : function()
40158     {
40159         if (!this.store) {
40160             throw "can not find store for combo";
40161         }
40162         
40163         this.store = Roo.factory(this.store, Roo.data);
40164         this.store.parent = this;
40165         
40166         this.createList();
40167         
40168         this.triggerEl = this.el.select('.input-group-addon', true).first();
40169         
40170         this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40171         
40172         var _this = this;
40173         
40174         (function(){
40175             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40176             _this.list.setWidth(lw);
40177         }).defer(100);
40178         
40179         this.list.on('mouseover', this.onViewOver, this);
40180         this.list.on('mousemove', this.onViewMove, this);
40181         this.list.on('scroll', this.onViewScroll, this);
40182         
40183         if(!this.tpl){
40184             this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40185         }
40186         
40187         this.view = new Roo.View(this.list, this.tpl, {
40188             singleSelect:true, store: this.store, selectedClass: this.selectedClass
40189         });
40190         
40191         this.view.on('click', this.onViewClick, this);
40192         
40193         this.store.on('beforeload', this.onBeforeLoad, this);
40194         this.store.on('load', this.onLoad, this);
40195         this.store.on('loadexception', this.onLoadException, this);
40196         
40197         this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40198             "up" : function(e){
40199                 this.inKeyMode = true;
40200                 this.selectPrev();
40201             },
40202
40203             "down" : function(e){
40204                 if(!this.isExpanded()){
40205                     this.onTriggerClick();
40206                 }else{
40207                     this.inKeyMode = true;
40208                     this.selectNext();
40209                 }
40210             },
40211
40212             "enter" : function(e){
40213                 this.collapse();
40214                 
40215                 if(this.fireEvent("specialkey", this, e)){
40216                     this.onViewClick(false);
40217                 }
40218                 
40219                 return true;
40220             },
40221
40222             "esc" : function(e){
40223                 this.collapse();
40224             },
40225
40226             "tab" : function(e){
40227                 this.collapse();
40228                 
40229                 if(this.fireEvent("specialkey", this, e)){
40230                     this.onViewClick(false);
40231                 }
40232                 
40233                 return true;
40234             },
40235
40236             scope : this,
40237
40238             doRelay : function(foo, bar, hname){
40239                 if(hname == 'down' || this.scope.isExpanded()){
40240                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40241                 }
40242                 return true;
40243             },
40244
40245             forceKeyDown: true
40246         });
40247         
40248         this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40249         
40250     },
40251     
40252     initNumberEvent : function(e)
40253     {
40254         this.inputEl().on("keydown" , this.fireKey,  this);
40255         this.inputEl().on("focus", this.onFocus,  this);
40256         this.inputEl().on("blur", this.onBlur,  this);
40257         
40258         this.inputEl().relayEvent('keyup', this);
40259         
40260         if(this.indicator){
40261             this.indicator.addClass('invisible');
40262         }
40263  
40264         this.originalValue = this.getValue();
40265         
40266         if(this.validationEvent == 'keyup'){
40267             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40268             this.inputEl().on('keyup', this.filterValidation, this);
40269         }
40270         else if(this.validationEvent !== false){
40271             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40272         }
40273         
40274         if(this.selectOnFocus){
40275             this.on("focus", this.preFocus, this);
40276             
40277         }
40278         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40279             this.inputEl().on("keypress", this.filterKeys, this);
40280         } else {
40281             this.inputEl().relayEvent('keypress', this);
40282         }
40283         
40284         var allowed = "0123456789";
40285         
40286         if(this.allowDecimals){
40287             allowed += this.decimalSeparator;
40288         }
40289         
40290         if(this.allowNegative){
40291             allowed += "-";
40292         }
40293         
40294         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40295         
40296         var keyPress = function(e){
40297             
40298             var k = e.getKey();
40299             
40300             var c = e.getCharCode();
40301             
40302             if(
40303                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40304                     allowed.indexOf(String.fromCharCode(c)) === -1
40305             ){
40306                 e.stopEvent();
40307                 return;
40308             }
40309             
40310             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40311                 return;
40312             }
40313             
40314             if(allowed.indexOf(String.fromCharCode(c)) === -1){
40315                 e.stopEvent();
40316             }
40317         };
40318         
40319         this.inputEl().on("keypress", keyPress, this);
40320         
40321     },
40322     
40323     onTriggerClick : function(e)
40324     {   
40325         if(this.disabled){
40326             return;
40327         }
40328         
40329         this.page = 0;
40330         this.loadNext = false;
40331         
40332         if(this.isExpanded()){
40333             this.collapse();
40334             return;
40335         }
40336         
40337         this.hasFocus = true;
40338         
40339         if(this.triggerAction == 'all') {
40340             this.doQuery(this.allQuery, true);
40341             return;
40342         }
40343         
40344         this.doQuery(this.getRawValue());
40345     },
40346     
40347     getCurrency : function()
40348     {   
40349         var v = this.currencyEl().getValue();
40350         
40351         return v;
40352     },
40353     
40354     restrictHeight : function()
40355     {
40356         this.list.alignTo(this.currencyEl(), this.listAlign);
40357         this.list.alignTo(this.currencyEl(), this.listAlign);
40358     },
40359     
40360     onViewClick : function(view, doFocus, el, e)
40361     {
40362         var index = this.view.getSelectedIndexes()[0];
40363         
40364         var r = this.store.getAt(index);
40365         
40366         if(r){
40367             this.onSelect(r, index);
40368         }
40369     },
40370     
40371     onSelect : function(record, index){
40372         
40373         if(this.fireEvent('beforeselect', this, record, index) !== false){
40374         
40375             this.setFromCurrencyData(index > -1 ? record.data : false);
40376             
40377             this.collapse();
40378             
40379             this.fireEvent('select', this, record, index);
40380         }
40381     },
40382     
40383     setFromCurrencyData : function(o)
40384     {
40385         var currency = '';
40386         
40387         this.lastCurrency = o;
40388         
40389         if (this.currencyField) {
40390             currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40391         } else {
40392             Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
40393         }
40394         
40395         this.lastSelectionText = currency;
40396         
40397         Roo.log(o['currencyField']);
40398         
40399         if(o.length * 1 == 0 && this.defaultCurrency) {
40400             Roo.log('setting currency');
40401             this.setCurrency(this.defaultCurrency);
40402         }
40403         
40404         this.setCurrency(currency);
40405     },
40406     
40407     setFromData : function(o)
40408     {
40409         var c = {};
40410         
40411         c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40412         
40413         this.setFromCurrencyData(c);
40414         
40415         var value = '';
40416         
40417         if (this.name) {
40418             value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40419         } else {
40420             Roo.log('no value set for '+ (this.name ? this.name : this.id));
40421         }
40422         
40423         this.setValue(value);
40424         
40425     },
40426     
40427     setCurrency : function(v)
40428     {   
40429         this.currencyValue = v;
40430         
40431         if(this.rendered){
40432             this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40433             this.validate();
40434         }
40435     },
40436     
40437     setValue : function(v)
40438     {
40439         v = this.fixPrecision(v);
40440         
40441         v = String(v).replace(".", this.decimalSeparator);
40442         
40443         this.value = v;
40444         
40445         if(this.rendered){
40446             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40447             this.validate();
40448         }
40449     },
40450     
40451     getRawValue : function()
40452     {
40453         var v = this.inputEl().getValue();
40454         
40455         return v;
40456     },
40457     
40458     getValue : function()
40459     {
40460         return this.fixPrecision(this.parseValue(this.getRawValue()));
40461     },
40462     
40463     parseValue : function(value)
40464     {
40465         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40466         return isNaN(value) ? '' : value;
40467     },
40468     
40469     fixPrecision : function(value)
40470     {
40471         var nan = isNaN(value);
40472         
40473         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40474             return nan ? '' : value;
40475         }
40476         
40477         return parseFloat(value).toFixed(this.decimalPrecision);
40478     },
40479     
40480     decimalPrecisionFcn : function(v)
40481     {
40482         return Math.floor(v);
40483     },
40484     
40485     validateValue : function(value)
40486     {
40487         if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40488             return false;
40489         }
40490         
40491         var num = this.parseValue(value);
40492         
40493         if(isNaN(num)){
40494             this.markInvalid(String.format(this.nanText, value));
40495             return false;
40496         }
40497         
40498         if(num < this.minValue){
40499             this.markInvalid(String.format(this.minText, this.minValue));
40500             return false;
40501         }
40502         
40503         if(num > this.maxValue){
40504             this.markInvalid(String.format(this.maxText, this.maxValue));
40505             return false;
40506         }
40507         
40508         return true;
40509     },
40510     
40511     validate : function()
40512     {
40513         if(this.disabled || this.allowBlank){
40514             this.markValid();
40515             return true;
40516         }
40517         
40518         var currency = this.getCurrency();
40519         
40520         if(this.validateValue(this.getRawValue()) && currency.length){
40521             this.markValid();
40522             return true;
40523         }
40524         
40525         this.markInvalid();
40526         return false;
40527     },
40528     
40529     getName: function()
40530     {
40531         return this.name;
40532     },
40533     
40534     beforeBlur : function()
40535     {
40536         if(!this.castInt){
40537             return;
40538         }
40539         
40540         var v = this.parseValue(this.getRawValue());
40541         
40542         if(v){
40543             this.setValue(v);
40544         }
40545     },
40546     
40547     onBlur : function()
40548     {
40549         this.beforeBlur();
40550         
40551         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40552             //this.el.removeClass(this.focusClass);
40553         }
40554         
40555         this.hasFocus = false;
40556         
40557         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40558             this.validate();
40559         }
40560         
40561         var v = this.getValue();
40562         
40563         if(String(v) !== String(this.startValue)){
40564             this.fireEvent('change', this, v, this.startValue);
40565         }
40566         
40567         this.fireEvent("blur", this);
40568     },
40569     
40570     inputEl : function()
40571     {
40572         return this.el.select('.roo-money-amount-input', true).first();
40573     },
40574     
40575     currencyEl : function()
40576     {
40577         return this.el.select('.roo-money-currency-input', true).first();
40578     }
40579     
40580 });