roojs-bootstrap.js
[roojs1] / roojs-bootstrap-debug.js
1 /*
2  * - LGPL
3  *
4  * base class for bootstrap elements.
5  * 
6  */
7
8 Roo.bootstrap = Roo.bootstrap || {};
9 /**
10  * @class Roo.bootstrap.Component
11  * @extends Roo.Component
12  * Bootstrap Component base class
13  * @cfg {String} cls css class
14  * @cfg {String} style any extra css
15  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16  * @cfg {Boolean} can_build_overlaid  True if element can be rebuild from a HTML page
17  * @cfg {string} dataId cutomer id
18  * @cfg {string} name Specifies name attribute
19  * @cfg {string} tooltip  Text for the tooltip
20  * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar -  getHeaderChildContainer)
21  * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
22  
23  * @constructor
24  * Do not use directly - it does not do anything..
25  * @param {Object} config The config object
26  */
27
28
29
30 Roo.bootstrap.Component = function(config){
31     Roo.bootstrap.Component.superclass.constructor.call(this, config);
32        
33     this.addEvents({
34         /**
35          * @event childrenrendered
36          * Fires when the children have been rendered..
37          * @param {Roo.bootstrap.Component} this
38          */
39         "childrenrendered" : true
40         
41         
42         
43     });
44     
45     
46 };
47
48 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
49     
50     
51     allowDomMove : false, // to stop relocations in parent onRender...
52     
53     cls : false,
54     
55     style : false,
56     
57     autoCreate : false,
58     
59     tooltip : null,
60     /**
61      * Initialize Events for the element
62      */
63     initEvents : function() { },
64     
65     xattr : false,
66     
67     parentId : false,
68     
69     can_build_overlaid : true,
70     
71     container_method : false,
72     
73     dataId : false,
74     
75     name : false,
76     
77     parent: function() {
78         // returns the parent component..
79         return Roo.ComponentMgr.get(this.parentId)
80         
81         
82     },
83     
84     // private
85     onRender : function(ct, position)
86     {
87        // Roo.log("Call onRender: " + this.xtype);
88         
89         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
90         
91         if(this.el){
92             if (this.el.attr('xtype')) {
93                 this.el.attr('xtypex', this.el.attr('xtype'));
94                 this.el.dom.removeAttribute('xtype');
95                 
96                 this.initEvents();
97             }
98             
99             return;
100         }
101         
102          
103         
104         var cfg = Roo.apply({},  this.getAutoCreate());
105         
106         cfg.id = this.id || Roo.id();
107         
108         // fill in the extra attributes 
109         if (this.xattr && typeof(this.xattr) =='object') {
110             for (var i in this.xattr) {
111                 cfg[i] = this.xattr[i];
112             }
113         }
114         
115         if(this.dataId){
116             cfg.dataId = this.dataId;
117         }
118         
119         if (this.cls) {
120             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121         }
122         
123         if (this.style) { // fixme needs to support more complex style data.
124             cfg.style = this.style;
125         }
126         
127         if(this.name){
128             cfg.name = this.name;
129         }
130         
131         this.el = ct.createChild(cfg, position);
132         
133         if (this.tooltip) {
134             this.tooltipEl().attr('tooltip', this.tooltip);
135         }
136         
137         if(this.tabIndex !== undefined){
138             this.el.dom.setAttribute('tabIndex', this.tabIndex);
139         }
140         
141         this.initEvents();
142         
143     },
144     /**
145      * Fetch the element to add children to
146      * @return {Roo.Element} defaults to this.el
147      */
148     getChildContainer : function()
149     {
150         return this.el;
151     },
152     /**
153      * Fetch the element to display the tooltip on.
154      * @return {Roo.Element} defaults to this.el
155      */
156     tooltipEl : function()
157     {
158         return this.el;
159     },
160         
161     addxtype  : function(tree,cntr)
162     {
163         var cn = this;
164         
165         cn = Roo.factory(tree);
166         //Roo.log(['addxtype', cn]);
167            
168         cn.parentType = this.xtype; //??
169         cn.parentId = this.id;
170         
171         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
172         if (typeof(cn.container_method) == 'string') {
173             cntr = cn.container_method;
174         }
175         
176         
177         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
178         
179         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
180         
181         var build_from_html =  Roo.XComponent.build_from_html;
182           
183         var is_body  = (tree.xtype == 'Body') ;
184           
185         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186           
187         var self_cntr_el = Roo.get(this[cntr](false));
188         
189         // do not try and build conditional elements 
190         if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
191             return false;
192         }
193         
194         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
195             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
196                 return this.addxtypeChild(tree,cntr, is_body);
197             }
198             
199             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
200                 
201             if(echild){
202                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
203             }
204             
205             Roo.log('skipping render');
206             return cn;
207             
208         }
209         
210         var ret = false;
211         if (!build_from_html) {
212             return false;
213         }
214         
215         // this i think handles overlaying multiple children of the same type
216         // with the sam eelement.. - which might be buggy..
217         while (true) {
218             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
219             
220             if (!echild) {
221                 break;
222             }
223             
224             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
225                 break;
226             }
227             
228             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
229         }
230        
231         return ret;
232     },
233     
234     
235     addxtypeChild : function (tree, cntr, is_body)
236     {
237         Roo.debug && Roo.log('addxtypeChild:' + cntr);
238         var cn = this;
239         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
240         
241         
242         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
243                     (typeof(tree['flexy:foreach']) != 'undefined');
244           
245     
246         
247         skip_children = false;
248         // render the element if it's not BODY.
249         if (!is_body) {
250             
251             // if parent was disabled, then do not try and create the children..
252             if(!this[cntr](true)){
253                 tree.items = [];
254                 return tree;
255             }
256            
257             cn = Roo.factory(tree);
258            
259             cn.parentType = this.xtype; //??
260             cn.parentId = this.id;
261             
262             var build_from_html =  Roo.XComponent.build_from_html;
263             
264             
265             // does the container contain child eleemnts with 'xtype' attributes.
266             // that match this xtype..
267             // note - when we render we create these as well..
268             // so we should check to see if body has xtype set.
269             if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
270                
271                 var self_cntr_el = Roo.get(this[cntr](false));
272                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
273                 if (echild) { 
274                     //Roo.log(Roo.XComponent.build_from_html);
275                     //Roo.log("got echild:");
276                     //Roo.log(echild);
277                 }
278                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
279                 // and are not displayed -this causes this to use up the wrong element when matching.
280                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
281                 
282                 
283                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
284                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
285                   
286                   
287                   
288                     cn.el = echild;
289                   //  Roo.log("GOT");
290                     //echild.dom.removeAttribute('xtype');
291                 } else {
292                     Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
293                     Roo.debug && Roo.log(self_cntr_el);
294                     Roo.debug && Roo.log(echild);
295                     Roo.debug && Roo.log(cn);
296                 }
297             }
298            
299             
300            
301             // if object has flexy:if - then it may or may not be rendered.
302             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
303                 // skip a flexy if element.
304                 Roo.debug && Roo.log('skipping render');
305                 Roo.debug && Roo.log(tree);
306                 if (!cn.el) {
307                     Roo.debug && Roo.log('skipping all children');
308                     skip_children = true;
309                 }
310                 
311              } else {
312                  
313                 // actually if flexy:foreach is found, we really want to create 
314                 // multiple copies here...
315                 //Roo.log('render');
316                 //Roo.log(this[cntr]());
317                 // some elements do not have render methods.. like the layouts...
318                 /*
319                 if(this[cntr](true) === false){
320                     cn.items = [];
321                     return cn;
322                 }
323                 */
324                 cn.render && cn.render(this[cntr](true));
325                 
326              }
327             // then add the element..
328         }
329          
330         // handle the kids..
331         
332         var nitems = [];
333         /*
334         if (typeof (tree.menu) != 'undefined') {
335             tree.menu.parentType = cn.xtype;
336             tree.menu.triggerEl = cn.el;
337             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
338             
339         }
340         */
341         if (!tree.items || !tree.items.length) {
342             cn.items = nitems;
343             //Roo.log(["no children", this]);
344             
345             return cn;
346         }
347          
348         var items = tree.items;
349         delete tree.items;
350         
351         //Roo.log(items.length);
352             // add the items..
353         if (!skip_children) {    
354             for(var i =0;i < items.length;i++) {
355               //  Roo.log(['add child', items[i]]);
356                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
357             }
358         }
359         
360         cn.items = nitems;
361         
362         //Roo.log("fire childrenrendered");
363         
364         cn.fireEvent('childrenrendered', this);
365         
366         return cn;
367     },
368     
369     /**
370      * Set the element that will be used to show or hide
371      */
372     setVisibilityEl : function(el)
373     {
374         this.visibilityEl = el;
375     },
376     
377      /**
378      * Get the element that will be used to show or hide
379      */
380     getVisibilityEl : function()
381     {
382         if (typeof(this.visibilityEl) == 'object') {
383             return this.visibilityEl;
384         }
385         
386         if (typeof(this.visibilityEl) == 'string') {
387             return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
388         }
389         
390         return this.getEl();
391     },
392     
393     /**
394      * Show a component - removes 'hidden' class
395      */
396     show : function()
397     {
398         if(!this.getVisibilityEl()){
399             return;
400         }
401          
402         this.getVisibilityEl().removeClass('hidden');
403         
404         
405     },
406     /**
407      * Hide a component - adds 'hidden' class
408      */
409     hide: function()
410     {
411         if(!this.getVisibilityEl()){
412             return;
413         }
414         
415         this.getVisibilityEl().addClass('hidden');
416         
417     }
418 });
419
420  /*
421  * - LGPL
422  *
423  * Body
424  *
425  */
426
427 /**
428  * @class Roo.bootstrap.Body
429  * @extends Roo.bootstrap.Component
430  * Bootstrap Body class
431  *
432  * @constructor
433  * Create a new body
434  * @param {Object} config The config object
435  */
436
437 Roo.bootstrap.Body = function(config){
438
439     config = config || {};
440
441     Roo.bootstrap.Body.superclass.constructor.call(this, config);
442     this.el = Roo.get(config.el ? config.el : document.body );
443     if (this.cls && this.cls.length) {
444         Roo.get(document.body).addClass(this.cls);
445     }
446 };
447
448 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
449
450     is_body : true,// just to make sure it's constructed?
451
452         autoCreate : {
453         cls: 'container'
454     },
455     onRender : function(ct, position)
456     {
457        /* Roo.log("Roo.bootstrap.Body - onRender");
458         if (this.cls && this.cls.length) {
459             Roo.get(document.body).addClass(this.cls);
460         }
461         // style??? xttr???
462         */
463     }
464
465
466
467
468 });
469 /*
470  * - LGPL
471  *
472  * button group
473  * 
474  */
475
476
477 /**
478  * @class Roo.bootstrap.ButtonGroup
479  * @extends Roo.bootstrap.Component
480  * Bootstrap ButtonGroup class
481  * @cfg {String} size lg | sm | xs (default empty normal)
482  * @cfg {String} align vertical | justified  (default none)
483  * @cfg {String} direction up | down (default down)
484  * @cfg {Boolean} toolbar false | true
485  * @cfg {Boolean} btn true | false
486  * 
487  * 
488  * @constructor
489  * Create a new Input
490  * @param {Object} config The config object
491  */
492
493 Roo.bootstrap.ButtonGroup = function(config){
494     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
495 };
496
497 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
498     
499     size: '',
500     align: '',
501     direction: '',
502     toolbar: false,
503     btn: true,
504
505     getAutoCreate : function(){
506         var cfg = {
507             cls: 'btn-group',
508             html : null
509         };
510         
511         cfg.html = this.html || cfg.html;
512         
513         if (this.toolbar) {
514             cfg = {
515                 cls: 'btn-toolbar',
516                 html: null
517             };
518             
519             return cfg;
520         }
521         
522         if (['vertical','justified'].indexOf(this.align)!==-1) {
523             cfg.cls = 'btn-group-' + this.align;
524             
525             if (this.align == 'justified') {
526                 console.log(this.items);
527             }
528         }
529         
530         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
531             cfg.cls += ' btn-group-' + this.size;
532         }
533         
534         if (this.direction == 'up') {
535             cfg.cls += ' dropup' ;
536         }
537         
538         return cfg;
539     }
540    
541 });
542
543  /*
544  * - LGPL
545  *
546  * button
547  * 
548  */
549
550 /**
551  * @class Roo.bootstrap.Button
552  * @extends Roo.bootstrap.Component
553  * Bootstrap Button class
554  * @cfg {String} html The button content
555  * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default 
556  * @cfg {String} size ( lg | sm | xs)
557  * @cfg {String} tag ( a | input | submit)
558  * @cfg {String} href empty or href
559  * @cfg {Boolean} disabled default false;
560  * @cfg {Boolean} isClose default false;
561  * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
562  * @cfg {String} badge text for badge
563  * @cfg {String} theme default 
564  * @cfg {Boolean} inverse 
565  * @cfg {Boolean} toggle is it a slidy toggle button
566  * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
567  * @cfg {String} ontext text for on toggle state
568  * @cfg {String} offtext text for off toggle state
569  * @cfg {Boolean} defaulton 
570  * @cfg {Boolean} preventDefault  default true
571  * @cfg {Boolean} removeClass remove the standard class..
572  * @cfg {String} target  target for a href. (_self|_blank|_parent|_top| other)
573  * 
574  * @constructor
575  * Create a new button
576  * @param {Object} config The config object
577  */
578
579
580 Roo.bootstrap.Button = function(config){
581     Roo.bootstrap.Button.superclass.constructor.call(this, config);
582     this.weightClass = ["btn-default", 
583                        "btn-primary", 
584                        "btn-success", 
585                        "btn-info", 
586                        "btn-warning",
587                        "btn-danger",
588                        "btn-link"
589                       ],  
590     this.addEvents({
591         // raw events
592         /**
593          * @event click
594          * When a butotn is pressed
595          * @param {Roo.bootstrap.Button} btn
596          * @param {Roo.EventObject} e
597          */
598         "click" : true,
599          /**
600          * @event toggle
601          * After the button has been toggles
602          * @param {Roo.bootstrap.Button} btn
603          * @param {Roo.EventObject} e
604          * @param {boolean} pressed (also available as button.pressed)
605          */
606         "toggle" : true
607     });
608 };
609
610 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
611     html: false,
612     active: false,
613     weight: '',
614     size: '',
615     tag: 'button',
616     href: '',
617     disabled: false,
618     isClose: false,
619     glyphicon: '',
620     badge: '',
621     theme: 'default',
622     inverse: false,
623     
624     toggle: false,
625     ontext: 'ON',
626     offtext: 'OFF',
627     defaulton: true,
628     preventDefault: true,
629     removeClass: false,
630     name: false,
631     target: false,
632     
633     
634     pressed : null,
635      
636     
637     getAutoCreate : function(){
638         
639         var cfg = {
640             tag : 'button',
641             cls : 'roo-button',
642             html: ''
643         };
644         
645         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
646             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
647             this.tag = 'button';
648         } else {
649             cfg.tag = this.tag;
650         }
651         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
652         
653         if (this.toggle == true) {
654             cfg={
655                 tag: 'div',
656                 cls: 'slider-frame roo-button',
657                 cn: [
658                     {
659                         tag: 'span',
660                         'data-on-text':'ON',
661                         'data-off-text':'OFF',
662                         cls: 'slider-button',
663                         html: this.offtext
664                     }
665                 ]
666             };
667             
668             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
669                 cfg.cls += ' '+this.weight;
670             }
671             
672             return cfg;
673         }
674         
675         if (this.isClose) {
676             cfg.cls += ' close';
677             
678             cfg["aria-hidden"] = true;
679             
680             cfg.html = "&times;";
681             
682             return cfg;
683         }
684         
685          
686         if (this.theme==='default') {
687             cfg.cls = 'btn roo-button';
688             
689             //if (this.parentType != 'Navbar') {
690             this.weight = this.weight.length ?  this.weight : 'default';
691             //}
692             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
693                 
694                 cfg.cls += ' btn-' + this.weight;
695             }
696         } else if (this.theme==='glow') {
697             
698             cfg.tag = 'a';
699             cfg.cls = 'btn-glow roo-button';
700             
701             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
702                 
703                 cfg.cls += ' ' + this.weight;
704             }
705         }
706    
707         
708         if (this.inverse) {
709             this.cls += ' inverse';
710         }
711         
712         
713         if (this.active || this.pressed === true) {
714             cfg.cls += ' active';
715         }
716         
717         if (this.disabled) {
718             cfg.disabled = 'disabled';
719         }
720         
721         if (this.items) {
722             Roo.log('changing to ul' );
723             cfg.tag = 'ul';
724             this.glyphicon = 'caret';
725         }
726         
727         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
728          
729         //gsRoo.log(this.parentType);
730         if (this.parentType === 'Navbar' && !this.parent().bar) {
731             Roo.log('changing to li?');
732             
733             cfg.tag = 'li';
734             
735             cfg.cls = '';
736             cfg.cn =  [{
737                 tag : 'a',
738                 cls : 'roo-button',
739                 html : this.html,
740                 href : this.href || '#'
741             }];
742             if (this.menu) {
743                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
744                 cfg.cls += ' dropdown';
745             }   
746             
747             delete cfg.html;
748             
749         }
750         
751        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
752         
753         if (this.glyphicon) {
754             cfg.html = ' ' + cfg.html;
755             
756             cfg.cn = [
757                 {
758                     tag: 'span',
759                     cls: 'glyphicon glyphicon-' + this.glyphicon
760                 }
761             ];
762         }
763         
764         if (this.badge) {
765             cfg.html += ' ';
766             
767             cfg.tag = 'a';
768             
769 //            cfg.cls='btn roo-button';
770             
771             cfg.href=this.href;
772             
773             var value = cfg.html;
774             
775             if(this.glyphicon){
776                 value = {
777                             tag: 'span',
778                             cls: 'glyphicon glyphicon-' + this.glyphicon,
779                             html: this.html
780                         };
781                 
782             }
783             
784             cfg.cn = [
785                 value,
786                 {
787                     tag: 'span',
788                     cls: 'badge',
789                     html: this.badge
790                 }
791             ];
792             
793             cfg.html='';
794         }
795         
796         if (this.menu) {
797             cfg.cls += ' dropdown';
798             cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
799         }
800         
801         if (cfg.tag !== 'a' && this.href !== '') {
802             throw "Tag must be a to set href.";
803         } else if (this.href.length > 0) {
804             cfg.href = this.href;
805         }
806         
807         if(this.removeClass){
808             cfg.cls = '';
809         }
810         
811         if(this.target){
812             cfg.target = this.target;
813         }
814         
815         return cfg;
816     },
817     initEvents: function() {
818        // Roo.log('init events?');
819 //        Roo.log(this.el.dom);
820         // add the menu...
821         
822         if (typeof (this.menu) != 'undefined') {
823             this.menu.parentType = this.xtype;
824             this.menu.triggerEl = this.el;
825             this.addxtype(Roo.apply({}, this.menu));
826         }
827
828
829        if (this.el.hasClass('roo-button')) {
830             this.el.on('click', this.onClick, this);
831        } else {
832             this.el.select('.roo-button').on('click', this.onClick, this);
833        }
834        
835        if(this.removeClass){
836            this.el.on('click', this.onClick, this);
837        }
838        
839        this.el.enableDisplayMode();
840         
841     },
842     onClick : function(e)
843     {
844         if (this.disabled) {
845             return;
846         }
847         
848         
849         Roo.log('button on click ');
850         if(this.preventDefault){
851             e.preventDefault();
852         }
853         
854         if (this.pressed === true || this.pressed === false) {
855             this.pressed = !this.pressed;
856             this.el[this.pressed ? 'addClass' : 'removeClass']('active');
857             this.fireEvent('toggle', this, e, this.pressed);
858         }
859         
860         
861         this.fireEvent('click', this, e);
862     },
863     
864     /**
865      * Enables this button
866      */
867     enable : function()
868     {
869         this.disabled = false;
870         this.el.removeClass('disabled');
871     },
872     
873     /**
874      * Disable this button
875      */
876     disable : function()
877     {
878         this.disabled = true;
879         this.el.addClass('disabled');
880     },
881      /**
882      * sets the active state on/off, 
883      * @param {Boolean} state (optional) Force a particular state
884      */
885     setActive : function(v) {
886         
887         this.el[v ? 'addClass' : 'removeClass']('active');
888         this.pressed = v;
889     },
890      /**
891      * toggles the current active state 
892      */
893     toggleActive : function()
894     {
895        var active = this.el.hasClass('active');
896        this.setActive(!active);
897        
898         
899     },
900      /**
901      * get the current active state
902      * @return {boolean} true if it's active
903      */
904     isActive : function()
905     {
906         return this.el.hasClass('active');
907     },
908     /**
909      * set the text of the first selected button
910      */
911     setText : function(str)
912     {
913         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
914     },
915     /**
916      * get the text of the first selected button
917      */
918     getText : function()
919     {
920         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
921     },
922     hide: function() {
923        
924      
925         this.el.hide();   
926     },
927     show: function() {
928        
929         this.el.show();   
930     },
931     setWeight : function(str)
932     {
933         this.el.removeClass(this.weightClass);
934         this.el.addClass('btn-' + str);        
935     }
936     
937     
938 });
939
940  /*
941  * - LGPL
942  *
943  * column
944  * 
945  */
946
947 /**
948  * @class Roo.bootstrap.Column
949  * @extends Roo.bootstrap.Component
950  * Bootstrap Column class
951  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
952  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
953  * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
954  * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
955  * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
956  * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
957  * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
958  * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
959  *
960  * 
961  * @cfg {Boolean} hidden (true|false) hide the element
962  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
963  * @cfg {String} fa (ban|check|...) font awesome icon
964  * @cfg {Number} fasize (1|2|....) font awsome size
965
966  * @cfg {String} icon (info-sign|check|...) glyphicon name
967
968  * @cfg {String} html content of column.
969  * 
970  * @constructor
971  * Create a new Column
972  * @param {Object} config The config object
973  */
974
975 Roo.bootstrap.Column = function(config){
976     Roo.bootstrap.Column.superclass.constructor.call(this, config);
977 };
978
979 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
980     
981     xs: false,
982     sm: false,
983     md: false,
984     lg: false,
985     xsoff: false,
986     smoff: false,
987     mdoff: false,
988     lgoff: false,
989     html: '',
990     offset: 0,
991     alert: false,
992     fa: false,
993     icon : false,
994     hidden : false,
995     fasize : 1,
996     
997     getAutoCreate : function(){
998         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
999         
1000         cfg = {
1001             tag: 'div',
1002             cls: 'column'
1003         };
1004         
1005         var settings=this;
1006         ['xs','sm','md','lg'].map(function(size){
1007             //Roo.log( size + ':' + settings[size]);
1008             
1009             if (settings[size+'off'] !== false) {
1010                 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1011             }
1012             
1013             if (settings[size] === false) {
1014                 return;
1015             }
1016             
1017             if (!settings[size]) { // 0 = hidden
1018                 cfg.cls += ' hidden-' + size;
1019                 return;
1020             }
1021             cfg.cls += ' col-' + size + '-' + settings[size];
1022             
1023         });
1024         
1025         if (this.hidden) {
1026             cfg.cls += ' hidden';
1027         }
1028         
1029         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1030             cfg.cls +=' alert alert-' + this.alert;
1031         }
1032         
1033         
1034         if (this.html.length) {
1035             cfg.html = this.html;
1036         }
1037         if (this.fa) {
1038             var fasize = '';
1039             if (this.fasize > 1) {
1040                 fasize = ' fa-' + this.fasize + 'x';
1041             }
1042             cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1043             
1044             
1045         }
1046         if (this.icon) {
1047             cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' +  (cfg.html || '');
1048         }
1049         
1050         return cfg;
1051     }
1052    
1053 });
1054
1055  
1056
1057  /*
1058  * - LGPL
1059  *
1060  * page container.
1061  * 
1062  */
1063
1064
1065 /**
1066  * @class Roo.bootstrap.Container
1067  * @extends Roo.bootstrap.Component
1068  * Bootstrap Container class
1069  * @cfg {Boolean} jumbotron is it a jumbotron element
1070  * @cfg {String} html content of element
1071  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1072  * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel  - type - primary/success.....
1073  * @cfg {String} header content of header (for panel)
1074  * @cfg {String} footer content of footer (for panel)
1075  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1076  * @cfg {String} tag (header|aside|section) type of HTML tag.
1077  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1078  * @cfg {String} fa font awesome icon
1079  * @cfg {String} icon (info-sign|check|...) glyphicon name
1080  * @cfg {Boolean} hidden (true|false) hide the element
1081  * @cfg {Boolean} expandable (true|false) default false
1082  * @cfg {Boolean} expanded (true|false) default true
1083  * @cfg {String} rheader contet on the right of header
1084  * @cfg {Boolean} clickable (true|false) default false
1085
1086  *     
1087  * @constructor
1088  * Create a new Container
1089  * @param {Object} config The config object
1090  */
1091
1092 Roo.bootstrap.Container = function(config){
1093     Roo.bootstrap.Container.superclass.constructor.call(this, config);
1094     
1095     this.addEvents({
1096         // raw events
1097          /**
1098          * @event expand
1099          * After the panel has been expand
1100          * 
1101          * @param {Roo.bootstrap.Container} this
1102          */
1103         "expand" : true,
1104         /**
1105          * @event collapse
1106          * After the panel has been collapsed
1107          * 
1108          * @param {Roo.bootstrap.Container} this
1109          */
1110         "collapse" : true,
1111         /**
1112          * @event click
1113          * When a element is chick
1114          * @param {Roo.bootstrap.Container} this
1115          * @param {Roo.EventObject} e
1116          */
1117         "click" : true
1118     });
1119 };
1120
1121 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
1122     
1123     jumbotron : false,
1124     well: '',
1125     panel : '',
1126     header: '',
1127     footer : '',
1128     sticky: '',
1129     tag : false,
1130     alert : false,
1131     fa: false,
1132     icon : false,
1133     expandable : false,
1134     rheader : '',
1135     expanded : true,
1136     clickable: false,
1137   
1138      
1139     getChildContainer : function() {
1140         
1141         if(!this.el){
1142             return false;
1143         }
1144         
1145         if (this.panel.length) {
1146             return this.el.select('.panel-body',true).first();
1147         }
1148         
1149         return this.el;
1150     },
1151     
1152     
1153     getAutoCreate : function(){
1154         
1155         var cfg = {
1156             tag : this.tag || 'div',
1157             html : '',
1158             cls : ''
1159         };
1160         if (this.jumbotron) {
1161             cfg.cls = 'jumbotron';
1162         }
1163         
1164         
1165         
1166         // - this is applied by the parent..
1167         //if (this.cls) {
1168         //    cfg.cls = this.cls + '';
1169         //}
1170         
1171         if (this.sticky.length) {
1172             
1173             var bd = Roo.get(document.body);
1174             if (!bd.hasClass('bootstrap-sticky')) {
1175                 bd.addClass('bootstrap-sticky');
1176                 Roo.select('html',true).setStyle('height', '100%');
1177             }
1178              
1179             cfg.cls += 'bootstrap-sticky-' + this.sticky;
1180         }
1181         
1182         
1183         if (this.well.length) {
1184             switch (this.well) {
1185                 case 'lg':
1186                 case 'sm':
1187                     cfg.cls +=' well well-' +this.well;
1188                     break;
1189                 default:
1190                     cfg.cls +=' well';
1191                     break;
1192             }
1193         }
1194         
1195         if (this.hidden) {
1196             cfg.cls += ' hidden';
1197         }
1198         
1199         
1200         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1201             cfg.cls +=' alert alert-' + this.alert;
1202         }
1203         
1204         var body = cfg;
1205         
1206         if (this.panel.length) {
1207             cfg.cls += ' panel panel-' + this.panel;
1208             cfg.cn = [];
1209             if (this.header.length) {
1210                 
1211                 var h = [];
1212                 
1213                 if(this.expandable){
1214                     
1215                     cfg.cls = cfg.cls + ' expandable';
1216                     
1217                     h.push({
1218                         tag: 'i',
1219                         cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus') 
1220                     });
1221                     
1222                 }
1223                 
1224                 h.push(
1225                     {
1226                         tag: 'span',
1227                         cls : 'panel-title',
1228                         html : (this.expandable ? '&nbsp;' : '') + this.header
1229                     },
1230                     {
1231                         tag: 'span',
1232                         cls: 'panel-header-right',
1233                         html: this.rheader
1234                     }
1235                 );
1236                 
1237                 cfg.cn.push({
1238                     cls : 'panel-heading',
1239                     style : this.expandable ? 'cursor: pointer' : '',
1240                     cn : h
1241                 });
1242                 
1243             }
1244             
1245             body = false;
1246             cfg.cn.push({
1247                 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1248                 html : this.html
1249             });
1250             
1251             
1252             if (this.footer.length) {
1253                 cfg.cn.push({
1254                     cls : 'panel-footer',
1255                     html : this.footer
1256                     
1257                 });
1258             }
1259             
1260         }
1261         
1262         if (body) {
1263             body.html = this.html || cfg.html;
1264             // prefix with the icons..
1265             if (this.fa) {
1266                 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1267             }
1268             if (this.icon) {
1269                 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1270             }
1271             
1272             
1273         }
1274         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1275             cfg.cls =  'container';
1276         }
1277         
1278         return cfg;
1279     },
1280     
1281     initEvents: function() 
1282     {
1283         if(this.expandable){
1284             var headerEl = this.headerEl();
1285         
1286             if(headerEl){
1287                 headerEl.on('click', this.onToggleClick, this);
1288             }
1289         }
1290         
1291         if(this.clickable){
1292             this.el.on('click', this.onClick, this);
1293         }
1294         
1295     },
1296     
1297     onToggleClick : function()
1298     {
1299         var headerEl = this.headerEl();
1300         
1301         if(!headerEl){
1302             return;
1303         }
1304         
1305         if(this.expanded){
1306             this.collapse();
1307             return;
1308         }
1309         
1310         this.expand();
1311     },
1312     
1313     expand : function()
1314     {
1315         if(this.fireEvent('expand', this)) {
1316             
1317             this.expanded = true;
1318             
1319             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1320             
1321             this.el.select('.panel-body',true).first().removeClass('hide');
1322             
1323             var toggleEl = this.toggleEl();
1324
1325             if(!toggleEl){
1326                 return;
1327             }
1328
1329             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1330         }
1331         
1332     },
1333     
1334     collapse : function()
1335     {
1336         if(this.fireEvent('collapse', this)) {
1337             
1338             this.expanded = false;
1339             
1340             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1341             this.el.select('.panel-body',true).first().addClass('hide');
1342         
1343             var toggleEl = this.toggleEl();
1344
1345             if(!toggleEl){
1346                 return;
1347             }
1348
1349             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1350         }
1351     },
1352     
1353     toggleEl : function()
1354     {
1355         if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1356             return;
1357         }
1358         
1359         return this.el.select('.panel-heading .fa',true).first();
1360     },
1361     
1362     headerEl : function()
1363     {
1364         if(!this.el || !this.panel.length || !this.header.length){
1365             return;
1366         }
1367         
1368         return this.el.select('.panel-heading',true).first()
1369     },
1370     
1371     bodyEl : function()
1372     {
1373         if(!this.el || !this.panel.length){
1374             return;
1375         }
1376         
1377         return this.el.select('.panel-body',true).first()
1378     },
1379     
1380     titleEl : function()
1381     {
1382         if(!this.el || !this.panel.length || !this.header.length){
1383             return;
1384         }
1385         
1386         return this.el.select('.panel-title',true).first();
1387     },
1388     
1389     setTitle : function(v)
1390     {
1391         var titleEl = this.titleEl();
1392         
1393         if(!titleEl){
1394             return;
1395         }
1396         
1397         titleEl.dom.innerHTML = v;
1398     },
1399     
1400     getTitle : function()
1401     {
1402         
1403         var titleEl = this.titleEl();
1404         
1405         if(!titleEl){
1406             return '';
1407         }
1408         
1409         return titleEl.dom.innerHTML;
1410     },
1411     
1412     setRightTitle : function(v)
1413     {
1414         var t = this.el.select('.panel-header-right',true).first();
1415         
1416         if(!t){
1417             return;
1418         }
1419         
1420         t.dom.innerHTML = v;
1421     },
1422     
1423     onClick : function(e)
1424     {
1425         e.preventDefault();
1426         
1427         this.fireEvent('click', this, e);
1428     }
1429 });
1430
1431  /*
1432  * - LGPL
1433  *
1434  * image
1435  * 
1436  */
1437
1438
1439 /**
1440  * @class Roo.bootstrap.Img
1441  * @extends Roo.bootstrap.Component
1442  * Bootstrap Img class
1443  * @cfg {Boolean} imgResponsive false | true
1444  * @cfg {String} border rounded | circle | thumbnail
1445  * @cfg {String} src image source
1446  * @cfg {String} alt image alternative text
1447  * @cfg {String} href a tag href
1448  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1449  * @cfg {String} xsUrl xs image source
1450  * @cfg {String} smUrl sm image source
1451  * @cfg {String} mdUrl md image source
1452  * @cfg {String} lgUrl lg image source
1453  * 
1454  * @constructor
1455  * Create a new Input
1456  * @param {Object} config The config object
1457  */
1458
1459 Roo.bootstrap.Img = function(config){
1460     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1461     
1462     this.addEvents({
1463         // img events
1464         /**
1465          * @event click
1466          * The img click event for the img.
1467          * @param {Roo.EventObject} e
1468          */
1469         "click" : true
1470     });
1471 };
1472
1473 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1474     
1475     imgResponsive: true,
1476     border: '',
1477     src: 'about:blank',
1478     href: false,
1479     target: false,
1480     xsUrl: '',
1481     smUrl: '',
1482     mdUrl: '',
1483     lgUrl: '',
1484
1485     getAutoCreate : function()
1486     {   
1487         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1488             return this.createSingleImg();
1489         }
1490         
1491         var cfg = {
1492             tag: 'div',
1493             cls: 'roo-image-responsive-group',
1494             cn: []
1495         };
1496         var _this = this;
1497         
1498         Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1499             
1500             if(!_this[size + 'Url']){
1501                 return;
1502             }
1503             
1504             var img = {
1505                 tag: 'img',
1506                 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1507                 html: _this.html || cfg.html,
1508                 src: _this[size + 'Url']
1509             };
1510             
1511             img.cls += ' roo-image-responsive-' + size;
1512             
1513             var s = ['xs', 'sm', 'md', 'lg'];
1514             
1515             s.splice(s.indexOf(size), 1);
1516             
1517             Roo.each(s, function(ss){
1518                 img.cls += ' hidden-' + ss;
1519             });
1520             
1521             if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1522                 cfg.cls += ' img-' + _this.border;
1523             }
1524             
1525             if(_this.alt){
1526                 cfg.alt = _this.alt;
1527             }
1528             
1529             if(_this.href){
1530                 var a = {
1531                     tag: 'a',
1532                     href: _this.href,
1533                     cn: [
1534                         img
1535                     ]
1536                 };
1537
1538                 if(this.target){
1539                     a.target = _this.target;
1540                 }
1541             }
1542             
1543             cfg.cn.push((_this.href) ? a : img);
1544             
1545         });
1546         
1547         return cfg;
1548     },
1549     
1550     createSingleImg : function()
1551     {
1552         var cfg = {
1553             tag: 'img',
1554             cls: (this.imgResponsive) ? 'img-responsive' : '',
1555             html : null,
1556             src : 'about:blank'  // just incase src get's set to undefined?!?
1557         };
1558         
1559         cfg.html = this.html || cfg.html;
1560         
1561         cfg.src = this.src || cfg.src;
1562         
1563         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1564             cfg.cls += ' img-' + this.border;
1565         }
1566         
1567         if(this.alt){
1568             cfg.alt = this.alt;
1569         }
1570         
1571         if(this.href){
1572             var a = {
1573                 tag: 'a',
1574                 href: this.href,
1575                 cn: [
1576                     cfg
1577                 ]
1578             };
1579             
1580             if(this.target){
1581                 a.target = this.target;
1582             }
1583             
1584         }
1585         
1586         return (this.href) ? a : cfg;
1587     },
1588     
1589     initEvents: function() 
1590     {
1591         if(!this.href){
1592             this.el.on('click', this.onClick, this);
1593         }
1594         
1595     },
1596     
1597     onClick : function(e)
1598     {
1599         Roo.log('img onclick');
1600         this.fireEvent('click', this, e);
1601     },
1602     /**
1603      * Sets the url of the image - used to update it
1604      * @param {String} url the url of the image
1605      */
1606     
1607     setSrc : function(url)
1608     {
1609         this.src =  url;
1610         
1611         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1612             this.el.dom.src =  url;
1613             return;
1614         }
1615         
1616         this.el.select('img', true).first().dom.src =  url;
1617     }
1618     
1619     
1620    
1621 });
1622
1623  /*
1624  * - LGPL
1625  *
1626  * image
1627  * 
1628  */
1629
1630
1631 /**
1632  * @class Roo.bootstrap.Link
1633  * @extends Roo.bootstrap.Component
1634  * Bootstrap Link Class
1635  * @cfg {String} alt image alternative text
1636  * @cfg {String} href a tag href
1637  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1638  * @cfg {String} html the content of the link.
1639  * @cfg {String} anchor name for the anchor link
1640  * @cfg {String} fa - favicon
1641
1642  * @cfg {Boolean} preventDefault (true | false) default false
1643
1644  * 
1645  * @constructor
1646  * Create a new Input
1647  * @param {Object} config The config object
1648  */
1649
1650 Roo.bootstrap.Link = function(config){
1651     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1652     
1653     this.addEvents({
1654         // img events
1655         /**
1656          * @event click
1657          * The img click event for the img.
1658          * @param {Roo.EventObject} e
1659          */
1660         "click" : true
1661     });
1662 };
1663
1664 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1665     
1666     href: false,
1667     target: false,
1668     preventDefault: false,
1669     anchor : false,
1670     alt : false,
1671     fa: false,
1672
1673
1674     getAutoCreate : function()
1675     {
1676         var html = this.html || '';
1677         
1678         if (this.fa !== false) {
1679             html = '<i class="fa fa-' + this.fa + '"></i>';
1680         }
1681         var cfg = {
1682             tag: 'a'
1683         };
1684         // anchor's do not require html/href...
1685         if (this.anchor === false) {
1686             cfg.html = html;
1687             cfg.href = this.href || '#';
1688         } else {
1689             cfg.name = this.anchor;
1690             if (this.html !== false || this.fa !== false) {
1691                 cfg.html = html;
1692             }
1693             if (this.href !== false) {
1694                 cfg.href = this.href;
1695             }
1696         }
1697         
1698         if(this.alt !== false){
1699             cfg.alt = this.alt;
1700         }
1701         
1702         
1703         if(this.target !== false) {
1704             cfg.target = this.target;
1705         }
1706         
1707         return cfg;
1708     },
1709     
1710     initEvents: function() {
1711         
1712         if(!this.href || this.preventDefault){
1713             this.el.on('click', this.onClick, this);
1714         }
1715     },
1716     
1717     onClick : function(e)
1718     {
1719         if(this.preventDefault){
1720             e.preventDefault();
1721         }
1722         //Roo.log('img onclick');
1723         this.fireEvent('click', this, e);
1724     }
1725    
1726 });
1727
1728  /*
1729  * - LGPL
1730  *
1731  * header
1732  * 
1733  */
1734
1735 /**
1736  * @class Roo.bootstrap.Header
1737  * @extends Roo.bootstrap.Component
1738  * Bootstrap Header class
1739  * @cfg {String} html content of header
1740  * @cfg {Number} level (1|2|3|4|5|6) default 1
1741  * 
1742  * @constructor
1743  * Create a new Header
1744  * @param {Object} config The config object
1745  */
1746
1747
1748 Roo.bootstrap.Header  = function(config){
1749     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1750 };
1751
1752 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1753     
1754     //href : false,
1755     html : false,
1756     level : 1,
1757     
1758     
1759     
1760     getAutoCreate : function(){
1761         
1762         
1763         
1764         var cfg = {
1765             tag: 'h' + (1 *this.level),
1766             html: this.html || ''
1767         } ;
1768         
1769         return cfg;
1770     }
1771    
1772 });
1773
1774  
1775
1776  /*
1777  * Based on:
1778  * Ext JS Library 1.1.1
1779  * Copyright(c) 2006-2007, Ext JS, LLC.
1780  *
1781  * Originally Released Under LGPL - original licence link has changed is not relivant.
1782  *
1783  * Fork - LGPL
1784  * <script type="text/javascript">
1785  */
1786  
1787 /**
1788  * @class Roo.bootstrap.MenuMgr
1789  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1790  * @singleton
1791  */
1792 Roo.bootstrap.MenuMgr = function(){
1793    var menus, active, groups = {}, attached = false, lastShow = new Date();
1794
1795    // private - called when first menu is created
1796    function init(){
1797        menus = {};
1798        active = new Roo.util.MixedCollection();
1799        Roo.get(document).addKeyListener(27, function(){
1800            if(active.length > 0){
1801                hideAll();
1802            }
1803        });
1804    }
1805
1806    // private
1807    function hideAll(){
1808        if(active && active.length > 0){
1809            var c = active.clone();
1810            c.each(function(m){
1811                m.hide();
1812            });
1813        }
1814    }
1815
1816    // private
1817    function onHide(m){
1818        active.remove(m);
1819        if(active.length < 1){
1820            Roo.get(document).un("mouseup", onMouseDown);
1821             
1822            attached = false;
1823        }
1824    }
1825
1826    // private
1827    function onShow(m){
1828        var last = active.last();
1829        lastShow = new Date();
1830        active.add(m);
1831        if(!attached){
1832           Roo.get(document).on("mouseup", onMouseDown);
1833            
1834            attached = true;
1835        }
1836        if(m.parentMenu){
1837           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1838           m.parentMenu.activeChild = m;
1839        }else if(last && last.isVisible()){
1840           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1841        }
1842    }
1843
1844    // private
1845    function onBeforeHide(m){
1846        if(m.activeChild){
1847            m.activeChild.hide();
1848        }
1849        if(m.autoHideTimer){
1850            clearTimeout(m.autoHideTimer);
1851            delete m.autoHideTimer;
1852        }
1853    }
1854
1855    // private
1856    function onBeforeShow(m){
1857        var pm = m.parentMenu;
1858        if(!pm && !m.allowOtherMenus){
1859            hideAll();
1860        }else if(pm && pm.activeChild && active != m){
1861            pm.activeChild.hide();
1862        }
1863    }
1864
1865    // private this should really trigger on mouseup..
1866    function onMouseDown(e){
1867         Roo.log("on Mouse Up");
1868         
1869         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1870             Roo.log("MenuManager hideAll");
1871             hideAll();
1872             e.stopEvent();
1873         }
1874         
1875         
1876    }
1877
1878    // private
1879    function onBeforeCheck(mi, state){
1880        if(state){
1881            var g = groups[mi.group];
1882            for(var i = 0, l = g.length; i < l; i++){
1883                if(g[i] != mi){
1884                    g[i].setChecked(false);
1885                }
1886            }
1887        }
1888    }
1889
1890    return {
1891
1892        /**
1893         * Hides all menus that are currently visible
1894         */
1895        hideAll : function(){
1896             hideAll();  
1897        },
1898
1899        // private
1900        register : function(menu){
1901            if(!menus){
1902                init();
1903            }
1904            menus[menu.id] = menu;
1905            menu.on("beforehide", onBeforeHide);
1906            menu.on("hide", onHide);
1907            menu.on("beforeshow", onBeforeShow);
1908            menu.on("show", onShow);
1909            var g = menu.group;
1910            if(g && menu.events["checkchange"]){
1911                if(!groups[g]){
1912                    groups[g] = [];
1913                }
1914                groups[g].push(menu);
1915                menu.on("checkchange", onCheck);
1916            }
1917        },
1918
1919         /**
1920          * Returns a {@link Roo.menu.Menu} object
1921          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1922          * be used to generate and return a new Menu instance.
1923          */
1924        get : function(menu){
1925            if(typeof menu == "string"){ // menu id
1926                return menus[menu];
1927            }else if(menu.events){  // menu instance
1928                return menu;
1929            }
1930            /*else if(typeof menu.length == 'number'){ // array of menu items?
1931                return new Roo.bootstrap.Menu({items:menu});
1932            }else{ // otherwise, must be a config
1933                return new Roo.bootstrap.Menu(menu);
1934            }
1935            */
1936            return false;
1937        },
1938
1939        // private
1940        unregister : function(menu){
1941            delete menus[menu.id];
1942            menu.un("beforehide", onBeforeHide);
1943            menu.un("hide", onHide);
1944            menu.un("beforeshow", onBeforeShow);
1945            menu.un("show", onShow);
1946            var g = menu.group;
1947            if(g && menu.events["checkchange"]){
1948                groups[g].remove(menu);
1949                menu.un("checkchange", onCheck);
1950            }
1951        },
1952
1953        // private
1954        registerCheckable : function(menuItem){
1955            var g = menuItem.group;
1956            if(g){
1957                if(!groups[g]){
1958                    groups[g] = [];
1959                }
1960                groups[g].push(menuItem);
1961                menuItem.on("beforecheckchange", onBeforeCheck);
1962            }
1963        },
1964
1965        // private
1966        unregisterCheckable : function(menuItem){
1967            var g = menuItem.group;
1968            if(g){
1969                groups[g].remove(menuItem);
1970                menuItem.un("beforecheckchange", onBeforeCheck);
1971            }
1972        }
1973    };
1974 }();/*
1975  * - LGPL
1976  *
1977  * menu
1978  * 
1979  */
1980
1981 /**
1982  * @class Roo.bootstrap.Menu
1983  * @extends Roo.bootstrap.Component
1984  * Bootstrap Menu class - container for MenuItems
1985  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1986  * @cfg {bool} hidden  if the menu should be hidden when rendered.
1987  * @cfg {bool} stopEvent (true|false)  Stop event after trigger press (default true)
1988  * @cfg {bool} isLink (true|false)  the menu has link disable auto expand and collaspe (default false)
1989  * 
1990  * @constructor
1991  * Create a new Menu
1992  * @param {Object} config The config object
1993  */
1994
1995
1996 Roo.bootstrap.Menu = function(config){
1997     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1998     if (this.registerMenu && this.type != 'treeview')  {
1999         Roo.bootstrap.MenuMgr.register(this);
2000     }
2001     this.addEvents({
2002         /**
2003          * @event beforeshow
2004          * Fires before this menu is displayed
2005          * @param {Roo.menu.Menu} this
2006          */
2007         beforeshow : true,
2008         /**
2009          * @event beforehide
2010          * Fires before this menu is hidden
2011          * @param {Roo.menu.Menu} this
2012          */
2013         beforehide : true,
2014         /**
2015          * @event show
2016          * Fires after this menu is displayed
2017          * @param {Roo.menu.Menu} this
2018          */
2019         show : true,
2020         /**
2021          * @event hide
2022          * Fires after this menu is hidden
2023          * @param {Roo.menu.Menu} this
2024          */
2025         hide : true,
2026         /**
2027          * @event click
2028          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2029          * @param {Roo.menu.Menu} this
2030          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2031          * @param {Roo.EventObject} e
2032          */
2033         click : true,
2034         /**
2035          * @event mouseover
2036          * Fires when the mouse is hovering over this menu
2037          * @param {Roo.menu.Menu} this
2038          * @param {Roo.EventObject} e
2039          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2040          */
2041         mouseover : true,
2042         /**
2043          * @event mouseout
2044          * Fires when the mouse exits this menu
2045          * @param {Roo.menu.Menu} this
2046          * @param {Roo.EventObject} e
2047          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2048          */
2049         mouseout : true,
2050         /**
2051          * @event itemclick
2052          * Fires when a menu item contained in this menu is clicked
2053          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2054          * @param {Roo.EventObject} e
2055          */
2056         itemclick: true
2057     });
2058     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2059 };
2060
2061 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
2062     
2063    /// html : false,
2064     //align : '',
2065     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
2066     type: false,
2067     /**
2068      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2069      */
2070     registerMenu : true,
2071     
2072     menuItems :false, // stores the menu items..
2073     
2074     hidden:true,
2075         
2076     parentMenu : false,
2077     
2078     stopEvent : true,
2079     
2080     isLink : false,
2081     
2082     getChildContainer : function() {
2083         return this.el;  
2084     },
2085     
2086     getAutoCreate : function(){
2087          
2088         //if (['right'].indexOf(this.align)!==-1) {
2089         //    cfg.cn[1].cls += ' pull-right'
2090         //}
2091         
2092         
2093         var cfg = {
2094             tag : 'ul',
2095             cls : 'dropdown-menu' ,
2096             style : 'z-index:1000'
2097             
2098         };
2099         
2100         if (this.type === 'submenu') {
2101             cfg.cls = 'submenu active';
2102         }
2103         if (this.type === 'treeview') {
2104             cfg.cls = 'treeview-menu';
2105         }
2106         
2107         return cfg;
2108     },
2109     initEvents : function() {
2110         
2111        // Roo.log("ADD event");
2112        // Roo.log(this.triggerEl.dom);
2113         
2114         this.triggerEl.on('click', this.onTriggerClick, this);
2115         
2116         this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2117         
2118         this.triggerEl.addClass('dropdown-toggle');
2119         
2120         if (Roo.isTouch) {
2121             this.el.on('touchstart'  , this.onTouch, this);
2122         }
2123         this.el.on('click' , this.onClick, this);
2124
2125         this.el.on("mouseover", this.onMouseOver, this);
2126         this.el.on("mouseout", this.onMouseOut, this);
2127         
2128     },
2129     
2130     findTargetItem : function(e)
2131     {
2132         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
2133         if(!t){
2134             return false;
2135         }
2136         //Roo.log(t);         Roo.log(t.id);
2137         if(t && t.id){
2138             //Roo.log(this.menuitems);
2139             return this.menuitems.get(t.id);
2140             
2141             //return this.items.get(t.menuItemId);
2142         }
2143         
2144         return false;
2145     },
2146     
2147     onTouch : function(e) 
2148     {
2149         Roo.log("menu.onTouch");
2150         //e.stopEvent(); this make the user popdown broken
2151         this.onClick(e);
2152     },
2153     
2154     onClick : function(e)
2155     {
2156         Roo.log("menu.onClick");
2157         
2158         var t = this.findTargetItem(e);
2159         if(!t || t.isContainer){
2160             return;
2161         }
2162         Roo.log(e);
2163         /*
2164         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
2165             if(t == this.activeItem && t.shouldDeactivate(e)){
2166                 this.activeItem.deactivate();
2167                 delete this.activeItem;
2168                 return;
2169             }
2170             if(t.canActivate){
2171                 this.setActiveItem(t, true);
2172             }
2173             return;
2174             
2175             
2176         }
2177         */
2178        
2179         Roo.log('pass click event');
2180         
2181         t.onClick(e);
2182         
2183         this.fireEvent("click", this, t, e);
2184         
2185         var _this = this;
2186         
2187         if(!t.href.length || t.href == '#'){
2188             (function() { _this.hide(); }).defer(100);
2189         }
2190         
2191     },
2192     
2193     onMouseOver : function(e){
2194         var t  = this.findTargetItem(e);
2195         //Roo.log(t);
2196         //if(t){
2197         //    if(t.canActivate && !t.disabled){
2198         //        this.setActiveItem(t, true);
2199         //    }
2200         //}
2201         
2202         this.fireEvent("mouseover", this, e, t);
2203     },
2204     isVisible : function(){
2205         return !this.hidden;
2206     },
2207      onMouseOut : function(e){
2208         var t  = this.findTargetItem(e);
2209         
2210         //if(t ){
2211         //    if(t == this.activeItem && t.shouldDeactivate(e)){
2212         //        this.activeItem.deactivate();
2213         //        delete this.activeItem;
2214         //    }
2215         //}
2216         this.fireEvent("mouseout", this, e, t);
2217     },
2218     
2219     
2220     /**
2221      * Displays this menu relative to another element
2222      * @param {String/HTMLElement/Roo.Element} element The element to align to
2223      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2224      * the element (defaults to this.defaultAlign)
2225      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2226      */
2227     show : function(el, pos, parentMenu){
2228         this.parentMenu = parentMenu;
2229         if(!this.el){
2230             this.render();
2231         }
2232         this.fireEvent("beforeshow", this);
2233         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2234     },
2235      /**
2236      * Displays this menu at a specific xy position
2237      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2238      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2239      */
2240     showAt : function(xy, parentMenu, /* private: */_e){
2241         this.parentMenu = parentMenu;
2242         if(!this.el){
2243             this.render();
2244         }
2245         if(_e !== false){
2246             this.fireEvent("beforeshow", this);
2247             //xy = this.el.adjustForConstraints(xy);
2248         }
2249         
2250         //this.el.show();
2251         this.hideMenuItems();
2252         this.hidden = false;
2253         this.triggerEl.addClass('open');
2254         
2255         if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2256             xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2257         }
2258         
2259         if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2260             this.el.setXY(xy);
2261         }
2262         
2263         this.focus();
2264         this.fireEvent("show", this);
2265     },
2266     
2267     focus : function(){
2268         return;
2269         if(!this.hidden){
2270             this.doFocus.defer(50, this);
2271         }
2272     },
2273
2274     doFocus : function(){
2275         if(!this.hidden){
2276             this.focusEl.focus();
2277         }
2278     },
2279
2280     /**
2281      * Hides this menu and optionally all parent menus
2282      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2283      */
2284     hide : function(deep)
2285     {
2286         
2287         this.hideMenuItems();
2288         if(this.el && this.isVisible()){
2289             this.fireEvent("beforehide", this);
2290             if(this.activeItem){
2291                 this.activeItem.deactivate();
2292                 this.activeItem = null;
2293             }
2294             this.triggerEl.removeClass('open');;
2295             this.hidden = true;
2296             this.fireEvent("hide", this);
2297         }
2298         if(deep === true && this.parentMenu){
2299             this.parentMenu.hide(true);
2300         }
2301     },
2302     
2303     onTriggerClick : function(e)
2304     {
2305         Roo.log('trigger click');
2306         
2307         var target = e.getTarget();
2308         
2309         Roo.log(target.nodeName.toLowerCase());
2310         
2311         if(target.nodeName.toLowerCase() === 'i'){
2312             e.preventDefault();
2313         }
2314         
2315     },
2316     
2317     onTriggerPress  : function(e)
2318     {
2319         Roo.log('trigger press');
2320         //Roo.log(e.getTarget());
2321        // Roo.log(this.triggerEl.dom);
2322        
2323         // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2324         var pel = Roo.get(e.getTarget());
2325         if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2326             Roo.log('is treeview or dropdown?');
2327             return;
2328         }
2329         
2330         if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2331             return;
2332         }
2333         
2334         if (this.isVisible()) {
2335             Roo.log('hide');
2336             this.hide();
2337         } else {
2338             Roo.log('show');
2339             this.show(this.triggerEl, false, false);
2340         }
2341         
2342         if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2343             e.stopEvent();
2344         }
2345         
2346     },
2347        
2348     
2349     hideMenuItems : function()
2350     {
2351         Roo.log("hide Menu Items");
2352         if (!this.el) { 
2353             return;
2354         }
2355         //$(backdrop).remove()
2356         this.el.select('.open',true).each(function(aa) {
2357             
2358             aa.removeClass('open');
2359           //var parent = getParent($(this))
2360           //var relatedTarget = { relatedTarget: this }
2361           
2362            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2363           //if (e.isDefaultPrevented()) return
2364            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2365         });
2366     },
2367     addxtypeChild : function (tree, cntr) {
2368         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2369           
2370         this.menuitems.add(comp);
2371         return comp;
2372
2373     },
2374     getEl : function()
2375     {
2376         Roo.log(this.el);
2377         return this.el;
2378     },
2379     
2380     clear : function()
2381     {
2382         this.getEl().dom.innerHTML = '';
2383         this.menuitems.clear();
2384     }
2385 });
2386
2387  
2388  /*
2389  * - LGPL
2390  *
2391  * menu item
2392  * 
2393  */
2394
2395
2396 /**
2397  * @class Roo.bootstrap.MenuItem
2398  * @extends Roo.bootstrap.Component
2399  * Bootstrap MenuItem class
2400  * @cfg {String} html the menu label
2401  * @cfg {String} href the link
2402  * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2403  * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2404  * @cfg {Boolean} active  used on sidebars to highlight active itesm
2405  * @cfg {String} fa favicon to show on left of menu item.
2406  * @cfg {Roo.bootsrap.Menu} menu the child menu.
2407  * 
2408  * 
2409  * @constructor
2410  * Create a new MenuItem
2411  * @param {Object} config The config object
2412  */
2413
2414
2415 Roo.bootstrap.MenuItem = function(config){
2416     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2417     this.addEvents({
2418         // raw events
2419         /**
2420          * @event click
2421          * The raw click event for the entire grid.
2422          * @param {Roo.bootstrap.MenuItem} this
2423          * @param {Roo.EventObject} e
2424          */
2425         "click" : true
2426     });
2427 };
2428
2429 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
2430     
2431     href : false,
2432     html : false,
2433     preventDefault: false,
2434     isContainer : false,
2435     active : false,
2436     fa: false,
2437     
2438     getAutoCreate : function(){
2439         
2440         if(this.isContainer){
2441             return {
2442                 tag: 'li',
2443                 cls: 'dropdown-menu-item'
2444             };
2445         }
2446         var ctag = {
2447             tag: 'span',
2448             html: 'Link'
2449         };
2450         
2451         var anc = {
2452             tag : 'a',
2453             href : '#',
2454             cn : [  ]
2455         };
2456         
2457         if (this.fa !== false) {
2458             anc.cn.push({
2459                 tag : 'i',
2460                 cls : 'fa fa-' + this.fa
2461             });
2462         }
2463         
2464         anc.cn.push(ctag);
2465         
2466         
2467         var cfg= {
2468             tag: 'li',
2469             cls: 'dropdown-menu-item',
2470             cn: [ anc ]
2471         };
2472         if (this.parent().type == 'treeview') {
2473             cfg.cls = 'treeview-menu';
2474         }
2475         if (this.active) {
2476             cfg.cls += ' active';
2477         }
2478         
2479         
2480         
2481         anc.href = this.href || cfg.cn[0].href ;
2482         ctag.html = this.html || cfg.cn[0].html ;
2483         return cfg;
2484     },
2485     
2486     initEvents: function()
2487     {
2488         if (this.parent().type == 'treeview') {
2489             this.el.select('a').on('click', this.onClick, this);
2490         }
2491         
2492         if (this.menu) {
2493             this.menu.parentType = this.xtype;
2494             this.menu.triggerEl = this.el;
2495             this.menu = this.addxtype(Roo.apply({}, this.menu));
2496         }
2497         
2498     },
2499     onClick : function(e)
2500     {
2501         Roo.log('item on click ');
2502         
2503         if(this.preventDefault){
2504             e.preventDefault();
2505         }
2506         //this.parent().hideMenuItems();
2507         
2508         this.fireEvent('click', this, e);
2509     },
2510     getEl : function()
2511     {
2512         return this.el;
2513     } 
2514 });
2515
2516  
2517
2518  /*
2519  * - LGPL
2520  *
2521  * menu separator
2522  * 
2523  */
2524
2525
2526 /**
2527  * @class Roo.bootstrap.MenuSeparator
2528  * @extends Roo.bootstrap.Component
2529  * Bootstrap MenuSeparator class
2530  * 
2531  * @constructor
2532  * Create a new MenuItem
2533  * @param {Object} config The config object
2534  */
2535
2536
2537 Roo.bootstrap.MenuSeparator = function(config){
2538     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2539 };
2540
2541 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2542     
2543     getAutoCreate : function(){
2544         var cfg = {
2545             cls: 'divider',
2546             tag : 'li'
2547         };
2548         
2549         return cfg;
2550     }
2551    
2552 });
2553
2554  
2555
2556  
2557 /*
2558 * Licence: LGPL
2559 */
2560
2561 /**
2562  * @class Roo.bootstrap.Modal
2563  * @extends Roo.bootstrap.Component
2564  * Bootstrap Modal class
2565  * @cfg {String} title Title of dialog
2566  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2567  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn
2568  * @cfg {Boolean} specificTitle default false
2569  * @cfg {Array} buttons Array of buttons or standard button set..
2570  * @cfg {String} buttonPosition (left|right|center) default right
2571  * @cfg {Boolean} animate default true
2572  * @cfg {Boolean} allow_close default true
2573  * @cfg {Boolean} fitwindow default false
2574  * @cfg {String} size (sm|lg) default empty
2575  *
2576  *
2577  * @constructor
2578  * Create a new Modal Dialog
2579  * @param {Object} config The config object
2580  */
2581
2582 Roo.bootstrap.Modal = function(config){
2583     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2584     this.addEvents({
2585         // raw events
2586         /**
2587          * @event btnclick
2588          * The raw btnclick event for the button
2589          * @param {Roo.EventObject} e
2590          */
2591         "btnclick" : true,
2592         /**
2593          * @event resize
2594          * Fire when dialog resize
2595          * @param {Roo.bootstrap.Modal} this
2596          * @param {Roo.EventObject} e
2597          */
2598         "resize" : true
2599     });
2600     this.buttons = this.buttons || [];
2601
2602     if (this.tmpl) {
2603         this.tmpl = Roo.factory(this.tmpl);
2604     }
2605
2606 };
2607
2608 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2609
2610     title : 'test dialog',
2611
2612     buttons : false,
2613
2614     // set on load...
2615
2616     html: false,
2617
2618     tmp: false,
2619
2620     specificTitle: false,
2621
2622     buttonPosition: 'right',
2623
2624     allow_close : true,
2625
2626     animate : true,
2627
2628     fitwindow: false,
2629
2630
2631      // private
2632     dialogEl: false,
2633     bodyEl:  false,
2634     footerEl:  false,
2635     titleEl:  false,
2636     closeEl:  false,
2637
2638     size: '',
2639
2640
2641     onRender : function(ct, position)
2642     {
2643         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2644
2645         if(!this.el){
2646             var cfg = Roo.apply({},  this.getAutoCreate());
2647             cfg.id = Roo.id();
2648             //if(!cfg.name){
2649             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2650             //}
2651             //if (!cfg.name.length) {
2652             //    delete cfg.name;
2653            // }
2654             if (this.cls) {
2655                 cfg.cls += ' ' + this.cls;
2656             }
2657             if (this.style) {
2658                 cfg.style = this.style;
2659             }
2660             this.el = Roo.get(document.body).createChild(cfg, position);
2661         }
2662         //var type = this.el.dom.type;
2663
2664
2665         if(this.tabIndex !== undefined){
2666             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2667         }
2668
2669         this.dialogEl = this.el.select('.modal-dialog',true).first();
2670         this.bodyEl = this.el.select('.modal-body',true).first();
2671         this.closeEl = this.el.select('.modal-header .close', true).first();
2672         this.headerEl = this.el.select('.modal-header',true).first();
2673         this.titleEl = this.el.select('.modal-title',true).first();
2674         this.footerEl = this.el.select('.modal-footer',true).first();
2675
2676         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2677         this.maskEl.enableDisplayMode("block");
2678         this.maskEl.hide();
2679         //this.el.addClass("x-dlg-modal");
2680
2681         if (this.buttons.length) {
2682             Roo.each(this.buttons, function(bb) {
2683                 var b = Roo.apply({}, bb);
2684                 b.xns = b.xns || Roo.bootstrap;
2685                 b.xtype = b.xtype || 'Button';
2686                 if (typeof(b.listeners) == 'undefined') {
2687                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2688                 }
2689
2690                 var btn = Roo.factory(b);
2691
2692                 btn.render(this.el.select('.modal-footer div').first());
2693
2694             },this);
2695         }
2696         // render the children.
2697         var nitems = [];
2698
2699         if(typeof(this.items) != 'undefined'){
2700             var items = this.items;
2701             delete this.items;
2702
2703             for(var i =0;i < items.length;i++) {
2704                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2705             }
2706         }
2707
2708         this.items = nitems;
2709
2710         // where are these used - they used to be body/close/footer
2711
2712
2713         this.initEvents();
2714         //this.el.addClass([this.fieldClass, this.cls]);
2715
2716     },
2717
2718     getAutoCreate : function(){
2719
2720
2721         var bdy = {
2722                 cls : 'modal-body',
2723                 html : this.html || ''
2724         };
2725
2726         var title = {
2727             tag: 'h4',
2728             cls : 'modal-title',
2729             html : this.title
2730         };
2731
2732         if(this.specificTitle){
2733             title = this.title;
2734
2735         };
2736
2737         var header = [];
2738         if (this.allow_close) {
2739             header.push({
2740                 tag: 'button',
2741                 cls : 'close',
2742                 html : '&times'
2743             });
2744         }
2745
2746         header.push(title);
2747
2748         var size = '';
2749
2750         if(this.size.length){
2751             size = 'modal-' + this.size;
2752         }
2753
2754         var modal = {
2755             cls: "modal",
2756             style : 'display: none',
2757             cn : [
2758                 {
2759                     cls: "modal-dialog " + size,
2760                     cn : [
2761                         {
2762                             cls : "modal-content",
2763                             cn : [
2764                                 {
2765                                     cls : 'modal-header',
2766                                     cn : header
2767                                 },
2768                                 bdy,
2769                                 {
2770                                     cls : 'modal-footer',
2771                                     cn : [
2772                                         {
2773                                             tag: 'div',
2774                                             cls: 'btn-' + this.buttonPosition
2775                                         }
2776                                     ]
2777
2778                                 }
2779
2780
2781                             ]
2782
2783                         }
2784                     ]
2785
2786                 }
2787             ]
2788         };
2789
2790         if(this.animate){
2791             modal.cls += ' fade';
2792         }
2793
2794         return modal;
2795
2796     },
2797     getChildContainer : function() {
2798
2799          return this.bodyEl;
2800
2801     },
2802     getButtonContainer : function() {
2803          return this.el.select('.modal-footer div',true).first();
2804
2805     },
2806     initEvents : function()
2807     {
2808         if (this.allow_close) {
2809             this.closeEl.on('click', this.hide, this);
2810         }
2811         Roo.EventManager.onWindowResize(this.resize, this, true);
2812
2813
2814     },
2815
2816     resize : function()
2817     {
2818         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),  Roo.lib.Dom.getViewHeight(true));
2819         if (this.fitwindow) {
2820             var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2821             var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2822             this.setSize(w,h);
2823         }
2824     },
2825
2826     setSize : function(w,h)
2827     {
2828         if (!w && !h) {
2829             return;
2830         }
2831         this.resizeTo(w,h);
2832     },
2833
2834     show : function() {
2835
2836         if (!this.rendered) {
2837             this.render();
2838         }
2839
2840         this.el.setStyle('display', 'block');
2841
2842         if(this.animate){  // element has 'fade'  - so stuff happens after .3s ?- not sure why the delay?
2843             var _this = this;
2844             (function(){
2845                 this.el.addClass('in');
2846             }).defer(50, this);
2847         }else{
2848             this.el.addClass('in');
2849
2850         }
2851
2852         // not sure how we can show data in here..
2853         //if (this.tmpl) {
2854         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2855         //}
2856
2857         Roo.get(document.body).addClass("x-body-masked");
2858         
2859         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),   Roo.lib.Dom.getViewHeight(true));
2860         this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2861         this.maskEl.show();
2862         
2863         this.resize();
2864         
2865         this.fireEvent('show', this);
2866
2867         // set zindex here - otherwise it appears to be ignored...
2868         this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2869
2870         (function () {
2871             this.items.forEach( function(e) {
2872                 e.layout ? e.layout() : false;
2873
2874             });
2875         }).defer(100,this);
2876
2877     },
2878     hide : function()
2879     {
2880         if(this.fireEvent("beforehide", this) !== false){
2881             this.maskEl.hide();
2882             Roo.get(document.body).removeClass("x-body-masked");
2883             this.el.removeClass('in');
2884             this.el.select('.modal-dialog', true).first().setStyle('transform','');
2885
2886             if(this.animate){ // why
2887                 var _this = this;
2888                 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2889             }else{
2890                 this.el.setStyle('display', 'none');
2891             }
2892             this.fireEvent('hide', this);
2893         }
2894     },
2895
2896     addButton : function(str, cb)
2897     {
2898
2899
2900         var b = Roo.apply({}, { html : str } );
2901         b.xns = b.xns || Roo.bootstrap;
2902         b.xtype = b.xtype || 'Button';
2903         if (typeof(b.listeners) == 'undefined') {
2904             b.listeners = { click : cb.createDelegate(this)  };
2905         }
2906
2907         var btn = Roo.factory(b);
2908
2909         btn.render(this.el.select('.modal-footer div').first());
2910
2911         return btn;
2912
2913     },
2914
2915     setDefaultButton : function(btn)
2916     {
2917         //this.el.select('.modal-footer').()
2918     },
2919     diff : false,
2920
2921     resizeTo: function(w,h)
2922     {
2923         // skip.. ?? why??
2924
2925         this.dialogEl.setWidth(w);
2926         if (this.diff === false) {
2927             this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2928         }
2929
2930         this.bodyEl.setHeight(h-this.diff);
2931
2932         this.fireEvent('resize', this);
2933
2934     },
2935     setContentSize  : function(w, h)
2936     {
2937
2938     },
2939     onButtonClick: function(btn,e)
2940     {
2941         //Roo.log([a,b,c]);
2942         this.fireEvent('btnclick', btn.name, e);
2943     },
2944      /**
2945      * Set the title of the Dialog
2946      * @param {String} str new Title
2947      */
2948     setTitle: function(str) {
2949         this.titleEl.dom.innerHTML = str;
2950     },
2951     /**
2952      * Set the body of the Dialog
2953      * @param {String} str new Title
2954      */
2955     setBody: function(str) {
2956         this.bodyEl.dom.innerHTML = str;
2957     },
2958     /**
2959      * Set the body of the Dialog using the template
2960      * @param {Obj} data - apply this data to the template and replace the body contents.
2961      */
2962     applyBody: function(obj)
2963     {
2964         if (!this.tmpl) {
2965             Roo.log("Error - using apply Body without a template");
2966             //code
2967         }
2968         this.tmpl.overwrite(this.bodyEl, obj);
2969     }
2970
2971 });
2972
2973
2974 Roo.apply(Roo.bootstrap.Modal,  {
2975     /**
2976          * Button config that displays a single OK button
2977          * @type Object
2978          */
2979         OK :  [{
2980             name : 'ok',
2981             weight : 'primary',
2982             html : 'OK'
2983         }],
2984         /**
2985          * Button config that displays Yes and No buttons
2986          * @type Object
2987          */
2988         YESNO : [
2989             {
2990                 name  : 'no',
2991                 html : 'No'
2992             },
2993             {
2994                 name  :'yes',
2995                 weight : 'primary',
2996                 html : 'Yes'
2997             }
2998         ],
2999
3000         /**
3001          * Button config that displays OK and Cancel buttons
3002          * @type Object
3003          */
3004         OKCANCEL : [
3005             {
3006                name : 'cancel',
3007                 html : 'Cancel'
3008             },
3009             {
3010                 name : 'ok',
3011                 weight : 'primary',
3012                 html : 'OK'
3013             }
3014         ],
3015         /**
3016          * Button config that displays Yes, No and Cancel buttons
3017          * @type Object
3018          */
3019         YESNOCANCEL : [
3020             {
3021                 name : 'yes',
3022                 weight : 'primary',
3023                 html : 'Yes'
3024             },
3025             {
3026                 name : 'no',
3027                 html : 'No'
3028             },
3029             {
3030                 name : 'cancel',
3031                 html : 'Cancel'
3032             }
3033         ],
3034         
3035         zIndex : 10001
3036 });
3037 /*
3038  * - LGPL
3039  *
3040  * messagebox - can be used as a replace
3041  * 
3042  */
3043 /**
3044  * @class Roo.MessageBox
3045  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
3046  * Example usage:
3047  *<pre><code>
3048 // Basic alert:
3049 Roo.Msg.alert('Status', 'Changes saved successfully.');
3050
3051 // Prompt for user data:
3052 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3053     if (btn == 'ok'){
3054         // process text value...
3055     }
3056 });
3057
3058 // Show a dialog using config options:
3059 Roo.Msg.show({
3060    title:'Save Changes?',
3061    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3062    buttons: Roo.Msg.YESNOCANCEL,
3063    fn: processResult,
3064    animEl: 'elId'
3065 });
3066 </code></pre>
3067  * @singleton
3068  */
3069 Roo.bootstrap.MessageBox = function(){
3070     var dlg, opt, mask, waitTimer;
3071     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3072     var buttons, activeTextEl, bwidth;
3073
3074     
3075     // private
3076     var handleButton = function(button){
3077         dlg.hide();
3078         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3079     };
3080
3081     // private
3082     var handleHide = function(){
3083         if(opt && opt.cls){
3084             dlg.el.removeClass(opt.cls);
3085         }
3086         //if(waitTimer){
3087         //    Roo.TaskMgr.stop(waitTimer);
3088         //    waitTimer = null;
3089         //}
3090     };
3091
3092     // private
3093     var updateButtons = function(b){
3094         var width = 0;
3095         if(!b){
3096             buttons["ok"].hide();
3097             buttons["cancel"].hide();
3098             buttons["yes"].hide();
3099             buttons["no"].hide();
3100             //dlg.footer.dom.style.display = 'none';
3101             return width;
3102         }
3103         dlg.footerEl.dom.style.display = '';
3104         for(var k in buttons){
3105             if(typeof buttons[k] != "function"){
3106                 if(b[k]){
3107                     buttons[k].show();
3108                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3109                     width += buttons[k].el.getWidth()+15;
3110                 }else{
3111                     buttons[k].hide();
3112                 }
3113             }
3114         }
3115         return width;
3116     };
3117
3118     // private
3119     var handleEsc = function(d, k, e){
3120         if(opt && opt.closable !== false){
3121             dlg.hide();
3122         }
3123         if(e){
3124             e.stopEvent();
3125         }
3126     };
3127
3128     return {
3129         /**
3130          * Returns a reference to the underlying {@link Roo.BasicDialog} element
3131          * @return {Roo.BasicDialog} The BasicDialog element
3132          */
3133         getDialog : function(){
3134            if(!dlg){
3135                 dlg = new Roo.bootstrap.Modal( {
3136                     //draggable: true,
3137                     //resizable:false,
3138                     //constraintoviewport:false,
3139                     //fixedcenter:true,
3140                     //collapsible : false,
3141                     //shim:true,
3142                     //modal: true,
3143                 //    width: 'auto',
3144                   //  height:100,
3145                     //buttonAlign:"center",
3146                     closeClick : function(){
3147                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3148                             handleButton("no");
3149                         }else{
3150                             handleButton("cancel");
3151                         }
3152                     }
3153                 });
3154                 dlg.render();
3155                 dlg.on("hide", handleHide);
3156                 mask = dlg.mask;
3157                 //dlg.addKeyListener(27, handleEsc);
3158                 buttons = {};
3159                 this.buttons = buttons;
3160                 var bt = this.buttonText;
3161                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3162                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3163                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3164                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3165                 //Roo.log(buttons);
3166                 bodyEl = dlg.bodyEl.createChild({
3167
3168                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3169                         '<textarea class="roo-mb-textarea"></textarea>' +
3170                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
3171                 });
3172                 msgEl = bodyEl.dom.firstChild;
3173                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3174                 textboxEl.enableDisplayMode();
3175                 textboxEl.addKeyListener([10,13], function(){
3176                     if(dlg.isVisible() && opt && opt.buttons){
3177                         if(opt.buttons.ok){
3178                             handleButton("ok");
3179                         }else if(opt.buttons.yes){
3180                             handleButton("yes");
3181                         }
3182                     }
3183                 });
3184                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3185                 textareaEl.enableDisplayMode();
3186                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3187                 progressEl.enableDisplayMode();
3188                 
3189                 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3190                 var pf = progressEl.dom.firstChild;
3191                 if (pf) {
3192                     pp = Roo.get(pf.firstChild);
3193                     pp.setHeight(pf.offsetHeight);
3194                 }
3195                 
3196             }
3197             return dlg;
3198         },
3199
3200         /**
3201          * Updates the message box body text
3202          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3203          * the XHTML-compliant non-breaking space character '&amp;#160;')
3204          * @return {Roo.MessageBox} This message box
3205          */
3206         updateText : function(text)
3207         {
3208             if(!dlg.isVisible() && !opt.width){
3209                 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3210                 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3211             }
3212             msgEl.innerHTML = text || '&#160;';
3213       
3214             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3215             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3216             var w = Math.max(
3217                     Math.min(opt.width || cw , this.maxWidth), 
3218                     Math.max(opt.minWidth || this.minWidth, bwidth)
3219             );
3220             if(opt.prompt){
3221                 activeTextEl.setWidth(w);
3222             }
3223             if(dlg.isVisible()){
3224                 dlg.fixedcenter = false;
3225             }
3226             // to big, make it scroll. = But as usual stupid IE does not support
3227             // !important..
3228             
3229             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3230                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3231                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3232             } else {
3233                 bodyEl.dom.style.height = '';
3234                 bodyEl.dom.style.overflowY = '';
3235             }
3236             if (cw > w) {
3237                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3238             } else {
3239                 bodyEl.dom.style.overflowX = '';
3240             }
3241             
3242             dlg.setContentSize(w, bodyEl.getHeight());
3243             if(dlg.isVisible()){
3244                 dlg.fixedcenter = true;
3245             }
3246             return this;
3247         },
3248
3249         /**
3250          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
3251          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3252          * @param {Number} value Any number between 0 and 1 (e.g., .5)
3253          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3254          * @return {Roo.MessageBox} This message box
3255          */
3256         updateProgress : function(value, text){
3257             if(text){
3258                 this.updateText(text);
3259             }
3260             
3261             if (pp) { // weird bug on my firefox - for some reason this is not defined
3262                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3263                 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3264             }
3265             return this;
3266         },        
3267
3268         /**
3269          * Returns true if the message box is currently displayed
3270          * @return {Boolean} True if the message box is visible, else false
3271          */
3272         isVisible : function(){
3273             return dlg && dlg.isVisible();  
3274         },
3275
3276         /**
3277          * Hides the message box if it is displayed
3278          */
3279         hide : function(){
3280             if(this.isVisible()){
3281                 dlg.hide();
3282             }  
3283         },
3284
3285         /**
3286          * Displays a new message box, or reinitializes an existing message box, based on the config options
3287          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3288          * The following config object properties are supported:
3289          * <pre>
3290 Property    Type             Description
3291 ----------  ---------------  ------------------------------------------------------------------------------------
3292 animEl            String/Element   An id or Element from which the message box should animate as it opens and
3293                                    closes (defaults to undefined)
3294 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3295                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
3296 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
3297                                    progress and wait dialogs will ignore this property and always hide the
3298                                    close button as they can only be closed programmatically.
3299 cls               String           A custom CSS class to apply to the message box element
3300 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
3301                                    displayed (defaults to 75)
3302 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
3303                                    function will be btn (the name of the button that was clicked, if applicable,
3304                                    e.g. "ok"), and text (the value of the active text field, if applicable).
3305                                    Progress and wait dialogs will ignore this option since they do not respond to
3306                                    user actions and can only be closed programmatically, so any required function
3307                                    should be called by the same code after it closes the dialog.
3308 icon              String           A CSS class that provides a background image to be used as an icon for
3309                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3310 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
3311 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
3312 modal             Boolean          False to allow user interaction with the page while the message box is
3313                                    displayed (defaults to true)
3314 msg               String           A string that will replace the existing message box body text (defaults
3315                                    to the XHTML-compliant non-breaking space character '&#160;')
3316 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
3317 progress          Boolean          True to display a progress bar (defaults to false)
3318 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
3319 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
3320 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
3321 title             String           The title text
3322 value             String           The string value to set into the active textbox element if displayed
3323 wait              Boolean          True to display a progress bar (defaults to false)
3324 width             Number           The width of the dialog in pixels
3325 </pre>
3326          *
3327          * Example usage:
3328          * <pre><code>
3329 Roo.Msg.show({
3330    title: 'Address',
3331    msg: 'Please enter your address:',
3332    width: 300,
3333    buttons: Roo.MessageBox.OKCANCEL,
3334    multiline: true,
3335    fn: saveAddress,
3336    animEl: 'addAddressBtn'
3337 });
3338 </code></pre>
3339          * @param {Object} config Configuration options
3340          * @return {Roo.MessageBox} This message box
3341          */
3342         show : function(options)
3343         {
3344             
3345             // this causes nightmares if you show one dialog after another
3346             // especially on callbacks..
3347              
3348             if(this.isVisible()){
3349                 
3350                 this.hide();
3351                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3352                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
3353                 Roo.log("New Dialog Message:" +  options.msg )
3354                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3355                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3356                 
3357             }
3358             var d = this.getDialog();
3359             opt = options;
3360             d.setTitle(opt.title || "&#160;");
3361             d.closeEl.setDisplayed(opt.closable !== false);
3362             activeTextEl = textboxEl;
3363             opt.prompt = opt.prompt || (opt.multiline ? true : false);
3364             if(opt.prompt){
3365                 if(opt.multiline){
3366                     textboxEl.hide();
3367                     textareaEl.show();
3368                     textareaEl.setHeight(typeof opt.multiline == "number" ?
3369                         opt.multiline : this.defaultTextHeight);
3370                     activeTextEl = textareaEl;
3371                 }else{
3372                     textboxEl.show();
3373                     textareaEl.hide();
3374                 }
3375             }else{
3376                 textboxEl.hide();
3377                 textareaEl.hide();
3378             }
3379             progressEl.setDisplayed(opt.progress === true);
3380             this.updateProgress(0);
3381             activeTextEl.dom.value = opt.value || "";
3382             if(opt.prompt){
3383                 dlg.setDefaultButton(activeTextEl);
3384             }else{
3385                 var bs = opt.buttons;
3386                 var db = null;
3387                 if(bs && bs.ok){
3388                     db = buttons["ok"];
3389                 }else if(bs && bs.yes){
3390                     db = buttons["yes"];
3391                 }
3392                 dlg.setDefaultButton(db);
3393             }
3394             bwidth = updateButtons(opt.buttons);
3395             this.updateText(opt.msg);
3396             if(opt.cls){
3397                 d.el.addClass(opt.cls);
3398             }
3399             d.proxyDrag = opt.proxyDrag === true;
3400             d.modal = opt.modal !== false;
3401             d.mask = opt.modal !== false ? mask : false;
3402             if(!d.isVisible()){
3403                 // force it to the end of the z-index stack so it gets a cursor in FF
3404                 document.body.appendChild(dlg.el.dom);
3405                 d.animateTarget = null;
3406                 d.show(options.animEl);
3407             }
3408             return this;
3409         },
3410
3411         /**
3412          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
3413          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3414          * and closing the message box when the process is complete.
3415          * @param {String} title The title bar text
3416          * @param {String} msg The message box body text
3417          * @return {Roo.MessageBox} This message box
3418          */
3419         progress : function(title, msg){
3420             this.show({
3421                 title : title,
3422                 msg : msg,
3423                 buttons: false,
3424                 progress:true,
3425                 closable:false,
3426                 minWidth: this.minProgressWidth,
3427                 modal : true
3428             });
3429             return this;
3430         },
3431
3432         /**
3433          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3434          * If a callback function is passed it will be called after the user clicks the button, and the
3435          * id of the button that was clicked will be passed as the only parameter to the callback
3436          * (could also be the top-right close button).
3437          * @param {String} title The title bar text
3438          * @param {String} msg The message box body text
3439          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3440          * @param {Object} scope (optional) The scope of the callback function
3441          * @return {Roo.MessageBox} This message box
3442          */
3443         alert : function(title, msg, fn, scope)
3444         {
3445             this.show({
3446                 title : title,
3447                 msg : msg,
3448                 buttons: this.OK,
3449                 fn: fn,
3450                 closable : false,
3451                 scope : scope,
3452                 modal : true
3453             });
3454             return this;
3455         },
3456
3457         /**
3458          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
3459          * interaction while waiting for a long-running process to complete that does not have defined intervals.
3460          * You are responsible for closing the message box when the process is complete.
3461          * @param {String} msg The message box body text
3462          * @param {String} title (optional) The title bar text
3463          * @return {Roo.MessageBox} This message box
3464          */
3465         wait : function(msg, title){
3466             this.show({
3467                 title : title,
3468                 msg : msg,
3469                 buttons: false,
3470                 closable:false,
3471                 progress:true,
3472                 modal:true,
3473                 width:300,
3474                 wait:true
3475             });
3476             waitTimer = Roo.TaskMgr.start({
3477                 run: function(i){
3478                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3479                 },
3480                 interval: 1000
3481             });
3482             return this;
3483         },
3484
3485         /**
3486          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3487          * If a callback function is passed it will be called after the user clicks either button, and the id of the
3488          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3489          * @param {String} title The title bar text
3490          * @param {String} msg The message box body text
3491          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3492          * @param {Object} scope (optional) The scope of the callback function
3493          * @return {Roo.MessageBox} This message box
3494          */
3495         confirm : function(title, msg, fn, scope){
3496             this.show({
3497                 title : title,
3498                 msg : msg,
3499                 buttons: this.YESNO,
3500                 fn: fn,
3501                 scope : scope,
3502                 modal : true
3503             });
3504             return this;
3505         },
3506
3507         /**
3508          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3509          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
3510          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3511          * (could also be the top-right close button) and the text that was entered will be passed as the two
3512          * parameters to the callback.
3513          * @param {String} title The title bar text
3514          * @param {String} msg The message box body text
3515          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3516          * @param {Object} scope (optional) The scope of the callback function
3517          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3518          * property, or the height in pixels to create the textbox (defaults to false / single-line)
3519          * @return {Roo.MessageBox} This message box
3520          */
3521         prompt : function(title, msg, fn, scope, multiline){
3522             this.show({
3523                 title : title,
3524                 msg : msg,
3525                 buttons: this.OKCANCEL,
3526                 fn: fn,
3527                 minWidth:250,
3528                 scope : scope,
3529                 prompt:true,
3530                 multiline: multiline,
3531                 modal : true
3532             });
3533             return this;
3534         },
3535
3536         /**
3537          * Button config that displays a single OK button
3538          * @type Object
3539          */
3540         OK : {ok:true},
3541         /**
3542          * Button config that displays Yes and No buttons
3543          * @type Object
3544          */
3545         YESNO : {yes:true, no:true},
3546         /**
3547          * Button config that displays OK and Cancel buttons
3548          * @type Object
3549          */
3550         OKCANCEL : {ok:true, cancel:true},
3551         /**
3552          * Button config that displays Yes, No and Cancel buttons
3553          * @type Object
3554          */
3555         YESNOCANCEL : {yes:true, no:true, cancel:true},
3556
3557         /**
3558          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3559          * @type Number
3560          */
3561         defaultTextHeight : 75,
3562         /**
3563          * The maximum width in pixels of the message box (defaults to 600)
3564          * @type Number
3565          */
3566         maxWidth : 600,
3567         /**
3568          * The minimum width in pixels of the message box (defaults to 100)
3569          * @type Number
3570          */
3571         minWidth : 100,
3572         /**
3573          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
3574          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3575          * @type Number
3576          */
3577         minProgressWidth : 250,
3578         /**
3579          * An object containing the default button text strings that can be overriden for localized language support.
3580          * Supported properties are: ok, cancel, yes and no.
3581          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3582          * @type Object
3583          */
3584         buttonText : {
3585             ok : "OK",
3586             cancel : "Cancel",
3587             yes : "Yes",
3588             no : "No"
3589         }
3590     };
3591 }();
3592
3593 /**
3594  * Shorthand for {@link Roo.MessageBox}
3595  */
3596 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3597 Roo.Msg = Roo.Msg || Roo.MessageBox;
3598 /*
3599  * - LGPL
3600  *
3601  * navbar
3602  * 
3603  */
3604
3605 /**
3606  * @class Roo.bootstrap.Navbar
3607  * @extends Roo.bootstrap.Component
3608  * Bootstrap Navbar class
3609
3610  * @constructor
3611  * Create a new Navbar
3612  * @param {Object} config The config object
3613  */
3614
3615
3616 Roo.bootstrap.Navbar = function(config){
3617     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3618     this.addEvents({
3619         // raw events
3620         /**
3621          * @event beforetoggle
3622          * Fire before toggle the menu
3623          * @param {Roo.EventObject} e
3624          */
3625         "beforetoggle" : true
3626     });
3627 };
3628
3629 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3630     
3631     
3632    
3633     // private
3634     navItems : false,
3635     loadMask : false,
3636     
3637     
3638     getAutoCreate : function(){
3639         
3640         
3641         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3642         
3643     },
3644     
3645     initEvents :function ()
3646     {
3647         //Roo.log(this.el.select('.navbar-toggle',true));
3648         this.el.select('.navbar-toggle',true).on('click', function() {
3649             if(this.fireEvent('beforetoggle', this) !== false){
3650                this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3651             }
3652             
3653         }, this);
3654         
3655         var mark = {
3656             tag: "div",
3657             cls:"x-dlg-mask"
3658         };
3659         
3660         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3661         
3662         var size = this.el.getSize();
3663         this.maskEl.setSize(size.width, size.height);
3664         this.maskEl.enableDisplayMode("block");
3665         this.maskEl.hide();
3666         
3667         if(this.loadMask){
3668             this.maskEl.show();
3669         }
3670     },
3671     
3672     
3673     getChildContainer : function()
3674     {
3675         if (this.el.select('.collapse').getCount()) {
3676             return this.el.select('.collapse',true).first();
3677         }
3678         
3679         return this.el;
3680     },
3681     
3682     mask : function()
3683     {
3684         this.maskEl.show();
3685     },
3686     
3687     unmask : function()
3688     {
3689         this.maskEl.hide();
3690     } 
3691     
3692     
3693     
3694     
3695 });
3696
3697
3698
3699  
3700
3701  /*
3702  * - LGPL
3703  *
3704  * navbar
3705  * 
3706  */
3707
3708 /**
3709  * @class Roo.bootstrap.NavSimplebar
3710  * @extends Roo.bootstrap.Navbar
3711  * Bootstrap Sidebar class
3712  *
3713  * @cfg {Boolean} inverse is inverted color
3714  * 
3715  * @cfg {String} type (nav | pills | tabs)
3716  * @cfg {Boolean} arrangement stacked | justified
3717  * @cfg {String} align (left | right) alignment
3718  * 
3719  * @cfg {Boolean} main (true|false) main nav bar? default false
3720  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3721  * 
3722  * @cfg {String} tag (header|footer|nav|div) default is nav 
3723
3724  * 
3725  * 
3726  * 
3727  * @constructor
3728  * Create a new Sidebar
3729  * @param {Object} config The config object
3730  */
3731
3732
3733 Roo.bootstrap.NavSimplebar = function(config){
3734     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3735 };
3736
3737 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3738     
3739     inverse: false,
3740     
3741     type: false,
3742     arrangement: '',
3743     align : false,
3744     
3745     
3746     
3747     main : false,
3748     
3749     
3750     tag : false,
3751     
3752     
3753     getAutoCreate : function(){
3754         
3755         
3756         var cfg = {
3757             tag : this.tag || 'div',
3758             cls : 'navbar'
3759         };
3760           
3761         
3762         cfg.cn = [
3763             {
3764                 cls: 'nav',
3765                 tag : 'ul'
3766             }
3767         ];
3768         
3769          
3770         this.type = this.type || 'nav';
3771         if (['tabs','pills'].indexOf(this.type)!==-1) {
3772             cfg.cn[0].cls += ' nav-' + this.type
3773         
3774         
3775         } else {
3776             if (this.type!=='nav') {
3777                 Roo.log('nav type must be nav/tabs/pills')
3778             }
3779             cfg.cn[0].cls += ' navbar-nav'
3780         }
3781         
3782         
3783         
3784         
3785         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3786             cfg.cn[0].cls += ' nav-' + this.arrangement;
3787         }
3788         
3789         
3790         if (this.align === 'right') {
3791             cfg.cn[0].cls += ' navbar-right';
3792         }
3793         
3794         if (this.inverse) {
3795             cfg.cls += ' navbar-inverse';
3796             
3797         }
3798         
3799         
3800         return cfg;
3801     
3802         
3803     }
3804     
3805     
3806     
3807 });
3808
3809
3810
3811  
3812
3813  
3814        /*
3815  * - LGPL
3816  *
3817  * navbar
3818  * 
3819  */
3820
3821 /**
3822  * @class Roo.bootstrap.NavHeaderbar
3823  * @extends Roo.bootstrap.NavSimplebar
3824  * Bootstrap Sidebar class
3825  *
3826  * @cfg {String} brand what is brand
3827  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3828  * @cfg {String} brand_href href of the brand
3829  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3830  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3831  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3832  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3833  * 
3834  * @constructor
3835  * Create a new Sidebar
3836  * @param {Object} config The config object
3837  */
3838
3839
3840 Roo.bootstrap.NavHeaderbar = function(config){
3841     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3842       
3843 };
3844
3845 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3846     
3847     position: '',
3848     brand: '',
3849     brand_href: false,
3850     srButton : true,
3851     autohide : false,
3852     desktopCenter : false,
3853    
3854     
3855     getAutoCreate : function(){
3856         
3857         var   cfg = {
3858             tag: this.nav || 'nav',
3859             cls: 'navbar',
3860             role: 'navigation',
3861             cn: []
3862         };
3863         
3864         var cn = cfg.cn;
3865         if (this.desktopCenter) {
3866             cn.push({cls : 'container', cn : []});
3867             cn = cn[0].cn;
3868         }
3869         
3870         if(this.srButton){
3871             cn.push({
3872                 tag: 'div',
3873                 cls: 'navbar-header',
3874                 cn: [
3875                     {
3876                         tag: 'button',
3877                         type: 'button',
3878                         cls: 'navbar-toggle',
3879                         'data-toggle': 'collapse',
3880                         cn: [
3881                             {
3882                                 tag: 'span',
3883                                 cls: 'sr-only',
3884                                 html: 'Toggle navigation'
3885                             },
3886                             {
3887                                 tag: 'span',
3888                                 cls: 'icon-bar'
3889                             },
3890                             {
3891                                 tag: 'span',
3892                                 cls: 'icon-bar'
3893                             },
3894                             {
3895                                 tag: 'span',
3896                                 cls: 'icon-bar'
3897                             }
3898                         ]
3899                     }
3900                 ]
3901             });
3902         }
3903         
3904         cn.push({
3905             tag: 'div',
3906             cls: 'collapse navbar-collapse',
3907             cn : []
3908         });
3909         
3910         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3911         
3912         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3913             cfg.cls += ' navbar-' + this.position;
3914             
3915             // tag can override this..
3916             
3917             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3918         }
3919         
3920         if (this.brand !== '') {
3921             cn[0].cn.push({
3922                 tag: 'a',
3923                 href: this.brand_href ? this.brand_href : '#',
3924                 cls: 'navbar-brand',
3925                 cn: [
3926                 this.brand
3927                 ]
3928             });
3929         }
3930         
3931         if(this.main){
3932             cfg.cls += ' main-nav';
3933         }
3934         
3935         
3936         return cfg;
3937
3938         
3939     },
3940     getHeaderChildContainer : function()
3941     {
3942         if (this.srButton && this.el.select('.navbar-header').getCount()) {
3943             return this.el.select('.navbar-header',true).first();
3944         }
3945         
3946         return this.getChildContainer();
3947     },
3948     
3949     
3950     initEvents : function()
3951     {
3952         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3953         
3954         if (this.autohide) {
3955             
3956             var prevScroll = 0;
3957             var ft = this.el;
3958             
3959             Roo.get(document).on('scroll',function(e) {
3960                 var ns = Roo.get(document).getScroll().top;
3961                 var os = prevScroll;
3962                 prevScroll = ns;
3963                 
3964                 if(ns > os){
3965                     ft.removeClass('slideDown');
3966                     ft.addClass('slideUp');
3967                     return;
3968                 }
3969                 ft.removeClass('slideUp');
3970                 ft.addClass('slideDown');
3971                  
3972               
3973           },this);
3974         }
3975     }    
3976     
3977 });
3978
3979
3980
3981  
3982
3983  /*
3984  * - LGPL
3985  *
3986  * navbar
3987  * 
3988  */
3989
3990 /**
3991  * @class Roo.bootstrap.NavSidebar
3992  * @extends Roo.bootstrap.Navbar
3993  * Bootstrap Sidebar class
3994  * 
3995  * @constructor
3996  * Create a new Sidebar
3997  * @param {Object} config The config object
3998  */
3999
4000
4001 Roo.bootstrap.NavSidebar = function(config){
4002     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4003 };
4004
4005 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
4006     
4007     sidebar : true, // used by Navbar Item and NavbarGroup at present...
4008     
4009     getAutoCreate : function(){
4010         
4011         
4012         return  {
4013             tag: 'div',
4014             cls: 'sidebar sidebar-nav'
4015         };
4016     
4017         
4018     }
4019     
4020     
4021     
4022 });
4023
4024
4025
4026  
4027
4028  /*
4029  * - LGPL
4030  *
4031  * nav group
4032  * 
4033  */
4034
4035 /**
4036  * @class Roo.bootstrap.NavGroup
4037  * @extends Roo.bootstrap.Component
4038  * Bootstrap NavGroup class
4039  * @cfg {String} align (left|right)
4040  * @cfg {Boolean} inverse
4041  * @cfg {String} type (nav|pills|tab) default nav
4042  * @cfg {String} navId - reference Id for navbar.
4043
4044  * 
4045  * @constructor
4046  * Create a new nav group
4047  * @param {Object} config The config object
4048  */
4049
4050 Roo.bootstrap.NavGroup = function(config){
4051     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4052     this.navItems = [];
4053    
4054     Roo.bootstrap.NavGroup.register(this);
4055      this.addEvents({
4056         /**
4057              * @event changed
4058              * Fires when the active item changes
4059              * @param {Roo.bootstrap.NavGroup} this
4060              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4061              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
4062          */
4063         'changed': true
4064      });
4065     
4066 };
4067
4068 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
4069     
4070     align: '',
4071     inverse: false,
4072     form: false,
4073     type: 'nav',
4074     navId : '',
4075     // private
4076     
4077     navItems : false, 
4078     
4079     getAutoCreate : function()
4080     {
4081         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4082         
4083         cfg = {
4084             tag : 'ul',
4085             cls: 'nav' 
4086         };
4087         
4088         if (['tabs','pills'].indexOf(this.type)!==-1) {
4089             cfg.cls += ' nav-' + this.type
4090         } else {
4091             if (this.type!=='nav') {
4092                 Roo.log('nav type must be nav/tabs/pills')
4093             }
4094             cfg.cls += ' navbar-nav'
4095         }
4096         
4097         if (this.parent() && this.parent().sidebar) {
4098             cfg = {
4099                 tag: 'ul',
4100                 cls: 'dashboard-menu sidebar-menu'
4101             };
4102             
4103             return cfg;
4104         }
4105         
4106         if (this.form === true) {
4107             cfg = {
4108                 tag: 'form',
4109                 cls: 'navbar-form'
4110             };
4111             
4112             if (this.align === 'right') {
4113                 cfg.cls += ' navbar-right';
4114             } else {
4115                 cfg.cls += ' navbar-left';
4116             }
4117         }
4118         
4119         if (this.align === 'right') {
4120             cfg.cls += ' navbar-right';
4121         }
4122         
4123         if (this.inverse) {
4124             cfg.cls += ' navbar-inverse';
4125             
4126         }
4127         
4128         
4129         return cfg;
4130     },
4131     /**
4132     * sets the active Navigation item
4133     * @param {Roo.bootstrap.NavItem} the new current navitem
4134     */
4135     setActiveItem : function(item)
4136     {
4137         var prev = false;
4138         Roo.each(this.navItems, function(v){
4139             if (v == item) {
4140                 return ;
4141             }
4142             if (v.isActive()) {
4143                 v.setActive(false, true);
4144                 prev = v;
4145                 
4146             }
4147             
4148         });
4149
4150         item.setActive(true, true);
4151         this.fireEvent('changed', this, item, prev);
4152         
4153         
4154     },
4155     /**
4156     * gets the active Navigation item
4157     * @return {Roo.bootstrap.NavItem} the current navitem
4158     */
4159     getActive : function()
4160     {
4161         
4162         var prev = false;
4163         Roo.each(this.navItems, function(v){
4164             
4165             if (v.isActive()) {
4166                 prev = v;
4167                 
4168             }
4169             
4170         });
4171         return prev;
4172     },
4173     
4174     indexOfNav : function()
4175     {
4176         
4177         var prev = false;
4178         Roo.each(this.navItems, function(v,i){
4179             
4180             if (v.isActive()) {
4181                 prev = i;
4182                 
4183             }
4184             
4185         });
4186         return prev;
4187     },
4188     /**
4189     * adds a Navigation item
4190     * @param {Roo.bootstrap.NavItem} the navitem to add
4191     */
4192     addItem : function(cfg)
4193     {
4194         var cn = new Roo.bootstrap.NavItem(cfg);
4195         this.register(cn);
4196         cn.parentId = this.id;
4197         cn.onRender(this.el, null);
4198         return cn;
4199     },
4200     /**
4201     * register a Navigation item
4202     * @param {Roo.bootstrap.NavItem} the navitem to add
4203     */
4204     register : function(item)
4205     {
4206         this.navItems.push( item);
4207         item.navId = this.navId;
4208     
4209     },
4210     
4211     /**
4212     * clear all the Navigation item
4213     */
4214    
4215     clearAll : function()
4216     {
4217         this.navItems = [];
4218         this.el.dom.innerHTML = '';
4219     },
4220     
4221     getNavItem: function(tabId)
4222     {
4223         var ret = false;
4224         Roo.each(this.navItems, function(e) {
4225             if (e.tabId == tabId) {
4226                ret =  e;
4227                return false;
4228             }
4229             return true;
4230             
4231         });
4232         return ret;
4233     },
4234     
4235     setActiveNext : function()
4236     {
4237         var i = this.indexOfNav(this.getActive());
4238         if (i > this.navItems.length) {
4239             return;
4240         }
4241         this.setActiveItem(this.navItems[i+1]);
4242     },
4243     setActivePrev : function()
4244     {
4245         var i = this.indexOfNav(this.getActive());
4246         if (i  < 1) {
4247             return;
4248         }
4249         this.setActiveItem(this.navItems[i-1]);
4250     },
4251     clearWasActive : function(except) {
4252         Roo.each(this.navItems, function(e) {
4253             if (e.tabId != except.tabId && e.was_active) {
4254                e.was_active = false;
4255                return false;
4256             }
4257             return true;
4258             
4259         });
4260     },
4261     getWasActive : function ()
4262     {
4263         var r = false;
4264         Roo.each(this.navItems, function(e) {
4265             if (e.was_active) {
4266                r = e;
4267                return false;
4268             }
4269             return true;
4270             
4271         });
4272         return r;
4273     }
4274     
4275     
4276 });
4277
4278  
4279 Roo.apply(Roo.bootstrap.NavGroup, {
4280     
4281     groups: {},
4282      /**
4283     * register a Navigation Group
4284     * @param {Roo.bootstrap.NavGroup} the navgroup to add
4285     */
4286     register : function(navgrp)
4287     {
4288         this.groups[navgrp.navId] = navgrp;
4289         
4290     },
4291     /**
4292     * fetch a Navigation Group based on the navigation ID
4293     * @param {string} the navgroup to add
4294     * @returns {Roo.bootstrap.NavGroup} the navgroup 
4295     */
4296     get: function(navId) {
4297         if (typeof(this.groups[navId]) == 'undefined') {
4298             return false;
4299             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4300         }
4301         return this.groups[navId] ;
4302     }
4303     
4304     
4305     
4306 });
4307
4308  /*
4309  * - LGPL
4310  *
4311  * row
4312  * 
4313  */
4314
4315 /**
4316  * @class Roo.bootstrap.NavItem
4317  * @extends Roo.bootstrap.Component
4318  * Bootstrap Navbar.NavItem class
4319  * @cfg {String} href  link to
4320  * @cfg {String} html content of button
4321  * @cfg {String} badge text inside badge
4322  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4323  * @cfg {String} glyphicon name of glyphicon
4324  * @cfg {String} icon name of font awesome icon
4325  * @cfg {Boolean} active Is item active
4326  * @cfg {Boolean} disabled Is item disabled
4327  
4328  * @cfg {Boolean} preventDefault (true | false) default false
4329  * @cfg {String} tabId the tab that this item activates.
4330  * @cfg {String} tagtype (a|span) render as a href or span?
4331  * @cfg {Boolean} animateRef (true|false) link to element default false  
4332   
4333  * @constructor
4334  * Create a new Navbar Item
4335  * @param {Object} config The config object
4336  */
4337 Roo.bootstrap.NavItem = function(config){
4338     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4339     this.addEvents({
4340         // raw events
4341         /**
4342          * @event click
4343          * The raw click event for the entire grid.
4344          * @param {Roo.EventObject} e
4345          */
4346         "click" : true,
4347          /**
4348             * @event changed
4349             * Fires when the active item active state changes
4350             * @param {Roo.bootstrap.NavItem} this
4351             * @param {boolean} state the new state
4352              
4353          */
4354         'changed': true,
4355         /**
4356             * @event scrollto
4357             * Fires when scroll to element
4358             * @param {Roo.bootstrap.NavItem} this
4359             * @param {Object} options
4360             * @param {Roo.EventObject} e
4361              
4362          */
4363         'scrollto': true
4364     });
4365    
4366 };
4367
4368 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
4369     
4370     href: false,
4371     html: '',
4372     badge: '',
4373     icon: false,
4374     glyphicon: false,
4375     active: false,
4376     preventDefault : false,
4377     tabId : false,
4378     tagtype : 'a',
4379     disabled : false,
4380     animateRef : false,
4381     was_active : false,
4382     
4383     getAutoCreate : function(){
4384          
4385         var cfg = {
4386             tag: 'li',
4387             cls: 'nav-item'
4388             
4389         };
4390         
4391         if (this.active) {
4392             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4393         }
4394         if (this.disabled) {
4395             cfg.cls += ' disabled';
4396         }
4397         
4398         if (this.href || this.html || this.glyphicon || this.icon) {
4399             cfg.cn = [
4400                 {
4401                     tag: this.tagtype,
4402                     href : this.href || "#",
4403                     html: this.html || ''
4404                 }
4405             ];
4406             
4407             if (this.icon) {
4408                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4409             }
4410
4411             if(this.glyphicon) {
4412                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
4413             }
4414             
4415             if (this.menu) {
4416                 
4417                 cfg.cn[0].html += " <span class='caret'></span>";
4418              
4419             }
4420             
4421             if (this.badge !== '') {
4422                  
4423                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4424             }
4425         }
4426         
4427         
4428         
4429         return cfg;
4430     },
4431     initEvents: function() 
4432     {
4433         if (typeof (this.menu) != 'undefined') {
4434             this.menu.parentType = this.xtype;
4435             this.menu.triggerEl = this.el;
4436             this.menu = this.addxtype(Roo.apply({}, this.menu));
4437         }
4438         
4439         this.el.select('a',true).on('click', this.onClick, this);
4440         
4441         if(this.tagtype == 'span'){
4442             this.el.select('span',true).on('click', this.onClick, this);
4443         }
4444        
4445         // at this point parent should be available..
4446         this.parent().register(this);
4447     },
4448     
4449     onClick : function(e)
4450     {
4451         if (e.getTarget('.dropdown-menu-item')) {
4452             // did you click on a menu itemm.... - then don't trigger onclick..
4453             return;
4454         }
4455         
4456         if(
4457                 this.preventDefault || 
4458                 this.href == '#' 
4459         ){
4460             Roo.log("NavItem - prevent Default?");
4461             e.preventDefault();
4462         }
4463         
4464         if (this.disabled) {
4465             return;
4466         }
4467         
4468         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4469         if (tg && tg.transition) {
4470             Roo.log("waiting for the transitionend");
4471             return;
4472         }
4473         
4474         
4475         
4476         //Roo.log("fire event clicked");
4477         if(this.fireEvent('click', this, e) === false){
4478             return;
4479         };
4480         
4481         if(this.tagtype == 'span'){
4482             return;
4483         }
4484         
4485         //Roo.log(this.href);
4486         var ael = this.el.select('a',true).first();
4487         //Roo.log(ael);
4488         
4489         if(ael && this.animateRef && this.href.indexOf('#') > -1){
4490             //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4491             if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4492                 return; // ignore... - it's a 'hash' to another page.
4493             }
4494             Roo.log("NavItem - prevent Default?");
4495             e.preventDefault();
4496             this.scrollToElement(e);
4497         }
4498         
4499         
4500         var p =  this.parent();
4501    
4502         if (['tabs','pills'].indexOf(p.type)!==-1) {
4503             if (typeof(p.setActiveItem) !== 'undefined') {
4504                 p.setActiveItem(this);
4505             }
4506         }
4507         
4508         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4509         if (p.parentType == 'NavHeaderbar' && !this.menu) {
4510             // remove the collapsed menu expand...
4511             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
4512         }
4513     },
4514     
4515     isActive: function () {
4516         return this.active
4517     },
4518     setActive : function(state, fire, is_was_active)
4519     {
4520         if (this.active && !state && this.navId) {
4521             this.was_active = true;
4522             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4523             if (nv) {
4524                 nv.clearWasActive(this);
4525             }
4526             
4527         }
4528         this.active = state;
4529         
4530         if (!state ) {
4531             this.el.removeClass('active');
4532         } else if (!this.el.hasClass('active')) {
4533             this.el.addClass('active');
4534         }
4535         if (fire) {
4536             this.fireEvent('changed', this, state);
4537         }
4538         
4539         // show a panel if it's registered and related..
4540         
4541         if (!this.navId || !this.tabId || !state || is_was_active) {
4542             return;
4543         }
4544         
4545         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4546         if (!tg) {
4547             return;
4548         }
4549         var pan = tg.getPanelByName(this.tabId);
4550         if (!pan) {
4551             return;
4552         }
4553         // if we can not flip to new panel - go back to old nav highlight..
4554         if (false == tg.showPanel(pan)) {
4555             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4556             if (nv) {
4557                 var onav = nv.getWasActive();
4558                 if (onav) {
4559                     onav.setActive(true, false, true);
4560                 }
4561             }
4562             
4563         }
4564         
4565         
4566         
4567     },
4568      // this should not be here...
4569     setDisabled : function(state)
4570     {
4571         this.disabled = state;
4572         if (!state ) {
4573             this.el.removeClass('disabled');
4574         } else if (!this.el.hasClass('disabled')) {
4575             this.el.addClass('disabled');
4576         }
4577         
4578     },
4579     
4580     /**
4581      * Fetch the element to display the tooltip on.
4582      * @return {Roo.Element} defaults to this.el
4583      */
4584     tooltipEl : function()
4585     {
4586         return this.el.select('' + this.tagtype + '', true).first();
4587     },
4588     
4589     scrollToElement : function(e)
4590     {
4591         var c = document.body;
4592         
4593         /*
4594          * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4595          */
4596         if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4597             c = document.documentElement;
4598         }
4599         
4600         var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4601         
4602         if(!target){
4603             return;
4604         }
4605
4606         var o = target.calcOffsetsTo(c);
4607         
4608         var options = {
4609             target : target,
4610             value : o[1]
4611         };
4612         
4613         this.fireEvent('scrollto', this, options, e);
4614         
4615         Roo.get(c).scrollTo('top', options.value, true);
4616         
4617         return;
4618     }
4619 });
4620  
4621
4622  /*
4623  * - LGPL
4624  *
4625  * sidebar item
4626  *
4627  *  li
4628  *    <span> icon </span>
4629  *    <span> text </span>
4630  *    <span>badge </span>
4631  */
4632
4633 /**
4634  * @class Roo.bootstrap.NavSidebarItem
4635  * @extends Roo.bootstrap.NavItem
4636  * Bootstrap Navbar.NavSidebarItem class
4637  * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4638  * {Boolean} open is the menu open
4639  * {Boolean} buttonView use button as the tigger el rather that a (default false)
4640  * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4641  * {String} buttonSize (sm|md|lg)the extra classes for the button
4642  * {Boolean} showArrow show arrow next to the text (default true)
4643  * @constructor
4644  * Create a new Navbar Button
4645  * @param {Object} config The config object
4646  */
4647 Roo.bootstrap.NavSidebarItem = function(config){
4648     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4649     this.addEvents({
4650         // raw events
4651         /**
4652          * @event click
4653          * The raw click event for the entire grid.
4654          * @param {Roo.EventObject} e
4655          */
4656         "click" : true,
4657          /**
4658             * @event changed
4659             * Fires when the active item active state changes
4660             * @param {Roo.bootstrap.NavSidebarItem} this
4661             * @param {boolean} state the new state
4662              
4663          */
4664         'changed': true
4665     });
4666    
4667 };
4668
4669 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4670     
4671     badgeWeight : 'default',
4672     
4673     open: false,
4674     
4675     buttonView : false,
4676     
4677     buttonWeight : 'default',
4678     
4679     buttonSize : 'md',
4680     
4681     showArrow : true,
4682     
4683     getAutoCreate : function(){
4684         
4685         
4686         var a = {
4687                 tag: 'a',
4688                 href : this.href || '#',
4689                 cls: '',
4690                 html : '',
4691                 cn : []
4692         };
4693         
4694         if(this.buttonView){
4695             a = {
4696                 tag: 'button',
4697                 href : this.href || '#',
4698                 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4699                 html : this.html,
4700                 cn : []
4701             };
4702         }
4703         
4704         var cfg = {
4705             tag: 'li',
4706             cls: '',
4707             cn: [ a ]
4708         };
4709         
4710         if (this.active) {
4711             cfg.cls += ' active';
4712         }
4713         
4714         if (this.disabled) {
4715             cfg.cls += ' disabled';
4716         }
4717         if (this.open) {
4718             cfg.cls += ' open x-open';
4719         }
4720         // left icon..
4721         if (this.glyphicon || this.icon) {
4722             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4723             a.cn.push({ tag : 'i', cls : c }) ;
4724         }
4725         
4726         if(!this.buttonView){
4727             var span = {
4728                 tag: 'span',
4729                 html : this.html || ''
4730             };
4731
4732             a.cn.push(span);
4733             
4734         }
4735         
4736         if (this.badge !== '') {
4737             a.cn.push({ tag: 'span',  cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge }); 
4738         }
4739         
4740         if (this.menu) {
4741             
4742             if(this.showArrow){
4743                 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4744             }
4745             
4746             a.cls += ' dropdown-toggle treeview' ;
4747         }
4748         
4749         return cfg;
4750     },
4751     
4752     initEvents : function()
4753     { 
4754         if (typeof (this.menu) != 'undefined') {
4755             this.menu.parentType = this.xtype;
4756             this.menu.triggerEl = this.el;
4757             this.menu = this.addxtype(Roo.apply({}, this.menu));
4758         }
4759         
4760         this.el.on('click', this.onClick, this);
4761         
4762         if(this.badge !== ''){
4763             this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4764         }
4765         
4766     },
4767     
4768     onClick : function(e)
4769     {
4770         if(this.disabled){
4771             e.preventDefault();
4772             return;
4773         }
4774         
4775         if(this.preventDefault){
4776             e.preventDefault();
4777         }
4778         
4779         this.fireEvent('click', this);
4780     },
4781     
4782     disable : function()
4783     {
4784         this.setDisabled(true);
4785     },
4786     
4787     enable : function()
4788     {
4789         this.setDisabled(false);
4790     },
4791     
4792     setDisabled : function(state)
4793     {
4794         if(this.disabled == state){
4795             return;
4796         }
4797         
4798         this.disabled = state;
4799         
4800         if (state) {
4801             this.el.addClass('disabled');
4802             return;
4803         }
4804         
4805         this.el.removeClass('disabled');
4806         
4807         return;
4808     },
4809     
4810     setActive : function(state)
4811     {
4812         if(this.active == state){
4813             return;
4814         }
4815         
4816         this.active = state;
4817         
4818         if (state) {
4819             this.el.addClass('active');
4820             return;
4821         }
4822         
4823         this.el.removeClass('active');
4824         
4825         return;
4826     },
4827     
4828     isActive: function () 
4829     {
4830         return this.active;
4831     },
4832     
4833     setBadge : function(str)
4834     {
4835         if(!this.badgeEl){
4836             return;
4837         }
4838         
4839         this.badgeEl.dom.innerHTML = str;
4840     }
4841     
4842    
4843      
4844  
4845 });
4846  
4847
4848  /*
4849  * - LGPL
4850  *
4851  * row
4852  * 
4853  */
4854
4855 /**
4856  * @class Roo.bootstrap.Row
4857  * @extends Roo.bootstrap.Component
4858  * Bootstrap Row class (contains columns...)
4859  * 
4860  * @constructor
4861  * Create a new Row
4862  * @param {Object} config The config object
4863  */
4864
4865 Roo.bootstrap.Row = function(config){
4866     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4867 };
4868
4869 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4870     
4871     getAutoCreate : function(){
4872        return {
4873             cls: 'row clearfix'
4874        };
4875     }
4876     
4877     
4878 });
4879
4880  
4881
4882  /*
4883  * - LGPL
4884  *
4885  * element
4886  * 
4887  */
4888
4889 /**
4890  * @class Roo.bootstrap.Element
4891  * @extends Roo.bootstrap.Component
4892  * Bootstrap Element class
4893  * @cfg {String} html contents of the element
4894  * @cfg {String} tag tag of the element
4895  * @cfg {String} cls class of the element
4896  * @cfg {Boolean} preventDefault (true|false) default false
4897  * @cfg {Boolean} clickable (true|false) default false
4898  * 
4899  * @constructor
4900  * Create a new Element
4901  * @param {Object} config The config object
4902  */
4903
4904 Roo.bootstrap.Element = function(config){
4905     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4906     
4907     this.addEvents({
4908         // raw events
4909         /**
4910          * @event click
4911          * When a element is chick
4912          * @param {Roo.bootstrap.Element} this
4913          * @param {Roo.EventObject} e
4914          */
4915         "click" : true
4916     });
4917 };
4918
4919 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4920     
4921     tag: 'div',
4922     cls: '',
4923     html: '',
4924     preventDefault: false, 
4925     clickable: false,
4926     
4927     getAutoCreate : function(){
4928         
4929         var cfg = {
4930             tag: this.tag,
4931             // cls: this.cls, double assign in parent class Component.js :: onRender
4932             html: this.html
4933         };
4934         
4935         return cfg;
4936     },
4937     
4938     initEvents: function() 
4939     {
4940         Roo.bootstrap.Element.superclass.initEvents.call(this);
4941         
4942         if(this.clickable){
4943             this.el.on('click', this.onClick, this);
4944         }
4945         
4946     },
4947     
4948     onClick : function(e)
4949     {
4950         if(this.preventDefault){
4951             e.preventDefault();
4952         }
4953         
4954         this.fireEvent('click', this, e);
4955     },
4956     
4957     getValue : function()
4958     {
4959         return this.el.dom.innerHTML;
4960     },
4961     
4962     setValue : function(value)
4963     {
4964         this.el.dom.innerHTML = value;
4965     }
4966    
4967 });
4968
4969  
4970
4971  /*
4972  * - LGPL
4973  *
4974  * pagination
4975  * 
4976  */
4977
4978 /**
4979  * @class Roo.bootstrap.Pagination
4980  * @extends Roo.bootstrap.Component
4981  * Bootstrap Pagination class
4982  * @cfg {String} size xs | sm | md | lg
4983  * @cfg {Boolean} inverse false | true
4984  * 
4985  * @constructor
4986  * Create a new Pagination
4987  * @param {Object} config The config object
4988  */
4989
4990 Roo.bootstrap.Pagination = function(config){
4991     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4992 };
4993
4994 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
4995     
4996     cls: false,
4997     size: false,
4998     inverse: false,
4999     
5000     getAutoCreate : function(){
5001         var cfg = {
5002             tag: 'ul',
5003                 cls: 'pagination'
5004         };
5005         if (this.inverse) {
5006             cfg.cls += ' inverse';
5007         }
5008         if (this.html) {
5009             cfg.html=this.html;
5010         }
5011         if (this.cls) {
5012             cfg.cls += " " + this.cls;
5013         }
5014         return cfg;
5015     }
5016    
5017 });
5018
5019  
5020
5021  /*
5022  * - LGPL
5023  *
5024  * Pagination item
5025  * 
5026  */
5027
5028
5029 /**
5030  * @class Roo.bootstrap.PaginationItem
5031  * @extends Roo.bootstrap.Component
5032  * Bootstrap PaginationItem class
5033  * @cfg {String} html text
5034  * @cfg {String} href the link
5035  * @cfg {Boolean} preventDefault (true | false) default true
5036  * @cfg {Boolean} active (true | false) default false
5037  * @cfg {Boolean} disabled default false
5038  * 
5039  * 
5040  * @constructor
5041  * Create a new PaginationItem
5042  * @param {Object} config The config object
5043  */
5044
5045
5046 Roo.bootstrap.PaginationItem = function(config){
5047     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5048     this.addEvents({
5049         // raw events
5050         /**
5051          * @event click
5052          * The raw click event for the entire grid.
5053          * @param {Roo.EventObject} e
5054          */
5055         "click" : true
5056     });
5057 };
5058
5059 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
5060     
5061     href : false,
5062     html : false,
5063     preventDefault: true,
5064     active : false,
5065     cls : false,
5066     disabled: false,
5067     
5068     getAutoCreate : function(){
5069         var cfg= {
5070             tag: 'li',
5071             cn: [
5072                 {
5073                     tag : 'a',
5074                     href : this.href ? this.href : '#',
5075                     html : this.html ? this.html : ''
5076                 }
5077             ]
5078         };
5079         
5080         if(this.cls){
5081             cfg.cls = this.cls;
5082         }
5083         
5084         if(this.disabled){
5085             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5086         }
5087         
5088         if(this.active){
5089             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5090         }
5091         
5092         return cfg;
5093     },
5094     
5095     initEvents: function() {
5096         
5097         this.el.on('click', this.onClick, this);
5098         
5099     },
5100     onClick : function(e)
5101     {
5102         Roo.log('PaginationItem on click ');
5103         if(this.preventDefault){
5104             e.preventDefault();
5105         }
5106         
5107         if(this.disabled){
5108             return;
5109         }
5110         
5111         this.fireEvent('click', this, e);
5112     }
5113    
5114 });
5115
5116  
5117
5118  /*
5119  * - LGPL
5120  *
5121  * slider
5122  * 
5123  */
5124
5125
5126 /**
5127  * @class Roo.bootstrap.Slider
5128  * @extends Roo.bootstrap.Component
5129  * Bootstrap Slider class
5130  *    
5131  * @constructor
5132  * Create a new Slider
5133  * @param {Object} config The config object
5134  */
5135
5136 Roo.bootstrap.Slider = function(config){
5137     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5138 };
5139
5140 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
5141     
5142     getAutoCreate : function(){
5143         
5144         var cfg = {
5145             tag: 'div',
5146             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5147             cn: [
5148                 {
5149                     tag: 'a',
5150                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
5151                 }
5152             ]
5153         };
5154         
5155         return cfg;
5156     }
5157    
5158 });
5159
5160  /*
5161  * Based on:
5162  * Ext JS Library 1.1.1
5163  * Copyright(c) 2006-2007, Ext JS, LLC.
5164  *
5165  * Originally Released Under LGPL - original licence link has changed is not relivant.
5166  *
5167  * Fork - LGPL
5168  * <script type="text/javascript">
5169  */
5170  
5171
5172 /**
5173  * @class Roo.grid.ColumnModel
5174  * @extends Roo.util.Observable
5175  * This is the default implementation of a ColumnModel used by the Grid. It defines
5176  * the columns in the grid.
5177  * <br>Usage:<br>
5178  <pre><code>
5179  var colModel = new Roo.grid.ColumnModel([
5180         {header: "Ticker", width: 60, sortable: true, locked: true},
5181         {header: "Company Name", width: 150, sortable: true},
5182         {header: "Market Cap.", width: 100, sortable: true},
5183         {header: "$ Sales", width: 100, sortable: true, renderer: money},
5184         {header: "Employees", width: 100, sortable: true, resizable: false}
5185  ]);
5186  </code></pre>
5187  * <p>
5188  
5189  * The config options listed for this class are options which may appear in each
5190  * individual column definition.
5191  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5192  * @constructor
5193  * @param {Object} config An Array of column config objects. See this class's
5194  * config objects for details.
5195 */
5196 Roo.grid.ColumnModel = function(config){
5197         /**
5198      * The config passed into the constructor
5199      */
5200     this.config = config;
5201     this.lookup = {};
5202
5203     // if no id, create one
5204     // if the column does not have a dataIndex mapping,
5205     // map it to the order it is in the config
5206     for(var i = 0, len = config.length; i < len; i++){
5207         var c = config[i];
5208         if(typeof c.dataIndex == "undefined"){
5209             c.dataIndex = i;
5210         }
5211         if(typeof c.renderer == "string"){
5212             c.renderer = Roo.util.Format[c.renderer];
5213         }
5214         if(typeof c.id == "undefined"){
5215             c.id = Roo.id();
5216         }
5217         if(c.editor && c.editor.xtype){
5218             c.editor  = Roo.factory(c.editor, Roo.grid);
5219         }
5220         if(c.editor && c.editor.isFormField){
5221             c.editor = new Roo.grid.GridEditor(c.editor);
5222         }
5223         this.lookup[c.id] = c;
5224     }
5225
5226     /**
5227      * The width of columns which have no width specified (defaults to 100)
5228      * @type Number
5229      */
5230     this.defaultWidth = 100;
5231
5232     /**
5233      * Default sortable of columns which have no sortable specified (defaults to false)
5234      * @type Boolean
5235      */
5236     this.defaultSortable = false;
5237
5238     this.addEvents({
5239         /**
5240              * @event widthchange
5241              * Fires when the width of a column changes.
5242              * @param {ColumnModel} this
5243              * @param {Number} columnIndex The column index
5244              * @param {Number} newWidth The new width
5245              */
5246             "widthchange": true,
5247         /**
5248              * @event headerchange
5249              * Fires when the text of a header changes.
5250              * @param {ColumnModel} this
5251              * @param {Number} columnIndex The column index
5252              * @param {Number} newText The new header text
5253              */
5254             "headerchange": true,
5255         /**
5256              * @event hiddenchange
5257              * Fires when a column is hidden or "unhidden".
5258              * @param {ColumnModel} this
5259              * @param {Number} columnIndex The column index
5260              * @param {Boolean} hidden true if hidden, false otherwise
5261              */
5262             "hiddenchange": true,
5263             /**
5264          * @event columnmoved
5265          * Fires when a column is moved.
5266          * @param {ColumnModel} this
5267          * @param {Number} oldIndex
5268          * @param {Number} newIndex
5269          */
5270         "columnmoved" : true,
5271         /**
5272          * @event columlockchange
5273          * Fires when a column's locked state is changed
5274          * @param {ColumnModel} this
5275          * @param {Number} colIndex
5276          * @param {Boolean} locked true if locked
5277          */
5278         "columnlockchange" : true
5279     });
5280     Roo.grid.ColumnModel.superclass.constructor.call(this);
5281 };
5282 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5283     /**
5284      * @cfg {String} header The header text to display in the Grid view.
5285      */
5286     /**
5287      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5288      * {@link Roo.data.Record} definition from which to draw the column's value. If not
5289      * specified, the column's index is used as an index into the Record's data Array.
5290      */
5291     /**
5292      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5293      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5294      */
5295     /**
5296      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5297      * Defaults to the value of the {@link #defaultSortable} property.
5298      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5299      */
5300     /**
5301      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
5302      */
5303     /**
5304      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
5305      */
5306     /**
5307      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5308      */
5309     /**
5310      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5311      */
5312     /**
5313      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5314      * given the cell's data value. See {@link #setRenderer}. If not specified, the
5315      * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5316      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5317      */
5318        /**
5319      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
5320      */
5321     /**
5322      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
5323      */
5324     /**
5325      * @cfg {String} cursor (Optional)
5326      */
5327     /**
5328      * @cfg {String} tooltip (Optional)
5329      */
5330     /**
5331      * @cfg {Number} xs (Optional)
5332      */
5333     /**
5334      * @cfg {Number} sm (Optional)
5335      */
5336     /**
5337      * @cfg {Number} md (Optional)
5338      */
5339     /**
5340      * @cfg {Number} lg (Optional)
5341      */
5342     /**
5343      * Returns the id of the column at the specified index.
5344      * @param {Number} index The column index
5345      * @return {String} the id
5346      */
5347     getColumnId : function(index){
5348         return this.config[index].id;
5349     },
5350
5351     /**
5352      * Returns the column for a specified id.
5353      * @param {String} id The column id
5354      * @return {Object} the column
5355      */
5356     getColumnById : function(id){
5357         return this.lookup[id];
5358     },
5359
5360     
5361     /**
5362      * Returns the column for a specified dataIndex.
5363      * @param {String} dataIndex The column dataIndex
5364      * @return {Object|Boolean} the column or false if not found
5365      */
5366     getColumnByDataIndex: function(dataIndex){
5367         var index = this.findColumnIndex(dataIndex);
5368         return index > -1 ? this.config[index] : false;
5369     },
5370     
5371     /**
5372      * Returns the index for a specified column id.
5373      * @param {String} id The column id
5374      * @return {Number} the index, or -1 if not found
5375      */
5376     getIndexById : function(id){
5377         for(var i = 0, len = this.config.length; i < len; i++){
5378             if(this.config[i].id == id){
5379                 return i;
5380             }
5381         }
5382         return -1;
5383     },
5384     
5385     /**
5386      * Returns the index for a specified column dataIndex.
5387      * @param {String} dataIndex The column dataIndex
5388      * @return {Number} the index, or -1 if not found
5389      */
5390     
5391     findColumnIndex : function(dataIndex){
5392         for(var i = 0, len = this.config.length; i < len; i++){
5393             if(this.config[i].dataIndex == dataIndex){
5394                 return i;
5395             }
5396         }
5397         return -1;
5398     },
5399     
5400     
5401     moveColumn : function(oldIndex, newIndex){
5402         var c = this.config[oldIndex];
5403         this.config.splice(oldIndex, 1);
5404         this.config.splice(newIndex, 0, c);
5405         this.dataMap = null;
5406         this.fireEvent("columnmoved", this, oldIndex, newIndex);
5407     },
5408
5409     isLocked : function(colIndex){
5410         return this.config[colIndex].locked === true;
5411     },
5412
5413     setLocked : function(colIndex, value, suppressEvent){
5414         if(this.isLocked(colIndex) == value){
5415             return;
5416         }
5417         this.config[colIndex].locked = value;
5418         if(!suppressEvent){
5419             this.fireEvent("columnlockchange", this, colIndex, value);
5420         }
5421     },
5422
5423     getTotalLockedWidth : function(){
5424         var totalWidth = 0;
5425         for(var i = 0; i < this.config.length; i++){
5426             if(this.isLocked(i) && !this.isHidden(i)){
5427                 this.totalWidth += this.getColumnWidth(i);
5428             }
5429         }
5430         return totalWidth;
5431     },
5432
5433     getLockedCount : function(){
5434         for(var i = 0, len = this.config.length; i < len; i++){
5435             if(!this.isLocked(i)){
5436                 return i;
5437             }
5438         }
5439         
5440         return this.config.length;
5441     },
5442
5443     /**
5444      * Returns the number of columns.
5445      * @return {Number}
5446      */
5447     getColumnCount : function(visibleOnly){
5448         if(visibleOnly === true){
5449             var c = 0;
5450             for(var i = 0, len = this.config.length; i < len; i++){
5451                 if(!this.isHidden(i)){
5452                     c++;
5453                 }
5454             }
5455             return c;
5456         }
5457         return this.config.length;
5458     },
5459
5460     /**
5461      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5462      * @param {Function} fn
5463      * @param {Object} scope (optional)
5464      * @return {Array} result
5465      */
5466     getColumnsBy : function(fn, scope){
5467         var r = [];
5468         for(var i = 0, len = this.config.length; i < len; i++){
5469             var c = this.config[i];
5470             if(fn.call(scope||this, c, i) === true){
5471                 r[r.length] = c;
5472             }
5473         }
5474         return r;
5475     },
5476
5477     /**
5478      * Returns true if the specified column is sortable.
5479      * @param {Number} col The column index
5480      * @return {Boolean}
5481      */
5482     isSortable : function(col){
5483         if(typeof this.config[col].sortable == "undefined"){
5484             return this.defaultSortable;
5485         }
5486         return this.config[col].sortable;
5487     },
5488
5489     /**
5490      * Returns the rendering (formatting) function defined for the column.
5491      * @param {Number} col The column index.
5492      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5493      */
5494     getRenderer : function(col){
5495         if(!this.config[col].renderer){
5496             return Roo.grid.ColumnModel.defaultRenderer;
5497         }
5498         return this.config[col].renderer;
5499     },
5500
5501     /**
5502      * Sets the rendering (formatting) function for a column.
5503      * @param {Number} col The column index
5504      * @param {Function} fn The function to use to process the cell's raw data
5505      * to return HTML markup for the grid view. The render function is called with
5506      * the following parameters:<ul>
5507      * <li>Data value.</li>
5508      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5509      * <li>css A CSS style string to apply to the table cell.</li>
5510      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5511      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5512      * <li>Row index</li>
5513      * <li>Column index</li>
5514      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5515      */
5516     setRenderer : function(col, fn){
5517         this.config[col].renderer = fn;
5518     },
5519
5520     /**
5521      * Returns the width for the specified column.
5522      * @param {Number} col The column index
5523      * @return {Number}
5524      */
5525     getColumnWidth : function(col){
5526         return this.config[col].width * 1 || this.defaultWidth;
5527     },
5528
5529     /**
5530      * Sets the width for a column.
5531      * @param {Number} col The column index
5532      * @param {Number} width The new width
5533      */
5534     setColumnWidth : function(col, width, suppressEvent){
5535         this.config[col].width = width;
5536         this.totalWidth = null;
5537         if(!suppressEvent){
5538              this.fireEvent("widthchange", this, col, width);
5539         }
5540     },
5541
5542     /**
5543      * Returns the total width of all columns.
5544      * @param {Boolean} includeHidden True to include hidden column widths
5545      * @return {Number}
5546      */
5547     getTotalWidth : function(includeHidden){
5548         if(!this.totalWidth){
5549             this.totalWidth = 0;
5550             for(var i = 0, len = this.config.length; i < len; i++){
5551                 if(includeHidden || !this.isHidden(i)){
5552                     this.totalWidth += this.getColumnWidth(i);
5553                 }
5554             }
5555         }
5556         return this.totalWidth;
5557     },
5558
5559     /**
5560      * Returns the header for the specified column.
5561      * @param {Number} col The column index
5562      * @return {String}
5563      */
5564     getColumnHeader : function(col){
5565         return this.config[col].header;
5566     },
5567
5568     /**
5569      * Sets the header for a column.
5570      * @param {Number} col The column index
5571      * @param {String} header The new header
5572      */
5573     setColumnHeader : function(col, header){
5574         this.config[col].header = header;
5575         this.fireEvent("headerchange", this, col, header);
5576     },
5577
5578     /**
5579      * Returns the tooltip for the specified column.
5580      * @param {Number} col The column index
5581      * @return {String}
5582      */
5583     getColumnTooltip : function(col){
5584             return this.config[col].tooltip;
5585     },
5586     /**
5587      * Sets the tooltip for a column.
5588      * @param {Number} col The column index
5589      * @param {String} tooltip The new tooltip
5590      */
5591     setColumnTooltip : function(col, tooltip){
5592             this.config[col].tooltip = tooltip;
5593     },
5594
5595     /**
5596      * Returns the dataIndex for the specified column.
5597      * @param {Number} col The column index
5598      * @return {Number}
5599      */
5600     getDataIndex : function(col){
5601         return this.config[col].dataIndex;
5602     },
5603
5604     /**
5605      * Sets the dataIndex for a column.
5606      * @param {Number} col The column index
5607      * @param {Number} dataIndex The new dataIndex
5608      */
5609     setDataIndex : function(col, dataIndex){
5610         this.config[col].dataIndex = dataIndex;
5611     },
5612
5613     
5614     
5615     /**
5616      * Returns true if the cell is editable.
5617      * @param {Number} colIndex The column index
5618      * @param {Number} rowIndex The row index - this is nto actually used..?
5619      * @return {Boolean}
5620      */
5621     isCellEditable : function(colIndex, rowIndex){
5622         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5623     },
5624
5625     /**
5626      * Returns the editor defined for the cell/column.
5627      * return false or null to disable editing.
5628      * @param {Number} colIndex The column index
5629      * @param {Number} rowIndex The row index
5630      * @return {Object}
5631      */
5632     getCellEditor : function(colIndex, rowIndex){
5633         return this.config[colIndex].editor;
5634     },
5635
5636     /**
5637      * Sets if a column is editable.
5638      * @param {Number} col The column index
5639      * @param {Boolean} editable True if the column is editable
5640      */
5641     setEditable : function(col, editable){
5642         this.config[col].editable = editable;
5643     },
5644
5645
5646     /**
5647      * Returns true if the column is hidden.
5648      * @param {Number} colIndex The column index
5649      * @return {Boolean}
5650      */
5651     isHidden : function(colIndex){
5652         return this.config[colIndex].hidden;
5653     },
5654
5655
5656     /**
5657      * Returns true if the column width cannot be changed
5658      */
5659     isFixed : function(colIndex){
5660         return this.config[colIndex].fixed;
5661     },
5662
5663     /**
5664      * Returns true if the column can be resized
5665      * @return {Boolean}
5666      */
5667     isResizable : function(colIndex){
5668         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5669     },
5670     /**
5671      * Sets if a column is hidden.
5672      * @param {Number} colIndex The column index
5673      * @param {Boolean} hidden True if the column is hidden
5674      */
5675     setHidden : function(colIndex, hidden){
5676         this.config[colIndex].hidden = hidden;
5677         this.totalWidth = null;
5678         this.fireEvent("hiddenchange", this, colIndex, hidden);
5679     },
5680
5681     /**
5682      * Sets the editor for a column.
5683      * @param {Number} col The column index
5684      * @param {Object} editor The editor object
5685      */
5686     setEditor : function(col, editor){
5687         this.config[col].editor = editor;
5688     }
5689 });
5690
5691 Roo.grid.ColumnModel.defaultRenderer = function(value)
5692 {
5693     if(typeof value == "object") {
5694         return value;
5695     }
5696         if(typeof value == "string" && value.length < 1){
5697             return "&#160;";
5698         }
5699     
5700         return String.format("{0}", value);
5701 };
5702
5703 // Alias for backwards compatibility
5704 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5705 /*
5706  * Based on:
5707  * Ext JS Library 1.1.1
5708  * Copyright(c) 2006-2007, Ext JS, LLC.
5709  *
5710  * Originally Released Under LGPL - original licence link has changed is not relivant.
5711  *
5712  * Fork - LGPL
5713  * <script type="text/javascript">
5714  */
5715  
5716 /**
5717  * @class Roo.LoadMask
5718  * A simple utility class for generically masking elements while loading data.  If the element being masked has
5719  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5720  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
5721  * element's UpdateManager load indicator and will be destroyed after the initial load.
5722  * @constructor
5723  * Create a new LoadMask
5724  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5725  * @param {Object} config The config object
5726  */
5727 Roo.LoadMask = function(el, config){
5728     this.el = Roo.get(el);
5729     Roo.apply(this, config);
5730     if(this.store){
5731         this.store.on('beforeload', this.onBeforeLoad, this);
5732         this.store.on('load', this.onLoad, this);
5733         this.store.on('loadexception', this.onLoadException, this);
5734         this.removeMask = false;
5735     }else{
5736         var um = this.el.getUpdateManager();
5737         um.showLoadIndicator = false; // disable the default indicator
5738         um.on('beforeupdate', this.onBeforeLoad, this);
5739         um.on('update', this.onLoad, this);
5740         um.on('failure', this.onLoad, this);
5741         this.removeMask = true;
5742     }
5743 };
5744
5745 Roo.LoadMask.prototype = {
5746     /**
5747      * @cfg {Boolean} removeMask
5748      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5749      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
5750      */
5751     /**
5752      * @cfg {String} msg
5753      * The text to display in a centered loading message box (defaults to 'Loading...')
5754      */
5755     msg : 'Loading...',
5756     /**
5757      * @cfg {String} msgCls
5758      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5759      */
5760     msgCls : 'x-mask-loading',
5761
5762     /**
5763      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5764      * @type Boolean
5765      */
5766     disabled: false,
5767
5768     /**
5769      * Disables the mask to prevent it from being displayed
5770      */
5771     disable : function(){
5772        this.disabled = true;
5773     },
5774
5775     /**
5776      * Enables the mask so that it can be displayed
5777      */
5778     enable : function(){
5779         this.disabled = false;
5780     },
5781     
5782     onLoadException : function()
5783     {
5784         Roo.log(arguments);
5785         
5786         if (typeof(arguments[3]) != 'undefined') {
5787             Roo.MessageBox.alert("Error loading",arguments[3]);
5788         } 
5789         /*
5790         try {
5791             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5792                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5793             }   
5794         } catch(e) {
5795             
5796         }
5797         */
5798     
5799         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5800     },
5801     // private
5802     onLoad : function()
5803     {
5804         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5805     },
5806
5807     // private
5808     onBeforeLoad : function(){
5809         if(!this.disabled){
5810             (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5811         }
5812     },
5813
5814     // private
5815     destroy : function(){
5816         if(this.store){
5817             this.store.un('beforeload', this.onBeforeLoad, this);
5818             this.store.un('load', this.onLoad, this);
5819             this.store.un('loadexception', this.onLoadException, this);
5820         }else{
5821             var um = this.el.getUpdateManager();
5822             um.un('beforeupdate', this.onBeforeLoad, this);
5823             um.un('update', this.onLoad, this);
5824             um.un('failure', this.onLoad, this);
5825         }
5826     }
5827 };/*
5828  * - LGPL
5829  *
5830  * table
5831  * 
5832  */
5833
5834 /**
5835  * @class Roo.bootstrap.Table
5836  * @extends Roo.bootstrap.Component
5837  * Bootstrap Table class
5838  * @cfg {String} cls table class
5839  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5840  * @cfg {String} bgcolor Specifies the background color for a table
5841  * @cfg {Number} border Specifies whether the table cells should have borders or not
5842  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5843  * @cfg {Number} cellspacing Specifies the space between cells
5844  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5845  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5846  * @cfg {String} sortable Specifies that the table should be sortable
5847  * @cfg {String} summary Specifies a summary of the content of a table
5848  * @cfg {Number} width Specifies the width of a table
5849  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5850  * 
5851  * @cfg {boolean} striped Should the rows be alternative striped
5852  * @cfg {boolean} bordered Add borders to the table
5853  * @cfg {boolean} hover Add hover highlighting
5854  * @cfg {boolean} condensed Format condensed
5855  * @cfg {boolean} responsive Format condensed
5856  * @cfg {Boolean} loadMask (true|false) default false
5857  * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5858  * @cfg {Boolean} headerShow (true|false) generate thead, default true
5859  * @cfg {Boolean} rowSelection (true|false) default false
5860  * @cfg {Boolean} cellSelection (true|false) default false
5861  * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5862  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5863  * @cfg {Boolean} lazyLoad  auto load data while scrolling to the end (default false)
5864  
5865  * 
5866  * @constructor
5867  * Create a new Table
5868  * @param {Object} config The config object
5869  */
5870
5871 Roo.bootstrap.Table = function(config){
5872     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5873     
5874   
5875     
5876     // BC...
5877     this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5878     this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5879     this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5880     this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5881     
5882     this.sm = this.sm || {xtype: 'RowSelectionModel'};
5883     if (this.sm) {
5884         this.sm.grid = this;
5885         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5886         this.sm = this.selModel;
5887         this.sm.xmodule = this.xmodule || false;
5888     }
5889     
5890     if (this.cm && typeof(this.cm.config) == 'undefined') {
5891         this.colModel = new Roo.grid.ColumnModel(this.cm);
5892         this.cm = this.colModel;
5893         this.cm.xmodule = this.xmodule || false;
5894     }
5895     if (this.store) {
5896         this.store= Roo.factory(this.store, Roo.data);
5897         this.ds = this.store;
5898         this.ds.xmodule = this.xmodule || false;
5899          
5900     }
5901     if (this.footer && this.store) {
5902         this.footer.dataSource = this.ds;
5903         this.footer = Roo.factory(this.footer);
5904     }
5905     
5906     /** @private */
5907     this.addEvents({
5908         /**
5909          * @event cellclick
5910          * Fires when a cell is clicked
5911          * @param {Roo.bootstrap.Table} this
5912          * @param {Roo.Element} el
5913          * @param {Number} rowIndex
5914          * @param {Number} columnIndex
5915          * @param {Roo.EventObject} e
5916          */
5917         "cellclick" : true,
5918         /**
5919          * @event celldblclick
5920          * Fires when a cell is double clicked
5921          * @param {Roo.bootstrap.Table} this
5922          * @param {Roo.Element} el
5923          * @param {Number} rowIndex
5924          * @param {Number} columnIndex
5925          * @param {Roo.EventObject} e
5926          */
5927         "celldblclick" : true,
5928         /**
5929          * @event rowclick
5930          * Fires when a row is clicked
5931          * @param {Roo.bootstrap.Table} this
5932          * @param {Roo.Element} el
5933          * @param {Number} rowIndex
5934          * @param {Roo.EventObject} e
5935          */
5936         "rowclick" : true,
5937         /**
5938          * @event rowdblclick
5939          * Fires when a row is double clicked
5940          * @param {Roo.bootstrap.Table} this
5941          * @param {Roo.Element} el
5942          * @param {Number} rowIndex
5943          * @param {Roo.EventObject} e
5944          */
5945         "rowdblclick" : true,
5946         /**
5947          * @event mouseover
5948          * Fires when a mouseover occur
5949          * @param {Roo.bootstrap.Table} this
5950          * @param {Roo.Element} el
5951          * @param {Number} rowIndex
5952          * @param {Number} columnIndex
5953          * @param {Roo.EventObject} e
5954          */
5955         "mouseover" : true,
5956         /**
5957          * @event mouseout
5958          * Fires when a mouseout occur
5959          * @param {Roo.bootstrap.Table} this
5960          * @param {Roo.Element} el
5961          * @param {Number} rowIndex
5962          * @param {Number} columnIndex
5963          * @param {Roo.EventObject} e
5964          */
5965         "mouseout" : true,
5966         /**
5967          * @event rowclass
5968          * Fires when a row is rendered, so you can change add a style to it.
5969          * @param {Roo.bootstrap.Table} this
5970          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5971          */
5972         'rowclass' : true,
5973           /**
5974          * @event rowsrendered
5975          * Fires when all the  rows have been rendered
5976          * @param {Roo.bootstrap.Table} this
5977          */
5978         'rowsrendered' : true,
5979         /**
5980          * @event contextmenu
5981          * The raw contextmenu event for the entire grid.
5982          * @param {Roo.EventObject} e
5983          */
5984         "contextmenu" : true,
5985         /**
5986          * @event rowcontextmenu
5987          * Fires when a row is right clicked
5988          * @param {Roo.bootstrap.Table} this
5989          * @param {Number} rowIndex
5990          * @param {Roo.EventObject} e
5991          */
5992         "rowcontextmenu" : true,
5993         /**
5994          * @event cellcontextmenu
5995          * Fires when a cell is right clicked
5996          * @param {Roo.bootstrap.Table} this
5997          * @param {Number} rowIndex
5998          * @param {Number} cellIndex
5999          * @param {Roo.EventObject} e
6000          */
6001          "cellcontextmenu" : true,
6002          /**
6003          * @event headercontextmenu
6004          * Fires when a header is right clicked
6005          * @param {Roo.bootstrap.Table} this
6006          * @param {Number} columnIndex
6007          * @param {Roo.EventObject} e
6008          */
6009         "headercontextmenu" : true
6010     });
6011 };
6012
6013 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
6014     
6015     cls: false,
6016     align: false,
6017     bgcolor: false,
6018     border: false,
6019     cellpadding: false,
6020     cellspacing: false,
6021     frame: false,
6022     rules: false,
6023     sortable: false,
6024     summary: false,
6025     width: false,
6026     striped : false,
6027     scrollBody : false,
6028     bordered: false,
6029     hover:  false,
6030     condensed : false,
6031     responsive : false,
6032     sm : false,
6033     cm : false,
6034     store : false,
6035     loadMask : false,
6036     footerShow : true,
6037     headerShow : true,
6038   
6039     rowSelection : false,
6040     cellSelection : false,
6041     layout : false,
6042     
6043     // Roo.Element - the tbody
6044     mainBody: false,
6045     // Roo.Element - thead element
6046     mainHead: false,
6047     
6048     container: false, // used by gridpanel...
6049     
6050     lazyLoad : false,
6051     
6052     CSS : Roo.util.CSS,
6053     
6054     getAutoCreate : function()
6055     {
6056         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6057         
6058         cfg = {
6059             tag: 'table',
6060             cls : 'table',
6061             cn : []
6062         };
6063         if (this.scrollBody) {
6064             cfg.cls += ' table-body-fixed';
6065         }    
6066         if (this.striped) {
6067             cfg.cls += ' table-striped';
6068         }
6069         
6070         if (this.hover) {
6071             cfg.cls += ' table-hover';
6072         }
6073         if (this.bordered) {
6074             cfg.cls += ' table-bordered';
6075         }
6076         if (this.condensed) {
6077             cfg.cls += ' table-condensed';
6078         }
6079         if (this.responsive) {
6080             cfg.cls += ' table-responsive';
6081         }
6082         
6083         if (this.cls) {
6084             cfg.cls+=  ' ' +this.cls;
6085         }
6086         
6087         // this lot should be simplifed...
6088         
6089         if (this.align) {
6090             cfg.align=this.align;
6091         }
6092         if (this.bgcolor) {
6093             cfg.bgcolor=this.bgcolor;
6094         }
6095         if (this.border) {
6096             cfg.border=this.border;
6097         }
6098         if (this.cellpadding) {
6099             cfg.cellpadding=this.cellpadding;
6100         }
6101         if (this.cellspacing) {
6102             cfg.cellspacing=this.cellspacing;
6103         }
6104         if (this.frame) {
6105             cfg.frame=this.frame;
6106         }
6107         if (this.rules) {
6108             cfg.rules=this.rules;
6109         }
6110         if (this.sortable) {
6111             cfg.sortable=this.sortable;
6112         }
6113         if (this.summary) {
6114             cfg.summary=this.summary;
6115         }
6116         if (this.width) {
6117             cfg.width=this.width;
6118         }
6119         if (this.layout) {
6120             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6121         }
6122         
6123         if(this.store || this.cm){
6124             if(this.headerShow){
6125                 cfg.cn.push(this.renderHeader());
6126             }
6127             
6128             cfg.cn.push(this.renderBody());
6129             
6130             if(this.footerShow){
6131                 cfg.cn.push(this.renderFooter());
6132             }
6133             // where does this come from?
6134             //cfg.cls+=  ' TableGrid';
6135         }
6136         
6137         return { cn : [ cfg ] };
6138     },
6139     
6140     initEvents : function()
6141     {   
6142         if(!this.store || !this.cm){
6143             return;
6144         }
6145         if (this.selModel) {
6146             this.selModel.initEvents();
6147         }
6148         
6149         
6150         //Roo.log('initEvents with ds!!!!');
6151         
6152         this.mainBody = this.el.select('tbody', true).first();
6153         this.mainHead = this.el.select('thead', true).first();
6154         
6155         
6156         
6157         
6158         var _this = this;
6159         
6160         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6161             e.on('click', _this.sort, _this);
6162         });
6163         
6164         this.mainBody.on("click", this.onClick, this);
6165         this.mainBody.on("dblclick", this.onDblClick, this);
6166         
6167         // why is this done????? = it breaks dialogs??
6168         //this.parent().el.setStyle('position', 'relative');
6169         
6170         
6171         if (this.footer) {
6172             this.footer.parentId = this.id;
6173             this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6174             
6175             if(this.lazyLoad){
6176                 this.el.select('tfoot tr td').first().addClass('hide');
6177             }
6178         } 
6179         
6180         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6181         
6182         this.store.on('load', this.onLoad, this);
6183         this.store.on('beforeload', this.onBeforeLoad, this);
6184         this.store.on('update', this.onUpdate, this);
6185         this.store.on('add', this.onAdd, this);
6186         this.store.on("clear", this.clear, this);
6187         
6188         this.el.on("contextmenu", this.onContextMenu, this);
6189         
6190         this.mainBody.on('scroll', this.onBodyScroll, this);
6191         
6192         this.cm.on("headerchange", this.onHeaderChange, this);
6193         
6194         this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6195         
6196     },
6197     
6198     onContextMenu : function(e, t)
6199     {
6200         this.processEvent("contextmenu", e);
6201     },
6202     
6203     processEvent : function(name, e)
6204     {
6205         if (name != 'touchstart' ) {
6206             this.fireEvent(name, e);    
6207         }
6208         
6209         var t = e.getTarget();
6210         
6211         var cell = Roo.get(t);
6212         
6213         if(!cell){
6214             return;
6215         }
6216         
6217         if(cell.findParent('tfoot', false, true)){
6218             return;
6219         }
6220         
6221         if(cell.findParent('thead', false, true)){
6222             
6223             if(e.getTarget().nodeName.toLowerCase() != 'th'){
6224                 cell = Roo.get(t).findParent('th', false, true);
6225                 if (!cell) {
6226                     Roo.log("failed to find th in thead?");
6227                     Roo.log(e.getTarget());
6228                     return;
6229                 }
6230             }
6231             
6232             var cellIndex = cell.dom.cellIndex;
6233             
6234             var ename = name == 'touchstart' ? 'click' : name;
6235             this.fireEvent("header" + ename, this, cellIndex, e);
6236             
6237             return;
6238         }
6239         
6240         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6241             cell = Roo.get(t).findParent('td', false, true);
6242             if (!cell) {
6243                 Roo.log("failed to find th in tbody?");
6244                 Roo.log(e.getTarget());
6245                 return;
6246             }
6247         }
6248         
6249         var row = cell.findParent('tr', false, true);
6250         var cellIndex = cell.dom.cellIndex;
6251         var rowIndex = row.dom.rowIndex - 1;
6252         
6253         if(row !== false){
6254             
6255             this.fireEvent("row" + name, this, rowIndex, e);
6256             
6257             if(cell !== false){
6258             
6259                 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6260             }
6261         }
6262         
6263     },
6264     
6265     onMouseover : function(e, el)
6266     {
6267         var cell = Roo.get(el);
6268         
6269         if(!cell){
6270             return;
6271         }
6272         
6273         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6274             cell = cell.findParent('td', false, true);
6275         }
6276         
6277         var row = cell.findParent('tr', false, true);
6278         var cellIndex = cell.dom.cellIndex;
6279         var rowIndex = row.dom.rowIndex - 1; // start from 0
6280         
6281         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6282         
6283     },
6284     
6285     onMouseout : function(e, el)
6286     {
6287         var cell = Roo.get(el);
6288         
6289         if(!cell){
6290             return;
6291         }
6292         
6293         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6294             cell = cell.findParent('td', false, true);
6295         }
6296         
6297         var row = cell.findParent('tr', false, true);
6298         var cellIndex = cell.dom.cellIndex;
6299         var rowIndex = row.dom.rowIndex - 1; // start from 0
6300         
6301         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6302         
6303     },
6304     
6305     onClick : function(e, el)
6306     {
6307         var cell = Roo.get(el);
6308         
6309         if(!cell || (!this.cellSelection && !this.rowSelection)){
6310             return;
6311         }
6312         
6313         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6314             cell = cell.findParent('td', false, true);
6315         }
6316         
6317         if(!cell || typeof(cell) == 'undefined'){
6318             return;
6319         }
6320         
6321         var row = cell.findParent('tr', false, true);
6322         
6323         if(!row || typeof(row) == 'undefined'){
6324             return;
6325         }
6326         
6327         var cellIndex = cell.dom.cellIndex;
6328         var rowIndex = this.getRowIndex(row);
6329         
6330         // why??? - should these not be based on SelectionModel?
6331         if(this.cellSelection){
6332             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6333         }
6334         
6335         if(this.rowSelection){
6336             this.fireEvent('rowclick', this, row, rowIndex, e);
6337         }
6338         
6339         
6340     },
6341         
6342     onDblClick : function(e,el)
6343     {
6344         var cell = Roo.get(el);
6345         
6346         if(!cell || (!this.cellSelection && !this.rowSelection)){
6347             return;
6348         }
6349         
6350         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6351             cell = cell.findParent('td', false, true);
6352         }
6353         
6354         if(!cell || typeof(cell) == 'undefined'){
6355             return;
6356         }
6357         
6358         var row = cell.findParent('tr', false, true);
6359         
6360         if(!row || typeof(row) == 'undefined'){
6361             return;
6362         }
6363         
6364         var cellIndex = cell.dom.cellIndex;
6365         var rowIndex = this.getRowIndex(row);
6366         
6367         if(this.cellSelection){
6368             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6369         }
6370         
6371         if(this.rowSelection){
6372             this.fireEvent('rowdblclick', this, row, rowIndex, e);
6373         }
6374     },
6375     
6376     sort : function(e,el)
6377     {
6378         var col = Roo.get(el);
6379         
6380         if(!col.hasClass('sortable')){
6381             return;
6382         }
6383         
6384         var sort = col.attr('sort');
6385         var dir = 'ASC';
6386         
6387         if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6388             dir = 'DESC';
6389         }
6390         
6391         this.store.sortInfo = {field : sort, direction : dir};
6392         
6393         if (this.footer) {
6394             Roo.log("calling footer first");
6395             this.footer.onClick('first');
6396         } else {
6397         
6398             this.store.load({ params : { start : 0 } });
6399         }
6400     },
6401     
6402     renderHeader : function()
6403     {
6404         var header = {
6405             tag: 'thead',
6406             cn : []
6407         };
6408         
6409         var cm = this.cm;
6410         this.totalWidth = 0;
6411         
6412         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6413             
6414             var config = cm.config[i];
6415             
6416             var c = {
6417                 tag: 'th',
6418                 cls : 'roo-bootstrap-thead-col-' + i,
6419                 style : '',
6420                 html: cm.getColumnHeader(i)
6421             };
6422             
6423             var hh = '';
6424             
6425             if(typeof(config.sortable) != 'undefined' && config.sortable){
6426                 c.cls = 'sortable';
6427                 c.html = '<i class="glyphicon"></i>' + c.html;
6428             }
6429             
6430             if(typeof(config.lgHeader) != 'undefined'){
6431                 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6432             }
6433             
6434             if(typeof(config.mdHeader) != 'undefined'){
6435                 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6436             }
6437             
6438             if(typeof(config.smHeader) != 'undefined'){
6439                 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6440             }
6441             
6442             if(typeof(config.xsHeader) != 'undefined'){
6443                 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6444             }
6445             
6446             if(hh.length){
6447                 c.html = hh;
6448             }
6449             
6450             if(typeof(config.tooltip) != 'undefined'){
6451                 c.tooltip = config.tooltip;
6452             }
6453             
6454             if(typeof(config.colspan) != 'undefined'){
6455                 c.colspan = config.colspan;
6456             }
6457             
6458             if(typeof(config.hidden) != 'undefined' && config.hidden){
6459                 c.style += ' display:none;';
6460             }
6461             
6462             if(typeof(config.dataIndex) != 'undefined'){
6463                 c.sort = config.dataIndex;
6464             }
6465             
6466            
6467             
6468             if(typeof(config.align) != 'undefined' && config.align.length){
6469                 c.style += ' text-align:' + config.align + ';';
6470             }
6471             
6472             if(typeof(config.width) != 'undefined'){
6473                 c.style += ' width:' + config.width + 'px;';
6474                 this.totalWidth += config.width;
6475             } else {
6476                 this.totalWidth += 100; // assume minimum of 100 per column?
6477             }
6478             
6479             if(typeof(config.cls) != 'undefined'){
6480                 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6481             }
6482             
6483             ['xs','sm','md','lg'].map(function(size){
6484                 
6485                 if(typeof(config[size]) == 'undefined'){
6486                     return;
6487                 }
6488                 
6489                 if (!config[size]) { // 0 = hidden
6490                     c.cls += ' hidden-' + size;
6491                     return;
6492                 }
6493                 
6494                 c.cls += ' col-' + size + '-' + config[size];
6495
6496             });
6497             
6498             header.cn.push(c)
6499         }
6500         
6501         return header;
6502     },
6503     
6504     renderBody : function()
6505     {
6506         var body = {
6507             tag: 'tbody',
6508             cn : [
6509                 {
6510                     tag: 'tr',
6511                     cn : [
6512                         {
6513                             tag : 'td',
6514                             colspan :  this.cm.getColumnCount()
6515                         }
6516                     ]
6517                 }
6518             ]
6519         };
6520         
6521         return body;
6522     },
6523     
6524     renderFooter : function()
6525     {
6526         var footer = {
6527             tag: 'tfoot',
6528             cn : [
6529                 {
6530                     tag: 'tr',
6531                     cn : [
6532                         {
6533                             tag : 'td',
6534                             colspan :  this.cm.getColumnCount()
6535                         }
6536                     ]
6537                 }
6538             ]
6539         };
6540         
6541         return footer;
6542     },
6543     
6544     
6545     
6546     onLoad : function()
6547     {
6548 //        Roo.log('ds onload');
6549         this.clear();
6550         
6551         var _this = this;
6552         var cm = this.cm;
6553         var ds = this.store;
6554         
6555         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6556             e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6557             if (_this.store.sortInfo) {
6558                     
6559                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6560                     e.select('i', true).addClass(['glyphicon-arrow-up']);
6561                 }
6562                 
6563                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6564                     e.select('i', true).addClass(['glyphicon-arrow-down']);
6565                 }
6566             }
6567         });
6568         
6569         var tbody =  this.mainBody;
6570               
6571         if(ds.getCount() > 0){
6572             ds.data.each(function(d,rowIndex){
6573                 var row =  this.renderRow(cm, ds, rowIndex);
6574                 
6575                 tbody.createChild(row);
6576                 
6577                 var _this = this;
6578                 
6579                 if(row.cellObjects.length){
6580                     Roo.each(row.cellObjects, function(r){
6581                         _this.renderCellObject(r);
6582                     })
6583                 }
6584                 
6585             }, this);
6586         }
6587         
6588         Roo.each(this.el.select('tbody td', true).elements, function(e){
6589             e.on('mouseover', _this.onMouseover, _this);
6590         });
6591         
6592         Roo.each(this.el.select('tbody td', true).elements, function(e){
6593             e.on('mouseout', _this.onMouseout, _this);
6594         });
6595         this.fireEvent('rowsrendered', this);
6596         //if(this.loadMask){
6597         //    this.maskEl.hide();
6598         //}
6599         
6600         this.autoSize();
6601     },
6602     
6603     
6604     onUpdate : function(ds,record)
6605     {
6606         this.refreshRow(record);
6607         this.autoSize();
6608     },
6609     
6610     onRemove : function(ds, record, index, isUpdate){
6611         if(isUpdate !== true){
6612             this.fireEvent("beforerowremoved", this, index, record);
6613         }
6614         var bt = this.mainBody.dom;
6615         
6616         var rows = this.el.select('tbody > tr', true).elements;
6617         
6618         if(typeof(rows[index]) != 'undefined'){
6619             bt.removeChild(rows[index].dom);
6620         }
6621         
6622 //        if(bt.rows[index]){
6623 //            bt.removeChild(bt.rows[index]);
6624 //        }
6625         
6626         if(isUpdate !== true){
6627             //this.stripeRows(index);
6628             //this.syncRowHeights(index, index);
6629             //this.layout();
6630             this.fireEvent("rowremoved", this, index, record);
6631         }
6632     },
6633     
6634     onAdd : function(ds, records, rowIndex)
6635     {
6636         //Roo.log('on Add called');
6637         // - note this does not handle multiple adding very well..
6638         var bt = this.mainBody.dom;
6639         for (var i =0 ; i < records.length;i++) {
6640             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6641             //Roo.log(records[i]);
6642             //Roo.log(this.store.getAt(rowIndex+i));
6643             this.insertRow(this.store, rowIndex + i, false);
6644             return;
6645         }
6646         
6647     },
6648     
6649     
6650     refreshRow : function(record){
6651         var ds = this.store, index;
6652         if(typeof record == 'number'){
6653             index = record;
6654             record = ds.getAt(index);
6655         }else{
6656             index = ds.indexOf(record);
6657         }
6658         this.insertRow(ds, index, true);
6659         this.autoSize();
6660         this.onRemove(ds, record, index+1, true);
6661         this.autoSize();
6662         //this.syncRowHeights(index, index);
6663         //this.layout();
6664         this.fireEvent("rowupdated", this, index, record);
6665     },
6666     
6667     insertRow : function(dm, rowIndex, isUpdate){
6668         
6669         if(!isUpdate){
6670             this.fireEvent("beforerowsinserted", this, rowIndex);
6671         }
6672             //var s = this.getScrollState();
6673         var row = this.renderRow(this.cm, this.store, rowIndex);
6674         // insert before rowIndex..
6675         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6676         
6677         var _this = this;
6678                 
6679         if(row.cellObjects.length){
6680             Roo.each(row.cellObjects, function(r){
6681                 _this.renderCellObject(r);
6682             })
6683         }
6684             
6685         if(!isUpdate){
6686             this.fireEvent("rowsinserted", this, rowIndex);
6687             //this.syncRowHeights(firstRow, lastRow);
6688             //this.stripeRows(firstRow);
6689             //this.layout();
6690         }
6691         
6692     },
6693     
6694     
6695     getRowDom : function(rowIndex)
6696     {
6697         var rows = this.el.select('tbody > tr', true).elements;
6698         
6699         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6700         
6701     },
6702     // returns the object tree for a tr..
6703   
6704     
6705     renderRow : function(cm, ds, rowIndex) 
6706     {
6707         var d = ds.getAt(rowIndex);
6708         
6709         var row = {
6710             tag : 'tr',
6711             cls : 'roo-bootstrap-tbody-row-' + rowIndex,
6712             cn : []
6713         };
6714             
6715         var cellObjects = [];
6716         
6717         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6718             var config = cm.config[i];
6719             
6720             var renderer = cm.getRenderer(i);
6721             var value = '';
6722             var id = false;
6723             
6724             if(typeof(renderer) !== 'undefined'){
6725                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6726             }
6727             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6728             // and are rendered into the cells after the row is rendered - using the id for the element.
6729             
6730             if(typeof(value) === 'object'){
6731                 id = Roo.id();
6732                 cellObjects.push({
6733                     container : id,
6734                     cfg : value 
6735                 })
6736             }
6737             
6738             var rowcfg = {
6739                 record: d,
6740                 rowIndex : rowIndex,
6741                 colIndex : i,
6742                 rowClass : ''
6743             };
6744
6745             this.fireEvent('rowclass', this, rowcfg);
6746             
6747             var td = {
6748                 tag: 'td',
6749                 cls : rowcfg.rowClass + ' roo-bootstrap-tbody-col-' + i,
6750                 style: '',
6751                 html: (typeof(value) === 'object') ? '' : value
6752             };
6753             
6754             if (id) {
6755                 td.id = id;
6756             }
6757             
6758             if(typeof(config.colspan) != 'undefined'){
6759                 td.colspan = config.colspan;
6760             }
6761             
6762             if(typeof(config.hidden) != 'undefined' && config.hidden){
6763                 td.style += ' display:none;';
6764             }
6765             
6766             if(typeof(config.align) != 'undefined' && config.align.length){
6767                 td.style += ' text-align:' + config.align + ';';
6768             }
6769             
6770             if(typeof(config.width) != 'undefined'){
6771                 td.style += ' width:' +  config.width + 'px;';
6772             }
6773             
6774             if(typeof(config.cursor) != 'undefined'){
6775                 td.style += ' cursor:' +  config.cursor + ';';
6776             }
6777             
6778             if(typeof(config.cls) != 'undefined'){
6779                 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6780             }
6781             
6782             ['xs','sm','md','lg'].map(function(size){
6783                 
6784                 if(typeof(config[size]) == 'undefined'){
6785                     return;
6786                 }
6787                 
6788                 if (!config[size]) { // 0 = hidden
6789                     td.cls += ' hidden-' + size;
6790                     return;
6791                 }
6792                 
6793                 td.cls += ' col-' + size + '-' + config[size];
6794
6795             });
6796             
6797             row.cn.push(td);
6798            
6799         }
6800         
6801         row.cellObjects = cellObjects;
6802         
6803         return row;
6804           
6805     },
6806     
6807     
6808     
6809     onBeforeLoad : function()
6810     {
6811         //Roo.log('ds onBeforeLoad');
6812         
6813         //this.clear();
6814         
6815         //if(this.loadMask){
6816         //    this.maskEl.show();
6817         //}
6818     },
6819      /**
6820      * Remove all rows
6821      */
6822     clear : function()
6823     {
6824         this.el.select('tbody', true).first().dom.innerHTML = '';
6825     },
6826     /**
6827      * Show or hide a row.
6828      * @param {Number} rowIndex to show or hide
6829      * @param {Boolean} state hide
6830      */
6831     setRowVisibility : function(rowIndex, state)
6832     {
6833         var bt = this.mainBody.dom;
6834         
6835         var rows = this.el.select('tbody > tr', true).elements;
6836         
6837         if(typeof(rows[rowIndex]) == 'undefined'){
6838             return;
6839         }
6840         rows[rowIndex].dom.style.display = state ? '' : 'none';
6841     },
6842     
6843     
6844     getSelectionModel : function(){
6845         if(!this.selModel){
6846             this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6847         }
6848         return this.selModel;
6849     },
6850     /*
6851      * Render the Roo.bootstrap object from renderder
6852      */
6853     renderCellObject : function(r)
6854     {
6855         var _this = this;
6856         
6857         r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6858         
6859         var t = r.cfg.render(r.container);
6860         
6861         if(r.cfg.cn){
6862             Roo.each(r.cfg.cn, function(c){
6863                 var child = {
6864                     container: t.getChildContainer(),
6865                     cfg: c
6866                 };
6867                 _this.renderCellObject(child);
6868             })
6869         }
6870     },
6871     
6872     getRowIndex : function(row)
6873     {
6874         var rowIndex = -1;
6875         
6876         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6877             if(el != row){
6878                 return;
6879             }
6880             
6881             rowIndex = index;
6882         });
6883         
6884         return rowIndex;
6885     },
6886      /**
6887      * Returns the grid's underlying element = used by panel.Grid
6888      * @return {Element} The element
6889      */
6890     getGridEl : function(){
6891         return this.el;
6892     },
6893      /**
6894      * Forces a resize - used by panel.Grid
6895      * @return {Element} The element
6896      */
6897     autoSize : function()
6898     {
6899         //var ctr = Roo.get(this.container.dom.parentElement);
6900         var ctr = Roo.get(this.el.dom);
6901         
6902         var thd = this.getGridEl().select('thead',true).first();
6903         var tbd = this.getGridEl().select('tbody', true).first();
6904         var tfd = this.getGridEl().select('tfoot', true).first();
6905         
6906         var cw = ctr.getWidth();
6907         
6908         if (tbd) {
6909             
6910             tbd.setSize(ctr.getWidth(),
6911                         ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6912             );
6913             var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6914             cw -= barsize;
6915         }
6916         cw = Math.max(cw, this.totalWidth);
6917         this.getGridEl().select('tr',true).setWidth(cw);
6918         // resize 'expandable coloumn?
6919         
6920         return; // we doe not have a view in this design..
6921         
6922     },
6923     onBodyScroll: function()
6924     {
6925         //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6926         if(this.mainHead){
6927             this.mainHead.setStyle({
6928                 'position' : 'relative',
6929                 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6930             });
6931         }
6932         
6933         if(this.lazyLoad){
6934             
6935             var scrollHeight = this.mainBody.dom.scrollHeight;
6936             
6937             var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6938             
6939             var height = this.mainBody.getHeight();
6940             
6941             if(scrollHeight - height == scrollTop) {
6942                 
6943                 var total = this.ds.getTotalCount();
6944                 
6945                 if(this.footer.cursor + this.footer.pageSize < total){
6946                     
6947                     this.footer.ds.load({
6948                         params : {
6949                             start : this.footer.cursor + this.footer.pageSize,
6950                             limit : this.footer.pageSize
6951                         },
6952                         add : true
6953                     });
6954                 }
6955             }
6956             
6957         }
6958     },
6959     
6960     onHeaderChange : function()
6961     {
6962         var header = this.renderHeader();
6963         var table = this.el.select('table', true).first();
6964         
6965         this.mainHead.remove();
6966         this.mainHead = table.createChild(header, this.mainBody, false);
6967     },
6968     
6969     onHiddenChange : function(colModel, colIndex, hidden)
6970     {
6971         var thSelector = 'roo-bootstrap-thead-col-' + colIndex;
6972         var tdSelector = 'roo-bootstrap-tbody-col-' + colIndex;
6973         
6974         this.CSS.updateRule(thSelector, "display", "");
6975         this.CSS.updateRule(tdSelector, "display", "");
6976         
6977         if(hidden){
6978             this.CSS.updateRule(thSelector, "display", "none");
6979             this.CSS.updateRule(tdSelector, "display", "none");
6980         }
6981         
6982         this.onHeaderChange();
6983         this.onLoad();
6984         
6985     }
6986     
6987 });
6988
6989  
6990
6991  /*
6992  * - LGPL
6993  *
6994  * table cell
6995  * 
6996  */
6997
6998 /**
6999  * @class Roo.bootstrap.TableCell
7000  * @extends Roo.bootstrap.Component
7001  * Bootstrap TableCell class
7002  * @cfg {String} html cell contain text
7003  * @cfg {String} cls cell class
7004  * @cfg {String} tag cell tag (td|th) default td
7005  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7006  * @cfg {String} align Aligns the content in a cell
7007  * @cfg {String} axis Categorizes cells
7008  * @cfg {String} bgcolor Specifies the background color of a cell
7009  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7010  * @cfg {Number} colspan Specifies the number of columns a cell should span
7011  * @cfg {String} headers Specifies one or more header cells a cell is related to
7012  * @cfg {Number} height Sets the height of a cell
7013  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7014  * @cfg {Number} rowspan Sets the number of rows a cell should span
7015  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7016  * @cfg {String} valign Vertical aligns the content in a cell
7017  * @cfg {Number} width Specifies the width of a cell
7018  * 
7019  * @constructor
7020  * Create a new TableCell
7021  * @param {Object} config The config object
7022  */
7023
7024 Roo.bootstrap.TableCell = function(config){
7025     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7026 };
7027
7028 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
7029     
7030     html: false,
7031     cls: false,
7032     tag: false,
7033     abbr: false,
7034     align: false,
7035     axis: false,
7036     bgcolor: false,
7037     charoff: false,
7038     colspan: false,
7039     headers: false,
7040     height: false,
7041     nowrap: false,
7042     rowspan: false,
7043     scope: false,
7044     valign: false,
7045     width: false,
7046     
7047     
7048     getAutoCreate : function(){
7049         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7050         
7051         cfg = {
7052             tag: 'td'
7053         };
7054         
7055         if(this.tag){
7056             cfg.tag = this.tag;
7057         }
7058         
7059         if (this.html) {
7060             cfg.html=this.html
7061         }
7062         if (this.cls) {
7063             cfg.cls=this.cls
7064         }
7065         if (this.abbr) {
7066             cfg.abbr=this.abbr
7067         }
7068         if (this.align) {
7069             cfg.align=this.align
7070         }
7071         if (this.axis) {
7072             cfg.axis=this.axis
7073         }
7074         if (this.bgcolor) {
7075             cfg.bgcolor=this.bgcolor
7076         }
7077         if (this.charoff) {
7078             cfg.charoff=this.charoff
7079         }
7080         if (this.colspan) {
7081             cfg.colspan=this.colspan
7082         }
7083         if (this.headers) {
7084             cfg.headers=this.headers
7085         }
7086         if (this.height) {
7087             cfg.height=this.height
7088         }
7089         if (this.nowrap) {
7090             cfg.nowrap=this.nowrap
7091         }
7092         if (this.rowspan) {
7093             cfg.rowspan=this.rowspan
7094         }
7095         if (this.scope) {
7096             cfg.scope=this.scope
7097         }
7098         if (this.valign) {
7099             cfg.valign=this.valign
7100         }
7101         if (this.width) {
7102             cfg.width=this.width
7103         }
7104         
7105         
7106         return cfg;
7107     }
7108    
7109 });
7110
7111  
7112
7113  /*
7114  * - LGPL
7115  *
7116  * table row
7117  * 
7118  */
7119
7120 /**
7121  * @class Roo.bootstrap.TableRow
7122  * @extends Roo.bootstrap.Component
7123  * Bootstrap TableRow class
7124  * @cfg {String} cls row class
7125  * @cfg {String} align Aligns the content in a table row
7126  * @cfg {String} bgcolor Specifies a background color for a table row
7127  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7128  * @cfg {String} valign Vertical aligns the content in a table row
7129  * 
7130  * @constructor
7131  * Create a new TableRow
7132  * @param {Object} config The config object
7133  */
7134
7135 Roo.bootstrap.TableRow = function(config){
7136     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7137 };
7138
7139 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
7140     
7141     cls: false,
7142     align: false,
7143     bgcolor: false,
7144     charoff: false,
7145     valign: false,
7146     
7147     getAutoCreate : function(){
7148         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7149         
7150         cfg = {
7151             tag: 'tr'
7152         };
7153             
7154         if(this.cls){
7155             cfg.cls = this.cls;
7156         }
7157         if(this.align){
7158             cfg.align = this.align;
7159         }
7160         if(this.bgcolor){
7161             cfg.bgcolor = this.bgcolor;
7162         }
7163         if(this.charoff){
7164             cfg.charoff = this.charoff;
7165         }
7166         if(this.valign){
7167             cfg.valign = this.valign;
7168         }
7169         
7170         return cfg;
7171     }
7172    
7173 });
7174
7175  
7176
7177  /*
7178  * - LGPL
7179  *
7180  * table body
7181  * 
7182  */
7183
7184 /**
7185  * @class Roo.bootstrap.TableBody
7186  * @extends Roo.bootstrap.Component
7187  * Bootstrap TableBody class
7188  * @cfg {String} cls element class
7189  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7190  * @cfg {String} align Aligns the content inside the element
7191  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7192  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7193  * 
7194  * @constructor
7195  * Create a new TableBody
7196  * @param {Object} config The config object
7197  */
7198
7199 Roo.bootstrap.TableBody = function(config){
7200     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7201 };
7202
7203 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
7204     
7205     cls: false,
7206     tag: false,
7207     align: false,
7208     charoff: false,
7209     valign: false,
7210     
7211     getAutoCreate : function(){
7212         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7213         
7214         cfg = {
7215             tag: 'tbody'
7216         };
7217             
7218         if (this.cls) {
7219             cfg.cls=this.cls
7220         }
7221         if(this.tag){
7222             cfg.tag = this.tag;
7223         }
7224         
7225         if(this.align){
7226             cfg.align = this.align;
7227         }
7228         if(this.charoff){
7229             cfg.charoff = this.charoff;
7230         }
7231         if(this.valign){
7232             cfg.valign = this.valign;
7233         }
7234         
7235         return cfg;
7236     }
7237     
7238     
7239 //    initEvents : function()
7240 //    {
7241 //        
7242 //        if(!this.store){
7243 //            return;
7244 //        }
7245 //        
7246 //        this.store = Roo.factory(this.store, Roo.data);
7247 //        this.store.on('load', this.onLoad, this);
7248 //        
7249 //        this.store.load();
7250 //        
7251 //    },
7252 //    
7253 //    onLoad: function () 
7254 //    {   
7255 //        this.fireEvent('load', this);
7256 //    }
7257 //    
7258 //   
7259 });
7260
7261  
7262
7263  /*
7264  * Based on:
7265  * Ext JS Library 1.1.1
7266  * Copyright(c) 2006-2007, Ext JS, LLC.
7267  *
7268  * Originally Released Under LGPL - original licence link has changed is not relivant.
7269  *
7270  * Fork - LGPL
7271  * <script type="text/javascript">
7272  */
7273
7274 // as we use this in bootstrap.
7275 Roo.namespace('Roo.form');
7276  /**
7277  * @class Roo.form.Action
7278  * Internal Class used to handle form actions
7279  * @constructor
7280  * @param {Roo.form.BasicForm} el The form element or its id
7281  * @param {Object} config Configuration options
7282  */
7283
7284  
7285  
7286 // define the action interface
7287 Roo.form.Action = function(form, options){
7288     this.form = form;
7289     this.options = options || {};
7290 };
7291 /**
7292  * Client Validation Failed
7293  * @const 
7294  */
7295 Roo.form.Action.CLIENT_INVALID = 'client';
7296 /**
7297  * Server Validation Failed
7298  * @const 
7299  */
7300 Roo.form.Action.SERVER_INVALID = 'server';
7301  /**
7302  * Connect to Server Failed
7303  * @const 
7304  */
7305 Roo.form.Action.CONNECT_FAILURE = 'connect';
7306 /**
7307  * Reading Data from Server Failed
7308  * @const 
7309  */
7310 Roo.form.Action.LOAD_FAILURE = 'load';
7311
7312 Roo.form.Action.prototype = {
7313     type : 'default',
7314     failureType : undefined,
7315     response : undefined,
7316     result : undefined,
7317
7318     // interface method
7319     run : function(options){
7320
7321     },
7322
7323     // interface method
7324     success : function(response){
7325
7326     },
7327
7328     // interface method
7329     handleResponse : function(response){
7330
7331     },
7332
7333     // default connection failure
7334     failure : function(response){
7335         
7336         this.response = response;
7337         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7338         this.form.afterAction(this, false);
7339     },
7340
7341     processResponse : function(response){
7342         this.response = response;
7343         if(!response.responseText){
7344             return true;
7345         }
7346         this.result = this.handleResponse(response);
7347         return this.result;
7348     },
7349
7350     // utility functions used internally
7351     getUrl : function(appendParams){
7352         var url = this.options.url || this.form.url || this.form.el.dom.action;
7353         if(appendParams){
7354             var p = this.getParams();
7355             if(p){
7356                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7357             }
7358         }
7359         return url;
7360     },
7361
7362     getMethod : function(){
7363         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7364     },
7365
7366     getParams : function(){
7367         var bp = this.form.baseParams;
7368         var p = this.options.params;
7369         if(p){
7370             if(typeof p == "object"){
7371                 p = Roo.urlEncode(Roo.applyIf(p, bp));
7372             }else if(typeof p == 'string' && bp){
7373                 p += '&' + Roo.urlEncode(bp);
7374             }
7375         }else if(bp){
7376             p = Roo.urlEncode(bp);
7377         }
7378         return p;
7379     },
7380
7381     createCallback : function(){
7382         return {
7383             success: this.success,
7384             failure: this.failure,
7385             scope: this,
7386             timeout: (this.form.timeout*1000),
7387             upload: this.form.fileUpload ? this.success : undefined
7388         };
7389     }
7390 };
7391
7392 Roo.form.Action.Submit = function(form, options){
7393     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7394 };
7395
7396 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7397     type : 'submit',
7398
7399     haveProgress : false,
7400     uploadComplete : false,
7401     
7402     // uploadProgress indicator.
7403     uploadProgress : function()
7404     {
7405         if (!this.form.progressUrl) {
7406             return;
7407         }
7408         
7409         if (!this.haveProgress) {
7410             Roo.MessageBox.progress("Uploading", "Uploading");
7411         }
7412         if (this.uploadComplete) {
7413            Roo.MessageBox.hide();
7414            return;
7415         }
7416         
7417         this.haveProgress = true;
7418    
7419         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7420         
7421         var c = new Roo.data.Connection();
7422         c.request({
7423             url : this.form.progressUrl,
7424             params: {
7425                 id : uid
7426             },
7427             method: 'GET',
7428             success : function(req){
7429                //console.log(data);
7430                 var rdata = false;
7431                 var edata;
7432                 try  {
7433                    rdata = Roo.decode(req.responseText)
7434                 } catch (e) {
7435                     Roo.log("Invalid data from server..");
7436                     Roo.log(edata);
7437                     return;
7438                 }
7439                 if (!rdata || !rdata.success) {
7440                     Roo.log(rdata);
7441                     Roo.MessageBox.alert(Roo.encode(rdata));
7442                     return;
7443                 }
7444                 var data = rdata.data;
7445                 
7446                 if (this.uploadComplete) {
7447                    Roo.MessageBox.hide();
7448                    return;
7449                 }
7450                    
7451                 if (data){
7452                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7453                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7454                     );
7455                 }
7456                 this.uploadProgress.defer(2000,this);
7457             },
7458        
7459             failure: function(data) {
7460                 Roo.log('progress url failed ');
7461                 Roo.log(data);
7462             },
7463             scope : this
7464         });
7465            
7466     },
7467     
7468     
7469     run : function()
7470     {
7471         // run get Values on the form, so it syncs any secondary forms.
7472         this.form.getValues();
7473         
7474         var o = this.options;
7475         var method = this.getMethod();
7476         var isPost = method == 'POST';
7477         if(o.clientValidation === false || this.form.isValid()){
7478             
7479             if (this.form.progressUrl) {
7480                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7481                     (new Date() * 1) + '' + Math.random());
7482                     
7483             } 
7484             
7485             
7486             Roo.Ajax.request(Roo.apply(this.createCallback(), {
7487                 form:this.form.el.dom,
7488                 url:this.getUrl(!isPost),
7489                 method: method,
7490                 params:isPost ? this.getParams() : null,
7491                 isUpload: this.form.fileUpload
7492             }));
7493             
7494             this.uploadProgress();
7495
7496         }else if (o.clientValidation !== false){ // client validation failed
7497             this.failureType = Roo.form.Action.CLIENT_INVALID;
7498             this.form.afterAction(this, false);
7499         }
7500     },
7501
7502     success : function(response)
7503     {
7504         this.uploadComplete= true;
7505         if (this.haveProgress) {
7506             Roo.MessageBox.hide();
7507         }
7508         
7509         
7510         var result = this.processResponse(response);
7511         if(result === true || result.success){
7512             this.form.afterAction(this, true);
7513             return;
7514         }
7515         if(result.errors){
7516             this.form.markInvalid(result.errors);
7517             this.failureType = Roo.form.Action.SERVER_INVALID;
7518         }
7519         this.form.afterAction(this, false);
7520     },
7521     failure : function(response)
7522     {
7523         this.uploadComplete= true;
7524         if (this.haveProgress) {
7525             Roo.MessageBox.hide();
7526         }
7527         
7528         this.response = response;
7529         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7530         this.form.afterAction(this, false);
7531     },
7532     
7533     handleResponse : function(response){
7534         if(this.form.errorReader){
7535             var rs = this.form.errorReader.read(response);
7536             var errors = [];
7537             if(rs.records){
7538                 for(var i = 0, len = rs.records.length; i < len; i++) {
7539                     var r = rs.records[i];
7540                     errors[i] = r.data;
7541                 }
7542             }
7543             if(errors.length < 1){
7544                 errors = null;
7545             }
7546             return {
7547                 success : rs.success,
7548                 errors : errors
7549             };
7550         }
7551         var ret = false;
7552         try {
7553             ret = Roo.decode(response.responseText);
7554         } catch (e) {
7555             ret = {
7556                 success: false,
7557                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7558                 errors : []
7559             };
7560         }
7561         return ret;
7562         
7563     }
7564 });
7565
7566
7567 Roo.form.Action.Load = function(form, options){
7568     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7569     this.reader = this.form.reader;
7570 };
7571
7572 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7573     type : 'load',
7574
7575     run : function(){
7576         
7577         Roo.Ajax.request(Roo.apply(
7578                 this.createCallback(), {
7579                     method:this.getMethod(),
7580                     url:this.getUrl(false),
7581                     params:this.getParams()
7582         }));
7583     },
7584
7585     success : function(response){
7586         
7587         var result = this.processResponse(response);
7588         if(result === true || !result.success || !result.data){
7589             this.failureType = Roo.form.Action.LOAD_FAILURE;
7590             this.form.afterAction(this, false);
7591             return;
7592         }
7593         this.form.clearInvalid();
7594         this.form.setValues(result.data);
7595         this.form.afterAction(this, true);
7596     },
7597
7598     handleResponse : function(response){
7599         if(this.form.reader){
7600             var rs = this.form.reader.read(response);
7601             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7602             return {
7603                 success : rs.success,
7604                 data : data
7605             };
7606         }
7607         return Roo.decode(response.responseText);
7608     }
7609 });
7610
7611 Roo.form.Action.ACTION_TYPES = {
7612     'load' : Roo.form.Action.Load,
7613     'submit' : Roo.form.Action.Submit
7614 };/*
7615  * - LGPL
7616  *
7617  * form
7618  *
7619  */
7620
7621 /**
7622  * @class Roo.bootstrap.Form
7623  * @extends Roo.bootstrap.Component
7624  * Bootstrap Form class
7625  * @cfg {String} method  GET | POST (default POST)
7626  * @cfg {String} labelAlign top | left (default top)
7627  * @cfg {String} align left  | right - for navbars
7628  * @cfg {Boolean} loadMask load mask when submit (default true)
7629
7630  *
7631  * @constructor
7632  * Create a new Form
7633  * @param {Object} config The config object
7634  */
7635
7636
7637 Roo.bootstrap.Form = function(config){
7638     
7639     Roo.bootstrap.Form.superclass.constructor.call(this, config);
7640     
7641     Roo.bootstrap.Form.popover.apply();
7642     
7643     this.addEvents({
7644         /**
7645          * @event clientvalidation
7646          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7647          * @param {Form} this
7648          * @param {Boolean} valid true if the form has passed client-side validation
7649          */
7650         clientvalidation: true,
7651         /**
7652          * @event beforeaction
7653          * Fires before any action is performed. Return false to cancel the action.
7654          * @param {Form} this
7655          * @param {Action} action The action to be performed
7656          */
7657         beforeaction: true,
7658         /**
7659          * @event actionfailed
7660          * Fires when an action fails.
7661          * @param {Form} this
7662          * @param {Action} action The action that failed
7663          */
7664         actionfailed : true,
7665         /**
7666          * @event actioncomplete
7667          * Fires when an action is completed.
7668          * @param {Form} this
7669          * @param {Action} action The action that completed
7670          */
7671         actioncomplete : true
7672     });
7673 };
7674
7675 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
7676
7677      /**
7678      * @cfg {String} method
7679      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7680      */
7681     method : 'POST',
7682     /**
7683      * @cfg {String} url
7684      * The URL to use for form actions if one isn't supplied in the action options.
7685      */
7686     /**
7687      * @cfg {Boolean} fileUpload
7688      * Set to true if this form is a file upload.
7689      */
7690
7691     /**
7692      * @cfg {Object} baseParams
7693      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7694      */
7695
7696     /**
7697      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7698      */
7699     timeout: 30,
7700     /**
7701      * @cfg {Sting} align (left|right) for navbar forms
7702      */
7703     align : 'left',
7704
7705     // private
7706     activeAction : null,
7707
7708     /**
7709      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7710      * element by passing it or its id or mask the form itself by passing in true.
7711      * @type Mixed
7712      */
7713     waitMsgTarget : false,
7714
7715     loadMask : true,
7716     
7717     /**
7718      * @cfg {Boolean} errorMask (true|false) default false
7719      */
7720     errorMask : false,
7721     
7722     /**
7723      * @cfg {Number} maskOffset Default 100
7724      */
7725     maskOffset : 100,
7726     
7727     /**
7728      * @cfg {Boolean} maskBody
7729      */
7730     maskBody : false,
7731
7732     getAutoCreate : function(){
7733
7734         var cfg = {
7735             tag: 'form',
7736             method : this.method || 'POST',
7737             id : this.id || Roo.id(),
7738             cls : ''
7739         };
7740         if (this.parent().xtype.match(/^Nav/)) {
7741             cfg.cls = 'navbar-form navbar-' + this.align;
7742
7743         }
7744
7745         if (this.labelAlign == 'left' ) {
7746             cfg.cls += ' form-horizontal';
7747         }
7748
7749
7750         return cfg;
7751     },
7752     initEvents : function()
7753     {
7754         this.el.on('submit', this.onSubmit, this);
7755         // this was added as random key presses on the form where triggering form submit.
7756         this.el.on('keypress', function(e) {
7757             if (e.getCharCode() != 13) {
7758                 return true;
7759             }
7760             // we might need to allow it for textareas.. and some other items.
7761             // check e.getTarget().
7762
7763             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7764                 return true;
7765             }
7766
7767             Roo.log("keypress blocked");
7768
7769             e.preventDefault();
7770             return false;
7771         });
7772         
7773     },
7774     // private
7775     onSubmit : function(e){
7776         e.stopEvent();
7777     },
7778
7779      /**
7780      * Returns true if client-side validation on the form is successful.
7781      * @return Boolean
7782      */
7783     isValid : function(){
7784         var items = this.getItems();
7785         var valid = true;
7786         var target = false;
7787         
7788         items.each(function(f){
7789             if(f.validate()){
7790                 return;
7791             }
7792             valid = false;
7793
7794             if(!target && f.el.isVisible(true)){
7795                 target = f;
7796             }
7797            
7798         });
7799         
7800         if(this.errorMask && !valid){
7801             Roo.bootstrap.Form.popover.mask(this, target);
7802         }
7803         
7804         return valid;
7805     },
7806     
7807     /**
7808      * Returns true if any fields in this form have changed since their original load.
7809      * @return Boolean
7810      */
7811     isDirty : function(){
7812         var dirty = false;
7813         var items = this.getItems();
7814         items.each(function(f){
7815            if(f.isDirty()){
7816                dirty = true;
7817                return false;
7818            }
7819            return true;
7820         });
7821         return dirty;
7822     },
7823      /**
7824      * Performs a predefined action (submit or load) or custom actions you define on this form.
7825      * @param {String} actionName The name of the action type
7826      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
7827      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7828      * accept other config options):
7829      * <pre>
7830 Property          Type             Description
7831 ----------------  ---------------  ----------------------------------------------------------------------------------
7832 url               String           The url for the action (defaults to the form's url)
7833 method            String           The form method to use (defaults to the form's method, or POST if not defined)
7834 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
7835 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
7836                                    validate the form on the client (defaults to false)
7837      * </pre>
7838      * @return {BasicForm} this
7839      */
7840     doAction : function(action, options){
7841         if(typeof action == 'string'){
7842             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7843         }
7844         if(this.fireEvent('beforeaction', this, action) !== false){
7845             this.beforeAction(action);
7846             action.run.defer(100, action);
7847         }
7848         return this;
7849     },
7850
7851     // private
7852     beforeAction : function(action){
7853         var o = action.options;
7854         
7855         if(this.loadMask){
7856             
7857             if(this.maskBody){
7858                 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7859             } else {
7860                 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7861             }
7862         }
7863         // not really supported yet.. ??
7864
7865         //if(this.waitMsgTarget === true){
7866         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7867         //}else if(this.waitMsgTarget){
7868         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7869         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7870         //}else {
7871         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7872        // }
7873
7874     },
7875
7876     // private
7877     afterAction : function(action, success){
7878         this.activeAction = null;
7879         var o = action.options;
7880
7881         if(this.loadMask){
7882             
7883             if(this.maskBody){
7884                 Roo.get(document.body).unmask();
7885             } else {
7886                 this.el.unmask();
7887             }
7888         }
7889         
7890         //if(this.waitMsgTarget === true){
7891 //            this.el.unmask();
7892         //}else if(this.waitMsgTarget){
7893         //    this.waitMsgTarget.unmask();
7894         //}else{
7895         //    Roo.MessageBox.updateProgress(1);
7896         //    Roo.MessageBox.hide();
7897        // }
7898         //
7899         if(success){
7900             if(o.reset){
7901                 this.reset();
7902             }
7903             Roo.callback(o.success, o.scope, [this, action]);
7904             this.fireEvent('actioncomplete', this, action);
7905
7906         }else{
7907
7908             // failure condition..
7909             // we have a scenario where updates need confirming.
7910             // eg. if a locking scenario exists..
7911             // we look for { errors : { needs_confirm : true }} in the response.
7912             if (
7913                 (typeof(action.result) != 'undefined')  &&
7914                 (typeof(action.result.errors) != 'undefined')  &&
7915                 (typeof(action.result.errors.needs_confirm) != 'undefined')
7916            ){
7917                 var _t = this;
7918                 Roo.log("not supported yet");
7919                  /*
7920
7921                 Roo.MessageBox.confirm(
7922                     "Change requires confirmation",
7923                     action.result.errorMsg,
7924                     function(r) {
7925                         if (r != 'yes') {
7926                             return;
7927                         }
7928                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
7929                     }
7930
7931                 );
7932                 */
7933
7934
7935                 return;
7936             }
7937
7938             Roo.callback(o.failure, o.scope, [this, action]);
7939             // show an error message if no failed handler is set..
7940             if (!this.hasListener('actionfailed')) {
7941                 Roo.log("need to add dialog support");
7942                 /*
7943                 Roo.MessageBox.alert("Error",
7944                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7945                         action.result.errorMsg :
7946                         "Saving Failed, please check your entries or try again"
7947                 );
7948                 */
7949             }
7950
7951             this.fireEvent('actionfailed', this, action);
7952         }
7953
7954     },
7955     /**
7956      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7957      * @param {String} id The value to search for
7958      * @return Field
7959      */
7960     findField : function(id){
7961         var items = this.getItems();
7962         var field = items.get(id);
7963         if(!field){
7964              items.each(function(f){
7965                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7966                     field = f;
7967                     return false;
7968                 }
7969                 return true;
7970             });
7971         }
7972         return field || null;
7973     },
7974      /**
7975      * Mark fields in this form invalid in bulk.
7976      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7977      * @return {BasicForm} this
7978      */
7979     markInvalid : function(errors){
7980         if(errors instanceof Array){
7981             for(var i = 0, len = errors.length; i < len; i++){
7982                 var fieldError = errors[i];
7983                 var f = this.findField(fieldError.id);
7984                 if(f){
7985                     f.markInvalid(fieldError.msg);
7986                 }
7987             }
7988         }else{
7989             var field, id;
7990             for(id in errors){
7991                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7992                     field.markInvalid(errors[id]);
7993                 }
7994             }
7995         }
7996         //Roo.each(this.childForms || [], function (f) {
7997         //    f.markInvalid(errors);
7998         //});
7999
8000         return this;
8001     },
8002
8003     /**
8004      * Set values for fields in this form in bulk.
8005      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8006      * @return {BasicForm} this
8007      */
8008     setValues : function(values){
8009         if(values instanceof Array){ // array of objects
8010             for(var i = 0, len = values.length; i < len; i++){
8011                 var v = values[i];
8012                 var f = this.findField(v.id);
8013                 if(f){
8014                     f.setValue(v.value);
8015                     if(this.trackResetOnLoad){
8016                         f.originalValue = f.getValue();
8017                     }
8018                 }
8019             }
8020         }else{ // object hash
8021             var field, id;
8022             for(id in values){
8023                 if(typeof values[id] != 'function' && (field = this.findField(id))){
8024
8025                     if (field.setFromData &&
8026                         field.valueField &&
8027                         field.displayField &&
8028                         // combos' with local stores can
8029                         // be queried via setValue()
8030                         // to set their value..
8031                         (field.store && !field.store.isLocal)
8032                         ) {
8033                         // it's a combo
8034                         var sd = { };
8035                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8036                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8037                         field.setFromData(sd);
8038
8039                     } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8040                         
8041                         field.setFromData(values);
8042                         
8043                     } else {
8044                         field.setValue(values[id]);
8045                     }
8046
8047
8048                     if(this.trackResetOnLoad){
8049                         field.originalValue = field.getValue();
8050                     }
8051                 }
8052             }
8053         }
8054
8055         //Roo.each(this.childForms || [], function (f) {
8056         //    f.setValues(values);
8057         //});
8058
8059         return this;
8060     },
8061
8062     /**
8063      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8064      * they are returned as an array.
8065      * @param {Boolean} asString
8066      * @return {Object}
8067      */
8068     getValues : function(asString){
8069         //if (this.childForms) {
8070             // copy values from the child forms
8071         //    Roo.each(this.childForms, function (f) {
8072         //        this.setValues(f.getValues());
8073         //    }, this);
8074         //}
8075
8076
8077
8078         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8079         if(asString === true){
8080             return fs;
8081         }
8082         return Roo.urlDecode(fs);
8083     },
8084
8085     /**
8086      * Returns the fields in this form as an object with key/value pairs.
8087      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8088      * @return {Object}
8089      */
8090     getFieldValues : function(with_hidden)
8091     {
8092         var items = this.getItems();
8093         var ret = {};
8094         items.each(function(f){
8095             
8096             if (!f.getName()) {
8097                 return;
8098             }
8099             
8100             var v = f.getValue();
8101             
8102             if (f.inputType =='radio') {
8103                 if (typeof(ret[f.getName()]) == 'undefined') {
8104                     ret[f.getName()] = ''; // empty..
8105                 }
8106
8107                 if (!f.el.dom.checked) {
8108                     return;
8109
8110                 }
8111                 v = f.el.dom.value;
8112
8113             }
8114             
8115             if(f.xtype == 'MoneyField'){
8116                 ret[f.currencyName] = f.getCurrency();
8117             }
8118
8119             // not sure if this supported any more..
8120             if ((typeof(v) == 'object') && f.getRawValue) {
8121                 v = f.getRawValue() ; // dates..
8122             }
8123             // combo boxes where name != hiddenName...
8124             if (f.name !== false && f.name != '' && f.name != f.getName()) {
8125                 ret[f.name] = f.getRawValue();
8126             }
8127             ret[f.getName()] = v;
8128         });
8129
8130         return ret;
8131     },
8132
8133     /**
8134      * Clears all invalid messages in this form.
8135      * @return {BasicForm} this
8136      */
8137     clearInvalid : function(){
8138         var items = this.getItems();
8139
8140         items.each(function(f){
8141            f.clearInvalid();
8142         });
8143
8144         return this;
8145     },
8146
8147     /**
8148      * Resets this form.
8149      * @return {BasicForm} this
8150      */
8151     reset : function(){
8152         var items = this.getItems();
8153         items.each(function(f){
8154             f.reset();
8155         });
8156
8157         Roo.each(this.childForms || [], function (f) {
8158             f.reset();
8159         });
8160
8161
8162         return this;
8163     },
8164     
8165     getItems : function()
8166     {
8167         var r=new Roo.util.MixedCollection(false, function(o){
8168             return o.id || (o.id = Roo.id());
8169         });
8170         var iter = function(el) {
8171             if (el.inputEl) {
8172                 r.add(el);
8173             }
8174             if (!el.items) {
8175                 return;
8176             }
8177             Roo.each(el.items,function(e) {
8178                 iter(e);
8179             });
8180         };
8181
8182         iter(this);
8183         return r;
8184     },
8185     
8186     hideFields : function(items)
8187     {
8188         Roo.each(items, function(i){
8189             
8190             var f = this.findField(i);
8191             
8192             if(!f){
8193                 return;
8194             }
8195             
8196             if(f.xtype == 'DateField'){
8197                 f.setVisible(false);
8198                 return;
8199             }
8200             
8201             f.hide();
8202             
8203         }, this);
8204     },
8205     
8206     showFields : function(items)
8207     {
8208         Roo.each(items, function(i){
8209             
8210             var f = this.findField(i);
8211             
8212             if(!f){
8213                 return;
8214             }
8215             
8216             if(f.xtype == 'DateField'){
8217                 f.setVisible(true);
8218                 return;
8219             }
8220             
8221             f.show();
8222             
8223         }, this);
8224     }
8225
8226 });
8227
8228 Roo.apply(Roo.bootstrap.Form, {
8229     
8230     popover : {
8231         
8232         padding : 5,
8233         
8234         isApplied : false,
8235         
8236         isMasked : false,
8237         
8238         form : false,
8239         
8240         target : false,
8241         
8242         toolTip : false,
8243         
8244         intervalID : false,
8245         
8246         maskEl : false,
8247         
8248         apply : function()
8249         {
8250             if(this.isApplied){
8251                 return;
8252             }
8253             
8254             this.maskEl = {
8255                 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8256                 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8257                 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8258                 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8259             };
8260             
8261             this.maskEl.top.enableDisplayMode("block");
8262             this.maskEl.left.enableDisplayMode("block");
8263             this.maskEl.bottom.enableDisplayMode("block");
8264             this.maskEl.right.enableDisplayMode("block");
8265             
8266             this.toolTip = new Roo.bootstrap.Tooltip({
8267                 cls : 'roo-form-error-popover',
8268                 alignment : {
8269                     'left' : ['r-l', [-2,0], 'right'],
8270                     'right' : ['l-r', [2,0], 'left'],
8271                     'bottom' : ['tl-bl', [0,2], 'top'],
8272                     'top' : [ 'bl-tl', [0,-2], 'bottom']
8273                 }
8274             });
8275             
8276             this.toolTip.render(Roo.get(document.body));
8277
8278             this.toolTip.el.enableDisplayMode("block");
8279             
8280             Roo.get(document.body).on('click', function(){
8281                 this.unmask();
8282             }, this);
8283             
8284             Roo.get(document.body).on('touchstart', function(){
8285                 this.unmask();
8286             }, this);
8287             
8288             this.isApplied = true
8289         },
8290         
8291         mask : function(form, target)
8292         {
8293             this.form = form;
8294             
8295             this.target = target;
8296             
8297             if(!this.form.errorMask || !target.el){
8298                 return;
8299             }
8300             
8301             var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8302             
8303             Roo.log(scrollable);
8304             
8305             var ot = this.target.el.calcOffsetsTo(scrollable);
8306             
8307             var scrollTo = ot[1] - this.form.maskOffset;
8308             
8309             scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8310             
8311             scrollable.scrollTo('top', scrollTo);
8312             
8313             var box = this.target.el.getBox();
8314             Roo.log(box);
8315             var zIndex = Roo.bootstrap.Modal.zIndex++;
8316
8317             
8318             this.maskEl.top.setStyle('position', 'absolute');
8319             this.maskEl.top.setStyle('z-index', zIndex);
8320             this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8321             this.maskEl.top.setLeft(0);
8322             this.maskEl.top.setTop(0);
8323             this.maskEl.top.show();
8324             
8325             this.maskEl.left.setStyle('position', 'absolute');
8326             this.maskEl.left.setStyle('z-index', zIndex);
8327             this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8328             this.maskEl.left.setLeft(0);
8329             this.maskEl.left.setTop(box.y - this.padding);
8330             this.maskEl.left.show();
8331
8332             this.maskEl.bottom.setStyle('position', 'absolute');
8333             this.maskEl.bottom.setStyle('z-index', zIndex);
8334             this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8335             this.maskEl.bottom.setLeft(0);
8336             this.maskEl.bottom.setTop(box.bottom + this.padding);
8337             this.maskEl.bottom.show();
8338
8339             this.maskEl.right.setStyle('position', 'absolute');
8340             this.maskEl.right.setStyle('z-index', zIndex);
8341             this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8342             this.maskEl.right.setLeft(box.right + this.padding);
8343             this.maskEl.right.setTop(box.y - this.padding);
8344             this.maskEl.right.show();
8345
8346             this.toolTip.bindEl = this.target.el;
8347
8348             this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8349
8350             var tip = this.target.blankText;
8351
8352             if(this.target.getValue() !== '' ) {
8353                 
8354                 if (this.target.invalidText.length) {
8355                     tip = this.target.invalidText;
8356                 } else if (this.target.regexText.length){
8357                     tip = this.target.regexText;
8358                 }
8359             }
8360
8361             this.toolTip.show(tip);
8362
8363             this.intervalID = window.setInterval(function() {
8364                 Roo.bootstrap.Form.popover.unmask();
8365             }, 10000);
8366
8367             window.onwheel = function(){ return false;};
8368             
8369             (function(){ this.isMasked = true; }).defer(500, this);
8370             
8371         },
8372         
8373         unmask : function()
8374         {
8375             if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8376                 return;
8377             }
8378             
8379             this.maskEl.top.setStyle('position', 'absolute');
8380             this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8381             this.maskEl.top.hide();
8382
8383             this.maskEl.left.setStyle('position', 'absolute');
8384             this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8385             this.maskEl.left.hide();
8386
8387             this.maskEl.bottom.setStyle('position', 'absolute');
8388             this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8389             this.maskEl.bottom.hide();
8390
8391             this.maskEl.right.setStyle('position', 'absolute');
8392             this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8393             this.maskEl.right.hide();
8394             
8395             this.toolTip.hide();
8396             
8397             this.toolTip.el.hide();
8398             
8399             window.onwheel = function(){ return true;};
8400             
8401             if(this.intervalID){
8402                 window.clearInterval(this.intervalID);
8403                 this.intervalID = false;
8404             }
8405             
8406             this.isMasked = false;
8407             
8408         }
8409         
8410     }
8411     
8412 });
8413
8414 /*
8415  * Based on:
8416  * Ext JS Library 1.1.1
8417  * Copyright(c) 2006-2007, Ext JS, LLC.
8418  *
8419  * Originally Released Under LGPL - original licence link has changed is not relivant.
8420  *
8421  * Fork - LGPL
8422  * <script type="text/javascript">
8423  */
8424 /**
8425  * @class Roo.form.VTypes
8426  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8427  * @singleton
8428  */
8429 Roo.form.VTypes = function(){
8430     // closure these in so they are only created once.
8431     var alpha = /^[a-zA-Z_]+$/;
8432     var alphanum = /^[a-zA-Z0-9_]+$/;
8433     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8434     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8435
8436     // All these messages and functions are configurable
8437     return {
8438         /**
8439          * The function used to validate email addresses
8440          * @param {String} value The email address
8441          */
8442         'email' : function(v){
8443             return email.test(v);
8444         },
8445         /**
8446          * The error text to display when the email validation function returns false
8447          * @type String
8448          */
8449         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8450         /**
8451          * The keystroke filter mask to be applied on email input
8452          * @type RegExp
8453          */
8454         'emailMask' : /[a-z0-9_\.\-@]/i,
8455
8456         /**
8457          * The function used to validate URLs
8458          * @param {String} value The URL
8459          */
8460         'url' : function(v){
8461             return url.test(v);
8462         },
8463         /**
8464          * The error text to display when the url validation function returns false
8465          * @type String
8466          */
8467         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8468         
8469         /**
8470          * The function used to validate alpha values
8471          * @param {String} value The value
8472          */
8473         'alpha' : function(v){
8474             return alpha.test(v);
8475         },
8476         /**
8477          * The error text to display when the alpha validation function returns false
8478          * @type String
8479          */
8480         'alphaText' : 'This field should only contain letters and _',
8481         /**
8482          * The keystroke filter mask to be applied on alpha input
8483          * @type RegExp
8484          */
8485         'alphaMask' : /[a-z_]/i,
8486
8487         /**
8488          * The function used to validate alphanumeric values
8489          * @param {String} value The value
8490          */
8491         'alphanum' : function(v){
8492             return alphanum.test(v);
8493         },
8494         /**
8495          * The error text to display when the alphanumeric validation function returns false
8496          * @type String
8497          */
8498         'alphanumText' : 'This field should only contain letters, numbers and _',
8499         /**
8500          * The keystroke filter mask to be applied on alphanumeric input
8501          * @type RegExp
8502          */
8503         'alphanumMask' : /[a-z0-9_]/i
8504     };
8505 }();/*
8506  * - LGPL
8507  *
8508  * Input
8509  * 
8510  */
8511
8512 /**
8513  * @class Roo.bootstrap.Input
8514  * @extends Roo.bootstrap.Component
8515  * Bootstrap Input class
8516  * @cfg {Boolean} disabled is it disabled
8517  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8518  * @cfg {String} name name of the input
8519  * @cfg {string} fieldLabel - the label associated
8520  * @cfg {string} placeholder - placeholder to put in text.
8521  * @cfg {string}  before - input group add on before
8522  * @cfg {string} after - input group add on after
8523  * @cfg {string} size - (lg|sm) or leave empty..
8524  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8525  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8526  * @cfg {Number} md colspan out of 12 for computer-sized screens
8527  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8528  * @cfg {string} value default value of the input
8529  * @cfg {Number} labelWidth set the width of label 
8530  * @cfg {Number} labellg set the width of label (1-12)
8531  * @cfg {Number} labelmd set the width of label (1-12)
8532  * @cfg {Number} labelsm set the width of label (1-12)
8533  * @cfg {Number} labelxs set the width of label (1-12)
8534  * @cfg {String} labelAlign (top|left)
8535  * @cfg {Boolean} readOnly Specifies that the field should be read-only
8536  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8537  * @cfg {String} indicatorpos (left|right) default left
8538
8539  * @cfg {String} align (left|center|right) Default left
8540  * @cfg {Boolean} forceFeedback (true|false) Default false
8541  * 
8542  * @constructor
8543  * Create a new Input
8544  * @param {Object} config The config object
8545  */
8546
8547 Roo.bootstrap.Input = function(config){
8548     
8549     Roo.bootstrap.Input.superclass.constructor.call(this, config);
8550     
8551     this.addEvents({
8552         /**
8553          * @event focus
8554          * Fires when this field receives input focus.
8555          * @param {Roo.form.Field} this
8556          */
8557         focus : true,
8558         /**
8559          * @event blur
8560          * Fires when this field loses input focus.
8561          * @param {Roo.form.Field} this
8562          */
8563         blur : true,
8564         /**
8565          * @event specialkey
8566          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
8567          * {@link Roo.EventObject#getKey} to determine which key was pressed.
8568          * @param {Roo.form.Field} this
8569          * @param {Roo.EventObject} e The event object
8570          */
8571         specialkey : true,
8572         /**
8573          * @event change
8574          * Fires just before the field blurs if the field value has changed.
8575          * @param {Roo.form.Field} this
8576          * @param {Mixed} newValue The new value
8577          * @param {Mixed} oldValue The original value
8578          */
8579         change : true,
8580         /**
8581          * @event invalid
8582          * Fires after the field has been marked as invalid.
8583          * @param {Roo.form.Field} this
8584          * @param {String} msg The validation message
8585          */
8586         invalid : true,
8587         /**
8588          * @event valid
8589          * Fires after the field has been validated with no errors.
8590          * @param {Roo.form.Field} this
8591          */
8592         valid : true,
8593          /**
8594          * @event keyup
8595          * Fires after the key up
8596          * @param {Roo.form.Field} this
8597          * @param {Roo.EventObject}  e The event Object
8598          */
8599         keyup : true
8600     });
8601 };
8602
8603 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
8604      /**
8605      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8606       automatic validation (defaults to "keyup").
8607      */
8608     validationEvent : "keyup",
8609      /**
8610      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8611      */
8612     validateOnBlur : true,
8613     /**
8614      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8615      */
8616     validationDelay : 250,
8617      /**
8618      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8619      */
8620     focusClass : "x-form-focus",  // not needed???
8621     
8622        
8623     /**
8624      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8625      */
8626     invalidClass : "has-warning",
8627     
8628     /**
8629      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8630      */
8631     validClass : "has-success",
8632     
8633     /**
8634      * @cfg {Boolean} hasFeedback (true|false) default true
8635      */
8636     hasFeedback : true,
8637     
8638     /**
8639      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8640      */
8641     invalidFeedbackClass : "glyphicon-warning-sign",
8642     
8643     /**
8644      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8645      */
8646     validFeedbackClass : "glyphicon-ok",
8647     
8648     /**
8649      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8650      */
8651     selectOnFocus : false,
8652     
8653      /**
8654      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8655      */
8656     maskRe : null,
8657        /**
8658      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8659      */
8660     vtype : null,
8661     
8662       /**
8663      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8664      */
8665     disableKeyFilter : false,
8666     
8667        /**
8668      * @cfg {Boolean} disabled True to disable the field (defaults to false).
8669      */
8670     disabled : false,
8671      /**
8672      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8673      */
8674     allowBlank : true,
8675     /**
8676      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8677      */
8678     blankText : "Please complete this mandatory field",
8679     
8680      /**
8681      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8682      */
8683     minLength : 0,
8684     /**
8685      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8686      */
8687     maxLength : Number.MAX_VALUE,
8688     /**
8689      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8690      */
8691     minLengthText : "The minimum length for this field is {0}",
8692     /**
8693      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8694      */
8695     maxLengthText : "The maximum length for this field is {0}",
8696   
8697     
8698     /**
8699      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8700      * If available, this function will be called only after the basic validators all return true, and will be passed the
8701      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8702      */
8703     validator : null,
8704     /**
8705      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8706      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8707      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
8708      */
8709     regex : null,
8710     /**
8711      * @cfg {String} regexText -- Depricated - use Invalid Text
8712      */
8713     regexText : "",
8714     
8715     /**
8716      * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8717      */
8718     invalidText : "",
8719     
8720     
8721     
8722     autocomplete: false,
8723     
8724     
8725     fieldLabel : '',
8726     inputType : 'text',
8727     
8728     name : false,
8729     placeholder: false,
8730     before : false,
8731     after : false,
8732     size : false,
8733     hasFocus : false,
8734     preventMark: false,
8735     isFormField : true,
8736     value : '',
8737     labelWidth : 2,
8738     labelAlign : false,
8739     readOnly : false,
8740     align : false,
8741     formatedValue : false,
8742     forceFeedback : false,
8743     
8744     indicatorpos : 'left',
8745     
8746     labellg : 0,
8747     labelmd : 0,
8748     labelsm : 0,
8749     labelxs : 0,
8750     
8751     parentLabelAlign : function()
8752     {
8753         var parent = this;
8754         while (parent.parent()) {
8755             parent = parent.parent();
8756             if (typeof(parent.labelAlign) !='undefined') {
8757                 return parent.labelAlign;
8758             }
8759         }
8760         return 'left';
8761         
8762     },
8763     
8764     getAutoCreate : function()
8765     {
8766         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8767         
8768         var id = Roo.id();
8769         
8770         var cfg = {};
8771         
8772         if(this.inputType != 'hidden'){
8773             cfg.cls = 'form-group' //input-group
8774         }
8775         
8776         var input =  {
8777             tag: 'input',
8778             id : id,
8779             type : this.inputType,
8780             value : this.value,
8781             cls : 'form-control',
8782             placeholder : this.placeholder || '',
8783             autocomplete : this.autocomplete || 'new-password'
8784         };
8785         
8786         if(this.align){
8787             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8788         }
8789         
8790         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8791             input.maxLength = this.maxLength;
8792         }
8793         
8794         if (this.disabled) {
8795             input.disabled=true;
8796         }
8797         
8798         if (this.readOnly) {
8799             input.readonly=true;
8800         }
8801         
8802         if (this.name) {
8803             input.name = this.name;
8804         }
8805         
8806         if (this.size) {
8807             input.cls += ' input-' + this.size;
8808         }
8809         
8810         var settings=this;
8811         ['xs','sm','md','lg'].map(function(size){
8812             if (settings[size]) {
8813                 cfg.cls += ' col-' + size + '-' + settings[size];
8814             }
8815         });
8816         
8817         var inputblock = input;
8818         
8819         var feedback = {
8820             tag: 'span',
8821             cls: 'glyphicon form-control-feedback'
8822         };
8823             
8824         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8825             
8826             inputblock = {
8827                 cls : 'has-feedback',
8828                 cn :  [
8829                     input,
8830                     feedback
8831                 ] 
8832             };  
8833         }
8834         
8835         if (this.before || this.after) {
8836             
8837             inputblock = {
8838                 cls : 'input-group',
8839                 cn :  [] 
8840             };
8841             
8842             if (this.before && typeof(this.before) == 'string') {
8843                 
8844                 inputblock.cn.push({
8845                     tag :'span',
8846                     cls : 'roo-input-before input-group-addon',
8847                     html : this.before
8848                 });
8849             }
8850             if (this.before && typeof(this.before) == 'object') {
8851                 this.before = Roo.factory(this.before);
8852                 
8853                 inputblock.cn.push({
8854                     tag :'span',
8855                     cls : 'roo-input-before input-group-' +
8856                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8857                 });
8858             }
8859             
8860             inputblock.cn.push(input);
8861             
8862             if (this.after && typeof(this.after) == 'string') {
8863                 inputblock.cn.push({
8864                     tag :'span',
8865                     cls : 'roo-input-after input-group-addon',
8866                     html : this.after
8867                 });
8868             }
8869             if (this.after && typeof(this.after) == 'object') {
8870                 this.after = Roo.factory(this.after);
8871                 
8872                 inputblock.cn.push({
8873                     tag :'span',
8874                     cls : 'roo-input-after input-group-' +
8875                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8876                 });
8877             }
8878             
8879             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8880                 inputblock.cls += ' has-feedback';
8881                 inputblock.cn.push(feedback);
8882             }
8883         };
8884         
8885         if (align ==='left' && this.fieldLabel.length) {
8886             
8887             cfg.cls += ' roo-form-group-label-left';
8888             
8889             cfg.cn = [
8890                 {
8891                     tag : 'i',
8892                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8893                     tooltip : 'This field is required'
8894                 },
8895                 {
8896                     tag: 'label',
8897                     'for' :  id,
8898                     cls : 'control-label',
8899                     html : this.fieldLabel
8900
8901                 },
8902                 {
8903                     cls : "", 
8904                     cn: [
8905                         inputblock
8906                     ]
8907                 }
8908             ];
8909             
8910             var labelCfg = cfg.cn[1];
8911             var contentCfg = cfg.cn[2];
8912             
8913             if(this.indicatorpos == 'right'){
8914                 cfg.cn = [
8915                     {
8916                         tag: 'label',
8917                         'for' :  id,
8918                         cls : 'control-label',
8919                         cn : [
8920                             {
8921                                 tag : 'span',
8922                                 html : this.fieldLabel
8923                             },
8924                             {
8925                                 tag : 'i',
8926                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8927                                 tooltip : 'This field is required'
8928                             }
8929                         ]
8930                     },
8931                     {
8932                         cls : "",
8933                         cn: [
8934                             inputblock
8935                         ]
8936                     }
8937
8938                 ];
8939                 
8940                 labelCfg = cfg.cn[0];
8941                 contentCfg = cfg.cn[1];
8942             
8943             }
8944             
8945             if(this.labelWidth > 12){
8946                 labelCfg.style = "width: " + this.labelWidth + 'px';
8947             }
8948             
8949             if(this.labelWidth < 13 && this.labelmd == 0){
8950                 this.labelmd = this.labelWidth;
8951             }
8952             
8953             if(this.labellg > 0){
8954                 labelCfg.cls += ' col-lg-' + this.labellg;
8955                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8956             }
8957             
8958             if(this.labelmd > 0){
8959                 labelCfg.cls += ' col-md-' + this.labelmd;
8960                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8961             }
8962             
8963             if(this.labelsm > 0){
8964                 labelCfg.cls += ' col-sm-' + this.labelsm;
8965                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8966             }
8967             
8968             if(this.labelxs > 0){
8969                 labelCfg.cls += ' col-xs-' + this.labelxs;
8970                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8971             }
8972             
8973             
8974         } else if ( this.fieldLabel.length) {
8975                 
8976             cfg.cn = [
8977                 {
8978                     tag : 'i',
8979                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8980                     tooltip : 'This field is required'
8981                 },
8982                 {
8983                     tag: 'label',
8984                    //cls : 'input-group-addon',
8985                     html : this.fieldLabel
8986
8987                 },
8988
8989                inputblock
8990
8991            ];
8992            
8993            if(this.indicatorpos == 'right'){
8994                 
8995                 cfg.cn = [
8996                     {
8997                         tag: 'label',
8998                        //cls : 'input-group-addon',
8999                         html : this.fieldLabel
9000
9001                     },
9002                     {
9003                         tag : 'i',
9004                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9005                         tooltip : 'This field is required'
9006                     },
9007
9008                    inputblock
9009
9010                ];
9011
9012             }
9013
9014         } else {
9015             
9016             cfg.cn = [
9017
9018                     inputblock
9019
9020             ];
9021                 
9022                 
9023         };
9024         
9025         if (this.parentType === 'Navbar' &&  this.parent().bar) {
9026            cfg.cls += ' navbar-form';
9027         }
9028         
9029         if (this.parentType === 'NavGroup') {
9030            cfg.cls += ' navbar-form';
9031            cfg.tag = 'li';
9032         }
9033         
9034         return cfg;
9035         
9036     },
9037     /**
9038      * return the real input element.
9039      */
9040     inputEl: function ()
9041     {
9042         return this.el.select('input.form-control',true).first();
9043     },
9044     
9045     tooltipEl : function()
9046     {
9047         return this.inputEl();
9048     },
9049     
9050     indicatorEl : function()
9051     {
9052         var indicator = this.el.select('i.roo-required-indicator',true).first();
9053         
9054         if(!indicator){
9055             return false;
9056         }
9057         
9058         return indicator;
9059         
9060     },
9061     
9062     setDisabled : function(v)
9063     {
9064         var i  = this.inputEl().dom;
9065         if (!v) {
9066             i.removeAttribute('disabled');
9067             return;
9068             
9069         }
9070         i.setAttribute('disabled','true');
9071     },
9072     initEvents : function()
9073     {
9074           
9075         this.inputEl().on("keydown" , this.fireKey,  this);
9076         this.inputEl().on("focus", this.onFocus,  this);
9077         this.inputEl().on("blur", this.onBlur,  this);
9078         
9079         this.inputEl().relayEvent('keyup', this);
9080         
9081         this.indicator = this.indicatorEl();
9082         
9083         if(this.indicator){
9084             this.indicator.addClass('invisible');
9085         }
9086  
9087         // reference to original value for reset
9088         this.originalValue = this.getValue();
9089         //Roo.form.TextField.superclass.initEvents.call(this);
9090         if(this.validationEvent == 'keyup'){
9091             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9092             this.inputEl().on('keyup', this.filterValidation, this);
9093         }
9094         else if(this.validationEvent !== false){
9095             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9096         }
9097         
9098         if(this.selectOnFocus){
9099             this.on("focus", this.preFocus, this);
9100             
9101         }
9102         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9103             this.inputEl().on("keypress", this.filterKeys, this);
9104         } else {
9105             this.inputEl().relayEvent('keypress', this);
9106         }
9107        /* if(this.grow){
9108             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
9109             this.el.on("click", this.autoSize,  this);
9110         }
9111         */
9112         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9113             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9114         }
9115         
9116         if (typeof(this.before) == 'object') {
9117             this.before.render(this.el.select('.roo-input-before',true).first());
9118         }
9119         if (typeof(this.after) == 'object') {
9120             this.after.render(this.el.select('.roo-input-after',true).first());
9121         }
9122         
9123         
9124     },
9125     filterValidation : function(e){
9126         if(!e.isNavKeyPress()){
9127             this.validationTask.delay(this.validationDelay);
9128         }
9129     },
9130      /**
9131      * Validates the field value
9132      * @return {Boolean} True if the value is valid, else false
9133      */
9134     validate : function(){
9135         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9136         if(this.disabled || this.validateValue(this.getRawValue())){
9137             this.markValid();
9138             return true;
9139         }
9140         
9141         this.markInvalid();
9142         return false;
9143     },
9144     
9145     
9146     /**
9147      * Validates a value according to the field's validation rules and marks the field as invalid
9148      * if the validation fails
9149      * @param {Mixed} value The value to validate
9150      * @return {Boolean} True if the value is valid, else false
9151      */
9152     validateValue : function(value)
9153     {
9154         if(this.getVisibilityEl().hasClass('hidden')){
9155             return true;
9156         }
9157         
9158         if(value.length < 1)  { // if it's blank
9159             if(this.allowBlank){
9160                 return true;
9161             }
9162             return false;
9163         }
9164         
9165         if(value.length < this.minLength){
9166             return false;
9167         }
9168         if(value.length > this.maxLength){
9169             return false;
9170         }
9171         if(this.vtype){
9172             var vt = Roo.form.VTypes;
9173             if(!vt[this.vtype](value, this)){
9174                 return false;
9175             }
9176         }
9177         if(typeof this.validator == "function"){
9178             var msg = this.validator(value);
9179             if(msg !== true){
9180                 return false;
9181             }
9182             if (typeof(msg) == 'string') {
9183                 this.invalidText = msg;
9184             }
9185         }
9186         
9187         if(this.regex && !this.regex.test(value)){
9188             return false;
9189         }
9190         
9191         return true;
9192     },
9193     
9194      // private
9195     fireKey : function(e){
9196         //Roo.log('field ' + e.getKey());
9197         if(e.isNavKeyPress()){
9198             this.fireEvent("specialkey", this, e);
9199         }
9200     },
9201     focus : function (selectText){
9202         if(this.rendered){
9203             this.inputEl().focus();
9204             if(selectText === true){
9205                 this.inputEl().dom.select();
9206             }
9207         }
9208         return this;
9209     } ,
9210     
9211     onFocus : function(){
9212         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9213            // this.el.addClass(this.focusClass);
9214         }
9215         if(!this.hasFocus){
9216             this.hasFocus = true;
9217             this.startValue = this.getValue();
9218             this.fireEvent("focus", this);
9219         }
9220     },
9221     
9222     beforeBlur : Roo.emptyFn,
9223
9224     
9225     // private
9226     onBlur : function(){
9227         this.beforeBlur();
9228         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9229             //this.el.removeClass(this.focusClass);
9230         }
9231         this.hasFocus = false;
9232         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9233             this.validate();
9234         }
9235         var v = this.getValue();
9236         if(String(v) !== String(this.startValue)){
9237             this.fireEvent('change', this, v, this.startValue);
9238         }
9239         this.fireEvent("blur", this);
9240     },
9241     
9242     /**
9243      * Resets the current field value to the originally loaded value and clears any validation messages
9244      */
9245     reset : function(){
9246         this.setValue(this.originalValue);
9247         this.validate();
9248     },
9249      /**
9250      * Returns the name of the field
9251      * @return {Mixed} name The name field
9252      */
9253     getName: function(){
9254         return this.name;
9255     },
9256      /**
9257      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
9258      * @return {Mixed} value The field value
9259      */
9260     getValue : function(){
9261         
9262         var v = this.inputEl().getValue();
9263         
9264         return v;
9265     },
9266     /**
9267      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
9268      * @return {Mixed} value The field value
9269      */
9270     getRawValue : function(){
9271         var v = this.inputEl().getValue();
9272         
9273         return v;
9274     },
9275     
9276     /**
9277      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
9278      * @param {Mixed} value The value to set
9279      */
9280     setRawValue : function(v){
9281         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9282     },
9283     
9284     selectText : function(start, end){
9285         var v = this.getRawValue();
9286         if(v.length > 0){
9287             start = start === undefined ? 0 : start;
9288             end = end === undefined ? v.length : end;
9289             var d = this.inputEl().dom;
9290             if(d.setSelectionRange){
9291                 d.setSelectionRange(start, end);
9292             }else if(d.createTextRange){
9293                 var range = d.createTextRange();
9294                 range.moveStart("character", start);
9295                 range.moveEnd("character", v.length-end);
9296                 range.select();
9297             }
9298         }
9299     },
9300     
9301     /**
9302      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
9303      * @param {Mixed} value The value to set
9304      */
9305     setValue : function(v){
9306         this.value = v;
9307         if(this.rendered){
9308             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9309             this.validate();
9310         }
9311     },
9312     
9313     /*
9314     processValue : function(value){
9315         if(this.stripCharsRe){
9316             var newValue = value.replace(this.stripCharsRe, '');
9317             if(newValue !== value){
9318                 this.setRawValue(newValue);
9319                 return newValue;
9320             }
9321         }
9322         return value;
9323     },
9324   */
9325     preFocus : function(){
9326         
9327         if(this.selectOnFocus){
9328             this.inputEl().dom.select();
9329         }
9330     },
9331     filterKeys : function(e){
9332         var k = e.getKey();
9333         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9334             return;
9335         }
9336         var c = e.getCharCode(), cc = String.fromCharCode(c);
9337         if(Roo.isIE && (e.isSpecialKey() || !cc)){
9338             return;
9339         }
9340         if(!this.maskRe.test(cc)){
9341             e.stopEvent();
9342         }
9343     },
9344      /**
9345      * Clear any invalid styles/messages for this field
9346      */
9347     clearInvalid : function(){
9348         
9349         if(!this.el || this.preventMark){ // not rendered
9350             return;
9351         }
9352         
9353      
9354         this.el.removeClass(this.invalidClass);
9355         
9356         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9357             
9358             var feedback = this.el.select('.form-control-feedback', true).first();
9359             
9360             if(feedback){
9361                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9362             }
9363             
9364         }
9365         
9366         this.fireEvent('valid', this);
9367     },
9368     
9369      /**
9370      * Mark this field as valid
9371      */
9372     markValid : function()
9373     {
9374         if(!this.el  || this.preventMark){ // not rendered...
9375             return;
9376         }
9377         
9378         this.el.removeClass([this.invalidClass, this.validClass]);
9379         
9380         var feedback = this.el.select('.form-control-feedback', true).first();
9381             
9382         if(feedback){
9383             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9384         }
9385         
9386         if(this.indicator){
9387             this.indicator.removeClass('visible');
9388             this.indicator.addClass('invisible');
9389         }
9390         
9391         if(this.disabled){
9392             return;
9393         }
9394         
9395         if(this.allowBlank && !this.getRawValue().length){
9396             return;
9397         }
9398         
9399         this.el.addClass(this.validClass);
9400         
9401         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9402             
9403             var feedback = this.el.select('.form-control-feedback', true).first();
9404             
9405             if(feedback){
9406                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9407                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9408             }
9409             
9410         }
9411         
9412         this.fireEvent('valid', this);
9413     },
9414     
9415      /**
9416      * Mark this field as invalid
9417      * @param {String} msg The validation message
9418      */
9419     markInvalid : function(msg)
9420     {
9421         if(!this.el  || this.preventMark){ // not rendered
9422             return;
9423         }
9424         
9425         this.el.removeClass([this.invalidClass, this.validClass]);
9426         
9427         var feedback = this.el.select('.form-control-feedback', true).first();
9428             
9429         if(feedback){
9430             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9431         }
9432
9433         if(this.disabled){
9434             return;
9435         }
9436         
9437         if(this.allowBlank && !this.getRawValue().length){
9438             return;
9439         }
9440         
9441         if(this.indicator){
9442             this.indicator.removeClass('invisible');
9443             this.indicator.addClass('visible');
9444         }
9445         
9446         this.el.addClass(this.invalidClass);
9447         
9448         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9449             
9450             var feedback = this.el.select('.form-control-feedback', true).first();
9451             
9452             if(feedback){
9453                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9454                 
9455                 if(this.getValue().length || this.forceFeedback){
9456                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9457                 }
9458                 
9459             }
9460             
9461         }
9462         
9463         this.fireEvent('invalid', this, msg);
9464     },
9465     // private
9466     SafariOnKeyDown : function(event)
9467     {
9468         // this is a workaround for a password hang bug on chrome/ webkit.
9469         if (this.inputEl().dom.type != 'password') {
9470             return;
9471         }
9472         
9473         var isSelectAll = false;
9474         
9475         if(this.inputEl().dom.selectionEnd > 0){
9476             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9477         }
9478         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9479             event.preventDefault();
9480             this.setValue('');
9481             return;
9482         }
9483         
9484         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9485             
9486             event.preventDefault();
9487             // this is very hacky as keydown always get's upper case.
9488             //
9489             var cc = String.fromCharCode(event.getCharCode());
9490             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
9491             
9492         }
9493     },
9494     adjustWidth : function(tag, w){
9495         tag = tag.toLowerCase();
9496         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9497             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9498                 if(tag == 'input'){
9499                     return w + 2;
9500                 }
9501                 if(tag == 'textarea'){
9502                     return w-2;
9503                 }
9504             }else if(Roo.isOpera){
9505                 if(tag == 'input'){
9506                     return w + 2;
9507                 }
9508                 if(tag == 'textarea'){
9509                     return w-2;
9510                 }
9511             }
9512         }
9513         return w;
9514     },
9515     
9516     setFieldLabel : function(v)
9517     {
9518         if(!this.rendered){
9519             return;
9520         }
9521         
9522         if(this.indicator){
9523             var ar = this.el.select('label > span',true);
9524             
9525             if (ar.elements.length) {
9526                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9527                 this.fieldLabel = v;
9528                 return;
9529             }
9530             
9531             var br = this.el.select('label',true);
9532             
9533             if(br.elements.length) {
9534                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9535                 this.fieldLabel = v;
9536                 return;
9537             }
9538             
9539             Roo.log('Cannot Found any of label > span || label in input');
9540             return;
9541         }
9542         
9543         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9544         this.fieldLabel = v;
9545         
9546         
9547     }
9548 });
9549
9550  
9551 /*
9552  * - LGPL
9553  *
9554  * Input
9555  * 
9556  */
9557
9558 /**
9559  * @class Roo.bootstrap.TextArea
9560  * @extends Roo.bootstrap.Input
9561  * Bootstrap TextArea class
9562  * @cfg {Number} cols Specifies the visible width of a text area
9563  * @cfg {Number} rows Specifies the visible number of lines in a text area
9564  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9565  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9566  * @cfg {string} html text
9567  * 
9568  * @constructor
9569  * Create a new TextArea
9570  * @param {Object} config The config object
9571  */
9572
9573 Roo.bootstrap.TextArea = function(config){
9574     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9575    
9576 };
9577
9578 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
9579      
9580     cols : false,
9581     rows : 5,
9582     readOnly : false,
9583     warp : 'soft',
9584     resize : false,
9585     value: false,
9586     html: false,
9587     
9588     getAutoCreate : function(){
9589         
9590         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9591         
9592         var id = Roo.id();
9593         
9594         var cfg = {};
9595         
9596         if(this.inputType != 'hidden'){
9597             cfg.cls = 'form-group' //input-group
9598         }
9599         
9600         var input =  {
9601             tag: 'textarea',
9602             id : id,
9603             warp : this.warp,
9604             rows : this.rows,
9605             value : this.value || '',
9606             html: this.html || '',
9607             cls : 'form-control',
9608             placeholder : this.placeholder || '' 
9609             
9610         };
9611         
9612         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9613             input.maxLength = this.maxLength;
9614         }
9615         
9616         if(this.resize){
9617             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9618         }
9619         
9620         if(this.cols){
9621             input.cols = this.cols;
9622         }
9623         
9624         if (this.readOnly) {
9625             input.readonly = true;
9626         }
9627         
9628         if (this.name) {
9629             input.name = this.name;
9630         }
9631         
9632         if (this.size) {
9633             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9634         }
9635         
9636         var settings=this;
9637         ['xs','sm','md','lg'].map(function(size){
9638             if (settings[size]) {
9639                 cfg.cls += ' col-' + size + '-' + settings[size];
9640             }
9641         });
9642         
9643         var inputblock = input;
9644         
9645         if(this.hasFeedback && !this.allowBlank){
9646             
9647             var feedback = {
9648                 tag: 'span',
9649                 cls: 'glyphicon form-control-feedback'
9650             };
9651
9652             inputblock = {
9653                 cls : 'has-feedback',
9654                 cn :  [
9655                     input,
9656                     feedback
9657                 ] 
9658             };  
9659         }
9660         
9661         
9662         if (this.before || this.after) {
9663             
9664             inputblock = {
9665                 cls : 'input-group',
9666                 cn :  [] 
9667             };
9668             if (this.before) {
9669                 inputblock.cn.push({
9670                     tag :'span',
9671                     cls : 'input-group-addon',
9672                     html : this.before
9673                 });
9674             }
9675             
9676             inputblock.cn.push(input);
9677             
9678             if(this.hasFeedback && !this.allowBlank){
9679                 inputblock.cls += ' has-feedback';
9680                 inputblock.cn.push(feedback);
9681             }
9682             
9683             if (this.after) {
9684                 inputblock.cn.push({
9685                     tag :'span',
9686                     cls : 'input-group-addon',
9687                     html : this.after
9688                 });
9689             }
9690             
9691         }
9692         
9693         if (align ==='left' && this.fieldLabel.length) {
9694             cfg.cn = [
9695                 {
9696                     tag: 'label',
9697                     'for' :  id,
9698                     cls : 'control-label',
9699                     html : this.fieldLabel
9700                 },
9701                 {
9702                     cls : "",
9703                     cn: [
9704                         inputblock
9705                     ]
9706                 }
9707
9708             ];
9709             
9710             if(this.labelWidth > 12){
9711                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9712             }
9713
9714             if(this.labelWidth < 13 && this.labelmd == 0){
9715                 this.labelmd = this.labelWidth;
9716             }
9717
9718             if(this.labellg > 0){
9719                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9720                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9721             }
9722
9723             if(this.labelmd > 0){
9724                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9725                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9726             }
9727
9728             if(this.labelsm > 0){
9729                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9730                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9731             }
9732
9733             if(this.labelxs > 0){
9734                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9735                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9736             }
9737             
9738         } else if ( this.fieldLabel.length) {
9739             cfg.cn = [
9740
9741                {
9742                    tag: 'label',
9743                    //cls : 'input-group-addon',
9744                    html : this.fieldLabel
9745
9746                },
9747
9748                inputblock
9749
9750            ];
9751
9752         } else {
9753
9754             cfg.cn = [
9755
9756                 inputblock
9757
9758             ];
9759                 
9760         }
9761         
9762         if (this.disabled) {
9763             input.disabled=true;
9764         }
9765         
9766         return cfg;
9767         
9768     },
9769     /**
9770      * return the real textarea element.
9771      */
9772     inputEl: function ()
9773     {
9774         return this.el.select('textarea.form-control',true).first();
9775     },
9776     
9777     /**
9778      * Clear any invalid styles/messages for this field
9779      */
9780     clearInvalid : function()
9781     {
9782         
9783         if(!this.el || this.preventMark){ // not rendered
9784             return;
9785         }
9786         
9787         var label = this.el.select('label', true).first();
9788         var icon = this.el.select('i.fa-star', true).first();
9789         
9790         if(label && icon){
9791             icon.remove();
9792         }
9793         
9794         this.el.removeClass(this.invalidClass);
9795         
9796         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9797             
9798             var feedback = this.el.select('.form-control-feedback', true).first();
9799             
9800             if(feedback){
9801                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9802             }
9803             
9804         }
9805         
9806         this.fireEvent('valid', this);
9807     },
9808     
9809      /**
9810      * Mark this field as valid
9811      */
9812     markValid : function()
9813     {
9814         if(!this.el  || this.preventMark){ // not rendered
9815             return;
9816         }
9817         
9818         this.el.removeClass([this.invalidClass, this.validClass]);
9819         
9820         var feedback = this.el.select('.form-control-feedback', true).first();
9821             
9822         if(feedback){
9823             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9824         }
9825
9826         if(this.disabled || this.allowBlank){
9827             return;
9828         }
9829         
9830         var label = this.el.select('label', true).first();
9831         var icon = this.el.select('i.fa-star', true).first();
9832         
9833         if(label && icon){
9834             icon.remove();
9835         }
9836         
9837         this.el.addClass(this.validClass);
9838         
9839         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9840             
9841             var feedback = this.el.select('.form-control-feedback', true).first();
9842             
9843             if(feedback){
9844                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9845                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9846             }
9847             
9848         }
9849         
9850         this.fireEvent('valid', this);
9851     },
9852     
9853      /**
9854      * Mark this field as invalid
9855      * @param {String} msg The validation message
9856      */
9857     markInvalid : function(msg)
9858     {
9859         if(!this.el  || this.preventMark){ // not rendered
9860             return;
9861         }
9862         
9863         this.el.removeClass([this.invalidClass, this.validClass]);
9864         
9865         var feedback = this.el.select('.form-control-feedback', true).first();
9866             
9867         if(feedback){
9868             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9869         }
9870
9871         if(this.disabled || this.allowBlank){
9872             return;
9873         }
9874         
9875         var label = this.el.select('label', true).first();
9876         var icon = this.el.select('i.fa-star', true).first();
9877         
9878         if(!this.getValue().length && label && !icon){
9879             this.el.createChild({
9880                 tag : 'i',
9881                 cls : 'text-danger fa fa-lg fa-star',
9882                 tooltip : 'This field is required',
9883                 style : 'margin-right:5px;'
9884             }, label, true);
9885         }
9886
9887         this.el.addClass(this.invalidClass);
9888         
9889         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9890             
9891             var feedback = this.el.select('.form-control-feedback', true).first();
9892             
9893             if(feedback){
9894                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9895                 
9896                 if(this.getValue().length || this.forceFeedback){
9897                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9898                 }
9899                 
9900             }
9901             
9902         }
9903         
9904         this.fireEvent('invalid', this, msg);
9905     }
9906 });
9907
9908  
9909 /*
9910  * - LGPL
9911  *
9912  * trigger field - base class for combo..
9913  * 
9914  */
9915  
9916 /**
9917  * @class Roo.bootstrap.TriggerField
9918  * @extends Roo.bootstrap.Input
9919  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9920  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9921  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9922  * for which you can provide a custom implementation.  For example:
9923  * <pre><code>
9924 var trigger = new Roo.bootstrap.TriggerField();
9925 trigger.onTriggerClick = myTriggerFn;
9926 trigger.applyTo('my-field');
9927 </code></pre>
9928  *
9929  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9930  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9931  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
9932  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9933  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9934
9935  * @constructor
9936  * Create a new TriggerField.
9937  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9938  * to the base TextField)
9939  */
9940 Roo.bootstrap.TriggerField = function(config){
9941     this.mimicing = false;
9942     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9943 };
9944
9945 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
9946     /**
9947      * @cfg {String} triggerClass A CSS class to apply to the trigger
9948      */
9949      /**
9950      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9951      */
9952     hideTrigger:false,
9953
9954     /**
9955      * @cfg {Boolean} removable (true|false) special filter default false
9956      */
9957     removable : false,
9958     
9959     /** @cfg {Boolean} grow @hide */
9960     /** @cfg {Number} growMin @hide */
9961     /** @cfg {Number} growMax @hide */
9962
9963     /**
9964      * @hide 
9965      * @method
9966      */
9967     autoSize: Roo.emptyFn,
9968     // private
9969     monitorTab : true,
9970     // private
9971     deferHeight : true,
9972
9973     
9974     actionMode : 'wrap',
9975     
9976     caret : false,
9977     
9978     
9979     getAutoCreate : function(){
9980        
9981         var align = this.labelAlign || this.parentLabelAlign();
9982         
9983         var id = Roo.id();
9984         
9985         var cfg = {
9986             cls: 'form-group' //input-group
9987         };
9988         
9989         
9990         var input =  {
9991             tag: 'input',
9992             id : id,
9993             type : this.inputType,
9994             cls : 'form-control',
9995             autocomplete: 'new-password',
9996             placeholder : this.placeholder || '' 
9997             
9998         };
9999         if (this.name) {
10000             input.name = this.name;
10001         }
10002         if (this.size) {
10003             input.cls += ' input-' + this.size;
10004         }
10005         
10006         if (this.disabled) {
10007             input.disabled=true;
10008         }
10009         
10010         var inputblock = input;
10011         
10012         if(this.hasFeedback && !this.allowBlank){
10013             
10014             var feedback = {
10015                 tag: 'span',
10016                 cls: 'glyphicon form-control-feedback'
10017             };
10018             
10019             if(this.removable && !this.editable && !this.tickable){
10020                 inputblock = {
10021                     cls : 'has-feedback',
10022                     cn :  [
10023                         inputblock,
10024                         {
10025                             tag: 'button',
10026                             html : 'x',
10027                             cls : 'roo-combo-removable-btn close'
10028                         },
10029                         feedback
10030                     ] 
10031                 };
10032             } else {
10033                 inputblock = {
10034                     cls : 'has-feedback',
10035                     cn :  [
10036                         inputblock,
10037                         feedback
10038                     ] 
10039                 };
10040             }
10041
10042         } else {
10043             if(this.removable && !this.editable && !this.tickable){
10044                 inputblock = {
10045                     cls : 'roo-removable',
10046                     cn :  [
10047                         inputblock,
10048                         {
10049                             tag: 'button',
10050                             html : 'x',
10051                             cls : 'roo-combo-removable-btn close'
10052                         }
10053                     ] 
10054                 };
10055             }
10056         }
10057         
10058         if (this.before || this.after) {
10059             
10060             inputblock = {
10061                 cls : 'input-group',
10062                 cn :  [] 
10063             };
10064             if (this.before) {
10065                 inputblock.cn.push({
10066                     tag :'span',
10067                     cls : 'input-group-addon',
10068                     html : this.before
10069                 });
10070             }
10071             
10072             inputblock.cn.push(input);
10073             
10074             if(this.hasFeedback && !this.allowBlank){
10075                 inputblock.cls += ' has-feedback';
10076                 inputblock.cn.push(feedback);
10077             }
10078             
10079             if (this.after) {
10080                 inputblock.cn.push({
10081                     tag :'span',
10082                     cls : 'input-group-addon',
10083                     html : this.after
10084                 });
10085             }
10086             
10087         };
10088         
10089         var box = {
10090             tag: 'div',
10091             cn: [
10092                 {
10093                     tag: 'input',
10094                     type : 'hidden',
10095                     cls: 'form-hidden-field'
10096                 },
10097                 inputblock
10098             ]
10099             
10100         };
10101         
10102         if(this.multiple){
10103             box = {
10104                 tag: 'div',
10105                 cn: [
10106                     {
10107                         tag: 'input',
10108                         type : 'hidden',
10109                         cls: 'form-hidden-field'
10110                     },
10111                     {
10112                         tag: 'ul',
10113                         cls: 'roo-select2-choices',
10114                         cn:[
10115                             {
10116                                 tag: 'li',
10117                                 cls: 'roo-select2-search-field',
10118                                 cn: [
10119
10120                                     inputblock
10121                                 ]
10122                             }
10123                         ]
10124                     }
10125                 ]
10126             }
10127         };
10128         
10129         var combobox = {
10130             cls: 'roo-select2-container input-group',
10131             cn: [
10132                 box
10133 //                {
10134 //                    tag: 'ul',
10135 //                    cls: 'typeahead typeahead-long dropdown-menu',
10136 //                    style: 'display:none'
10137 //                }
10138             ]
10139         };
10140         
10141         if(!this.multiple && this.showToggleBtn){
10142             
10143             var caret = {
10144                         tag: 'span',
10145                         cls: 'caret'
10146              };
10147             if (this.caret != false) {
10148                 caret = {
10149                      tag: 'i',
10150                      cls: 'fa fa-' + this.caret
10151                 };
10152                 
10153             }
10154             
10155             combobox.cn.push({
10156                 tag :'span',
10157                 cls : 'input-group-addon btn dropdown-toggle',
10158                 cn : [
10159                     caret,
10160                     {
10161                         tag: 'span',
10162                         cls: 'combobox-clear',
10163                         cn  : [
10164                             {
10165                                 tag : 'i',
10166                                 cls: 'icon-remove'
10167                             }
10168                         ]
10169                     }
10170                 ]
10171
10172             })
10173         }
10174         
10175         if(this.multiple){
10176             combobox.cls += ' roo-select2-container-multi';
10177         }
10178         
10179         if (align ==='left' && this.fieldLabel.length) {
10180             
10181             cfg.cls += ' roo-form-group-label-left';
10182
10183             cfg.cn = [
10184                 {
10185                     tag : 'i',
10186                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10187                     tooltip : 'This field is required'
10188                 },
10189                 {
10190                     tag: 'label',
10191                     'for' :  id,
10192                     cls : 'control-label',
10193                     html : this.fieldLabel
10194
10195                 },
10196                 {
10197                     cls : "", 
10198                     cn: [
10199                         combobox
10200                     ]
10201                 }
10202
10203             ];
10204             
10205             var labelCfg = cfg.cn[1];
10206             var contentCfg = cfg.cn[2];
10207             
10208             if(this.indicatorpos == 'right'){
10209                 cfg.cn = [
10210                     {
10211                         tag: 'label',
10212                         'for' :  id,
10213                         cls : 'control-label',
10214                         cn : [
10215                             {
10216                                 tag : 'span',
10217                                 html : this.fieldLabel
10218                             },
10219                             {
10220                                 tag : 'i',
10221                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10222                                 tooltip : 'This field is required'
10223                             }
10224                         ]
10225                     },
10226                     {
10227                         cls : "", 
10228                         cn: [
10229                             combobox
10230                         ]
10231                     }
10232
10233                 ];
10234                 
10235                 labelCfg = cfg.cn[0];
10236                 contentCfg = cfg.cn[1];
10237             }
10238             
10239             if(this.labelWidth > 12){
10240                 labelCfg.style = "width: " + this.labelWidth + 'px';
10241             }
10242             
10243             if(this.labelWidth < 13 && this.labelmd == 0){
10244                 this.labelmd = this.labelWidth;
10245             }
10246             
10247             if(this.labellg > 0){
10248                 labelCfg.cls += ' col-lg-' + this.labellg;
10249                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10250             }
10251             
10252             if(this.labelmd > 0){
10253                 labelCfg.cls += ' col-md-' + this.labelmd;
10254                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10255             }
10256             
10257             if(this.labelsm > 0){
10258                 labelCfg.cls += ' col-sm-' + this.labelsm;
10259                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10260             }
10261             
10262             if(this.labelxs > 0){
10263                 labelCfg.cls += ' col-xs-' + this.labelxs;
10264                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10265             }
10266             
10267         } else if ( this.fieldLabel.length) {
10268 //                Roo.log(" label");
10269             cfg.cn = [
10270                 {
10271                    tag : 'i',
10272                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10273                    tooltip : 'This field is required'
10274                },
10275                {
10276                    tag: 'label',
10277                    //cls : 'input-group-addon',
10278                    html : this.fieldLabel
10279
10280                },
10281
10282                combobox
10283
10284             ];
10285             
10286             if(this.indicatorpos == 'right'){
10287                 
10288                 cfg.cn = [
10289                     {
10290                        tag: 'label',
10291                        cn : [
10292                            {
10293                                tag : 'span',
10294                                html : this.fieldLabel
10295                            },
10296                            {
10297                               tag : 'i',
10298                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10299                               tooltip : 'This field is required'
10300                            }
10301                        ]
10302
10303                     },
10304                     combobox
10305
10306                 ];
10307
10308             }
10309
10310         } else {
10311             
10312 //                Roo.log(" no label && no align");
10313                 cfg = combobox
10314                      
10315                 
10316         }
10317         
10318         var settings=this;
10319         ['xs','sm','md','lg'].map(function(size){
10320             if (settings[size]) {
10321                 cfg.cls += ' col-' + size + '-' + settings[size];
10322             }
10323         });
10324         
10325         return cfg;
10326         
10327     },
10328     
10329     
10330     
10331     // private
10332     onResize : function(w, h){
10333 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10334 //        if(typeof w == 'number'){
10335 //            var x = w - this.trigger.getWidth();
10336 //            this.inputEl().setWidth(this.adjustWidth('input', x));
10337 //            this.trigger.setStyle('left', x+'px');
10338 //        }
10339     },
10340
10341     // private
10342     adjustSize : Roo.BoxComponent.prototype.adjustSize,
10343
10344     // private
10345     getResizeEl : function(){
10346         return this.inputEl();
10347     },
10348
10349     // private
10350     getPositionEl : function(){
10351         return this.inputEl();
10352     },
10353
10354     // private
10355     alignErrorIcon : function(){
10356         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10357     },
10358
10359     // private
10360     initEvents : function(){
10361         
10362         this.createList();
10363         
10364         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10365         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10366         if(!this.multiple && this.showToggleBtn){
10367             this.trigger = this.el.select('span.dropdown-toggle',true).first();
10368             if(this.hideTrigger){
10369                 this.trigger.setDisplayed(false);
10370             }
10371             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10372         }
10373         
10374         if(this.multiple){
10375             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10376         }
10377         
10378         if(this.removable && !this.editable && !this.tickable){
10379             var close = this.closeTriggerEl();
10380             
10381             if(close){
10382                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10383                 close.on('click', this.removeBtnClick, this, close);
10384             }
10385         }
10386         
10387         //this.trigger.addClassOnOver('x-form-trigger-over');
10388         //this.trigger.addClassOnClick('x-form-trigger-click');
10389         
10390         //if(!this.width){
10391         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10392         //}
10393     },
10394     
10395     closeTriggerEl : function()
10396     {
10397         var close = this.el.select('.roo-combo-removable-btn', true).first();
10398         return close ? close : false;
10399     },
10400     
10401     removeBtnClick : function(e, h, el)
10402     {
10403         e.preventDefault();
10404         
10405         if(this.fireEvent("remove", this) !== false){
10406             this.reset();
10407             this.fireEvent("afterremove", this)
10408         }
10409     },
10410     
10411     createList : function()
10412     {
10413         this.list = Roo.get(document.body).createChild({
10414             tag: 'ul',
10415             cls: 'typeahead typeahead-long dropdown-menu',
10416             style: 'display:none'
10417         });
10418         
10419         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10420         
10421     },
10422
10423     // private
10424     initTrigger : function(){
10425        
10426     },
10427
10428     // private
10429     onDestroy : function(){
10430         if(this.trigger){
10431             this.trigger.removeAllListeners();
10432           //  this.trigger.remove();
10433         }
10434         //if(this.wrap){
10435         //    this.wrap.remove();
10436         //}
10437         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10438     },
10439
10440     // private
10441     onFocus : function(){
10442         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10443         /*
10444         if(!this.mimicing){
10445             this.wrap.addClass('x-trigger-wrap-focus');
10446             this.mimicing = true;
10447             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10448             if(this.monitorTab){
10449                 this.el.on("keydown", this.checkTab, this);
10450             }
10451         }
10452         */
10453     },
10454
10455     // private
10456     checkTab : function(e){
10457         if(e.getKey() == e.TAB){
10458             this.triggerBlur();
10459         }
10460     },
10461
10462     // private
10463     onBlur : function(){
10464         // do nothing
10465     },
10466
10467     // private
10468     mimicBlur : function(e, t){
10469         /*
10470         if(!this.wrap.contains(t) && this.validateBlur()){
10471             this.triggerBlur();
10472         }
10473         */
10474     },
10475
10476     // private
10477     triggerBlur : function(){
10478         this.mimicing = false;
10479         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10480         if(this.monitorTab){
10481             this.el.un("keydown", this.checkTab, this);
10482         }
10483         //this.wrap.removeClass('x-trigger-wrap-focus');
10484         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10485     },
10486
10487     // private
10488     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10489     validateBlur : function(e, t){
10490         return true;
10491     },
10492
10493     // private
10494     onDisable : function(){
10495         this.inputEl().dom.disabled = true;
10496         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10497         //if(this.wrap){
10498         //    this.wrap.addClass('x-item-disabled');
10499         //}
10500     },
10501
10502     // private
10503     onEnable : function(){
10504         this.inputEl().dom.disabled = false;
10505         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10506         //if(this.wrap){
10507         //    this.el.removeClass('x-item-disabled');
10508         //}
10509     },
10510
10511     // private
10512     onShow : function(){
10513         var ae = this.getActionEl();
10514         
10515         if(ae){
10516             ae.dom.style.display = '';
10517             ae.dom.style.visibility = 'visible';
10518         }
10519     },
10520
10521     // private
10522     
10523     onHide : function(){
10524         var ae = this.getActionEl();
10525         ae.dom.style.display = 'none';
10526     },
10527
10528     /**
10529      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
10530      * by an implementing function.
10531      * @method
10532      * @param {EventObject} e
10533      */
10534     onTriggerClick : Roo.emptyFn
10535 });
10536  /*
10537  * Based on:
10538  * Ext JS Library 1.1.1
10539  * Copyright(c) 2006-2007, Ext JS, LLC.
10540  *
10541  * Originally Released Under LGPL - original licence link has changed is not relivant.
10542  *
10543  * Fork - LGPL
10544  * <script type="text/javascript">
10545  */
10546
10547
10548 /**
10549  * @class Roo.data.SortTypes
10550  * @singleton
10551  * Defines the default sorting (casting?) comparison functions used when sorting data.
10552  */
10553 Roo.data.SortTypes = {
10554     /**
10555      * Default sort that does nothing
10556      * @param {Mixed} s The value being converted
10557      * @return {Mixed} The comparison value
10558      */
10559     none : function(s){
10560         return s;
10561     },
10562     
10563     /**
10564      * The regular expression used to strip tags
10565      * @type {RegExp}
10566      * @property
10567      */
10568     stripTagsRE : /<\/?[^>]+>/gi,
10569     
10570     /**
10571      * Strips all HTML tags to sort on text only
10572      * @param {Mixed} s The value being converted
10573      * @return {String} The comparison value
10574      */
10575     asText : function(s){
10576         return String(s).replace(this.stripTagsRE, "");
10577     },
10578     
10579     /**
10580      * Strips all HTML tags to sort on text only - Case insensitive
10581      * @param {Mixed} s The value being converted
10582      * @return {String} The comparison value
10583      */
10584     asUCText : function(s){
10585         return String(s).toUpperCase().replace(this.stripTagsRE, "");
10586     },
10587     
10588     /**
10589      * Case insensitive string
10590      * @param {Mixed} s The value being converted
10591      * @return {String} The comparison value
10592      */
10593     asUCString : function(s) {
10594         return String(s).toUpperCase();
10595     },
10596     
10597     /**
10598      * Date sorting
10599      * @param {Mixed} s The value being converted
10600      * @return {Number} The comparison value
10601      */
10602     asDate : function(s) {
10603         if(!s){
10604             return 0;
10605         }
10606         if(s instanceof Date){
10607             return s.getTime();
10608         }
10609         return Date.parse(String(s));
10610     },
10611     
10612     /**
10613      * Float sorting
10614      * @param {Mixed} s The value being converted
10615      * @return {Float} The comparison value
10616      */
10617     asFloat : function(s) {
10618         var val = parseFloat(String(s).replace(/,/g, ""));
10619         if(isNaN(val)) {
10620             val = 0;
10621         }
10622         return val;
10623     },
10624     
10625     /**
10626      * Integer sorting
10627      * @param {Mixed} s The value being converted
10628      * @return {Number} The comparison value
10629      */
10630     asInt : function(s) {
10631         var val = parseInt(String(s).replace(/,/g, ""));
10632         if(isNaN(val)) {
10633             val = 0;
10634         }
10635         return val;
10636     }
10637 };/*
10638  * Based on:
10639  * Ext JS Library 1.1.1
10640  * Copyright(c) 2006-2007, Ext JS, LLC.
10641  *
10642  * Originally Released Under LGPL - original licence link has changed is not relivant.
10643  *
10644  * Fork - LGPL
10645  * <script type="text/javascript">
10646  */
10647
10648 /**
10649 * @class Roo.data.Record
10650  * Instances of this class encapsulate both record <em>definition</em> information, and record
10651  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10652  * to access Records cached in an {@link Roo.data.Store} object.<br>
10653  * <p>
10654  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10655  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10656  * objects.<br>
10657  * <p>
10658  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10659  * @constructor
10660  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10661  * {@link #create}. The parameters are the same.
10662  * @param {Array} data An associative Array of data values keyed by the field name.
10663  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10664  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10665  * not specified an integer id is generated.
10666  */
10667 Roo.data.Record = function(data, id){
10668     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10669     this.data = data;
10670 };
10671
10672 /**
10673  * Generate a constructor for a specific record layout.
10674  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10675  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10676  * Each field definition object may contain the following properties: <ul>
10677  * <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,
10678  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10679  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10680  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10681  * is being used, then this is a string containing the javascript expression to reference the data relative to 
10682  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10683  * to the data item relative to the record element. If the mapping expression is the same as the field name,
10684  * this may be omitted.</p></li>
10685  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10686  * <ul><li>auto (Default, implies no conversion)</li>
10687  * <li>string</li>
10688  * <li>int</li>
10689  * <li>float</li>
10690  * <li>boolean</li>
10691  * <li>date</li></ul></p></li>
10692  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10693  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10694  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10695  * by the Reader into an object that will be stored in the Record. It is passed the
10696  * following parameters:<ul>
10697  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10698  * </ul></p></li>
10699  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10700  * </ul>
10701  * <br>usage:<br><pre><code>
10702 var TopicRecord = Roo.data.Record.create(
10703     {name: 'title', mapping: 'topic_title'},
10704     {name: 'author', mapping: 'username'},
10705     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10706     {name: 'lastPost', mapping: 'post_time', type: 'date'},
10707     {name: 'lastPoster', mapping: 'user2'},
10708     {name: 'excerpt', mapping: 'post_text'}
10709 );
10710
10711 var myNewRecord = new TopicRecord({
10712     title: 'Do my job please',
10713     author: 'noobie',
10714     totalPosts: 1,
10715     lastPost: new Date(),
10716     lastPoster: 'Animal',
10717     excerpt: 'No way dude!'
10718 });
10719 myStore.add(myNewRecord);
10720 </code></pre>
10721  * @method create
10722  * @static
10723  */
10724 Roo.data.Record.create = function(o){
10725     var f = function(){
10726         f.superclass.constructor.apply(this, arguments);
10727     };
10728     Roo.extend(f, Roo.data.Record);
10729     var p = f.prototype;
10730     p.fields = new Roo.util.MixedCollection(false, function(field){
10731         return field.name;
10732     });
10733     for(var i = 0, len = o.length; i < len; i++){
10734         p.fields.add(new Roo.data.Field(o[i]));
10735     }
10736     f.getField = function(name){
10737         return p.fields.get(name);  
10738     };
10739     return f;
10740 };
10741
10742 Roo.data.Record.AUTO_ID = 1000;
10743 Roo.data.Record.EDIT = 'edit';
10744 Roo.data.Record.REJECT = 'reject';
10745 Roo.data.Record.COMMIT = 'commit';
10746
10747 Roo.data.Record.prototype = {
10748     /**
10749      * Readonly flag - true if this record has been modified.
10750      * @type Boolean
10751      */
10752     dirty : false,
10753     editing : false,
10754     error: null,
10755     modified: null,
10756
10757     // private
10758     join : function(store){
10759         this.store = store;
10760     },
10761
10762     /**
10763      * Set the named field to the specified value.
10764      * @param {String} name The name of the field to set.
10765      * @param {Object} value The value to set the field to.
10766      */
10767     set : function(name, value){
10768         if(this.data[name] == value){
10769             return;
10770         }
10771         this.dirty = true;
10772         if(!this.modified){
10773             this.modified = {};
10774         }
10775         if(typeof this.modified[name] == 'undefined'){
10776             this.modified[name] = this.data[name];
10777         }
10778         this.data[name] = value;
10779         if(!this.editing && this.store){
10780             this.store.afterEdit(this);
10781         }       
10782     },
10783
10784     /**
10785      * Get the value of the named field.
10786      * @param {String} name The name of the field to get the value of.
10787      * @return {Object} The value of the field.
10788      */
10789     get : function(name){
10790         return this.data[name]; 
10791     },
10792
10793     // private
10794     beginEdit : function(){
10795         this.editing = true;
10796         this.modified = {}; 
10797     },
10798
10799     // private
10800     cancelEdit : function(){
10801         this.editing = false;
10802         delete this.modified;
10803     },
10804
10805     // private
10806     endEdit : function(){
10807         this.editing = false;
10808         if(this.dirty && this.store){
10809             this.store.afterEdit(this);
10810         }
10811     },
10812
10813     /**
10814      * Usually called by the {@link Roo.data.Store} which owns the Record.
10815      * Rejects all changes made to the Record since either creation, or the last commit operation.
10816      * Modified fields are reverted to their original values.
10817      * <p>
10818      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10819      * of reject operations.
10820      */
10821     reject : function(){
10822         var m = this.modified;
10823         for(var n in m){
10824             if(typeof m[n] != "function"){
10825                 this.data[n] = m[n];
10826             }
10827         }
10828         this.dirty = false;
10829         delete this.modified;
10830         this.editing = false;
10831         if(this.store){
10832             this.store.afterReject(this);
10833         }
10834     },
10835
10836     /**
10837      * Usually called by the {@link Roo.data.Store} which owns the Record.
10838      * Commits all changes made to the Record since either creation, or the last commit operation.
10839      * <p>
10840      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10841      * of commit operations.
10842      */
10843     commit : function(){
10844         this.dirty = false;
10845         delete this.modified;
10846         this.editing = false;
10847         if(this.store){
10848             this.store.afterCommit(this);
10849         }
10850     },
10851
10852     // private
10853     hasError : function(){
10854         return this.error != null;
10855     },
10856
10857     // private
10858     clearError : function(){
10859         this.error = null;
10860     },
10861
10862     /**
10863      * Creates a copy of this record.
10864      * @param {String} id (optional) A new record id if you don't want to use this record's id
10865      * @return {Record}
10866      */
10867     copy : function(newId) {
10868         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10869     }
10870 };/*
10871  * Based on:
10872  * Ext JS Library 1.1.1
10873  * Copyright(c) 2006-2007, Ext JS, LLC.
10874  *
10875  * Originally Released Under LGPL - original licence link has changed is not relivant.
10876  *
10877  * Fork - LGPL
10878  * <script type="text/javascript">
10879  */
10880
10881
10882
10883 /**
10884  * @class Roo.data.Store
10885  * @extends Roo.util.Observable
10886  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10887  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10888  * <p>
10889  * 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
10890  * has no knowledge of the format of the data returned by the Proxy.<br>
10891  * <p>
10892  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10893  * instances from the data object. These records are cached and made available through accessor functions.
10894  * @constructor
10895  * Creates a new Store.
10896  * @param {Object} config A config object containing the objects needed for the Store to access data,
10897  * and read the data into Records.
10898  */
10899 Roo.data.Store = function(config){
10900     this.data = new Roo.util.MixedCollection(false);
10901     this.data.getKey = function(o){
10902         return o.id;
10903     };
10904     this.baseParams = {};
10905     // private
10906     this.paramNames = {
10907         "start" : "start",
10908         "limit" : "limit",
10909         "sort" : "sort",
10910         "dir" : "dir",
10911         "multisort" : "_multisort"
10912     };
10913
10914     if(config && config.data){
10915         this.inlineData = config.data;
10916         delete config.data;
10917     }
10918
10919     Roo.apply(this, config);
10920     
10921     if(this.reader){ // reader passed
10922         this.reader = Roo.factory(this.reader, Roo.data);
10923         this.reader.xmodule = this.xmodule || false;
10924         if(!this.recordType){
10925             this.recordType = this.reader.recordType;
10926         }
10927         if(this.reader.onMetaChange){
10928             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10929         }
10930     }
10931
10932     if(this.recordType){
10933         this.fields = this.recordType.prototype.fields;
10934     }
10935     this.modified = [];
10936
10937     this.addEvents({
10938         /**
10939          * @event datachanged
10940          * Fires when the data cache has changed, and a widget which is using this Store
10941          * as a Record cache should refresh its view.
10942          * @param {Store} this
10943          */
10944         datachanged : true,
10945         /**
10946          * @event metachange
10947          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10948          * @param {Store} this
10949          * @param {Object} meta The JSON metadata
10950          */
10951         metachange : true,
10952         /**
10953          * @event add
10954          * Fires when Records have been added to the Store
10955          * @param {Store} this
10956          * @param {Roo.data.Record[]} records The array of Records added
10957          * @param {Number} index The index at which the record(s) were added
10958          */
10959         add : true,
10960         /**
10961          * @event remove
10962          * Fires when a Record has been removed from the Store
10963          * @param {Store} this
10964          * @param {Roo.data.Record} record The Record that was removed
10965          * @param {Number} index The index at which the record was removed
10966          */
10967         remove : true,
10968         /**
10969          * @event update
10970          * Fires when a Record has been updated
10971          * @param {Store} this
10972          * @param {Roo.data.Record} record The Record that was updated
10973          * @param {String} operation The update operation being performed.  Value may be one of:
10974          * <pre><code>
10975  Roo.data.Record.EDIT
10976  Roo.data.Record.REJECT
10977  Roo.data.Record.COMMIT
10978          * </code></pre>
10979          */
10980         update : true,
10981         /**
10982          * @event clear
10983          * Fires when the data cache has been cleared.
10984          * @param {Store} this
10985          */
10986         clear : true,
10987         /**
10988          * @event beforeload
10989          * Fires before a request is made for a new data object.  If the beforeload handler returns false
10990          * the load action will be canceled.
10991          * @param {Store} this
10992          * @param {Object} options The loading options that were specified (see {@link #load} for details)
10993          */
10994         beforeload : true,
10995         /**
10996          * @event beforeloadadd
10997          * Fires after a new set of Records has been loaded.
10998          * @param {Store} this
10999          * @param {Roo.data.Record[]} records The Records that were loaded
11000          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11001          */
11002         beforeloadadd : true,
11003         /**
11004          * @event load
11005          * Fires after a new set of Records has been loaded, before they are added to the store.
11006          * @param {Store} this
11007          * @param {Roo.data.Record[]} records The Records that were loaded
11008          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11009          * @params {Object} return from reader
11010          */
11011         load : true,
11012         /**
11013          * @event loadexception
11014          * Fires if an exception occurs in the Proxy during loading.
11015          * Called with the signature of the Proxy's "loadexception" event.
11016          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11017          * 
11018          * @param {Proxy} 
11019          * @param {Object} return from JsonData.reader() - success, totalRecords, records
11020          * @param {Object} load options 
11021          * @param {Object} jsonData from your request (normally this contains the Exception)
11022          */
11023         loadexception : true
11024     });
11025     
11026     if(this.proxy){
11027         this.proxy = Roo.factory(this.proxy, Roo.data);
11028         this.proxy.xmodule = this.xmodule || false;
11029         this.relayEvents(this.proxy,  ["loadexception"]);
11030     }
11031     this.sortToggle = {};
11032     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11033
11034     Roo.data.Store.superclass.constructor.call(this);
11035
11036     if(this.inlineData){
11037         this.loadData(this.inlineData);
11038         delete this.inlineData;
11039     }
11040 };
11041
11042 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11043      /**
11044     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
11045     * without a remote query - used by combo/forms at present.
11046     */
11047     
11048     /**
11049     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11050     */
11051     /**
11052     * @cfg {Array} data Inline data to be loaded when the store is initialized.
11053     */
11054     /**
11055     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11056     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11057     */
11058     /**
11059     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11060     * on any HTTP request
11061     */
11062     /**
11063     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11064     */
11065     /**
11066     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11067     */
11068     multiSort: false,
11069     /**
11070     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11071     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11072     */
11073     remoteSort : false,
11074
11075     /**
11076     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11077      * loaded or when a record is removed. (defaults to false).
11078     */
11079     pruneModifiedRecords : false,
11080
11081     // private
11082     lastOptions : null,
11083
11084     /**
11085      * Add Records to the Store and fires the add event.
11086      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11087      */
11088     add : function(records){
11089         records = [].concat(records);
11090         for(var i = 0, len = records.length; i < len; i++){
11091             records[i].join(this);
11092         }
11093         var index = this.data.length;
11094         this.data.addAll(records);
11095         this.fireEvent("add", this, records, index);
11096     },
11097
11098     /**
11099      * Remove a Record from the Store and fires the remove event.
11100      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11101      */
11102     remove : function(record){
11103         var index = this.data.indexOf(record);
11104         this.data.removeAt(index);
11105         if(this.pruneModifiedRecords){
11106             this.modified.remove(record);
11107         }
11108         this.fireEvent("remove", this, record, index);
11109     },
11110
11111     /**
11112      * Remove all Records from the Store and fires the clear event.
11113      */
11114     removeAll : function(){
11115         this.data.clear();
11116         if(this.pruneModifiedRecords){
11117             this.modified = [];
11118         }
11119         this.fireEvent("clear", this);
11120     },
11121
11122     /**
11123      * Inserts Records to the Store at the given index and fires the add event.
11124      * @param {Number} index The start index at which to insert the passed Records.
11125      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11126      */
11127     insert : function(index, records){
11128         records = [].concat(records);
11129         for(var i = 0, len = records.length; i < len; i++){
11130             this.data.insert(index, records[i]);
11131             records[i].join(this);
11132         }
11133         this.fireEvent("add", this, records, index);
11134     },
11135
11136     /**
11137      * Get the index within the cache of the passed Record.
11138      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11139      * @return {Number} The index of the passed Record. Returns -1 if not found.
11140      */
11141     indexOf : function(record){
11142         return this.data.indexOf(record);
11143     },
11144
11145     /**
11146      * Get the index within the cache of the Record with the passed id.
11147      * @param {String} id The id of the Record to find.
11148      * @return {Number} The index of the Record. Returns -1 if not found.
11149      */
11150     indexOfId : function(id){
11151         return this.data.indexOfKey(id);
11152     },
11153
11154     /**
11155      * Get the Record with the specified id.
11156      * @param {String} id The id of the Record to find.
11157      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11158      */
11159     getById : function(id){
11160         return this.data.key(id);
11161     },
11162
11163     /**
11164      * Get the Record at the specified index.
11165      * @param {Number} index The index of the Record to find.
11166      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11167      */
11168     getAt : function(index){
11169         return this.data.itemAt(index);
11170     },
11171
11172     /**
11173      * Returns a range of Records between specified indices.
11174      * @param {Number} startIndex (optional) The starting index (defaults to 0)
11175      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11176      * @return {Roo.data.Record[]} An array of Records
11177      */
11178     getRange : function(start, end){
11179         return this.data.getRange(start, end);
11180     },
11181
11182     // private
11183     storeOptions : function(o){
11184         o = Roo.apply({}, o);
11185         delete o.callback;
11186         delete o.scope;
11187         this.lastOptions = o;
11188     },
11189
11190     /**
11191      * Loads the Record cache from the configured Proxy using the configured Reader.
11192      * <p>
11193      * If using remote paging, then the first load call must specify the <em>start</em>
11194      * and <em>limit</em> properties in the options.params property to establish the initial
11195      * position within the dataset, and the number of Records to cache on each read from the Proxy.
11196      * <p>
11197      * <strong>It is important to note that for remote data sources, loading is asynchronous,
11198      * and this call will return before the new data has been loaded. Perform any post-processing
11199      * in a callback function, or in a "load" event handler.</strong>
11200      * <p>
11201      * @param {Object} options An object containing properties which control loading options:<ul>
11202      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11203      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11204      * passed the following arguments:<ul>
11205      * <li>r : Roo.data.Record[]</li>
11206      * <li>options: Options object from the load call</li>
11207      * <li>success: Boolean success indicator</li></ul></li>
11208      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11209      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11210      * </ul>
11211      */
11212     load : function(options){
11213         options = options || {};
11214         if(this.fireEvent("beforeload", this, options) !== false){
11215             this.storeOptions(options);
11216             var p = Roo.apply(options.params || {}, this.baseParams);
11217             // if meta was not loaded from remote source.. try requesting it.
11218             if (!this.reader.metaFromRemote) {
11219                 p._requestMeta = 1;
11220             }
11221             if(this.sortInfo && this.remoteSort){
11222                 var pn = this.paramNames;
11223                 p[pn["sort"]] = this.sortInfo.field;
11224                 p[pn["dir"]] = this.sortInfo.direction;
11225             }
11226             if (this.multiSort) {
11227                 var pn = this.paramNames;
11228                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11229             }
11230             
11231             this.proxy.load(p, this.reader, this.loadRecords, this, options);
11232         }
11233     },
11234
11235     /**
11236      * Reloads the Record cache from the configured Proxy using the configured Reader and
11237      * the options from the last load operation performed.
11238      * @param {Object} options (optional) An object containing properties which may override the options
11239      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11240      * the most recently used options are reused).
11241      */
11242     reload : function(options){
11243         this.load(Roo.applyIf(options||{}, this.lastOptions));
11244     },
11245
11246     // private
11247     // Called as a callback by the Reader during a load operation.
11248     loadRecords : function(o, options, success){
11249         if(!o || success === false){
11250             if(success !== false){
11251                 this.fireEvent("load", this, [], options, o);
11252             }
11253             if(options.callback){
11254                 options.callback.call(options.scope || this, [], options, false);
11255             }
11256             return;
11257         }
11258         // if data returned failure - throw an exception.
11259         if (o.success === false) {
11260             // show a message if no listener is registered.
11261             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11262                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11263             }
11264             // loadmask wil be hooked into this..
11265             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11266             return;
11267         }
11268         var r = o.records, t = o.totalRecords || r.length;
11269         
11270         this.fireEvent("beforeloadadd", this, r, options, o);
11271         
11272         if(!options || options.add !== true){
11273             if(this.pruneModifiedRecords){
11274                 this.modified = [];
11275             }
11276             for(var i = 0, len = r.length; i < len; i++){
11277                 r[i].join(this);
11278             }
11279             if(this.snapshot){
11280                 this.data = this.snapshot;
11281                 delete this.snapshot;
11282             }
11283             this.data.clear();
11284             this.data.addAll(r);
11285             this.totalLength = t;
11286             this.applySort();
11287             this.fireEvent("datachanged", this);
11288         }else{
11289             this.totalLength = Math.max(t, this.data.length+r.length);
11290             this.add(r);
11291         }
11292         
11293         if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11294                 
11295             var e = new Roo.data.Record({});
11296
11297             e.set(this.parent.displayField, this.parent.emptyTitle);
11298             e.set(this.parent.valueField, '');
11299
11300             this.insert(0, e);
11301         }
11302             
11303         this.fireEvent("load", this, r, options, o);
11304         if(options.callback){
11305             options.callback.call(options.scope || this, r, options, true);
11306         }
11307     },
11308
11309
11310     /**
11311      * Loads data from a passed data block. A Reader which understands the format of the data
11312      * must have been configured in the constructor.
11313      * @param {Object} data The data block from which to read the Records.  The format of the data expected
11314      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11315      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11316      */
11317     loadData : function(o, append){
11318         var r = this.reader.readRecords(o);
11319         this.loadRecords(r, {add: append}, true);
11320     },
11321
11322     /**
11323      * Gets the number of cached records.
11324      * <p>
11325      * <em>If using paging, this may not be the total size of the dataset. If the data object
11326      * used by the Reader contains the dataset size, then the getTotalCount() function returns
11327      * the data set size</em>
11328      */
11329     getCount : function(){
11330         return this.data.length || 0;
11331     },
11332
11333     /**
11334      * Gets the total number of records in the dataset as returned by the server.
11335      * <p>
11336      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11337      * the dataset size</em>
11338      */
11339     getTotalCount : function(){
11340         return this.totalLength || 0;
11341     },
11342
11343     /**
11344      * Returns the sort state of the Store as an object with two properties:
11345      * <pre><code>
11346  field {String} The name of the field by which the Records are sorted
11347  direction {String} The sort order, "ASC" or "DESC"
11348      * </code></pre>
11349      */
11350     getSortState : function(){
11351         return this.sortInfo;
11352     },
11353
11354     // private
11355     applySort : function(){
11356         if(this.sortInfo && !this.remoteSort){
11357             var s = this.sortInfo, f = s.field;
11358             var st = this.fields.get(f).sortType;
11359             var fn = function(r1, r2){
11360                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11361                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11362             };
11363             this.data.sort(s.direction, fn);
11364             if(this.snapshot && this.snapshot != this.data){
11365                 this.snapshot.sort(s.direction, fn);
11366             }
11367         }
11368     },
11369
11370     /**
11371      * Sets the default sort column and order to be used by the next load operation.
11372      * @param {String} fieldName The name of the field to sort by.
11373      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11374      */
11375     setDefaultSort : function(field, dir){
11376         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11377     },
11378
11379     /**
11380      * Sort the Records.
11381      * If remote sorting is used, the sort is performed on the server, and the cache is
11382      * reloaded. If local sorting is used, the cache is sorted internally.
11383      * @param {String} fieldName The name of the field to sort by.
11384      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11385      */
11386     sort : function(fieldName, dir){
11387         var f = this.fields.get(fieldName);
11388         if(!dir){
11389             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11390             
11391             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11392                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11393             }else{
11394                 dir = f.sortDir;
11395             }
11396         }
11397         this.sortToggle[f.name] = dir;
11398         this.sortInfo = {field: f.name, direction: dir};
11399         if(!this.remoteSort){
11400             this.applySort();
11401             this.fireEvent("datachanged", this);
11402         }else{
11403             this.load(this.lastOptions);
11404         }
11405     },
11406
11407     /**
11408      * Calls the specified function for each of the Records in the cache.
11409      * @param {Function} fn The function to call. The Record is passed as the first parameter.
11410      * Returning <em>false</em> aborts and exits the iteration.
11411      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11412      */
11413     each : function(fn, scope){
11414         this.data.each(fn, scope);
11415     },
11416
11417     /**
11418      * Gets all records modified since the last commit.  Modified records are persisted across load operations
11419      * (e.g., during paging).
11420      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11421      */
11422     getModifiedRecords : function(){
11423         return this.modified;
11424     },
11425
11426     // private
11427     createFilterFn : function(property, value, anyMatch){
11428         if(!value.exec){ // not a regex
11429             value = String(value);
11430             if(value.length == 0){
11431                 return false;
11432             }
11433             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11434         }
11435         return function(r){
11436             return value.test(r.data[property]);
11437         };
11438     },
11439
11440     /**
11441      * Sums the value of <i>property</i> for each record between start and end and returns the result.
11442      * @param {String} property A field on your records
11443      * @param {Number} start The record index to start at (defaults to 0)
11444      * @param {Number} end The last record index to include (defaults to length - 1)
11445      * @return {Number} The sum
11446      */
11447     sum : function(property, start, end){
11448         var rs = this.data.items, v = 0;
11449         start = start || 0;
11450         end = (end || end === 0) ? end : rs.length-1;
11451
11452         for(var i = start; i <= end; i++){
11453             v += (rs[i].data[property] || 0);
11454         }
11455         return v;
11456     },
11457
11458     /**
11459      * Filter the records by a specified property.
11460      * @param {String} field A field on your records
11461      * @param {String/RegExp} value Either a string that the field
11462      * should start with or a RegExp to test against the field
11463      * @param {Boolean} anyMatch True to match any part not just the beginning
11464      */
11465     filter : function(property, value, anyMatch){
11466         var fn = this.createFilterFn(property, value, anyMatch);
11467         return fn ? this.filterBy(fn) : this.clearFilter();
11468     },
11469
11470     /**
11471      * Filter by a function. The specified function will be called with each
11472      * record in this data source. If the function returns true the record is included,
11473      * otherwise it is filtered.
11474      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11475      * @param {Object} scope (optional) The scope of the function (defaults to this)
11476      */
11477     filterBy : function(fn, scope){
11478         this.snapshot = this.snapshot || this.data;
11479         this.data = this.queryBy(fn, scope||this);
11480         this.fireEvent("datachanged", this);
11481     },
11482
11483     /**
11484      * Query the records by a specified property.
11485      * @param {String} field A field on your records
11486      * @param {String/RegExp} value Either a string that the field
11487      * should start with or a RegExp to test against the field
11488      * @param {Boolean} anyMatch True to match any part not just the beginning
11489      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11490      */
11491     query : function(property, value, anyMatch){
11492         var fn = this.createFilterFn(property, value, anyMatch);
11493         return fn ? this.queryBy(fn) : this.data.clone();
11494     },
11495
11496     /**
11497      * Query by a function. The specified function will be called with each
11498      * record in this data source. If the function returns true the record is included
11499      * in the results.
11500      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11501      * @param {Object} scope (optional) The scope of the function (defaults to this)
11502       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11503      **/
11504     queryBy : function(fn, scope){
11505         var data = this.snapshot || this.data;
11506         return data.filterBy(fn, scope||this);
11507     },
11508
11509     /**
11510      * Collects unique values for a particular dataIndex from this store.
11511      * @param {String} dataIndex The property to collect
11512      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11513      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11514      * @return {Array} An array of the unique values
11515      **/
11516     collect : function(dataIndex, allowNull, bypassFilter){
11517         var d = (bypassFilter === true && this.snapshot) ?
11518                 this.snapshot.items : this.data.items;
11519         var v, sv, r = [], l = {};
11520         for(var i = 0, len = d.length; i < len; i++){
11521             v = d[i].data[dataIndex];
11522             sv = String(v);
11523             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11524                 l[sv] = true;
11525                 r[r.length] = v;
11526             }
11527         }
11528         return r;
11529     },
11530
11531     /**
11532      * Revert to a view of the Record cache with no filtering applied.
11533      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11534      */
11535     clearFilter : function(suppressEvent){
11536         if(this.snapshot && this.snapshot != this.data){
11537             this.data = this.snapshot;
11538             delete this.snapshot;
11539             if(suppressEvent !== true){
11540                 this.fireEvent("datachanged", this);
11541             }
11542         }
11543     },
11544
11545     // private
11546     afterEdit : function(record){
11547         if(this.modified.indexOf(record) == -1){
11548             this.modified.push(record);
11549         }
11550         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11551     },
11552     
11553     // private
11554     afterReject : function(record){
11555         this.modified.remove(record);
11556         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11557     },
11558
11559     // private
11560     afterCommit : function(record){
11561         this.modified.remove(record);
11562         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11563     },
11564
11565     /**
11566      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11567      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11568      */
11569     commitChanges : function(){
11570         var m = this.modified.slice(0);
11571         this.modified = [];
11572         for(var i = 0, len = m.length; i < len; i++){
11573             m[i].commit();
11574         }
11575     },
11576
11577     /**
11578      * Cancel outstanding changes on all changed records.
11579      */
11580     rejectChanges : function(){
11581         var m = this.modified.slice(0);
11582         this.modified = [];
11583         for(var i = 0, len = m.length; i < len; i++){
11584             m[i].reject();
11585         }
11586     },
11587
11588     onMetaChange : function(meta, rtype, o){
11589         this.recordType = rtype;
11590         this.fields = rtype.prototype.fields;
11591         delete this.snapshot;
11592         this.sortInfo = meta.sortInfo || this.sortInfo;
11593         this.modified = [];
11594         this.fireEvent('metachange', this, this.reader.meta);
11595     },
11596     
11597     moveIndex : function(data, type)
11598     {
11599         var index = this.indexOf(data);
11600         
11601         var newIndex = index + type;
11602         
11603         this.remove(data);
11604         
11605         this.insert(newIndex, data);
11606         
11607     }
11608 });/*
11609  * Based on:
11610  * Ext JS Library 1.1.1
11611  * Copyright(c) 2006-2007, Ext JS, LLC.
11612  *
11613  * Originally Released Under LGPL - original licence link has changed is not relivant.
11614  *
11615  * Fork - LGPL
11616  * <script type="text/javascript">
11617  */
11618
11619 /**
11620  * @class Roo.data.SimpleStore
11621  * @extends Roo.data.Store
11622  * Small helper class to make creating Stores from Array data easier.
11623  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11624  * @cfg {Array} fields An array of field definition objects, or field name strings.
11625  * @cfg {Array} data The multi-dimensional array of data
11626  * @constructor
11627  * @param {Object} config
11628  */
11629 Roo.data.SimpleStore = function(config){
11630     Roo.data.SimpleStore.superclass.constructor.call(this, {
11631         isLocal : true,
11632         reader: new Roo.data.ArrayReader({
11633                 id: config.id
11634             },
11635             Roo.data.Record.create(config.fields)
11636         ),
11637         proxy : new Roo.data.MemoryProxy(config.data)
11638     });
11639     this.load();
11640 };
11641 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11642  * Based on:
11643  * Ext JS Library 1.1.1
11644  * Copyright(c) 2006-2007, Ext JS, LLC.
11645  *
11646  * Originally Released Under LGPL - original licence link has changed is not relivant.
11647  *
11648  * Fork - LGPL
11649  * <script type="text/javascript">
11650  */
11651
11652 /**
11653 /**
11654  * @extends Roo.data.Store
11655  * @class Roo.data.JsonStore
11656  * Small helper class to make creating Stores for JSON data easier. <br/>
11657 <pre><code>
11658 var store = new Roo.data.JsonStore({
11659     url: 'get-images.php',
11660     root: 'images',
11661     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11662 });
11663 </code></pre>
11664  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11665  * JsonReader and HttpProxy (unless inline data is provided).</b>
11666  * @cfg {Array} fields An array of field definition objects, or field name strings.
11667  * @constructor
11668  * @param {Object} config
11669  */
11670 Roo.data.JsonStore = function(c){
11671     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11672         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11673         reader: new Roo.data.JsonReader(c, c.fields)
11674     }));
11675 };
11676 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11677  * Based on:
11678  * Ext JS Library 1.1.1
11679  * Copyright(c) 2006-2007, Ext JS, LLC.
11680  *
11681  * Originally Released Under LGPL - original licence link has changed is not relivant.
11682  *
11683  * Fork - LGPL
11684  * <script type="text/javascript">
11685  */
11686
11687  
11688 Roo.data.Field = function(config){
11689     if(typeof config == "string"){
11690         config = {name: config};
11691     }
11692     Roo.apply(this, config);
11693     
11694     if(!this.type){
11695         this.type = "auto";
11696     }
11697     
11698     var st = Roo.data.SortTypes;
11699     // named sortTypes are supported, here we look them up
11700     if(typeof this.sortType == "string"){
11701         this.sortType = st[this.sortType];
11702     }
11703     
11704     // set default sortType for strings and dates
11705     if(!this.sortType){
11706         switch(this.type){
11707             case "string":
11708                 this.sortType = st.asUCString;
11709                 break;
11710             case "date":
11711                 this.sortType = st.asDate;
11712                 break;
11713             default:
11714                 this.sortType = st.none;
11715         }
11716     }
11717
11718     // define once
11719     var stripRe = /[\$,%]/g;
11720
11721     // prebuilt conversion function for this field, instead of
11722     // switching every time we're reading a value
11723     if(!this.convert){
11724         var cv, dateFormat = this.dateFormat;
11725         switch(this.type){
11726             case "":
11727             case "auto":
11728             case undefined:
11729                 cv = function(v){ return v; };
11730                 break;
11731             case "string":
11732                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11733                 break;
11734             case "int":
11735                 cv = function(v){
11736                     return v !== undefined && v !== null && v !== '' ?
11737                            parseInt(String(v).replace(stripRe, ""), 10) : '';
11738                     };
11739                 break;
11740             case "float":
11741                 cv = function(v){
11742                     return v !== undefined && v !== null && v !== '' ?
11743                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
11744                     };
11745                 break;
11746             case "bool":
11747             case "boolean":
11748                 cv = function(v){ return v === true || v === "true" || v == 1; };
11749                 break;
11750             case "date":
11751                 cv = function(v){
11752                     if(!v){
11753                         return '';
11754                     }
11755                     if(v instanceof Date){
11756                         return v;
11757                     }
11758                     if(dateFormat){
11759                         if(dateFormat == "timestamp"){
11760                             return new Date(v*1000);
11761                         }
11762                         return Date.parseDate(v, dateFormat);
11763                     }
11764                     var parsed = Date.parse(v);
11765                     return parsed ? new Date(parsed) : null;
11766                 };
11767              break;
11768             
11769         }
11770         this.convert = cv;
11771     }
11772 };
11773
11774 Roo.data.Field.prototype = {
11775     dateFormat: null,
11776     defaultValue: "",
11777     mapping: null,
11778     sortType : null,
11779     sortDir : "ASC"
11780 };/*
11781  * Based on:
11782  * Ext JS Library 1.1.1
11783  * Copyright(c) 2006-2007, Ext JS, LLC.
11784  *
11785  * Originally Released Under LGPL - original licence link has changed is not relivant.
11786  *
11787  * Fork - LGPL
11788  * <script type="text/javascript">
11789  */
11790  
11791 // Base class for reading structured data from a data source.  This class is intended to be
11792 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11793
11794 /**
11795  * @class Roo.data.DataReader
11796  * Base class for reading structured data from a data source.  This class is intended to be
11797  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11798  */
11799
11800 Roo.data.DataReader = function(meta, recordType){
11801     
11802     this.meta = meta;
11803     
11804     this.recordType = recordType instanceof Array ? 
11805         Roo.data.Record.create(recordType) : recordType;
11806 };
11807
11808 Roo.data.DataReader.prototype = {
11809      /**
11810      * Create an empty record
11811      * @param {Object} data (optional) - overlay some values
11812      * @return {Roo.data.Record} record created.
11813      */
11814     newRow :  function(d) {
11815         var da =  {};
11816         this.recordType.prototype.fields.each(function(c) {
11817             switch( c.type) {
11818                 case 'int' : da[c.name] = 0; break;
11819                 case 'date' : da[c.name] = new Date(); break;
11820                 case 'float' : da[c.name] = 0.0; break;
11821                 case 'boolean' : da[c.name] = false; break;
11822                 default : da[c.name] = ""; break;
11823             }
11824             
11825         });
11826         return new this.recordType(Roo.apply(da, d));
11827     }
11828     
11829 };/*
11830  * Based on:
11831  * Ext JS Library 1.1.1
11832  * Copyright(c) 2006-2007, Ext JS, LLC.
11833  *
11834  * Originally Released Under LGPL - original licence link has changed is not relivant.
11835  *
11836  * Fork - LGPL
11837  * <script type="text/javascript">
11838  */
11839
11840 /**
11841  * @class Roo.data.DataProxy
11842  * @extends Roo.data.Observable
11843  * This class is an abstract base class for implementations which provide retrieval of
11844  * unformatted data objects.<br>
11845  * <p>
11846  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11847  * (of the appropriate type which knows how to parse the data object) to provide a block of
11848  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11849  * <p>
11850  * Custom implementations must implement the load method as described in
11851  * {@link Roo.data.HttpProxy#load}.
11852  */
11853 Roo.data.DataProxy = function(){
11854     this.addEvents({
11855         /**
11856          * @event beforeload
11857          * Fires before a network request is made to retrieve a data object.
11858          * @param {Object} This DataProxy object.
11859          * @param {Object} params The params parameter to the load function.
11860          */
11861         beforeload : true,
11862         /**
11863          * @event load
11864          * Fires before the load method's callback is called.
11865          * @param {Object} This DataProxy object.
11866          * @param {Object} o The data object.
11867          * @param {Object} arg The callback argument object passed to the load function.
11868          */
11869         load : true,
11870         /**
11871          * @event loadexception
11872          * Fires if an Exception occurs during data retrieval.
11873          * @param {Object} This DataProxy object.
11874          * @param {Object} o The data object.
11875          * @param {Object} arg The callback argument object passed to the load function.
11876          * @param {Object} e The Exception.
11877          */
11878         loadexception : true
11879     });
11880     Roo.data.DataProxy.superclass.constructor.call(this);
11881 };
11882
11883 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11884
11885     /**
11886      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11887      */
11888 /*
11889  * Based on:
11890  * Ext JS Library 1.1.1
11891  * Copyright(c) 2006-2007, Ext JS, LLC.
11892  *
11893  * Originally Released Under LGPL - original licence link has changed is not relivant.
11894  *
11895  * Fork - LGPL
11896  * <script type="text/javascript">
11897  */
11898 /**
11899  * @class Roo.data.MemoryProxy
11900  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11901  * to the Reader when its load method is called.
11902  * @constructor
11903  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11904  */
11905 Roo.data.MemoryProxy = function(data){
11906     if (data.data) {
11907         data = data.data;
11908     }
11909     Roo.data.MemoryProxy.superclass.constructor.call(this);
11910     this.data = data;
11911 };
11912
11913 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11914     
11915     /**
11916      * Load data from the requested source (in this case an in-memory
11917      * data object passed to the constructor), read the data object into
11918      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11919      * process that block using the passed callback.
11920      * @param {Object} params This parameter is not used by the MemoryProxy class.
11921      * @param {Roo.data.DataReader} reader The Reader object which converts the data
11922      * object into a block of Roo.data.Records.
11923      * @param {Function} callback The function into which to pass the block of Roo.data.records.
11924      * The function must be passed <ul>
11925      * <li>The Record block object</li>
11926      * <li>The "arg" argument from the load function</li>
11927      * <li>A boolean success indicator</li>
11928      * </ul>
11929      * @param {Object} scope The scope in which to call the callback
11930      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11931      */
11932     load : function(params, reader, callback, scope, arg){
11933         params = params || {};
11934         var result;
11935         try {
11936             result = reader.readRecords(this.data);
11937         }catch(e){
11938             this.fireEvent("loadexception", this, arg, null, e);
11939             callback.call(scope, null, arg, false);
11940             return;
11941         }
11942         callback.call(scope, result, arg, true);
11943     },
11944     
11945     // private
11946     update : function(params, records){
11947         
11948     }
11949 });/*
11950  * Based on:
11951  * Ext JS Library 1.1.1
11952  * Copyright(c) 2006-2007, Ext JS, LLC.
11953  *
11954  * Originally Released Under LGPL - original licence link has changed is not relivant.
11955  *
11956  * Fork - LGPL
11957  * <script type="text/javascript">
11958  */
11959 /**
11960  * @class Roo.data.HttpProxy
11961  * @extends Roo.data.DataProxy
11962  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11963  * configured to reference a certain URL.<br><br>
11964  * <p>
11965  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11966  * from which the running page was served.<br><br>
11967  * <p>
11968  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11969  * <p>
11970  * Be aware that to enable the browser to parse an XML document, the server must set
11971  * the Content-Type header in the HTTP response to "text/xml".
11972  * @constructor
11973  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11974  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
11975  * will be used to make the request.
11976  */
11977 Roo.data.HttpProxy = function(conn){
11978     Roo.data.HttpProxy.superclass.constructor.call(this);
11979     // is conn a conn config or a real conn?
11980     this.conn = conn;
11981     this.useAjax = !conn || !conn.events;
11982   
11983 };
11984
11985 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11986     // thse are take from connection...
11987     
11988     /**
11989      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11990      */
11991     /**
11992      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11993      * extra parameters to each request made by this object. (defaults to undefined)
11994      */
11995     /**
11996      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11997      *  to each request made by this object. (defaults to undefined)
11998      */
11999     /**
12000      * @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)
12001      */
12002     /**
12003      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12004      */
12005      /**
12006      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12007      * @type Boolean
12008      */
12009   
12010
12011     /**
12012      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12013      * @type Boolean
12014      */
12015     /**
12016      * Return the {@link Roo.data.Connection} object being used by this Proxy.
12017      * @return {Connection} The Connection object. This object may be used to subscribe to events on
12018      * a finer-grained basis than the DataProxy events.
12019      */
12020     getConnection : function(){
12021         return this.useAjax ? Roo.Ajax : this.conn;
12022     },
12023
12024     /**
12025      * Load data from the configured {@link Roo.data.Connection}, read the data object into
12026      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12027      * process that block using the passed callback.
12028      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12029      * for the request to the remote server.
12030      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12031      * object into a block of Roo.data.Records.
12032      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12033      * The function must be passed <ul>
12034      * <li>The Record block object</li>
12035      * <li>The "arg" argument from the load function</li>
12036      * <li>A boolean success indicator</li>
12037      * </ul>
12038      * @param {Object} scope The scope in which to call the callback
12039      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12040      */
12041     load : function(params, reader, callback, scope, arg){
12042         if(this.fireEvent("beforeload", this, params) !== false){
12043             var  o = {
12044                 params : params || {},
12045                 request: {
12046                     callback : callback,
12047                     scope : scope,
12048                     arg : arg
12049                 },
12050                 reader: reader,
12051                 callback : this.loadResponse,
12052                 scope: this
12053             };
12054             if(this.useAjax){
12055                 Roo.applyIf(o, this.conn);
12056                 if(this.activeRequest){
12057                     Roo.Ajax.abort(this.activeRequest);
12058                 }
12059                 this.activeRequest = Roo.Ajax.request(o);
12060             }else{
12061                 this.conn.request(o);
12062             }
12063         }else{
12064             callback.call(scope||this, null, arg, false);
12065         }
12066     },
12067
12068     // private
12069     loadResponse : function(o, success, response){
12070         delete this.activeRequest;
12071         if(!success){
12072             this.fireEvent("loadexception", this, o, response);
12073             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12074             return;
12075         }
12076         var result;
12077         try {
12078             result = o.reader.read(response);
12079         }catch(e){
12080             this.fireEvent("loadexception", this, o, response, e);
12081             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12082             return;
12083         }
12084         
12085         this.fireEvent("load", this, o, o.request.arg);
12086         o.request.callback.call(o.request.scope, result, o.request.arg, true);
12087     },
12088
12089     // private
12090     update : function(dataSet){
12091
12092     },
12093
12094     // private
12095     updateResponse : function(dataSet){
12096
12097     }
12098 });/*
12099  * Based on:
12100  * Ext JS Library 1.1.1
12101  * Copyright(c) 2006-2007, Ext JS, LLC.
12102  *
12103  * Originally Released Under LGPL - original licence link has changed is not relivant.
12104  *
12105  * Fork - LGPL
12106  * <script type="text/javascript">
12107  */
12108
12109 /**
12110  * @class Roo.data.ScriptTagProxy
12111  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12112  * other than the originating domain of the running page.<br><br>
12113  * <p>
12114  * <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
12115  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12116  * <p>
12117  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12118  * source code that is used as the source inside a &lt;script> tag.<br><br>
12119  * <p>
12120  * In order for the browser to process the returned data, the server must wrap the data object
12121  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12122  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12123  * depending on whether the callback name was passed:
12124  * <p>
12125  * <pre><code>
12126 boolean scriptTag = false;
12127 String cb = request.getParameter("callback");
12128 if (cb != null) {
12129     scriptTag = true;
12130     response.setContentType("text/javascript");
12131 } else {
12132     response.setContentType("application/x-json");
12133 }
12134 Writer out = response.getWriter();
12135 if (scriptTag) {
12136     out.write(cb + "(");
12137 }
12138 out.print(dataBlock.toJsonString());
12139 if (scriptTag) {
12140     out.write(");");
12141 }
12142 </pre></code>
12143  *
12144  * @constructor
12145  * @param {Object} config A configuration object.
12146  */
12147 Roo.data.ScriptTagProxy = function(config){
12148     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12149     Roo.apply(this, config);
12150     this.head = document.getElementsByTagName("head")[0];
12151 };
12152
12153 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12154
12155 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12156     /**
12157      * @cfg {String} url The URL from which to request the data object.
12158      */
12159     /**
12160      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12161      */
12162     timeout : 30000,
12163     /**
12164      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12165      * the server the name of the callback function set up by the load call to process the returned data object.
12166      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12167      * javascript output which calls this named function passing the data object as its only parameter.
12168      */
12169     callbackParam : "callback",
12170     /**
12171      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12172      * name to the request.
12173      */
12174     nocache : true,
12175
12176     /**
12177      * Load data from the configured URL, read the data object into
12178      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12179      * process that block using the passed callback.
12180      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12181      * for the request to the remote server.
12182      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12183      * object into a block of Roo.data.Records.
12184      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12185      * The function must be passed <ul>
12186      * <li>The Record block object</li>
12187      * <li>The "arg" argument from the load function</li>
12188      * <li>A boolean success indicator</li>
12189      * </ul>
12190      * @param {Object} scope The scope in which to call the callback
12191      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12192      */
12193     load : function(params, reader, callback, scope, arg){
12194         if(this.fireEvent("beforeload", this, params) !== false){
12195
12196             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12197
12198             var url = this.url;
12199             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12200             if(this.nocache){
12201                 url += "&_dc=" + (new Date().getTime());
12202             }
12203             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12204             var trans = {
12205                 id : transId,
12206                 cb : "stcCallback"+transId,
12207                 scriptId : "stcScript"+transId,
12208                 params : params,
12209                 arg : arg,
12210                 url : url,
12211                 callback : callback,
12212                 scope : scope,
12213                 reader : reader
12214             };
12215             var conn = this;
12216
12217             window[trans.cb] = function(o){
12218                 conn.handleResponse(o, trans);
12219             };
12220
12221             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12222
12223             if(this.autoAbort !== false){
12224                 this.abort();
12225             }
12226
12227             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12228
12229             var script = document.createElement("script");
12230             script.setAttribute("src", url);
12231             script.setAttribute("type", "text/javascript");
12232             script.setAttribute("id", trans.scriptId);
12233             this.head.appendChild(script);
12234
12235             this.trans = trans;
12236         }else{
12237             callback.call(scope||this, null, arg, false);
12238         }
12239     },
12240
12241     // private
12242     isLoading : function(){
12243         return this.trans ? true : false;
12244     },
12245
12246     /**
12247      * Abort the current server request.
12248      */
12249     abort : function(){
12250         if(this.isLoading()){
12251             this.destroyTrans(this.trans);
12252         }
12253     },
12254
12255     // private
12256     destroyTrans : function(trans, isLoaded){
12257         this.head.removeChild(document.getElementById(trans.scriptId));
12258         clearTimeout(trans.timeoutId);
12259         if(isLoaded){
12260             window[trans.cb] = undefined;
12261             try{
12262                 delete window[trans.cb];
12263             }catch(e){}
12264         }else{
12265             // if hasn't been loaded, wait for load to remove it to prevent script error
12266             window[trans.cb] = function(){
12267                 window[trans.cb] = undefined;
12268                 try{
12269                     delete window[trans.cb];
12270                 }catch(e){}
12271             };
12272         }
12273     },
12274
12275     // private
12276     handleResponse : function(o, trans){
12277         this.trans = false;
12278         this.destroyTrans(trans, true);
12279         var result;
12280         try {
12281             result = trans.reader.readRecords(o);
12282         }catch(e){
12283             this.fireEvent("loadexception", this, o, trans.arg, e);
12284             trans.callback.call(trans.scope||window, null, trans.arg, false);
12285             return;
12286         }
12287         this.fireEvent("load", this, o, trans.arg);
12288         trans.callback.call(trans.scope||window, result, trans.arg, true);
12289     },
12290
12291     // private
12292     handleFailure : function(trans){
12293         this.trans = false;
12294         this.destroyTrans(trans, false);
12295         this.fireEvent("loadexception", this, null, trans.arg);
12296         trans.callback.call(trans.scope||window, null, trans.arg, false);
12297     }
12298 });/*
12299  * Based on:
12300  * Ext JS Library 1.1.1
12301  * Copyright(c) 2006-2007, Ext JS, LLC.
12302  *
12303  * Originally Released Under LGPL - original licence link has changed is not relivant.
12304  *
12305  * Fork - LGPL
12306  * <script type="text/javascript">
12307  */
12308
12309 /**
12310  * @class Roo.data.JsonReader
12311  * @extends Roo.data.DataReader
12312  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12313  * based on mappings in a provided Roo.data.Record constructor.
12314  * 
12315  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12316  * in the reply previously. 
12317  * 
12318  * <p>
12319  * Example code:
12320  * <pre><code>
12321 var RecordDef = Roo.data.Record.create([
12322     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
12323     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
12324 ]);
12325 var myReader = new Roo.data.JsonReader({
12326     totalProperty: "results",    // The property which contains the total dataset size (optional)
12327     root: "rows",                // The property which contains an Array of row objects
12328     id: "id"                     // The property within each row object that provides an ID for the record (optional)
12329 }, RecordDef);
12330 </code></pre>
12331  * <p>
12332  * This would consume a JSON file like this:
12333  * <pre><code>
12334 { 'results': 2, 'rows': [
12335     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12336     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12337 }
12338 </code></pre>
12339  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12340  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12341  * paged from the remote server.
12342  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12343  * @cfg {String} root name of the property which contains the Array of row objects.
12344  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12345  * @cfg {Array} fields Array of field definition objects
12346  * @constructor
12347  * Create a new JsonReader
12348  * @param {Object} meta Metadata configuration options
12349  * @param {Object} recordType Either an Array of field definition objects,
12350  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12351  */
12352 Roo.data.JsonReader = function(meta, recordType){
12353     
12354     meta = meta || {};
12355     // set some defaults:
12356     Roo.applyIf(meta, {
12357         totalProperty: 'total',
12358         successProperty : 'success',
12359         root : 'data',
12360         id : 'id'
12361     });
12362     
12363     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12364 };
12365 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12366     
12367     /**
12368      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
12369      * Used by Store query builder to append _requestMeta to params.
12370      * 
12371      */
12372     metaFromRemote : false,
12373     /**
12374      * This method is only used by a DataProxy which has retrieved data from a remote server.
12375      * @param {Object} response The XHR object which contains the JSON data in its responseText.
12376      * @return {Object} data A data block which is used by an Roo.data.Store object as
12377      * a cache of Roo.data.Records.
12378      */
12379     read : function(response){
12380         var json = response.responseText;
12381        
12382         var o = /* eval:var:o */ eval("("+json+")");
12383         if(!o) {
12384             throw {message: "JsonReader.read: Json object not found"};
12385         }
12386         
12387         if(o.metaData){
12388             
12389             delete this.ef;
12390             this.metaFromRemote = true;
12391             this.meta = o.metaData;
12392             this.recordType = Roo.data.Record.create(o.metaData.fields);
12393             this.onMetaChange(this.meta, this.recordType, o);
12394         }
12395         return this.readRecords(o);
12396     },
12397
12398     // private function a store will implement
12399     onMetaChange : function(meta, recordType, o){
12400
12401     },
12402
12403     /**
12404          * @ignore
12405          */
12406     simpleAccess: function(obj, subsc) {
12407         return obj[subsc];
12408     },
12409
12410         /**
12411          * @ignore
12412          */
12413     getJsonAccessor: function(){
12414         var re = /[\[\.]/;
12415         return function(expr) {
12416             try {
12417                 return(re.test(expr))
12418                     ? new Function("obj", "return obj." + expr)
12419                     : function(obj){
12420                         return obj[expr];
12421                     };
12422             } catch(e){}
12423             return Roo.emptyFn;
12424         };
12425     }(),
12426
12427     /**
12428      * Create a data block containing Roo.data.Records from an XML document.
12429      * @param {Object} o An object which contains an Array of row objects in the property specified
12430      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12431      * which contains the total size of the dataset.
12432      * @return {Object} data A data block which is used by an Roo.data.Store object as
12433      * a cache of Roo.data.Records.
12434      */
12435     readRecords : function(o){
12436         /**
12437          * After any data loads, the raw JSON data is available for further custom processing.
12438          * @type Object
12439          */
12440         this.o = o;
12441         var s = this.meta, Record = this.recordType,
12442             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12443
12444 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
12445         if (!this.ef) {
12446             if(s.totalProperty) {
12447                     this.getTotal = this.getJsonAccessor(s.totalProperty);
12448                 }
12449                 if(s.successProperty) {
12450                     this.getSuccess = this.getJsonAccessor(s.successProperty);
12451                 }
12452                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12453                 if (s.id) {
12454                         var g = this.getJsonAccessor(s.id);
12455                         this.getId = function(rec) {
12456                                 var r = g(rec);  
12457                                 return (r === undefined || r === "") ? null : r;
12458                         };
12459                 } else {
12460                         this.getId = function(){return null;};
12461                 }
12462             this.ef = [];
12463             for(var jj = 0; jj < fl; jj++){
12464                 f = fi[jj];
12465                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12466                 this.ef[jj] = this.getJsonAccessor(map);
12467             }
12468         }
12469
12470         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12471         if(s.totalProperty){
12472             var vt = parseInt(this.getTotal(o), 10);
12473             if(!isNaN(vt)){
12474                 totalRecords = vt;
12475             }
12476         }
12477         if(s.successProperty){
12478             var vs = this.getSuccess(o);
12479             if(vs === false || vs === 'false'){
12480                 success = false;
12481             }
12482         }
12483         var records = [];
12484         for(var i = 0; i < c; i++){
12485                 var n = root[i];
12486             var values = {};
12487             var id = this.getId(n);
12488             for(var j = 0; j < fl; j++){
12489                 f = fi[j];
12490             var v = this.ef[j](n);
12491             if (!f.convert) {
12492                 Roo.log('missing convert for ' + f.name);
12493                 Roo.log(f);
12494                 continue;
12495             }
12496             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12497             }
12498             var record = new Record(values, id);
12499             record.json = n;
12500             records[i] = record;
12501         }
12502         return {
12503             raw : o,
12504             success : success,
12505             records : records,
12506             totalRecords : totalRecords
12507         };
12508     }
12509 });/*
12510  * Based on:
12511  * Ext JS Library 1.1.1
12512  * Copyright(c) 2006-2007, Ext JS, LLC.
12513  *
12514  * Originally Released Under LGPL - original licence link has changed is not relivant.
12515  *
12516  * Fork - LGPL
12517  * <script type="text/javascript">
12518  */
12519
12520 /**
12521  * @class Roo.data.ArrayReader
12522  * @extends Roo.data.DataReader
12523  * Data reader class to create an Array of Roo.data.Record objects from an Array.
12524  * Each element of that Array represents a row of data fields. The
12525  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12526  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12527  * <p>
12528  * Example code:.
12529  * <pre><code>
12530 var RecordDef = Roo.data.Record.create([
12531     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
12532     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
12533 ]);
12534 var myReader = new Roo.data.ArrayReader({
12535     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
12536 }, RecordDef);
12537 </code></pre>
12538  * <p>
12539  * This would consume an Array like this:
12540  * <pre><code>
12541 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12542   </code></pre>
12543  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12544  * @constructor
12545  * Create a new JsonReader
12546  * @param {Object} meta Metadata configuration options.
12547  * @param {Object} recordType Either an Array of field definition objects
12548  * as specified to {@link Roo.data.Record#create},
12549  * or an {@link Roo.data.Record} object
12550  * created using {@link Roo.data.Record#create}.
12551  */
12552 Roo.data.ArrayReader = function(meta, recordType){
12553     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12554 };
12555
12556 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12557     /**
12558      * Create a data block containing Roo.data.Records from an XML document.
12559      * @param {Object} o An Array of row objects which represents the dataset.
12560      * @return {Object} data A data block which is used by an Roo.data.Store object as
12561      * a cache of Roo.data.Records.
12562      */
12563     readRecords : function(o){
12564         var sid = this.meta ? this.meta.id : null;
12565         var recordType = this.recordType, fields = recordType.prototype.fields;
12566         var records = [];
12567         var root = o;
12568             for(var i = 0; i < root.length; i++){
12569                     var n = root[i];
12570                 var values = {};
12571                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12572                 for(var j = 0, jlen = fields.length; j < jlen; j++){
12573                 var f = fields.items[j];
12574                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12575                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12576                 v = f.convert(v);
12577                 values[f.name] = v;
12578             }
12579                 var record = new recordType(values, id);
12580                 record.json = n;
12581                 records[records.length] = record;
12582             }
12583             return {
12584                 records : records,
12585                 totalRecords : records.length
12586             };
12587     }
12588 });/*
12589  * - LGPL
12590  * * 
12591  */
12592
12593 /**
12594  * @class Roo.bootstrap.ComboBox
12595  * @extends Roo.bootstrap.TriggerField
12596  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12597  * @cfg {Boolean} append (true|false) default false
12598  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12599  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12600  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12601  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12602  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12603  * @cfg {Boolean} animate default true
12604  * @cfg {Boolean} emptyResultText only for touch device
12605  * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12606  * @cfg {String} emptyTitle default ''
12607  * @constructor
12608  * Create a new ComboBox.
12609  * @param {Object} config Configuration options
12610  */
12611 Roo.bootstrap.ComboBox = function(config){
12612     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12613     this.addEvents({
12614         /**
12615          * @event expand
12616          * Fires when the dropdown list is expanded
12617         * @param {Roo.bootstrap.ComboBox} combo This combo box
12618         */
12619         'expand' : true,
12620         /**
12621          * @event collapse
12622          * Fires when the dropdown list is collapsed
12623         * @param {Roo.bootstrap.ComboBox} combo This combo box
12624         */
12625         'collapse' : true,
12626         /**
12627          * @event beforeselect
12628          * Fires before a list item is selected. Return false to cancel the selection.
12629         * @param {Roo.bootstrap.ComboBox} combo This combo box
12630         * @param {Roo.data.Record} record The data record returned from the underlying store
12631         * @param {Number} index The index of the selected item in the dropdown list
12632         */
12633         'beforeselect' : true,
12634         /**
12635          * @event select
12636          * Fires when a list item is selected
12637         * @param {Roo.bootstrap.ComboBox} combo This combo box
12638         * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12639         * @param {Number} index The index of the selected item in the dropdown list
12640         */
12641         'select' : true,
12642         /**
12643          * @event beforequery
12644          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12645          * The event object passed has these properties:
12646         * @param {Roo.bootstrap.ComboBox} combo This combo box
12647         * @param {String} query The query
12648         * @param {Boolean} forceAll true to force "all" query
12649         * @param {Boolean} cancel true to cancel the query
12650         * @param {Object} e The query event object
12651         */
12652         'beforequery': true,
12653          /**
12654          * @event add
12655          * Fires when the 'add' icon is pressed (add a listener to enable add button)
12656         * @param {Roo.bootstrap.ComboBox} combo This combo box
12657         */
12658         'add' : true,
12659         /**
12660          * @event edit
12661          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12662         * @param {Roo.bootstrap.ComboBox} combo This combo box
12663         * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12664         */
12665         'edit' : true,
12666         /**
12667          * @event remove
12668          * Fires when the remove value from the combobox array
12669         * @param {Roo.bootstrap.ComboBox} combo This combo box
12670         */
12671         'remove' : true,
12672         /**
12673          * @event afterremove
12674          * Fires when the remove value from the combobox array
12675         * @param {Roo.bootstrap.ComboBox} combo This combo box
12676         */
12677         'afterremove' : true,
12678         /**
12679          * @event specialfilter
12680          * Fires when specialfilter
12681             * @param {Roo.bootstrap.ComboBox} combo This combo box
12682             */
12683         'specialfilter' : true,
12684         /**
12685          * @event tick
12686          * Fires when tick the element
12687             * @param {Roo.bootstrap.ComboBox} combo This combo box
12688             */
12689         'tick' : true,
12690         /**
12691          * @event touchviewdisplay
12692          * Fires when touch view require special display (default is using displayField)
12693             * @param {Roo.bootstrap.ComboBox} combo This combo box
12694             * @param {Object} cfg set html .
12695             */
12696         'touchviewdisplay' : true
12697         
12698     });
12699     
12700     this.item = [];
12701     this.tickItems = [];
12702     
12703     this.selectedIndex = -1;
12704     if(this.mode == 'local'){
12705         if(config.queryDelay === undefined){
12706             this.queryDelay = 10;
12707         }
12708         if(config.minChars === undefined){
12709             this.minChars = 0;
12710         }
12711     }
12712 };
12713
12714 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12715      
12716     /**
12717      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12718      * rendering into an Roo.Editor, defaults to false)
12719      */
12720     /**
12721      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12722      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12723      */
12724     /**
12725      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12726      */
12727     /**
12728      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12729      * the dropdown list (defaults to undefined, with no header element)
12730      */
12731
12732      /**
12733      * @cfg {String/Roo.Template} tpl The template to use to render the output
12734      */
12735      
12736      /**
12737      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12738      */
12739     listWidth: undefined,
12740     /**
12741      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12742      * mode = 'remote' or 'text' if mode = 'local')
12743      */
12744     displayField: undefined,
12745     
12746     /**
12747      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12748      * mode = 'remote' or 'value' if mode = 'local'). 
12749      * Note: use of a valueField requires the user make a selection
12750      * in order for a value to be mapped.
12751      */
12752     valueField: undefined,
12753     /**
12754      * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12755      */
12756     modalTitle : '',
12757     
12758     /**
12759      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12760      * field's data value (defaults to the underlying DOM element's name)
12761      */
12762     hiddenName: undefined,
12763     /**
12764      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12765      */
12766     listClass: '',
12767     /**
12768      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12769      */
12770     selectedClass: 'active',
12771     
12772     /**
12773      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12774      */
12775     shadow:'sides',
12776     /**
12777      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12778      * anchor positions (defaults to 'tl-bl')
12779      */
12780     listAlign: 'tl-bl?',
12781     /**
12782      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12783      */
12784     maxHeight: 300,
12785     /**
12786      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
12787      * query specified by the allQuery config option (defaults to 'query')
12788      */
12789     triggerAction: 'query',
12790     /**
12791      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12792      * (defaults to 4, does not apply if editable = false)
12793      */
12794     minChars : 4,
12795     /**
12796      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12797      * delay (typeAheadDelay) if it matches a known value (defaults to false)
12798      */
12799     typeAhead: false,
12800     /**
12801      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12802      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12803      */
12804     queryDelay: 500,
12805     /**
12806      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12807      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
12808      */
12809     pageSize: 0,
12810     /**
12811      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
12812      * when editable = true (defaults to false)
12813      */
12814     selectOnFocus:false,
12815     /**
12816      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12817      */
12818     queryParam: 'query',
12819     /**
12820      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
12821      * when mode = 'remote' (defaults to 'Loading...')
12822      */
12823     loadingText: 'Loading...',
12824     /**
12825      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12826      */
12827     resizable: false,
12828     /**
12829      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12830      */
12831     handleHeight : 8,
12832     /**
12833      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12834      * traditional select (defaults to true)
12835      */
12836     editable: true,
12837     /**
12838      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12839      */
12840     allQuery: '',
12841     /**
12842      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12843      */
12844     mode: 'remote',
12845     /**
12846      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12847      * listWidth has a higher value)
12848      */
12849     minListWidth : 70,
12850     /**
12851      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12852      * allow the user to set arbitrary text into the field (defaults to false)
12853      */
12854     forceSelection:false,
12855     /**
12856      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12857      * if typeAhead = true (defaults to 250)
12858      */
12859     typeAheadDelay : 250,
12860     /**
12861      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12862      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12863      */
12864     valueNotFoundText : undefined,
12865     /**
12866      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12867      */
12868     blockFocus : false,
12869     
12870     /**
12871      * @cfg {Boolean} disableClear Disable showing of clear button.
12872      */
12873     disableClear : false,
12874     /**
12875      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
12876      */
12877     alwaysQuery : false,
12878     
12879     /**
12880      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
12881      */
12882     multiple : false,
12883     
12884     /**
12885      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12886      */
12887     invalidClass : "has-warning",
12888     
12889     /**
12890      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12891      */
12892     validClass : "has-success",
12893     
12894     /**
12895      * @cfg {Boolean} specialFilter (true|false) special filter default false
12896      */
12897     specialFilter : false,
12898     
12899     /**
12900      * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12901      */
12902     mobileTouchView : true,
12903     
12904     /**
12905      * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12906      */
12907     useNativeIOS : false,
12908     
12909     ios_options : false,
12910     
12911     //private
12912     addicon : false,
12913     editicon: false,
12914     
12915     page: 0,
12916     hasQuery: false,
12917     append: false,
12918     loadNext: false,
12919     autoFocus : true,
12920     tickable : false,
12921     btnPosition : 'right',
12922     triggerList : true,
12923     showToggleBtn : true,
12924     animate : true,
12925     emptyResultText: 'Empty',
12926     triggerText : 'Select',
12927     emptyTitle : '',
12928     
12929     // element that contains real text value.. (when hidden is used..)
12930     
12931     getAutoCreate : function()
12932     {   
12933         var cfg = false;
12934         //render
12935         /*
12936          * Render classic select for iso
12937          */
12938         
12939         if(Roo.isIOS && this.useNativeIOS){
12940             cfg = this.getAutoCreateNativeIOS();
12941             return cfg;
12942         }
12943         
12944         /*
12945          * Touch Devices
12946          */
12947         
12948         if(Roo.isTouch && this.mobileTouchView){
12949             cfg = this.getAutoCreateTouchView();
12950             return cfg;;
12951         }
12952         
12953         /*
12954          *  Normal ComboBox
12955          */
12956         if(!this.tickable){
12957             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12958             return cfg;
12959         }
12960         
12961         /*
12962          *  ComboBox with tickable selections
12963          */
12964              
12965         var align = this.labelAlign || this.parentLabelAlign();
12966         
12967         cfg = {
12968             cls : 'form-group roo-combobox-tickable' //input-group
12969         };
12970         
12971         var btn_text_select = '';
12972         var btn_text_done = '';
12973         var btn_text_cancel = '';
12974         
12975         if (this.btn_text_show) {
12976             btn_text_select = 'Select';
12977             btn_text_done = 'Done';
12978             btn_text_cancel = 'Cancel'; 
12979         }
12980         
12981         var buttons = {
12982             tag : 'div',
12983             cls : 'tickable-buttons',
12984             cn : [
12985                 {
12986                     tag : 'button',
12987                     type : 'button',
12988                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12989                     //html : this.triggerText
12990                     html: btn_text_select
12991                 },
12992                 {
12993                     tag : 'button',
12994                     type : 'button',
12995                     name : 'ok',
12996                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12997                     //html : 'Done'
12998                     html: btn_text_done
12999                 },
13000                 {
13001                     tag : 'button',
13002                     type : 'button',
13003                     name : 'cancel',
13004                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13005                     //html : 'Cancel'
13006                     html: btn_text_cancel
13007                 }
13008             ]
13009         };
13010         
13011         if(this.editable){
13012             buttons.cn.unshift({
13013                 tag: 'input',
13014                 cls: 'roo-select2-search-field-input'
13015             });
13016         }
13017         
13018         var _this = this;
13019         
13020         Roo.each(buttons.cn, function(c){
13021             if (_this.size) {
13022                 c.cls += ' btn-' + _this.size;
13023             }
13024
13025             if (_this.disabled) {
13026                 c.disabled = true;
13027             }
13028         });
13029         
13030         var box = {
13031             tag: 'div',
13032             cn: [
13033                 {
13034                     tag: 'input',
13035                     type : 'hidden',
13036                     cls: 'form-hidden-field'
13037                 },
13038                 {
13039                     tag: 'ul',
13040                     cls: 'roo-select2-choices',
13041                     cn:[
13042                         {
13043                             tag: 'li',
13044                             cls: 'roo-select2-search-field',
13045                             cn: [
13046                                 buttons
13047                             ]
13048                         }
13049                     ]
13050                 }
13051             ]
13052         };
13053         
13054         var combobox = {
13055             cls: 'roo-select2-container input-group roo-select2-container-multi',
13056             cn: [
13057                 box
13058 //                {
13059 //                    tag: 'ul',
13060 //                    cls: 'typeahead typeahead-long dropdown-menu',
13061 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
13062 //                }
13063             ]
13064         };
13065         
13066         if(this.hasFeedback && !this.allowBlank){
13067             
13068             var feedback = {
13069                 tag: 'span',
13070                 cls: 'glyphicon form-control-feedback'
13071             };
13072
13073             combobox.cn.push(feedback);
13074         }
13075         
13076         
13077         if (align ==='left' && this.fieldLabel.length) {
13078             
13079             cfg.cls += ' roo-form-group-label-left';
13080             
13081             cfg.cn = [
13082                 {
13083                     tag : 'i',
13084                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13085                     tooltip : 'This field is required'
13086                 },
13087                 {
13088                     tag: 'label',
13089                     'for' :  id,
13090                     cls : 'control-label',
13091                     html : this.fieldLabel
13092
13093                 },
13094                 {
13095                     cls : "", 
13096                     cn: [
13097                         combobox
13098                     ]
13099                 }
13100
13101             ];
13102             
13103             var labelCfg = cfg.cn[1];
13104             var contentCfg = cfg.cn[2];
13105             
13106
13107             if(this.indicatorpos == 'right'){
13108                 
13109                 cfg.cn = [
13110                     {
13111                         tag: 'label',
13112                         'for' :  id,
13113                         cls : 'control-label',
13114                         cn : [
13115                             {
13116                                 tag : 'span',
13117                                 html : this.fieldLabel
13118                             },
13119                             {
13120                                 tag : 'i',
13121                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13122                                 tooltip : 'This field is required'
13123                             }
13124                         ]
13125                     },
13126                     {
13127                         cls : "",
13128                         cn: [
13129                             combobox
13130                         ]
13131                     }
13132
13133                 ];
13134                 
13135                 
13136                 
13137                 labelCfg = cfg.cn[0];
13138                 contentCfg = cfg.cn[1];
13139             
13140             }
13141             
13142             if(this.labelWidth > 12){
13143                 labelCfg.style = "width: " + this.labelWidth + 'px';
13144             }
13145             
13146             if(this.labelWidth < 13 && this.labelmd == 0){
13147                 this.labelmd = this.labelWidth;
13148             }
13149             
13150             if(this.labellg > 0){
13151                 labelCfg.cls += ' col-lg-' + this.labellg;
13152                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13153             }
13154             
13155             if(this.labelmd > 0){
13156                 labelCfg.cls += ' col-md-' + this.labelmd;
13157                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13158             }
13159             
13160             if(this.labelsm > 0){
13161                 labelCfg.cls += ' col-sm-' + this.labelsm;
13162                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13163             }
13164             
13165             if(this.labelxs > 0){
13166                 labelCfg.cls += ' col-xs-' + this.labelxs;
13167                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13168             }
13169                 
13170                 
13171         } else if ( this.fieldLabel.length) {
13172 //                Roo.log(" label");
13173                  cfg.cn = [
13174                     {
13175                         tag : 'i',
13176                         cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13177                         tooltip : 'This field is required'
13178                     },
13179                     {
13180                         tag: 'label',
13181                         //cls : 'input-group-addon',
13182                         html : this.fieldLabel
13183                     },
13184                     combobox
13185                 ];
13186                 
13187                 if(this.indicatorpos == 'right'){
13188                     cfg.cn = [
13189                         {
13190                             tag: 'label',
13191                             //cls : 'input-group-addon',
13192                             html : this.fieldLabel
13193                         },
13194                         {
13195                             tag : 'i',
13196                             cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13197                             tooltip : 'This field is required'
13198                         },
13199                         combobox
13200                     ];
13201                     
13202                 }
13203
13204         } else {
13205             
13206 //                Roo.log(" no label && no align");
13207                 cfg = combobox
13208                      
13209                 
13210         }
13211          
13212         var settings=this;
13213         ['xs','sm','md','lg'].map(function(size){
13214             if (settings[size]) {
13215                 cfg.cls += ' col-' + size + '-' + settings[size];
13216             }
13217         });
13218         
13219         return cfg;
13220         
13221     },
13222     
13223     _initEventsCalled : false,
13224     
13225     // private
13226     initEvents: function()
13227     {   
13228         if (this._initEventsCalled) { // as we call render... prevent looping...
13229             return;
13230         }
13231         this._initEventsCalled = true;
13232         
13233         if (!this.store) {
13234             throw "can not find store for combo";
13235         }
13236         
13237         this.indicator = this.indicatorEl();
13238         
13239         this.store = Roo.factory(this.store, Roo.data);
13240         this.store.parent = this;
13241         
13242         // if we are building from html. then this element is so complex, that we can not really
13243         // use the rendered HTML.
13244         // so we have to trash and replace the previous code.
13245         if (Roo.XComponent.build_from_html) {
13246             // remove this element....
13247             var e = this.el.dom, k=0;
13248             while (e ) { e = e.previousSibling;  ++k;}
13249
13250             this.el.remove();
13251             
13252             this.el=false;
13253             this.rendered = false;
13254             
13255             this.render(this.parent().getChildContainer(true), k);
13256         }
13257         
13258         if(Roo.isIOS && this.useNativeIOS){
13259             this.initIOSView();
13260             return;
13261         }
13262         
13263         /*
13264          * Touch Devices
13265          */
13266         
13267         if(Roo.isTouch && this.mobileTouchView){
13268             this.initTouchView();
13269             return;
13270         }
13271         
13272         if(this.tickable){
13273             this.initTickableEvents();
13274             return;
13275         }
13276         
13277         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13278         
13279         if(this.hiddenName){
13280             
13281             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13282             
13283             this.hiddenField.dom.value =
13284                 this.hiddenValue !== undefined ? this.hiddenValue :
13285                 this.value !== undefined ? this.value : '';
13286
13287             // prevent input submission
13288             this.el.dom.removeAttribute('name');
13289             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13290              
13291              
13292         }
13293         //if(Roo.isGecko){
13294         //    this.el.dom.setAttribute('autocomplete', 'off');
13295         //}
13296         
13297         var cls = 'x-combo-list';
13298         
13299         //this.list = new Roo.Layer({
13300         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13301         //});
13302         
13303         var _this = this;
13304         
13305         (function(){
13306             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13307             _this.list.setWidth(lw);
13308         }).defer(100);
13309         
13310         this.list.on('mouseover', this.onViewOver, this);
13311         this.list.on('mousemove', this.onViewMove, this);
13312         this.list.on('scroll', this.onViewScroll, this);
13313         
13314         /*
13315         this.list.swallowEvent('mousewheel');
13316         this.assetHeight = 0;
13317
13318         if(this.title){
13319             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13320             this.assetHeight += this.header.getHeight();
13321         }
13322
13323         this.innerList = this.list.createChild({cls:cls+'-inner'});
13324         this.innerList.on('mouseover', this.onViewOver, this);
13325         this.innerList.on('mousemove', this.onViewMove, this);
13326         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13327         
13328         if(this.allowBlank && !this.pageSize && !this.disableClear){
13329             this.footer = this.list.createChild({cls:cls+'-ft'});
13330             this.pageTb = new Roo.Toolbar(this.footer);
13331            
13332         }
13333         if(this.pageSize){
13334             this.footer = this.list.createChild({cls:cls+'-ft'});
13335             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13336                     {pageSize: this.pageSize});
13337             
13338         }
13339         
13340         if (this.pageTb && this.allowBlank && !this.disableClear) {
13341             var _this = this;
13342             this.pageTb.add(new Roo.Toolbar.Fill(), {
13343                 cls: 'x-btn-icon x-btn-clear',
13344                 text: '&#160;',
13345                 handler: function()
13346                 {
13347                     _this.collapse();
13348                     _this.clearValue();
13349                     _this.onSelect(false, -1);
13350                 }
13351             });
13352         }
13353         if (this.footer) {
13354             this.assetHeight += this.footer.getHeight();
13355         }
13356         */
13357             
13358         if(!this.tpl){
13359             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13360         }
13361
13362         this.view = new Roo.View(this.list, this.tpl, {
13363             singleSelect:true, store: this.store, selectedClass: this.selectedClass
13364         });
13365         //this.view.wrapEl.setDisplayed(false);
13366         this.view.on('click', this.onViewClick, this);
13367         
13368         
13369         this.store.on('beforeload', this.onBeforeLoad, this);
13370         this.store.on('load', this.onLoad, this);
13371         this.store.on('loadexception', this.onLoadException, this);
13372         /*
13373         if(this.resizable){
13374             this.resizer = new Roo.Resizable(this.list,  {
13375                pinned:true, handles:'se'
13376             });
13377             this.resizer.on('resize', function(r, w, h){
13378                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13379                 this.listWidth = w;
13380                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13381                 this.restrictHeight();
13382             }, this);
13383             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13384         }
13385         */
13386         if(!this.editable){
13387             this.editable = true;
13388             this.setEditable(false);
13389         }
13390         
13391         /*
13392         
13393         if (typeof(this.events.add.listeners) != 'undefined') {
13394             
13395             this.addicon = this.wrap.createChild(
13396                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
13397        
13398             this.addicon.on('click', function(e) {
13399                 this.fireEvent('add', this);
13400             }, this);
13401         }
13402         if (typeof(this.events.edit.listeners) != 'undefined') {
13403             
13404             this.editicon = this.wrap.createChild(
13405                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
13406             if (this.addicon) {
13407                 this.editicon.setStyle('margin-left', '40px');
13408             }
13409             this.editicon.on('click', function(e) {
13410                 
13411                 // we fire even  if inothing is selected..
13412                 this.fireEvent('edit', this, this.lastData );
13413                 
13414             }, this);
13415         }
13416         */
13417         
13418         this.keyNav = new Roo.KeyNav(this.inputEl(), {
13419             "up" : function(e){
13420                 this.inKeyMode = true;
13421                 this.selectPrev();
13422             },
13423
13424             "down" : function(e){
13425                 if(!this.isExpanded()){
13426                     this.onTriggerClick();
13427                 }else{
13428                     this.inKeyMode = true;
13429                     this.selectNext();
13430                 }
13431             },
13432
13433             "enter" : function(e){
13434 //                this.onViewClick();
13435                 //return true;
13436                 this.collapse();
13437                 
13438                 if(this.fireEvent("specialkey", this, e)){
13439                     this.onViewClick(false);
13440                 }
13441                 
13442                 return true;
13443             },
13444
13445             "esc" : function(e){
13446                 this.collapse();
13447             },
13448
13449             "tab" : function(e){
13450                 this.collapse();
13451                 
13452                 if(this.fireEvent("specialkey", this, e)){
13453                     this.onViewClick(false);
13454                 }
13455                 
13456                 return true;
13457             },
13458
13459             scope : this,
13460
13461             doRelay : function(foo, bar, hname){
13462                 if(hname == 'down' || this.scope.isExpanded()){
13463                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13464                 }
13465                 return true;
13466             },
13467
13468             forceKeyDown: true
13469         });
13470         
13471         
13472         this.queryDelay = Math.max(this.queryDelay || 10,
13473                 this.mode == 'local' ? 10 : 250);
13474         
13475         
13476         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13477         
13478         if(this.typeAhead){
13479             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13480         }
13481         if(this.editable !== false){
13482             this.inputEl().on("keyup", this.onKeyUp, this);
13483         }
13484         if(this.forceSelection){
13485             this.inputEl().on('blur', this.doForce, this);
13486         }
13487         
13488         if(this.multiple){
13489             this.choices = this.el.select('ul.roo-select2-choices', true).first();
13490             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13491         }
13492     },
13493     
13494     initTickableEvents: function()
13495     {   
13496         this.createList();
13497         
13498         if(this.hiddenName){
13499             
13500             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13501             
13502             this.hiddenField.dom.value =
13503                 this.hiddenValue !== undefined ? this.hiddenValue :
13504                 this.value !== undefined ? this.value : '';
13505
13506             // prevent input submission
13507             this.el.dom.removeAttribute('name');
13508             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13509              
13510              
13511         }
13512         
13513 //        this.list = this.el.select('ul.dropdown-menu',true).first();
13514         
13515         this.choices = this.el.select('ul.roo-select2-choices', true).first();
13516         this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13517         if(this.triggerList){
13518             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13519         }
13520          
13521         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13522         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13523         
13524         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13525         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13526         
13527         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13528         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13529         
13530         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13531         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13532         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13533         
13534         this.okBtn.hide();
13535         this.cancelBtn.hide();
13536         
13537         var _this = this;
13538         
13539         (function(){
13540             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13541             _this.list.setWidth(lw);
13542         }).defer(100);
13543         
13544         this.list.on('mouseover', this.onViewOver, this);
13545         this.list.on('mousemove', this.onViewMove, this);
13546         
13547         this.list.on('scroll', this.onViewScroll, this);
13548         
13549         if(!this.tpl){
13550             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>';
13551         }
13552
13553         this.view = new Roo.View(this.list, this.tpl, {
13554             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13555         });
13556         
13557         //this.view.wrapEl.setDisplayed(false);
13558         this.view.on('click', this.onViewClick, this);
13559         
13560         
13561         
13562         this.store.on('beforeload', this.onBeforeLoad, this);
13563         this.store.on('load', this.onLoad, this);
13564         this.store.on('loadexception', this.onLoadException, this);
13565         
13566         if(this.editable){
13567             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13568                 "up" : function(e){
13569                     this.inKeyMode = true;
13570                     this.selectPrev();
13571                 },
13572
13573                 "down" : function(e){
13574                     this.inKeyMode = true;
13575                     this.selectNext();
13576                 },
13577
13578                 "enter" : function(e){
13579                     if(this.fireEvent("specialkey", this, e)){
13580                         this.onViewClick(false);
13581                     }
13582                     
13583                     return true;
13584                 },
13585
13586                 "esc" : function(e){
13587                     this.onTickableFooterButtonClick(e, false, false);
13588                 },
13589
13590                 "tab" : function(e){
13591                     this.fireEvent("specialkey", this, e);
13592                     
13593                     this.onTickableFooterButtonClick(e, false, false);
13594                     
13595                     return true;
13596                 },
13597
13598                 scope : this,
13599
13600                 doRelay : function(e, fn, key){
13601                     if(this.scope.isExpanded()){
13602                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13603                     }
13604                     return true;
13605                 },
13606
13607                 forceKeyDown: true
13608             });
13609         }
13610         
13611         this.queryDelay = Math.max(this.queryDelay || 10,
13612                 this.mode == 'local' ? 10 : 250);
13613         
13614         
13615         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13616         
13617         if(this.typeAhead){
13618             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13619         }
13620         
13621         if(this.editable !== false){
13622             this.tickableInputEl().on("keyup", this.onKeyUp, this);
13623         }
13624         
13625         this.indicator = this.indicatorEl();
13626         
13627         if(this.indicator){
13628             this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13629             this.indicator.hide();
13630         }
13631         
13632     },
13633
13634     onDestroy : function(){
13635         if(this.view){
13636             this.view.setStore(null);
13637             this.view.el.removeAllListeners();
13638             this.view.el.remove();
13639             this.view.purgeListeners();
13640         }
13641         if(this.list){
13642             this.list.dom.innerHTML  = '';
13643         }
13644         
13645         if(this.store){
13646             this.store.un('beforeload', this.onBeforeLoad, this);
13647             this.store.un('load', this.onLoad, this);
13648             this.store.un('loadexception', this.onLoadException, this);
13649         }
13650         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13651     },
13652
13653     // private
13654     fireKey : function(e){
13655         if(e.isNavKeyPress() && !this.list.isVisible()){
13656             this.fireEvent("specialkey", this, e);
13657         }
13658     },
13659
13660     // private
13661     onResize: function(w, h){
13662 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13663 //        
13664 //        if(typeof w != 'number'){
13665 //            // we do not handle it!?!?
13666 //            return;
13667 //        }
13668 //        var tw = this.trigger.getWidth();
13669 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
13670 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
13671 //        var x = w - tw;
13672 //        this.inputEl().setWidth( this.adjustWidth('input', x));
13673 //            
13674 //        //this.trigger.setStyle('left', x+'px');
13675 //        
13676 //        if(this.list && this.listWidth === undefined){
13677 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13678 //            this.list.setWidth(lw);
13679 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13680 //        }
13681         
13682     
13683         
13684     },
13685
13686     /**
13687      * Allow or prevent the user from directly editing the field text.  If false is passed,
13688      * the user will only be able to select from the items defined in the dropdown list.  This method
13689      * is the runtime equivalent of setting the 'editable' config option at config time.
13690      * @param {Boolean} value True to allow the user to directly edit the field text
13691      */
13692     setEditable : function(value){
13693         if(value == this.editable){
13694             return;
13695         }
13696         this.editable = value;
13697         if(!value){
13698             this.inputEl().dom.setAttribute('readOnly', true);
13699             this.inputEl().on('mousedown', this.onTriggerClick,  this);
13700             this.inputEl().addClass('x-combo-noedit');
13701         }else{
13702             this.inputEl().dom.setAttribute('readOnly', false);
13703             this.inputEl().un('mousedown', this.onTriggerClick,  this);
13704             this.inputEl().removeClass('x-combo-noedit');
13705         }
13706     },
13707
13708     // private
13709     
13710     onBeforeLoad : function(combo,opts){
13711         if(!this.hasFocus){
13712             return;
13713         }
13714          if (!opts.add) {
13715             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13716          }
13717         this.restrictHeight();
13718         this.selectedIndex = -1;
13719     },
13720
13721     // private
13722     onLoad : function(){
13723         
13724         this.hasQuery = false;
13725         
13726         if(!this.hasFocus){
13727             return;
13728         }
13729         
13730         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13731             this.loading.hide();
13732         }
13733         
13734         if(this.store.getCount() > 0){
13735             
13736             this.expand();
13737             this.restrictHeight();
13738             if(this.lastQuery == this.allQuery){
13739                 if(this.editable && !this.tickable){
13740                     this.inputEl().dom.select();
13741                 }
13742                 
13743                 if(
13744                     !this.selectByValue(this.value, true) &&
13745                     this.autoFocus && 
13746                     (
13747                         !this.store.lastOptions ||
13748                         typeof(this.store.lastOptions.add) == 'undefined' || 
13749                         this.store.lastOptions.add != true
13750                     )
13751                 ){
13752                     this.select(0, true);
13753                 }
13754             }else{
13755                 if(this.autoFocus){
13756                     this.selectNext();
13757                 }
13758                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13759                     this.taTask.delay(this.typeAheadDelay);
13760                 }
13761             }
13762         }else{
13763             this.onEmptyResults();
13764         }
13765         
13766         //this.el.focus();
13767     },
13768     // private
13769     onLoadException : function()
13770     {
13771         this.hasQuery = false;
13772         
13773         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13774             this.loading.hide();
13775         }
13776         
13777         if(this.tickable && this.editable){
13778             return;
13779         }
13780         
13781         this.collapse();
13782         // only causes errors at present
13783         //Roo.log(this.store.reader.jsonData);
13784         //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13785             // fixme
13786             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13787         //}
13788         
13789         
13790     },
13791     // private
13792     onTypeAhead : function(){
13793         if(this.store.getCount() > 0){
13794             var r = this.store.getAt(0);
13795             var newValue = r.data[this.displayField];
13796             var len = newValue.length;
13797             var selStart = this.getRawValue().length;
13798             
13799             if(selStart != len){
13800                 this.setRawValue(newValue);
13801                 this.selectText(selStart, newValue.length);
13802             }
13803         }
13804     },
13805
13806     // private
13807     onSelect : function(record, index){
13808         
13809         if(this.fireEvent('beforeselect', this, record, index) !== false){
13810         
13811             this.setFromData(index > -1 ? record.data : false);
13812             
13813             this.collapse();
13814             this.fireEvent('select', this, record, index);
13815         }
13816     },
13817
13818     /**
13819      * Returns the currently selected field value or empty string if no value is set.
13820      * @return {String} value The selected value
13821      */
13822     getValue : function()
13823     {
13824         if(Roo.isIOS && this.useNativeIOS){
13825             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13826         }
13827         
13828         if(this.multiple){
13829             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13830         }
13831         
13832         if(this.valueField){
13833             return typeof this.value != 'undefined' ? this.value : '';
13834         }else{
13835             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13836         }
13837     },
13838     
13839     getRawValue : function()
13840     {
13841         if(Roo.isIOS && this.useNativeIOS){
13842             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13843         }
13844         
13845         var v = this.inputEl().getValue();
13846         
13847         return v;
13848     },
13849
13850     /**
13851      * Clears any text/value currently set in the field
13852      */
13853     clearValue : function(){
13854         
13855         if(this.hiddenField){
13856             this.hiddenField.dom.value = '';
13857         }
13858         this.value = '';
13859         this.setRawValue('');
13860         this.lastSelectionText = '';
13861         this.lastData = false;
13862         
13863         var close = this.closeTriggerEl();
13864         
13865         if(close){
13866             close.hide();
13867         }
13868         
13869         this.validate();
13870         
13871     },
13872
13873     /**
13874      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
13875      * will be displayed in the field.  If the value does not match the data value of an existing item,
13876      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13877      * Otherwise the field will be blank (although the value will still be set).
13878      * @param {String} value The value to match
13879      */
13880     setValue : function(v)
13881     {
13882         if(Roo.isIOS && this.useNativeIOS){
13883             this.setIOSValue(v);
13884             return;
13885         }
13886         
13887         if(this.multiple){
13888             this.syncValue();
13889             return;
13890         }
13891         
13892         var text = v;
13893         if(this.valueField){
13894             var r = this.findRecord(this.valueField, v);
13895             if(r){
13896                 text = r.data[this.displayField];
13897             }else if(this.valueNotFoundText !== undefined){
13898                 text = this.valueNotFoundText;
13899             }
13900         }
13901         this.lastSelectionText = text;
13902         if(this.hiddenField){
13903             this.hiddenField.dom.value = v;
13904         }
13905         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13906         this.value = v;
13907         
13908         var close = this.closeTriggerEl();
13909         
13910         if(close){
13911             (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13912         }
13913         
13914         this.validate();
13915     },
13916     /**
13917      * @property {Object} the last set data for the element
13918      */
13919     
13920     lastData : false,
13921     /**
13922      * Sets the value of the field based on a object which is related to the record format for the store.
13923      * @param {Object} value the value to set as. or false on reset?
13924      */
13925     setFromData : function(o){
13926         
13927         if(this.multiple){
13928             this.addItem(o);
13929             return;
13930         }
13931             
13932         var dv = ''; // display value
13933         var vv = ''; // value value..
13934         this.lastData = o;
13935         if (this.displayField) {
13936             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13937         } else {
13938             // this is an error condition!!!
13939             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
13940         }
13941         
13942         if(this.valueField){
13943             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13944         }
13945         
13946         var close = this.closeTriggerEl();
13947         
13948         if(close){
13949             if(dv.length || vv * 1 > 0){
13950                 close.show() ;
13951                 this.blockFocus=true;
13952             } else {
13953                 close.hide();
13954             }             
13955         }
13956         
13957         if(this.hiddenField){
13958             this.hiddenField.dom.value = vv;
13959             
13960             this.lastSelectionText = dv;
13961             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13962             this.value = vv;
13963             return;
13964         }
13965         // no hidden field.. - we store the value in 'value', but still display
13966         // display field!!!!
13967         this.lastSelectionText = dv;
13968         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13969         this.value = vv;
13970         
13971         
13972         
13973     },
13974     // private
13975     reset : function(){
13976         // overridden so that last data is reset..
13977         
13978         if(this.multiple){
13979             this.clearItem();
13980             return;
13981         }
13982         
13983         this.setValue(this.originalValue);
13984         //this.clearInvalid();
13985         this.lastData = false;
13986         if (this.view) {
13987             this.view.clearSelections();
13988         }
13989         
13990         this.validate();
13991     },
13992     // private
13993     findRecord : function(prop, value){
13994         var record;
13995         if(this.store.getCount() > 0){
13996             this.store.each(function(r){
13997                 if(r.data[prop] == value){
13998                     record = r;
13999                     return false;
14000                 }
14001                 return true;
14002             });
14003         }
14004         return record;
14005     },
14006     
14007     getName: function()
14008     {
14009         // returns hidden if it's set..
14010         if (!this.rendered) {return ''};
14011         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
14012         
14013     },
14014     // private
14015     onViewMove : function(e, t){
14016         this.inKeyMode = false;
14017     },
14018
14019     // private
14020     onViewOver : function(e, t){
14021         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14022             return;
14023         }
14024         var item = this.view.findItemFromChild(t);
14025         
14026         if(item){
14027             var index = this.view.indexOf(item);
14028             this.select(index, false);
14029         }
14030     },
14031
14032     // private
14033     onViewClick : function(view, doFocus, el, e)
14034     {
14035         var index = this.view.getSelectedIndexes()[0];
14036         
14037         var r = this.store.getAt(index);
14038         
14039         if(this.tickable){
14040             
14041             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14042                 return;
14043             }
14044             
14045             var rm = false;
14046             var _this = this;
14047             
14048             Roo.each(this.tickItems, function(v,k){
14049                 
14050                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14051                     Roo.log(v);
14052                     _this.tickItems.splice(k, 1);
14053                     
14054                     if(typeof(e) == 'undefined' && view == false){
14055                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14056                     }
14057                     
14058                     rm = true;
14059                     return;
14060                 }
14061             });
14062             
14063             if(rm){
14064                 return;
14065             }
14066             
14067             if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14068                 this.tickItems.push(r.data);
14069             }
14070             
14071             if(typeof(e) == 'undefined' && view == false){
14072                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14073             }
14074                     
14075             return;
14076         }
14077         
14078         if(r){
14079             this.onSelect(r, index);
14080         }
14081         if(doFocus !== false && !this.blockFocus){
14082             this.inputEl().focus();
14083         }
14084     },
14085
14086     // private
14087     restrictHeight : function(){
14088         //this.innerList.dom.style.height = '';
14089         //var inner = this.innerList.dom;
14090         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14091         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14092         //this.list.beginUpdate();
14093         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14094         this.list.alignTo(this.inputEl(), this.listAlign);
14095         this.list.alignTo(this.inputEl(), this.listAlign);
14096         //this.list.endUpdate();
14097     },
14098
14099     // private
14100     onEmptyResults : function(){
14101         
14102         if(this.tickable && this.editable){
14103             this.hasFocus = false;
14104             this.restrictHeight();
14105             return;
14106         }
14107         
14108         this.collapse();
14109     },
14110
14111     /**
14112      * Returns true if the dropdown list is expanded, else false.
14113      */
14114     isExpanded : function(){
14115         return this.list.isVisible();
14116     },
14117
14118     /**
14119      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14120      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14121      * @param {String} value The data value of the item to select
14122      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14123      * selected item if it is not currently in view (defaults to true)
14124      * @return {Boolean} True if the value matched an item in the list, else false
14125      */
14126     selectByValue : function(v, scrollIntoView){
14127         if(v !== undefined && v !== null){
14128             var r = this.findRecord(this.valueField || this.displayField, v);
14129             if(r){
14130                 this.select(this.store.indexOf(r), scrollIntoView);
14131                 return true;
14132             }
14133         }
14134         return false;
14135     },
14136
14137     /**
14138      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14139      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14140      * @param {Number} index The zero-based index of the list item to select
14141      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14142      * selected item if it is not currently in view (defaults to true)
14143      */
14144     select : function(index, scrollIntoView){
14145         this.selectedIndex = index;
14146         this.view.select(index);
14147         if(scrollIntoView !== false){
14148             var el = this.view.getNode(index);
14149             /*
14150              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14151              */
14152             if(el){
14153                 this.list.scrollChildIntoView(el, false);
14154             }
14155         }
14156     },
14157
14158     // private
14159     selectNext : function(){
14160         var ct = this.store.getCount();
14161         if(ct > 0){
14162             if(this.selectedIndex == -1){
14163                 this.select(0);
14164             }else if(this.selectedIndex < ct-1){
14165                 this.select(this.selectedIndex+1);
14166             }
14167         }
14168     },
14169
14170     // private
14171     selectPrev : function(){
14172         var ct = this.store.getCount();
14173         if(ct > 0){
14174             if(this.selectedIndex == -1){
14175                 this.select(0);
14176             }else if(this.selectedIndex != 0){
14177                 this.select(this.selectedIndex-1);
14178             }
14179         }
14180     },
14181
14182     // private
14183     onKeyUp : function(e){
14184         if(this.editable !== false && !e.isSpecialKey()){
14185             this.lastKey = e.getKey();
14186             this.dqTask.delay(this.queryDelay);
14187         }
14188     },
14189
14190     // private
14191     validateBlur : function(){
14192         return !this.list || !this.list.isVisible();   
14193     },
14194
14195     // private
14196     initQuery : function(){
14197         
14198         var v = this.getRawValue();
14199         
14200         if(this.tickable && this.editable){
14201             v = this.tickableInputEl().getValue();
14202         }
14203         
14204         this.doQuery(v);
14205     },
14206
14207     // private
14208     doForce : function(){
14209         if(this.inputEl().dom.value.length > 0){
14210             this.inputEl().dom.value =
14211                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14212              
14213         }
14214     },
14215
14216     /**
14217      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
14218      * query allowing the query action to be canceled if needed.
14219      * @param {String} query The SQL query to execute
14220      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14221      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
14222      * saved in the current store (defaults to false)
14223      */
14224     doQuery : function(q, forceAll){
14225         
14226         if(q === undefined || q === null){
14227             q = '';
14228         }
14229         var qe = {
14230             query: q,
14231             forceAll: forceAll,
14232             combo: this,
14233             cancel:false
14234         };
14235         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14236             return false;
14237         }
14238         q = qe.query;
14239         
14240         forceAll = qe.forceAll;
14241         if(forceAll === true || (q.length >= this.minChars)){
14242             
14243             this.hasQuery = true;
14244             
14245             if(this.lastQuery != q || this.alwaysQuery){
14246                 this.lastQuery = q;
14247                 if(this.mode == 'local'){
14248                     this.selectedIndex = -1;
14249                     if(forceAll){
14250                         this.store.clearFilter();
14251                     }else{
14252                         
14253                         if(this.specialFilter){
14254                             this.fireEvent('specialfilter', this);
14255                             this.onLoad();
14256                             return;
14257                         }
14258                         
14259                         this.store.filter(this.displayField, q);
14260                     }
14261                     
14262                     this.store.fireEvent("datachanged", this.store);
14263                     
14264                     this.onLoad();
14265                     
14266                     
14267                 }else{
14268                     
14269                     this.store.baseParams[this.queryParam] = q;
14270                     
14271                     var options = {params : this.getParams(q)};
14272                     
14273                     if(this.loadNext){
14274                         options.add = true;
14275                         options.params.start = this.page * this.pageSize;
14276                     }
14277                     
14278                     this.store.load(options);
14279                     
14280                     /*
14281                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
14282                      *  we should expand the list on onLoad
14283                      *  so command out it
14284                      */
14285 //                    this.expand();
14286                 }
14287             }else{
14288                 this.selectedIndex = -1;
14289                 this.onLoad();   
14290             }
14291         }
14292         
14293         this.loadNext = false;
14294     },
14295     
14296     // private
14297     getParams : function(q){
14298         var p = {};
14299         //p[this.queryParam] = q;
14300         
14301         if(this.pageSize){
14302             p.start = 0;
14303             p.limit = this.pageSize;
14304         }
14305         return p;
14306     },
14307
14308     /**
14309      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14310      */
14311     collapse : function(){
14312         if(!this.isExpanded()){
14313             return;
14314         }
14315         
14316         this.list.hide();
14317         
14318         this.hasFocus = false;
14319         
14320         if(this.tickable){
14321             this.okBtn.hide();
14322             this.cancelBtn.hide();
14323             this.trigger.show();
14324             
14325             if(this.editable){
14326                 this.tickableInputEl().dom.value = '';
14327                 this.tickableInputEl().blur();
14328             }
14329             
14330         }
14331         
14332         Roo.get(document).un('mousedown', this.collapseIf, this);
14333         Roo.get(document).un('mousewheel', this.collapseIf, this);
14334         if (!this.editable) {
14335             Roo.get(document).un('keydown', this.listKeyPress, this);
14336         }
14337         this.fireEvent('collapse', this);
14338         
14339         this.validate();
14340     },
14341
14342     // private
14343     collapseIf : function(e){
14344         var in_combo  = e.within(this.el);
14345         var in_list =  e.within(this.list);
14346         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14347         
14348         if (in_combo || in_list || is_list) {
14349             //e.stopPropagation();
14350             return;
14351         }
14352         
14353         if(this.tickable){
14354             this.onTickableFooterButtonClick(e, false, false);
14355         }
14356
14357         this.collapse();
14358         
14359     },
14360
14361     /**
14362      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14363      */
14364     expand : function(){
14365        
14366         if(this.isExpanded() || !this.hasFocus){
14367             return;
14368         }
14369         
14370         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14371         this.list.setWidth(lw);
14372         
14373         Roo.log('expand');
14374         
14375         this.list.show();
14376         
14377         this.restrictHeight();
14378         
14379         if(this.tickable){
14380             
14381             this.tickItems = Roo.apply([], this.item);
14382             
14383             this.okBtn.show();
14384             this.cancelBtn.show();
14385             this.trigger.hide();
14386             
14387             if(this.editable){
14388                 this.tickableInputEl().focus();
14389             }
14390             
14391         }
14392         
14393         Roo.get(document).on('mousedown', this.collapseIf, this);
14394         Roo.get(document).on('mousewheel', this.collapseIf, this);
14395         if (!this.editable) {
14396             Roo.get(document).on('keydown', this.listKeyPress, this);
14397         }
14398         
14399         this.fireEvent('expand', this);
14400     },
14401
14402     // private
14403     // Implements the default empty TriggerField.onTriggerClick function
14404     onTriggerClick : function(e)
14405     {
14406         Roo.log('trigger click');
14407         
14408         if(this.disabled || !this.triggerList){
14409             return;
14410         }
14411         
14412         this.page = 0;
14413         this.loadNext = false;
14414         
14415         if(this.isExpanded()){
14416             this.collapse();
14417             if (!this.blockFocus) {
14418                 this.inputEl().focus();
14419             }
14420             
14421         }else {
14422             this.hasFocus = true;
14423             if(this.triggerAction == 'all') {
14424                 this.doQuery(this.allQuery, true);
14425             } else {
14426                 this.doQuery(this.getRawValue());
14427             }
14428             if (!this.blockFocus) {
14429                 this.inputEl().focus();
14430             }
14431         }
14432     },
14433     
14434     onTickableTriggerClick : function(e)
14435     {
14436         if(this.disabled){
14437             return;
14438         }
14439         
14440         this.page = 0;
14441         this.loadNext = false;
14442         this.hasFocus = true;
14443         
14444         if(this.triggerAction == 'all') {
14445             this.doQuery(this.allQuery, true);
14446         } else {
14447             this.doQuery(this.getRawValue());
14448         }
14449     },
14450     
14451     onSearchFieldClick : function(e)
14452     {
14453         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14454             this.onTickableFooterButtonClick(e, false, false);
14455             return;
14456         }
14457         
14458         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14459             return;
14460         }
14461         
14462         this.page = 0;
14463         this.loadNext = false;
14464         this.hasFocus = true;
14465         
14466         if(this.triggerAction == 'all') {
14467             this.doQuery(this.allQuery, true);
14468         } else {
14469             this.doQuery(this.getRawValue());
14470         }
14471     },
14472     
14473     listKeyPress : function(e)
14474     {
14475         //Roo.log('listkeypress');
14476         // scroll to first matching element based on key pres..
14477         if (e.isSpecialKey()) {
14478             return false;
14479         }
14480         var k = String.fromCharCode(e.getKey()).toUpperCase();
14481         //Roo.log(k);
14482         var match  = false;
14483         var csel = this.view.getSelectedNodes();
14484         var cselitem = false;
14485         if (csel.length) {
14486             var ix = this.view.indexOf(csel[0]);
14487             cselitem  = this.store.getAt(ix);
14488             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14489                 cselitem = false;
14490             }
14491             
14492         }
14493         
14494         this.store.each(function(v) { 
14495             if (cselitem) {
14496                 // start at existing selection.
14497                 if (cselitem.id == v.id) {
14498                     cselitem = false;
14499                 }
14500                 return true;
14501             }
14502                 
14503             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14504                 match = this.store.indexOf(v);
14505                 return false;
14506             }
14507             return true;
14508         }, this);
14509         
14510         if (match === false) {
14511             return true; // no more action?
14512         }
14513         // scroll to?
14514         this.view.select(match);
14515         var sn = Roo.get(this.view.getSelectedNodes()[0]);
14516         sn.scrollIntoView(sn.dom.parentNode, false);
14517     },
14518     
14519     onViewScroll : function(e, t){
14520         
14521         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){
14522             return;
14523         }
14524         
14525         this.hasQuery = true;
14526         
14527         this.loading = this.list.select('.loading', true).first();
14528         
14529         if(this.loading === null){
14530             this.list.createChild({
14531                 tag: 'div',
14532                 cls: 'loading roo-select2-more-results roo-select2-active',
14533                 html: 'Loading more results...'
14534             });
14535             
14536             this.loading = this.list.select('.loading', true).first();
14537             
14538             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14539             
14540             this.loading.hide();
14541         }
14542         
14543         this.loading.show();
14544         
14545         var _combo = this;
14546         
14547         this.page++;
14548         this.loadNext = true;
14549         
14550         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14551         
14552         return;
14553     },
14554     
14555     addItem : function(o)
14556     {   
14557         var dv = ''; // display value
14558         
14559         if (this.displayField) {
14560             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14561         } else {
14562             // this is an error condition!!!
14563             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14564         }
14565         
14566         if(!dv.length){
14567             return;
14568         }
14569         
14570         var choice = this.choices.createChild({
14571             tag: 'li',
14572             cls: 'roo-select2-search-choice',
14573             cn: [
14574                 {
14575                     tag: 'div',
14576                     html: dv
14577                 },
14578                 {
14579                     tag: 'a',
14580                     href: '#',
14581                     cls: 'roo-select2-search-choice-close fa fa-times',
14582                     tabindex: '-1'
14583                 }
14584             ]
14585             
14586         }, this.searchField);
14587         
14588         var close = choice.select('a.roo-select2-search-choice-close', true).first();
14589         
14590         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14591         
14592         this.item.push(o);
14593         
14594         this.lastData = o;
14595         
14596         this.syncValue();
14597         
14598         this.inputEl().dom.value = '';
14599         
14600         this.validate();
14601     },
14602     
14603     onRemoveItem : function(e, _self, o)
14604     {
14605         e.preventDefault();
14606         
14607         this.lastItem = Roo.apply([], this.item);
14608         
14609         var index = this.item.indexOf(o.data) * 1;
14610         
14611         if( index < 0){
14612             Roo.log('not this item?!');
14613             return;
14614         }
14615         
14616         this.item.splice(index, 1);
14617         o.item.remove();
14618         
14619         this.syncValue();
14620         
14621         this.fireEvent('remove', this, e);
14622         
14623         this.validate();
14624         
14625     },
14626     
14627     syncValue : function()
14628     {
14629         if(!this.item.length){
14630             this.clearValue();
14631             return;
14632         }
14633             
14634         var value = [];
14635         var _this = this;
14636         Roo.each(this.item, function(i){
14637             if(_this.valueField){
14638                 value.push(i[_this.valueField]);
14639                 return;
14640             }
14641
14642             value.push(i);
14643         });
14644
14645         this.value = value.join(',');
14646
14647         if(this.hiddenField){
14648             this.hiddenField.dom.value = this.value;
14649         }
14650         
14651         this.store.fireEvent("datachanged", this.store);
14652         
14653         this.validate();
14654     },
14655     
14656     clearItem : function()
14657     {
14658         if(!this.multiple){
14659             return;
14660         }
14661         
14662         this.item = [];
14663         
14664         Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14665            c.remove();
14666         });
14667         
14668         this.syncValue();
14669         
14670         this.validate();
14671         
14672         if(this.tickable && !Roo.isTouch){
14673             this.view.refresh();
14674         }
14675     },
14676     
14677     inputEl: function ()
14678     {
14679         if(Roo.isIOS && this.useNativeIOS){
14680             return this.el.select('select.roo-ios-select', true).first();
14681         }
14682         
14683         if(Roo.isTouch && this.mobileTouchView){
14684             return this.el.select('input.form-control',true).first();
14685         }
14686         
14687         if(this.tickable){
14688             return this.searchField;
14689         }
14690         
14691         return this.el.select('input.form-control',true).first();
14692     },
14693     
14694     onTickableFooterButtonClick : function(e, btn, el)
14695     {
14696         e.preventDefault();
14697         
14698         this.lastItem = Roo.apply([], this.item);
14699         
14700         if(btn && btn.name == 'cancel'){
14701             this.tickItems = Roo.apply([], this.item);
14702             this.collapse();
14703             return;
14704         }
14705         
14706         this.clearItem();
14707         
14708         var _this = this;
14709         
14710         Roo.each(this.tickItems, function(o){
14711             _this.addItem(o);
14712         });
14713         
14714         this.collapse();
14715         
14716     },
14717     
14718     validate : function()
14719     {
14720         if(this.getVisibilityEl().hasClass('hidden')){
14721             return true;
14722         }
14723         
14724         var v = this.getRawValue();
14725         
14726         if(this.multiple){
14727             v = this.getValue();
14728         }
14729         
14730         if(this.disabled || this.allowBlank || v.length){
14731             this.markValid();
14732             return true;
14733         }
14734         
14735         this.markInvalid();
14736         return false;
14737     },
14738     
14739     tickableInputEl : function()
14740     {
14741         if(!this.tickable || !this.editable){
14742             return this.inputEl();
14743         }
14744         
14745         return this.inputEl().select('.roo-select2-search-field-input', true).first();
14746     },
14747     
14748     
14749     getAutoCreateTouchView : function()
14750     {
14751         var id = Roo.id();
14752         
14753         var cfg = {
14754             cls: 'form-group' //input-group
14755         };
14756         
14757         var input =  {
14758             tag: 'input',
14759             id : id,
14760             type : this.inputType,
14761             cls : 'form-control x-combo-noedit',
14762             autocomplete: 'new-password',
14763             placeholder : this.placeholder || '',
14764             readonly : true
14765         };
14766         
14767         if (this.name) {
14768             input.name = this.name;
14769         }
14770         
14771         if (this.size) {
14772             input.cls += ' input-' + this.size;
14773         }
14774         
14775         if (this.disabled) {
14776             input.disabled = true;
14777         }
14778         
14779         var inputblock = {
14780             cls : '',
14781             cn : [
14782                 input
14783             ]
14784         };
14785         
14786         if(this.before){
14787             inputblock.cls += ' input-group';
14788             
14789             inputblock.cn.unshift({
14790                 tag :'span',
14791                 cls : 'input-group-addon',
14792                 html : this.before
14793             });
14794         }
14795         
14796         if(this.removable && !this.multiple){
14797             inputblock.cls += ' roo-removable';
14798             
14799             inputblock.cn.push({
14800                 tag: 'button',
14801                 html : 'x',
14802                 cls : 'roo-combo-removable-btn close'
14803             });
14804         }
14805
14806         if(this.hasFeedback && !this.allowBlank){
14807             
14808             inputblock.cls += ' has-feedback';
14809             
14810             inputblock.cn.push({
14811                 tag: 'span',
14812                 cls: 'glyphicon form-control-feedback'
14813             });
14814             
14815         }
14816         
14817         if (this.after) {
14818             
14819             inputblock.cls += (this.before) ? '' : ' input-group';
14820             
14821             inputblock.cn.push({
14822                 tag :'span',
14823                 cls : 'input-group-addon',
14824                 html : this.after
14825             });
14826         }
14827
14828         var box = {
14829             tag: 'div',
14830             cn: [
14831                 {
14832                     tag: 'input',
14833                     type : 'hidden',
14834                     cls: 'form-hidden-field'
14835                 },
14836                 inputblock
14837             ]
14838             
14839         };
14840         
14841         if(this.multiple){
14842             box = {
14843                 tag: 'div',
14844                 cn: [
14845                     {
14846                         tag: 'input',
14847                         type : 'hidden',
14848                         cls: 'form-hidden-field'
14849                     },
14850                     {
14851                         tag: 'ul',
14852                         cls: 'roo-select2-choices',
14853                         cn:[
14854                             {
14855                                 tag: 'li',
14856                                 cls: 'roo-select2-search-field',
14857                                 cn: [
14858
14859                                     inputblock
14860                                 ]
14861                             }
14862                         ]
14863                     }
14864                 ]
14865             }
14866         };
14867         
14868         var combobox = {
14869             cls: 'roo-select2-container input-group roo-touchview-combobox ',
14870             cn: [
14871                 box
14872             ]
14873         };
14874         
14875         if(!this.multiple && this.showToggleBtn){
14876             
14877             var caret = {
14878                         tag: 'span',
14879                         cls: 'caret'
14880             };
14881             
14882             if (this.caret != false) {
14883                 caret = {
14884                      tag: 'i',
14885                      cls: 'fa fa-' + this.caret
14886                 };
14887                 
14888             }
14889             
14890             combobox.cn.push({
14891                 tag :'span',
14892                 cls : 'input-group-addon btn dropdown-toggle',
14893                 cn : [
14894                     caret,
14895                     {
14896                         tag: 'span',
14897                         cls: 'combobox-clear',
14898                         cn  : [
14899                             {
14900                                 tag : 'i',
14901                                 cls: 'icon-remove'
14902                             }
14903                         ]
14904                     }
14905                 ]
14906
14907             })
14908         }
14909         
14910         if(this.multiple){
14911             combobox.cls += ' roo-select2-container-multi';
14912         }
14913         
14914         var align = this.labelAlign || this.parentLabelAlign();
14915         
14916         if (align ==='left' && this.fieldLabel.length) {
14917
14918             cfg.cn = [
14919                 {
14920                    tag : 'i',
14921                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14922                    tooltip : 'This field is required'
14923                 },
14924                 {
14925                     tag: 'label',
14926                     cls : 'control-label',
14927                     html : this.fieldLabel
14928
14929                 },
14930                 {
14931                     cls : '', 
14932                     cn: [
14933                         combobox
14934                     ]
14935                 }
14936             ];
14937             
14938             var labelCfg = cfg.cn[1];
14939             var contentCfg = cfg.cn[2];
14940             
14941
14942             if(this.indicatorpos == 'right'){
14943                 cfg.cn = [
14944                     {
14945                         tag: 'label',
14946                         'for' :  id,
14947                         cls : 'control-label',
14948                         cn : [
14949                             {
14950                                 tag : 'span',
14951                                 html : this.fieldLabel
14952                             },
14953                             {
14954                                 tag : 'i',
14955                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14956                                 tooltip : 'This field is required'
14957                             }
14958                         ]
14959                     },
14960                     {
14961                         cls : "",
14962                         cn: [
14963                             combobox
14964                         ]
14965                     }
14966
14967                 ];
14968                 
14969                 labelCfg = cfg.cn[0];
14970                 contentCfg = cfg.cn[1];
14971             }
14972             
14973            
14974             
14975             if(this.labelWidth > 12){
14976                 labelCfg.style = "width: " + this.labelWidth + 'px';
14977             }
14978             
14979             if(this.labelWidth < 13 && this.labelmd == 0){
14980                 this.labelmd = this.labelWidth;
14981             }
14982             
14983             if(this.labellg > 0){
14984                 labelCfg.cls += ' col-lg-' + this.labellg;
14985                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14986             }
14987             
14988             if(this.labelmd > 0){
14989                 labelCfg.cls += ' col-md-' + this.labelmd;
14990                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14991             }
14992             
14993             if(this.labelsm > 0){
14994                 labelCfg.cls += ' col-sm-' + this.labelsm;
14995                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14996             }
14997             
14998             if(this.labelxs > 0){
14999                 labelCfg.cls += ' col-xs-' + this.labelxs;
15000                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15001             }
15002                 
15003                 
15004         } else if ( this.fieldLabel.length) {
15005             cfg.cn = [
15006                 {
15007                    tag : 'i',
15008                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15009                    tooltip : 'This field is required'
15010                 },
15011                 {
15012                     tag: 'label',
15013                     cls : 'control-label',
15014                     html : this.fieldLabel
15015
15016                 },
15017                 {
15018                     cls : '', 
15019                     cn: [
15020                         combobox
15021                     ]
15022                 }
15023             ];
15024             
15025             if(this.indicatorpos == 'right'){
15026                 cfg.cn = [
15027                     {
15028                         tag: 'label',
15029                         cls : 'control-label',
15030                         html : this.fieldLabel,
15031                         cn : [
15032                             {
15033                                tag : 'i',
15034                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15035                                tooltip : 'This field is required'
15036                             }
15037                         ]
15038                     },
15039                     {
15040                         cls : '', 
15041                         cn: [
15042                             combobox
15043                         ]
15044                     }
15045                 ];
15046             }
15047         } else {
15048             cfg.cn = combobox;    
15049         }
15050         
15051         
15052         var settings = this;
15053         
15054         ['xs','sm','md','lg'].map(function(size){
15055             if (settings[size]) {
15056                 cfg.cls += ' col-' + size + '-' + settings[size];
15057             }
15058         });
15059         
15060         return cfg;
15061     },
15062     
15063     initTouchView : function()
15064     {
15065         this.renderTouchView();
15066         
15067         this.touchViewEl.on('scroll', function(){
15068             this.el.dom.scrollTop = 0;
15069         }, this);
15070         
15071         this.originalValue = this.getValue();
15072         
15073         this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15074         
15075         this.inputEl().on("click", this.showTouchView, this);
15076         if (this.triggerEl) {
15077             this.triggerEl.on("click", this.showTouchView, this);
15078         }
15079         
15080         
15081         this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15082         this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15083         
15084         this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15085         
15086         this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15087         this.store.on('load', this.onTouchViewLoad, this);
15088         this.store.on('loadexception', this.onTouchViewLoadException, this);
15089         
15090         if(this.hiddenName){
15091             
15092             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15093             
15094             this.hiddenField.dom.value =
15095                 this.hiddenValue !== undefined ? this.hiddenValue :
15096                 this.value !== undefined ? this.value : '';
15097         
15098             this.el.dom.removeAttribute('name');
15099             this.hiddenField.dom.setAttribute('name', this.hiddenName);
15100         }
15101         
15102         if(this.multiple){
15103             this.choices = this.el.select('ul.roo-select2-choices', true).first();
15104             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15105         }
15106         
15107         if(this.removable && !this.multiple){
15108             var close = this.closeTriggerEl();
15109             if(close){
15110                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15111                 close.on('click', this.removeBtnClick, this, close);
15112             }
15113         }
15114         /*
15115          * fix the bug in Safari iOS8
15116          */
15117         this.inputEl().on("focus", function(e){
15118             document.activeElement.blur();
15119         }, this);
15120         
15121         return;
15122         
15123         
15124     },
15125     
15126     renderTouchView : function()
15127     {
15128         this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15129         this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15130         
15131         this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15132         this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15133         
15134         this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15135         this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15136         this.touchViewBodyEl.setStyle('overflow', 'auto');
15137         
15138         this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15139         this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15140         
15141         this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15142         this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15143         
15144     },
15145     
15146     showTouchView : function()
15147     {
15148         if(this.disabled){
15149             return;
15150         }
15151         
15152         this.touchViewHeaderEl.hide();
15153
15154         if(this.modalTitle.length){
15155             this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15156             this.touchViewHeaderEl.show();
15157         }
15158
15159         this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15160         this.touchViewEl.show();
15161
15162         this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15163         
15164         //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15165         //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15166
15167         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15168
15169         if(this.modalTitle.length){
15170             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15171         }
15172         
15173         this.touchViewBodyEl.setHeight(bodyHeight);
15174
15175         if(this.animate){
15176             var _this = this;
15177             (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15178         }else{
15179             this.touchViewEl.addClass('in');
15180         }
15181
15182         this.doTouchViewQuery();
15183         
15184     },
15185     
15186     hideTouchView : function()
15187     {
15188         this.touchViewEl.removeClass('in');
15189
15190         if(this.animate){
15191             var _this = this;
15192             (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15193         }else{
15194             this.touchViewEl.setStyle('display', 'none');
15195         }
15196         
15197     },
15198     
15199     setTouchViewValue : function()
15200     {
15201         if(this.multiple){
15202             this.clearItem();
15203         
15204             var _this = this;
15205
15206             Roo.each(this.tickItems, function(o){
15207                 this.addItem(o);
15208             }, this);
15209         }
15210         
15211         this.hideTouchView();
15212     },
15213     
15214     doTouchViewQuery : function()
15215     {
15216         var qe = {
15217             query: '',
15218             forceAll: true,
15219             combo: this,
15220             cancel:false
15221         };
15222         
15223         if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15224             return false;
15225         }
15226         
15227         if(!this.alwaysQuery || this.mode == 'local'){
15228             this.onTouchViewLoad();
15229             return;
15230         }
15231         
15232         this.store.load();
15233     },
15234     
15235     onTouchViewBeforeLoad : function(combo,opts)
15236     {
15237         return;
15238     },
15239
15240     // private
15241     onTouchViewLoad : function()
15242     {
15243         if(this.store.getCount() < 1){
15244             this.onTouchViewEmptyResults();
15245             return;
15246         }
15247         
15248         this.clearTouchView();
15249         
15250         var rawValue = this.getRawValue();
15251         
15252         var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15253         
15254         this.tickItems = [];
15255         
15256         this.store.data.each(function(d, rowIndex){
15257             var row = this.touchViewListGroup.createChild(template);
15258             
15259             if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15260                 row.addClass(d.data.cls);
15261             }
15262             
15263             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15264                 var cfg = {
15265                     data : d.data,
15266                     html : d.data[this.displayField]
15267                 };
15268                 
15269                 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15270                     row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15271                 }
15272             }
15273             row.removeClass('selected');
15274             if(!this.multiple && this.valueField &&
15275                     typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15276             {
15277                 // radio buttons..
15278                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15279                 row.addClass('selected');
15280             }
15281             
15282             if(this.multiple && this.valueField &&
15283                     typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15284             {
15285                 
15286                 // checkboxes...
15287                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15288                 this.tickItems.push(d.data);
15289             }
15290             
15291             row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15292             
15293         }, this);
15294         
15295         var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15296         
15297         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15298
15299         if(this.modalTitle.length){
15300             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15301         }
15302
15303         var listHeight = this.touchViewListGroup.getHeight();
15304         
15305         var _this = this;
15306         
15307         if(firstChecked && listHeight > bodyHeight){
15308             (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15309         }
15310         
15311     },
15312     
15313     onTouchViewLoadException : function()
15314     {
15315         this.hideTouchView();
15316     },
15317     
15318     onTouchViewEmptyResults : function()
15319     {
15320         this.clearTouchView();
15321         
15322         this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15323         
15324         this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15325         
15326     },
15327     
15328     clearTouchView : function()
15329     {
15330         this.touchViewListGroup.dom.innerHTML = '';
15331     },
15332     
15333     onTouchViewClick : function(e, el, o)
15334     {
15335         e.preventDefault();
15336         
15337         var row = o.row;
15338         var rowIndex = o.rowIndex;
15339         
15340         var r = this.store.getAt(rowIndex);
15341         
15342         if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15343             
15344             if(!this.multiple){
15345                 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15346                     c.dom.removeAttribute('checked');
15347                 }, this);
15348
15349                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15350
15351                 this.setFromData(r.data);
15352
15353                 var close = this.closeTriggerEl();
15354
15355                 if(close){
15356                     close.show();
15357                 }
15358
15359                 this.hideTouchView();
15360
15361                 this.fireEvent('select', this, r, rowIndex);
15362
15363                 return;
15364             }
15365
15366             if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15367                 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15368                 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15369                 return;
15370             }
15371
15372             row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15373             this.addItem(r.data);
15374             this.tickItems.push(r.data);
15375         }
15376     },
15377     
15378     getAutoCreateNativeIOS : function()
15379     {
15380         var cfg = {
15381             cls: 'form-group' //input-group,
15382         };
15383         
15384         var combobox =  {
15385             tag: 'select',
15386             cls : 'roo-ios-select'
15387         };
15388         
15389         if (this.name) {
15390             combobox.name = this.name;
15391         }
15392         
15393         if (this.disabled) {
15394             combobox.disabled = true;
15395         }
15396         
15397         var settings = this;
15398         
15399         ['xs','sm','md','lg'].map(function(size){
15400             if (settings[size]) {
15401                 cfg.cls += ' col-' + size + '-' + settings[size];
15402             }
15403         });
15404         
15405         cfg.cn = combobox;
15406         
15407         return cfg;
15408         
15409     },
15410     
15411     initIOSView : function()
15412     {
15413         this.store.on('load', this.onIOSViewLoad, this);
15414         
15415         return;
15416     },
15417     
15418     onIOSViewLoad : function()
15419     {
15420         if(this.store.getCount() < 1){
15421             return;
15422         }
15423         
15424         this.clearIOSView();
15425         
15426         if(this.allowBlank) {
15427             
15428             var default_text = '-- SELECT --';
15429             
15430             if(this.placeholder.length){
15431                 default_text = this.placeholder;
15432             }
15433             
15434             if(this.emptyTitle.length){
15435                 default_text += ' - ' + this.emptyTitle + ' -';
15436             }
15437             
15438             var opt = this.inputEl().createChild({
15439                 tag: 'option',
15440                 value : 0,
15441                 html : default_text
15442             });
15443             
15444             var o = {};
15445             o[this.valueField] = 0;
15446             o[this.displayField] = default_text;
15447             
15448             this.ios_options.push({
15449                 data : o,
15450                 el : opt
15451             });
15452             
15453         }
15454         
15455         this.store.data.each(function(d, rowIndex){
15456             
15457             var html = '';
15458             
15459             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15460                 html = d.data[this.displayField];
15461             }
15462             
15463             var value = '';
15464             
15465             if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15466                 value = d.data[this.valueField];
15467             }
15468             
15469             var option = {
15470                 tag: 'option',
15471                 value : value,
15472                 html : html
15473             };
15474             
15475             if(this.value == d.data[this.valueField]){
15476                 option['selected'] = true;
15477             }
15478             
15479             var opt = this.inputEl().createChild(option);
15480             
15481             this.ios_options.push({
15482                 data : d.data,
15483                 el : opt
15484             });
15485             
15486         }, this);
15487         
15488         this.inputEl().on('change', function(){
15489            this.fireEvent('select', this);
15490         }, this);
15491         
15492     },
15493     
15494     clearIOSView: function()
15495     {
15496         this.inputEl().dom.innerHTML = '';
15497         
15498         this.ios_options = [];
15499     },
15500     
15501     setIOSValue: function(v)
15502     {
15503         this.value = v;
15504         
15505         if(!this.ios_options){
15506             return;
15507         }
15508         
15509         Roo.each(this.ios_options, function(opts){
15510            
15511            opts.el.dom.removeAttribute('selected');
15512            
15513            if(opts.data[this.valueField] != v){
15514                return;
15515            }
15516            
15517            opts.el.dom.setAttribute('selected', true);
15518            
15519         }, this);
15520     }
15521
15522     /** 
15523     * @cfg {Boolean} grow 
15524     * @hide 
15525     */
15526     /** 
15527     * @cfg {Number} growMin 
15528     * @hide 
15529     */
15530     /** 
15531     * @cfg {Number} growMax 
15532     * @hide 
15533     */
15534     /**
15535      * @hide
15536      * @method autoSize
15537      */
15538 });
15539
15540 Roo.apply(Roo.bootstrap.ComboBox,  {
15541     
15542     header : {
15543         tag: 'div',
15544         cls: 'modal-header',
15545         cn: [
15546             {
15547                 tag: 'h4',
15548                 cls: 'modal-title'
15549             }
15550         ]
15551     },
15552     
15553     body : {
15554         tag: 'div',
15555         cls: 'modal-body',
15556         cn: [
15557             {
15558                 tag: 'ul',
15559                 cls: 'list-group'
15560             }
15561         ]
15562     },
15563     
15564     listItemRadio : {
15565         tag: 'li',
15566         cls: 'list-group-item',
15567         cn: [
15568             {
15569                 tag: 'span',
15570                 cls: 'roo-combobox-list-group-item-value'
15571             },
15572             {
15573                 tag: 'div',
15574                 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15575                 cn: [
15576                     {
15577                         tag: 'input',
15578                         type: 'radio'
15579                     },
15580                     {
15581                         tag: 'label'
15582                     }
15583                 ]
15584             }
15585         ]
15586     },
15587     
15588     listItemCheckbox : {
15589         tag: 'li',
15590         cls: 'list-group-item',
15591         cn: [
15592             {
15593                 tag: 'span',
15594                 cls: 'roo-combobox-list-group-item-value'
15595             },
15596             {
15597                 tag: 'div',
15598                 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15599                 cn: [
15600                     {
15601                         tag: 'input',
15602                         type: 'checkbox'
15603                     },
15604                     {
15605                         tag: 'label'
15606                     }
15607                 ]
15608             }
15609         ]
15610     },
15611     
15612     emptyResult : {
15613         tag: 'div',
15614         cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15615     },
15616     
15617     footer : {
15618         tag: 'div',
15619         cls: 'modal-footer',
15620         cn: [
15621             {
15622                 tag: 'div',
15623                 cls: 'row',
15624                 cn: [
15625                     {
15626                         tag: 'div',
15627                         cls: 'col-xs-6 text-left',
15628                         cn: {
15629                             tag: 'button',
15630                             cls: 'btn btn-danger roo-touch-view-cancel',
15631                             html: 'Cancel'
15632                         }
15633                     },
15634                     {
15635                         tag: 'div',
15636                         cls: 'col-xs-6 text-right',
15637                         cn: {
15638                             tag: 'button',
15639                             cls: 'btn btn-success roo-touch-view-ok',
15640                             html: 'OK'
15641                         }
15642                     }
15643                 ]
15644             }
15645         ]
15646         
15647     }
15648 });
15649
15650 Roo.apply(Roo.bootstrap.ComboBox,  {
15651     
15652     touchViewTemplate : {
15653         tag: 'div',
15654         cls: 'modal fade roo-combobox-touch-view',
15655         cn: [
15656             {
15657                 tag: 'div',
15658                 cls: 'modal-dialog',
15659                 style : 'position:fixed', // we have to fix position....
15660                 cn: [
15661                     {
15662                         tag: 'div',
15663                         cls: 'modal-content',
15664                         cn: [
15665                             Roo.bootstrap.ComboBox.header,
15666                             Roo.bootstrap.ComboBox.body,
15667                             Roo.bootstrap.ComboBox.footer
15668                         ]
15669                     }
15670                 ]
15671             }
15672         ]
15673     }
15674 });/*
15675  * Based on:
15676  * Ext JS Library 1.1.1
15677  * Copyright(c) 2006-2007, Ext JS, LLC.
15678  *
15679  * Originally Released Under LGPL - original licence link has changed is not relivant.
15680  *
15681  * Fork - LGPL
15682  * <script type="text/javascript">
15683  */
15684
15685 /**
15686  * @class Roo.View
15687  * @extends Roo.util.Observable
15688  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
15689  * This class also supports single and multi selection modes. <br>
15690  * Create a data model bound view:
15691  <pre><code>
15692  var store = new Roo.data.Store(...);
15693
15694  var view = new Roo.View({
15695     el : "my-element",
15696     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
15697  
15698     singleSelect: true,
15699     selectedClass: "ydataview-selected",
15700     store: store
15701  });
15702
15703  // listen for node click?
15704  view.on("click", function(vw, index, node, e){
15705  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15706  });
15707
15708  // load XML data
15709  dataModel.load("foobar.xml");
15710  </code></pre>
15711  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15712  * <br><br>
15713  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15714  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15715  * 
15716  * Note: old style constructor is still suported (container, template, config)
15717  * 
15718  * @constructor
15719  * Create a new View
15720  * @param {Object} config The config object
15721  * 
15722  */
15723 Roo.View = function(config, depreciated_tpl, depreciated_config){
15724     
15725     this.parent = false;
15726     
15727     if (typeof(depreciated_tpl) == 'undefined') {
15728         // new way.. - universal constructor.
15729         Roo.apply(this, config);
15730         this.el  = Roo.get(this.el);
15731     } else {
15732         // old format..
15733         this.el  = Roo.get(config);
15734         this.tpl = depreciated_tpl;
15735         Roo.apply(this, depreciated_config);
15736     }
15737     this.wrapEl  = this.el.wrap().wrap();
15738     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15739     
15740     
15741     if(typeof(this.tpl) == "string"){
15742         this.tpl = new Roo.Template(this.tpl);
15743     } else {
15744         // support xtype ctors..
15745         this.tpl = new Roo.factory(this.tpl, Roo);
15746     }
15747     
15748     
15749     this.tpl.compile();
15750     
15751     /** @private */
15752     this.addEvents({
15753         /**
15754          * @event beforeclick
15755          * Fires before a click is processed. Returns false to cancel the default action.
15756          * @param {Roo.View} this
15757          * @param {Number} index The index of the target node
15758          * @param {HTMLElement} node The target node
15759          * @param {Roo.EventObject} e The raw event object
15760          */
15761             "beforeclick" : true,
15762         /**
15763          * @event click
15764          * Fires when a template node is clicked.
15765          * @param {Roo.View} this
15766          * @param {Number} index The index of the target node
15767          * @param {HTMLElement} node The target node
15768          * @param {Roo.EventObject} e The raw event object
15769          */
15770             "click" : true,
15771         /**
15772          * @event dblclick
15773          * Fires when a template node is double clicked.
15774          * @param {Roo.View} this
15775          * @param {Number} index The index of the target node
15776          * @param {HTMLElement} node The target node
15777          * @param {Roo.EventObject} e The raw event object
15778          */
15779             "dblclick" : true,
15780         /**
15781          * @event contextmenu
15782          * Fires when a template node is right clicked.
15783          * @param {Roo.View} this
15784          * @param {Number} index The index of the target node
15785          * @param {HTMLElement} node The target node
15786          * @param {Roo.EventObject} e The raw event object
15787          */
15788             "contextmenu" : true,
15789         /**
15790          * @event selectionchange
15791          * Fires when the selected nodes change.
15792          * @param {Roo.View} this
15793          * @param {Array} selections Array of the selected nodes
15794          */
15795             "selectionchange" : true,
15796     
15797         /**
15798          * @event beforeselect
15799          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15800          * @param {Roo.View} this
15801          * @param {HTMLElement} node The node to be selected
15802          * @param {Array} selections Array of currently selected nodes
15803          */
15804             "beforeselect" : true,
15805         /**
15806          * @event preparedata
15807          * Fires on every row to render, to allow you to change the data.
15808          * @param {Roo.View} this
15809          * @param {Object} data to be rendered (change this)
15810          */
15811           "preparedata" : true
15812           
15813           
15814         });
15815
15816
15817
15818     this.el.on({
15819         "click": this.onClick,
15820         "dblclick": this.onDblClick,
15821         "contextmenu": this.onContextMenu,
15822         scope:this
15823     });
15824
15825     this.selections = [];
15826     this.nodes = [];
15827     this.cmp = new Roo.CompositeElementLite([]);
15828     if(this.store){
15829         this.store = Roo.factory(this.store, Roo.data);
15830         this.setStore(this.store, true);
15831     }
15832     
15833     if ( this.footer && this.footer.xtype) {
15834            
15835          var fctr = this.wrapEl.appendChild(document.createElement("div"));
15836         
15837         this.footer.dataSource = this.store;
15838         this.footer.container = fctr;
15839         this.footer = Roo.factory(this.footer, Roo);
15840         fctr.insertFirst(this.el);
15841         
15842         // this is a bit insane - as the paging toolbar seems to detach the el..
15843 //        dom.parentNode.parentNode.parentNode
15844          // they get detached?
15845     }
15846     
15847     
15848     Roo.View.superclass.constructor.call(this);
15849     
15850     
15851 };
15852
15853 Roo.extend(Roo.View, Roo.util.Observable, {
15854     
15855      /**
15856      * @cfg {Roo.data.Store} store Data store to load data from.
15857      */
15858     store : false,
15859     
15860     /**
15861      * @cfg {String|Roo.Element} el The container element.
15862      */
15863     el : '',
15864     
15865     /**
15866      * @cfg {String|Roo.Template} tpl The template used by this View 
15867      */
15868     tpl : false,
15869     /**
15870      * @cfg {String} dataName the named area of the template to use as the data area
15871      *                          Works with domtemplates roo-name="name"
15872      */
15873     dataName: false,
15874     /**
15875      * @cfg {String} selectedClass The css class to add to selected nodes
15876      */
15877     selectedClass : "x-view-selected",
15878      /**
15879      * @cfg {String} emptyText The empty text to show when nothing is loaded.
15880      */
15881     emptyText : "",
15882     
15883     /**
15884      * @cfg {String} text to display on mask (default Loading)
15885      */
15886     mask : false,
15887     /**
15888      * @cfg {Boolean} multiSelect Allow multiple selection
15889      */
15890     multiSelect : false,
15891     /**
15892      * @cfg {Boolean} singleSelect Allow single selection
15893      */
15894     singleSelect:  false,
15895     
15896     /**
15897      * @cfg {Boolean} toggleSelect - selecting 
15898      */
15899     toggleSelect : false,
15900     
15901     /**
15902      * @cfg {Boolean} tickable - selecting 
15903      */
15904     tickable : false,
15905     
15906     /**
15907      * Returns the element this view is bound to.
15908      * @return {Roo.Element}
15909      */
15910     getEl : function(){
15911         return this.wrapEl;
15912     },
15913     
15914     
15915
15916     /**
15917      * Refreshes the view. - called by datachanged on the store. - do not call directly.
15918      */
15919     refresh : function(){
15920         //Roo.log('refresh');
15921         var t = this.tpl;
15922         
15923         // if we are using something like 'domtemplate', then
15924         // the what gets used is:
15925         // t.applySubtemplate(NAME, data, wrapping data..)
15926         // the outer template then get' applied with
15927         //     the store 'extra data'
15928         // and the body get's added to the
15929         //      roo-name="data" node?
15930         //      <span class='roo-tpl-{name}'></span> ?????
15931         
15932         
15933         
15934         this.clearSelections();
15935         this.el.update("");
15936         var html = [];
15937         var records = this.store.getRange();
15938         if(records.length < 1) {
15939             
15940             // is this valid??  = should it render a template??
15941             
15942             this.el.update(this.emptyText);
15943             return;
15944         }
15945         var el = this.el;
15946         if (this.dataName) {
15947             this.el.update(t.apply(this.store.meta)); //????
15948             el = this.el.child('.roo-tpl-' + this.dataName);
15949         }
15950         
15951         for(var i = 0, len = records.length; i < len; i++){
15952             var data = this.prepareData(records[i].data, i, records[i]);
15953             this.fireEvent("preparedata", this, data, i, records[i]);
15954             
15955             var d = Roo.apply({}, data);
15956             
15957             if(this.tickable){
15958                 Roo.apply(d, {'roo-id' : Roo.id()});
15959                 
15960                 var _this = this;
15961             
15962                 Roo.each(this.parent.item, function(item){
15963                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15964                         return;
15965                     }
15966                     Roo.apply(d, {'roo-data-checked' : 'checked'});
15967                 });
15968             }
15969             
15970             html[html.length] = Roo.util.Format.trim(
15971                 this.dataName ?
15972                     t.applySubtemplate(this.dataName, d, this.store.meta) :
15973                     t.apply(d)
15974             );
15975         }
15976         
15977         
15978         
15979         el.update(html.join(""));
15980         this.nodes = el.dom.childNodes;
15981         this.updateIndexes(0);
15982     },
15983     
15984
15985     /**
15986      * Function to override to reformat the data that is sent to
15987      * the template for each node.
15988      * DEPRICATED - use the preparedata event handler.
15989      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15990      * a JSON object for an UpdateManager bound view).
15991      */
15992     prepareData : function(data, index, record)
15993     {
15994         this.fireEvent("preparedata", this, data, index, record);
15995         return data;
15996     },
15997
15998     onUpdate : function(ds, record){
15999         // Roo.log('on update');   
16000         this.clearSelections();
16001         var index = this.store.indexOf(record);
16002         var n = this.nodes[index];
16003         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16004         n.parentNode.removeChild(n);
16005         this.updateIndexes(index, index);
16006     },
16007
16008     
16009     
16010 // --------- FIXME     
16011     onAdd : function(ds, records, index)
16012     {
16013         //Roo.log(['on Add', ds, records, index] );        
16014         this.clearSelections();
16015         if(this.nodes.length == 0){
16016             this.refresh();
16017             return;
16018         }
16019         var n = this.nodes[index];
16020         for(var i = 0, len = records.length; i < len; i++){
16021             var d = this.prepareData(records[i].data, i, records[i]);
16022             if(n){
16023                 this.tpl.insertBefore(n, d);
16024             }else{
16025                 
16026                 this.tpl.append(this.el, d);
16027             }
16028         }
16029         this.updateIndexes(index);
16030     },
16031
16032     onRemove : function(ds, record, index){
16033        // Roo.log('onRemove');
16034         this.clearSelections();
16035         var el = this.dataName  ?
16036             this.el.child('.roo-tpl-' + this.dataName) :
16037             this.el; 
16038         
16039         el.dom.removeChild(this.nodes[index]);
16040         this.updateIndexes(index);
16041     },
16042
16043     /**
16044      * Refresh an individual node.
16045      * @param {Number} index
16046      */
16047     refreshNode : function(index){
16048         this.onUpdate(this.store, this.store.getAt(index));
16049     },
16050
16051     updateIndexes : function(startIndex, endIndex){
16052         var ns = this.nodes;
16053         startIndex = startIndex || 0;
16054         endIndex = endIndex || ns.length - 1;
16055         for(var i = startIndex; i <= endIndex; i++){
16056             ns[i].nodeIndex = i;
16057         }
16058     },
16059
16060     /**
16061      * Changes the data store this view uses and refresh the view.
16062      * @param {Store} store
16063      */
16064     setStore : function(store, initial){
16065         if(!initial && this.store){
16066             this.store.un("datachanged", this.refresh);
16067             this.store.un("add", this.onAdd);
16068             this.store.un("remove", this.onRemove);
16069             this.store.un("update", this.onUpdate);
16070             this.store.un("clear", this.refresh);
16071             this.store.un("beforeload", this.onBeforeLoad);
16072             this.store.un("load", this.onLoad);
16073             this.store.un("loadexception", this.onLoad);
16074         }
16075         if(store){
16076           
16077             store.on("datachanged", this.refresh, this);
16078             store.on("add", this.onAdd, this);
16079             store.on("remove", this.onRemove, this);
16080             store.on("update", this.onUpdate, this);
16081             store.on("clear", this.refresh, this);
16082             store.on("beforeload", this.onBeforeLoad, this);
16083             store.on("load", this.onLoad, this);
16084             store.on("loadexception", this.onLoad, this);
16085         }
16086         
16087         if(store){
16088             this.refresh();
16089         }
16090     },
16091     /**
16092      * onbeforeLoad - masks the loading area.
16093      *
16094      */
16095     onBeforeLoad : function(store,opts)
16096     {
16097          //Roo.log('onBeforeLoad');   
16098         if (!opts.add) {
16099             this.el.update("");
16100         }
16101         this.el.mask(this.mask ? this.mask : "Loading" ); 
16102     },
16103     onLoad : function ()
16104     {
16105         this.el.unmask();
16106     },
16107     
16108
16109     /**
16110      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16111      * @param {HTMLElement} node
16112      * @return {HTMLElement} The template node
16113      */
16114     findItemFromChild : function(node){
16115         var el = this.dataName  ?
16116             this.el.child('.roo-tpl-' + this.dataName,true) :
16117             this.el.dom; 
16118         
16119         if(!node || node.parentNode == el){
16120                     return node;
16121             }
16122             var p = node.parentNode;
16123             while(p && p != el){
16124             if(p.parentNode == el){
16125                 return p;
16126             }
16127             p = p.parentNode;
16128         }
16129             return null;
16130     },
16131
16132     /** @ignore */
16133     onClick : function(e){
16134         var item = this.findItemFromChild(e.getTarget());
16135         if(item){
16136             var index = this.indexOf(item);
16137             if(this.onItemClick(item, index, e) !== false){
16138                 this.fireEvent("click", this, index, item, e);
16139             }
16140         }else{
16141             this.clearSelections();
16142         }
16143     },
16144
16145     /** @ignore */
16146     onContextMenu : function(e){
16147         var item = this.findItemFromChild(e.getTarget());
16148         if(item){
16149             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16150         }
16151     },
16152
16153     /** @ignore */
16154     onDblClick : function(e){
16155         var item = this.findItemFromChild(e.getTarget());
16156         if(item){
16157             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16158         }
16159     },
16160
16161     onItemClick : function(item, index, e)
16162     {
16163         if(this.fireEvent("beforeclick", this, index, item, e) === false){
16164             return false;
16165         }
16166         if (this.toggleSelect) {
16167             var m = this.isSelected(item) ? 'unselect' : 'select';
16168             //Roo.log(m);
16169             var _t = this;
16170             _t[m](item, true, false);
16171             return true;
16172         }
16173         if(this.multiSelect || this.singleSelect){
16174             if(this.multiSelect && e.shiftKey && this.lastSelection){
16175                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16176             }else{
16177                 this.select(item, this.multiSelect && e.ctrlKey);
16178                 this.lastSelection = item;
16179             }
16180             
16181             if(!this.tickable){
16182                 e.preventDefault();
16183             }
16184             
16185         }
16186         return true;
16187     },
16188
16189     /**
16190      * Get the number of selected nodes.
16191      * @return {Number}
16192      */
16193     getSelectionCount : function(){
16194         return this.selections.length;
16195     },
16196
16197     /**
16198      * Get the currently selected nodes.
16199      * @return {Array} An array of HTMLElements
16200      */
16201     getSelectedNodes : function(){
16202         return this.selections;
16203     },
16204
16205     /**
16206      * Get the indexes of the selected nodes.
16207      * @return {Array}
16208      */
16209     getSelectedIndexes : function(){
16210         var indexes = [], s = this.selections;
16211         for(var i = 0, len = s.length; i < len; i++){
16212             indexes.push(s[i].nodeIndex);
16213         }
16214         return indexes;
16215     },
16216
16217     /**
16218      * Clear all selections
16219      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16220      */
16221     clearSelections : function(suppressEvent){
16222         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16223             this.cmp.elements = this.selections;
16224             this.cmp.removeClass(this.selectedClass);
16225             this.selections = [];
16226             if(!suppressEvent){
16227                 this.fireEvent("selectionchange", this, this.selections);
16228             }
16229         }
16230     },
16231
16232     /**
16233      * Returns true if the passed node is selected
16234      * @param {HTMLElement/Number} node The node or node index
16235      * @return {Boolean}
16236      */
16237     isSelected : function(node){
16238         var s = this.selections;
16239         if(s.length < 1){
16240             return false;
16241         }
16242         node = this.getNode(node);
16243         return s.indexOf(node) !== -1;
16244     },
16245
16246     /**
16247      * Selects nodes.
16248      * @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
16249      * @param {Boolean} keepExisting (optional) true to keep existing selections
16250      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16251      */
16252     select : function(nodeInfo, keepExisting, suppressEvent){
16253         if(nodeInfo instanceof Array){
16254             if(!keepExisting){
16255                 this.clearSelections(true);
16256             }
16257             for(var i = 0, len = nodeInfo.length; i < len; i++){
16258                 this.select(nodeInfo[i], true, true);
16259             }
16260             return;
16261         } 
16262         var node = this.getNode(nodeInfo);
16263         if(!node || this.isSelected(node)){
16264             return; // already selected.
16265         }
16266         if(!keepExisting){
16267             this.clearSelections(true);
16268         }
16269         
16270         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16271             Roo.fly(node).addClass(this.selectedClass);
16272             this.selections.push(node);
16273             if(!suppressEvent){
16274                 this.fireEvent("selectionchange", this, this.selections);
16275             }
16276         }
16277         
16278         
16279     },
16280       /**
16281      * Unselects nodes.
16282      * @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
16283      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16284      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16285      */
16286     unselect : function(nodeInfo, keepExisting, suppressEvent)
16287     {
16288         if(nodeInfo instanceof Array){
16289             Roo.each(this.selections, function(s) {
16290                 this.unselect(s, nodeInfo);
16291             }, this);
16292             return;
16293         }
16294         var node = this.getNode(nodeInfo);
16295         if(!node || !this.isSelected(node)){
16296             //Roo.log("not selected");
16297             return; // not selected.
16298         }
16299         // fireevent???
16300         var ns = [];
16301         Roo.each(this.selections, function(s) {
16302             if (s == node ) {
16303                 Roo.fly(node).removeClass(this.selectedClass);
16304
16305                 return;
16306             }
16307             ns.push(s);
16308         },this);
16309         
16310         this.selections= ns;
16311         this.fireEvent("selectionchange", this, this.selections);
16312     },
16313
16314     /**
16315      * Gets a template node.
16316      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16317      * @return {HTMLElement} The node or null if it wasn't found
16318      */
16319     getNode : function(nodeInfo){
16320         if(typeof nodeInfo == "string"){
16321             return document.getElementById(nodeInfo);
16322         }else if(typeof nodeInfo == "number"){
16323             return this.nodes[nodeInfo];
16324         }
16325         return nodeInfo;
16326     },
16327
16328     /**
16329      * Gets a range template nodes.
16330      * @param {Number} startIndex
16331      * @param {Number} endIndex
16332      * @return {Array} An array of nodes
16333      */
16334     getNodes : function(start, end){
16335         var ns = this.nodes;
16336         start = start || 0;
16337         end = typeof end == "undefined" ? ns.length - 1 : end;
16338         var nodes = [];
16339         if(start <= end){
16340             for(var i = start; i <= end; i++){
16341                 nodes.push(ns[i]);
16342             }
16343         } else{
16344             for(var i = start; i >= end; i--){
16345                 nodes.push(ns[i]);
16346             }
16347         }
16348         return nodes;
16349     },
16350
16351     /**
16352      * Finds the index of the passed node
16353      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16354      * @return {Number} The index of the node or -1
16355      */
16356     indexOf : function(node){
16357         node = this.getNode(node);
16358         if(typeof node.nodeIndex == "number"){
16359             return node.nodeIndex;
16360         }
16361         var ns = this.nodes;
16362         for(var i = 0, len = ns.length; i < len; i++){
16363             if(ns[i] == node){
16364                 return i;
16365             }
16366         }
16367         return -1;
16368     }
16369 });
16370 /*
16371  * - LGPL
16372  *
16373  * based on jquery fullcalendar
16374  * 
16375  */
16376
16377 Roo.bootstrap = Roo.bootstrap || {};
16378 /**
16379  * @class Roo.bootstrap.Calendar
16380  * @extends Roo.bootstrap.Component
16381  * Bootstrap Calendar class
16382  * @cfg {Boolean} loadMask (true|false) default false
16383  * @cfg {Object} header generate the user specific header of the calendar, default false
16384
16385  * @constructor
16386  * Create a new Container
16387  * @param {Object} config The config object
16388  */
16389
16390
16391
16392 Roo.bootstrap.Calendar = function(config){
16393     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16394      this.addEvents({
16395         /**
16396              * @event select
16397              * Fires when a date is selected
16398              * @param {DatePicker} this
16399              * @param {Date} date The selected date
16400              */
16401         'select': true,
16402         /**
16403              * @event monthchange
16404              * Fires when the displayed month changes 
16405              * @param {DatePicker} this
16406              * @param {Date} date The selected month
16407              */
16408         'monthchange': true,
16409         /**
16410              * @event evententer
16411              * Fires when mouse over an event
16412              * @param {Calendar} this
16413              * @param {event} Event
16414              */
16415         'evententer': true,
16416         /**
16417              * @event eventleave
16418              * Fires when the mouse leaves an
16419              * @param {Calendar} this
16420              * @param {event}
16421              */
16422         'eventleave': true,
16423         /**
16424              * @event eventclick
16425              * Fires when the mouse click an
16426              * @param {Calendar} this
16427              * @param {event}
16428              */
16429         'eventclick': true
16430         
16431     });
16432
16433 };
16434
16435 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
16436     
16437      /**
16438      * @cfg {Number} startDay
16439      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16440      */
16441     startDay : 0,
16442     
16443     loadMask : false,
16444     
16445     header : false,
16446       
16447     getAutoCreate : function(){
16448         
16449         
16450         var fc_button = function(name, corner, style, content ) {
16451             return Roo.apply({},{
16452                 tag : 'span',
16453                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
16454                          (corner.length ?
16455                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16456                             ''
16457                         ),
16458                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16459                 unselectable: 'on'
16460             });
16461         };
16462         
16463         var header = {};
16464         
16465         if(!this.header){
16466             header = {
16467                 tag : 'table',
16468                 cls : 'fc-header',
16469                 style : 'width:100%',
16470                 cn : [
16471                     {
16472                         tag: 'tr',
16473                         cn : [
16474                             {
16475                                 tag : 'td',
16476                                 cls : 'fc-header-left',
16477                                 cn : [
16478                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
16479                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
16480                                     { tag: 'span', cls: 'fc-header-space' },
16481                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
16482
16483
16484                                 ]
16485                             },
16486
16487                             {
16488                                 tag : 'td',
16489                                 cls : 'fc-header-center',
16490                                 cn : [
16491                                     {
16492                                         tag: 'span',
16493                                         cls: 'fc-header-title',
16494                                         cn : {
16495                                             tag: 'H2',
16496                                             html : 'month / year'
16497                                         }
16498                                     }
16499
16500                                 ]
16501                             },
16502                             {
16503                                 tag : 'td',
16504                                 cls : 'fc-header-right',
16505                                 cn : [
16506                               /*      fc_button('month', 'left', '', 'month' ),
16507                                     fc_button('week', '', '', 'week' ),
16508                                     fc_button('day', 'right', '', 'day' )
16509                                 */    
16510
16511                                 ]
16512                             }
16513
16514                         ]
16515                     }
16516                 ]
16517             };
16518         }
16519         
16520         header = this.header;
16521         
16522        
16523         var cal_heads = function() {
16524             var ret = [];
16525             // fixme - handle this.
16526             
16527             for (var i =0; i < Date.dayNames.length; i++) {
16528                 var d = Date.dayNames[i];
16529                 ret.push({
16530                     tag: 'th',
16531                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16532                     html : d.substring(0,3)
16533                 });
16534                 
16535             }
16536             ret[0].cls += ' fc-first';
16537             ret[6].cls += ' fc-last';
16538             return ret;
16539         };
16540         var cal_cell = function(n) {
16541             return  {
16542                 tag: 'td',
16543                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16544                 cn : [
16545                     {
16546                         cn : [
16547                             {
16548                                 cls: 'fc-day-number',
16549                                 html: 'D'
16550                             },
16551                             {
16552                                 cls: 'fc-day-content',
16553                              
16554                                 cn : [
16555                                      {
16556                                         style: 'position: relative;' // height: 17px;
16557                                     }
16558                                 ]
16559                             }
16560                             
16561                             
16562                         ]
16563                     }
16564                 ]
16565                 
16566             }
16567         };
16568         var cal_rows = function() {
16569             
16570             var ret = [];
16571             for (var r = 0; r < 6; r++) {
16572                 var row= {
16573                     tag : 'tr',
16574                     cls : 'fc-week',
16575                     cn : []
16576                 };
16577                 
16578                 for (var i =0; i < Date.dayNames.length; i++) {
16579                     var d = Date.dayNames[i];
16580                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16581
16582                 }
16583                 row.cn[0].cls+=' fc-first';
16584                 row.cn[0].cn[0].style = 'min-height:90px';
16585                 row.cn[6].cls+=' fc-last';
16586                 ret.push(row);
16587                 
16588             }
16589             ret[0].cls += ' fc-first';
16590             ret[4].cls += ' fc-prev-last';
16591             ret[5].cls += ' fc-last';
16592             return ret;
16593             
16594         };
16595         
16596         var cal_table = {
16597             tag: 'table',
16598             cls: 'fc-border-separate',
16599             style : 'width:100%',
16600             cellspacing  : 0,
16601             cn : [
16602                 { 
16603                     tag: 'thead',
16604                     cn : [
16605                         { 
16606                             tag: 'tr',
16607                             cls : 'fc-first fc-last',
16608                             cn : cal_heads()
16609                         }
16610                     ]
16611                 },
16612                 { 
16613                     tag: 'tbody',
16614                     cn : cal_rows()
16615                 }
16616                   
16617             ]
16618         };
16619          
16620          var cfg = {
16621             cls : 'fc fc-ltr',
16622             cn : [
16623                 header,
16624                 {
16625                     cls : 'fc-content',
16626                     style : "position: relative;",
16627                     cn : [
16628                         {
16629                             cls : 'fc-view fc-view-month fc-grid',
16630                             style : 'position: relative',
16631                             unselectable : 'on',
16632                             cn : [
16633                                 {
16634                                     cls : 'fc-event-container',
16635                                     style : 'position:absolute;z-index:8;top:0;left:0;'
16636                                 },
16637                                 cal_table
16638                             ]
16639                         }
16640                     ]
16641     
16642                 }
16643            ] 
16644             
16645         };
16646         
16647          
16648         
16649         return cfg;
16650     },
16651     
16652     
16653     initEvents : function()
16654     {
16655         if(!this.store){
16656             throw "can not find store for calendar";
16657         }
16658         
16659         var mark = {
16660             tag: "div",
16661             cls:"x-dlg-mask",
16662             style: "text-align:center",
16663             cn: [
16664                 {
16665                     tag: "div",
16666                     style: "background-color:white;width:50%;margin:250 auto",
16667                     cn: [
16668                         {
16669                             tag: "img",
16670                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
16671                         },
16672                         {
16673                             tag: "span",
16674                             html: "Loading"
16675                         }
16676                         
16677                     ]
16678                 }
16679             ]
16680         };
16681         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16682         
16683         var size = this.el.select('.fc-content', true).first().getSize();
16684         this.maskEl.setSize(size.width, size.height);
16685         this.maskEl.enableDisplayMode("block");
16686         if(!this.loadMask){
16687             this.maskEl.hide();
16688         }
16689         
16690         this.store = Roo.factory(this.store, Roo.data);
16691         this.store.on('load', this.onLoad, this);
16692         this.store.on('beforeload', this.onBeforeLoad, this);
16693         
16694         this.resize();
16695         
16696         this.cells = this.el.select('.fc-day',true);
16697         //Roo.log(this.cells);
16698         this.textNodes = this.el.query('.fc-day-number');
16699         this.cells.addClassOnOver('fc-state-hover');
16700         
16701         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16702         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16703         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16704         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16705         
16706         this.on('monthchange', this.onMonthChange, this);
16707         
16708         this.update(new Date().clearTime());
16709     },
16710     
16711     resize : function() {
16712         var sz  = this.el.getSize();
16713         
16714         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16715         this.el.select('.fc-day-content div',true).setHeight(34);
16716     },
16717     
16718     
16719     // private
16720     showPrevMonth : function(e){
16721         this.update(this.activeDate.add("mo", -1));
16722     },
16723     showToday : function(e){
16724         this.update(new Date().clearTime());
16725     },
16726     // private
16727     showNextMonth : function(e){
16728         this.update(this.activeDate.add("mo", 1));
16729     },
16730
16731     // private
16732     showPrevYear : function(){
16733         this.update(this.activeDate.add("y", -1));
16734     },
16735
16736     // private
16737     showNextYear : function(){
16738         this.update(this.activeDate.add("y", 1));
16739     },
16740
16741     
16742    // private
16743     update : function(date)
16744     {
16745         var vd = this.activeDate;
16746         this.activeDate = date;
16747 //        if(vd && this.el){
16748 //            var t = date.getTime();
16749 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16750 //                Roo.log('using add remove');
16751 //                
16752 //                this.fireEvent('monthchange', this, date);
16753 //                
16754 //                this.cells.removeClass("fc-state-highlight");
16755 //                this.cells.each(function(c){
16756 //                   if(c.dateValue == t){
16757 //                       c.addClass("fc-state-highlight");
16758 //                       setTimeout(function(){
16759 //                            try{c.dom.firstChild.focus();}catch(e){}
16760 //                       }, 50);
16761 //                       return false;
16762 //                   }
16763 //                   return true;
16764 //                });
16765 //                return;
16766 //            }
16767 //        }
16768         
16769         var days = date.getDaysInMonth();
16770         
16771         var firstOfMonth = date.getFirstDateOfMonth();
16772         var startingPos = firstOfMonth.getDay()-this.startDay;
16773         
16774         if(startingPos < this.startDay){
16775             startingPos += 7;
16776         }
16777         
16778         var pm = date.add(Date.MONTH, -1);
16779         var prevStart = pm.getDaysInMonth()-startingPos;
16780 //        
16781         this.cells = this.el.select('.fc-day',true);
16782         this.textNodes = this.el.query('.fc-day-number');
16783         this.cells.addClassOnOver('fc-state-hover');
16784         
16785         var cells = this.cells.elements;
16786         var textEls = this.textNodes;
16787         
16788         Roo.each(cells, function(cell){
16789             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16790         });
16791         
16792         days += startingPos;
16793
16794         // convert everything to numbers so it's fast
16795         var day = 86400000;
16796         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16797         //Roo.log(d);
16798         //Roo.log(pm);
16799         //Roo.log(prevStart);
16800         
16801         var today = new Date().clearTime().getTime();
16802         var sel = date.clearTime().getTime();
16803         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16804         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16805         var ddMatch = this.disabledDatesRE;
16806         var ddText = this.disabledDatesText;
16807         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16808         var ddaysText = this.disabledDaysText;
16809         var format = this.format;
16810         
16811         var setCellClass = function(cal, cell){
16812             cell.row = 0;
16813             cell.events = [];
16814             cell.more = [];
16815             //Roo.log('set Cell Class');
16816             cell.title = "";
16817             var t = d.getTime();
16818             
16819             //Roo.log(d);
16820             
16821             cell.dateValue = t;
16822             if(t == today){
16823                 cell.className += " fc-today";
16824                 cell.className += " fc-state-highlight";
16825                 cell.title = cal.todayText;
16826             }
16827             if(t == sel){
16828                 // disable highlight in other month..
16829                 //cell.className += " fc-state-highlight";
16830                 
16831             }
16832             // disabling
16833             if(t < min) {
16834                 cell.className = " fc-state-disabled";
16835                 cell.title = cal.minText;
16836                 return;
16837             }
16838             if(t > max) {
16839                 cell.className = " fc-state-disabled";
16840                 cell.title = cal.maxText;
16841                 return;
16842             }
16843             if(ddays){
16844                 if(ddays.indexOf(d.getDay()) != -1){
16845                     cell.title = ddaysText;
16846                     cell.className = " fc-state-disabled";
16847                 }
16848             }
16849             if(ddMatch && format){
16850                 var fvalue = d.dateFormat(format);
16851                 if(ddMatch.test(fvalue)){
16852                     cell.title = ddText.replace("%0", fvalue);
16853                     cell.className = " fc-state-disabled";
16854                 }
16855             }
16856             
16857             if (!cell.initialClassName) {
16858                 cell.initialClassName = cell.dom.className;
16859             }
16860             
16861             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
16862         };
16863
16864         var i = 0;
16865         
16866         for(; i < startingPos; i++) {
16867             textEls[i].innerHTML = (++prevStart);
16868             d.setDate(d.getDate()+1);
16869             
16870             cells[i].className = "fc-past fc-other-month";
16871             setCellClass(this, cells[i]);
16872         }
16873         
16874         var intDay = 0;
16875         
16876         for(; i < days; i++){
16877             intDay = i - startingPos + 1;
16878             textEls[i].innerHTML = (intDay);
16879             d.setDate(d.getDate()+1);
16880             
16881             cells[i].className = ''; // "x-date-active";
16882             setCellClass(this, cells[i]);
16883         }
16884         var extraDays = 0;
16885         
16886         for(; i < 42; i++) {
16887             textEls[i].innerHTML = (++extraDays);
16888             d.setDate(d.getDate()+1);
16889             
16890             cells[i].className = "fc-future fc-other-month";
16891             setCellClass(this, cells[i]);
16892         }
16893         
16894         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16895         
16896         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16897         
16898         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16899         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16900         
16901         if(totalRows != 6){
16902             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16903             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16904         }
16905         
16906         this.fireEvent('monthchange', this, date);
16907         
16908         
16909         /*
16910         if(!this.internalRender){
16911             var main = this.el.dom.firstChild;
16912             var w = main.offsetWidth;
16913             this.el.setWidth(w + this.el.getBorderWidth("lr"));
16914             Roo.fly(main).setWidth(w);
16915             this.internalRender = true;
16916             // opera does not respect the auto grow header center column
16917             // then, after it gets a width opera refuses to recalculate
16918             // without a second pass
16919             if(Roo.isOpera && !this.secondPass){
16920                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16921                 this.secondPass = true;
16922                 this.update.defer(10, this, [date]);
16923             }
16924         }
16925         */
16926         
16927     },
16928     
16929     findCell : function(dt) {
16930         dt = dt.clearTime().getTime();
16931         var ret = false;
16932         this.cells.each(function(c){
16933             //Roo.log("check " +c.dateValue + '?=' + dt);
16934             if(c.dateValue == dt){
16935                 ret = c;
16936                 return false;
16937             }
16938             return true;
16939         });
16940         
16941         return ret;
16942     },
16943     
16944     findCells : function(ev) {
16945         var s = ev.start.clone().clearTime().getTime();
16946        // Roo.log(s);
16947         var e= ev.end.clone().clearTime().getTime();
16948        // Roo.log(e);
16949         var ret = [];
16950         this.cells.each(function(c){
16951              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16952             
16953             if(c.dateValue > e){
16954                 return ;
16955             }
16956             if(c.dateValue < s){
16957                 return ;
16958             }
16959             ret.push(c);
16960         });
16961         
16962         return ret;    
16963     },
16964     
16965 //    findBestRow: function(cells)
16966 //    {
16967 //        var ret = 0;
16968 //        
16969 //        for (var i =0 ; i < cells.length;i++) {
16970 //            ret  = Math.max(cells[i].rows || 0,ret);
16971 //        }
16972 //        return ret;
16973 //        
16974 //    },
16975     
16976     
16977     addItem : function(ev)
16978     {
16979         // look for vertical location slot in
16980         var cells = this.findCells(ev);
16981         
16982 //        ev.row = this.findBestRow(cells);
16983         
16984         // work out the location.
16985         
16986         var crow = false;
16987         var rows = [];
16988         for(var i =0; i < cells.length; i++) {
16989             
16990             cells[i].row = cells[0].row;
16991             
16992             if(i == 0){
16993                 cells[i].row = cells[i].row + 1;
16994             }
16995             
16996             if (!crow) {
16997                 crow = {
16998                     start : cells[i],
16999                     end :  cells[i]
17000                 };
17001                 continue;
17002             }
17003             if (crow.start.getY() == cells[i].getY()) {
17004                 // on same row.
17005                 crow.end = cells[i];
17006                 continue;
17007             }
17008             // different row.
17009             rows.push(crow);
17010             crow = {
17011                 start: cells[i],
17012                 end : cells[i]
17013             };
17014             
17015         }
17016         
17017         rows.push(crow);
17018         ev.els = [];
17019         ev.rows = rows;
17020         ev.cells = cells;
17021         
17022         cells[0].events.push(ev);
17023         
17024         this.calevents.push(ev);
17025     },
17026     
17027     clearEvents: function() {
17028         
17029         if(!this.calevents){
17030             return;
17031         }
17032         
17033         Roo.each(this.cells.elements, function(c){
17034             c.row = 0;
17035             c.events = [];
17036             c.more = [];
17037         });
17038         
17039         Roo.each(this.calevents, function(e) {
17040             Roo.each(e.els, function(el) {
17041                 el.un('mouseenter' ,this.onEventEnter, this);
17042                 el.un('mouseleave' ,this.onEventLeave, this);
17043                 el.remove();
17044             },this);
17045         },this);
17046         
17047         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17048             e.remove();
17049         });
17050         
17051     },
17052     
17053     renderEvents: function()
17054     {   
17055         var _this = this;
17056         
17057         this.cells.each(function(c) {
17058             
17059             if(c.row < 5){
17060                 return;
17061             }
17062             
17063             var ev = c.events;
17064             
17065             var r = 4;
17066             if(c.row != c.events.length){
17067                 r = 4 - (4 - (c.row - c.events.length));
17068             }
17069             
17070             c.events = ev.slice(0, r);
17071             c.more = ev.slice(r);
17072             
17073             if(c.more.length && c.more.length == 1){
17074                 c.events.push(c.more.pop());
17075             }
17076             
17077             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17078             
17079         });
17080             
17081         this.cells.each(function(c) {
17082             
17083             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17084             
17085             
17086             for (var e = 0; e < c.events.length; e++){
17087                 var ev = c.events[e];
17088                 var rows = ev.rows;
17089                 
17090                 for(var i = 0; i < rows.length; i++) {
17091                 
17092                     // how many rows should it span..
17093
17094                     var  cfg = {
17095                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17096                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17097
17098                         unselectable : "on",
17099                         cn : [
17100                             {
17101                                 cls: 'fc-event-inner',
17102                                 cn : [
17103     //                                {
17104     //                                  tag:'span',
17105     //                                  cls: 'fc-event-time',
17106     //                                  html : cells.length > 1 ? '' : ev.time
17107     //                                },
17108                                     {
17109                                       tag:'span',
17110                                       cls: 'fc-event-title',
17111                                       html : String.format('{0}', ev.title)
17112                                     }
17113
17114
17115                                 ]
17116                             },
17117                             {
17118                                 cls: 'ui-resizable-handle ui-resizable-e',
17119                                 html : '&nbsp;&nbsp;&nbsp'
17120                             }
17121
17122                         ]
17123                     };
17124
17125                     if (i == 0) {
17126                         cfg.cls += ' fc-event-start';
17127                     }
17128                     if ((i+1) == rows.length) {
17129                         cfg.cls += ' fc-event-end';
17130                     }
17131
17132                     var ctr = _this.el.select('.fc-event-container',true).first();
17133                     var cg = ctr.createChild(cfg);
17134
17135                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17136                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17137
17138                     var r = (c.more.length) ? 1 : 0;
17139                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
17140                     cg.setWidth(ebox.right - sbox.x -2);
17141
17142                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17143                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17144                     cg.on('click', _this.onEventClick, _this, ev);
17145
17146                     ev.els.push(cg);
17147                     
17148                 }
17149                 
17150             }
17151             
17152             
17153             if(c.more.length){
17154                 var  cfg = {
17155                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17156                     style : 'position: absolute',
17157                     unselectable : "on",
17158                     cn : [
17159                         {
17160                             cls: 'fc-event-inner',
17161                             cn : [
17162                                 {
17163                                   tag:'span',
17164                                   cls: 'fc-event-title',
17165                                   html : 'More'
17166                                 }
17167
17168
17169                             ]
17170                         },
17171                         {
17172                             cls: 'ui-resizable-handle ui-resizable-e',
17173                             html : '&nbsp;&nbsp;&nbsp'
17174                         }
17175
17176                     ]
17177                 };
17178
17179                 var ctr = _this.el.select('.fc-event-container',true).first();
17180                 var cg = ctr.createChild(cfg);
17181
17182                 var sbox = c.select('.fc-day-content',true).first().getBox();
17183                 var ebox = c.select('.fc-day-content',true).first().getBox();
17184                 //Roo.log(cg);
17185                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
17186                 cg.setWidth(ebox.right - sbox.x -2);
17187
17188                 cg.on('click', _this.onMoreEventClick, _this, c.more);
17189                 
17190             }
17191             
17192         });
17193         
17194         
17195         
17196     },
17197     
17198     onEventEnter: function (e, el,event,d) {
17199         this.fireEvent('evententer', this, el, event);
17200     },
17201     
17202     onEventLeave: function (e, el,event,d) {
17203         this.fireEvent('eventleave', this, el, event);
17204     },
17205     
17206     onEventClick: function (e, el,event,d) {
17207         this.fireEvent('eventclick', this, el, event);
17208     },
17209     
17210     onMonthChange: function () {
17211         this.store.load();
17212     },
17213     
17214     onMoreEventClick: function(e, el, more)
17215     {
17216         var _this = this;
17217         
17218         this.calpopover.placement = 'right';
17219         this.calpopover.setTitle('More');
17220         
17221         this.calpopover.setContent('');
17222         
17223         var ctr = this.calpopover.el.select('.popover-content', true).first();
17224         
17225         Roo.each(more, function(m){
17226             var cfg = {
17227                 cls : 'fc-event-hori fc-event-draggable',
17228                 html : m.title
17229             };
17230             var cg = ctr.createChild(cfg);
17231             
17232             cg.on('click', _this.onEventClick, _this, m);
17233         });
17234         
17235         this.calpopover.show(el);
17236         
17237         
17238     },
17239     
17240     onLoad: function () 
17241     {   
17242         this.calevents = [];
17243         var cal = this;
17244         
17245         if(this.store.getCount() > 0){
17246             this.store.data.each(function(d){
17247                cal.addItem({
17248                     id : d.data.id,
17249                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17250                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17251                     time : d.data.start_time,
17252                     title : d.data.title,
17253                     description : d.data.description,
17254                     venue : d.data.venue
17255                 });
17256             });
17257         }
17258         
17259         this.renderEvents();
17260         
17261         if(this.calevents.length && this.loadMask){
17262             this.maskEl.hide();
17263         }
17264     },
17265     
17266     onBeforeLoad: function()
17267     {
17268         this.clearEvents();
17269         if(this.loadMask){
17270             this.maskEl.show();
17271         }
17272     }
17273 });
17274
17275  
17276  /*
17277  * - LGPL
17278  *
17279  * element
17280  * 
17281  */
17282
17283 /**
17284  * @class Roo.bootstrap.Popover
17285  * @extends Roo.bootstrap.Component
17286  * Bootstrap Popover class
17287  * @cfg {String} html contents of the popover   (or false to use children..)
17288  * @cfg {String} title of popover (or false to hide)
17289  * @cfg {String} placement how it is placed
17290  * @cfg {String} trigger click || hover (or false to trigger manually)
17291  * @cfg {String} over what (parent or false to trigger manually.)
17292  * @cfg {Number} delay - delay before showing
17293  
17294  * @constructor
17295  * Create a new Popover
17296  * @param {Object} config The config object
17297  */
17298
17299 Roo.bootstrap.Popover = function(config){
17300     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17301     
17302     this.addEvents({
17303         // raw events
17304          /**
17305          * @event show
17306          * After the popover show
17307          * 
17308          * @param {Roo.bootstrap.Popover} this
17309          */
17310         "show" : true,
17311         /**
17312          * @event hide
17313          * After the popover hide
17314          * 
17315          * @param {Roo.bootstrap.Popover} this
17316          */
17317         "hide" : true
17318     });
17319 };
17320
17321 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
17322     
17323     title: 'Fill in a title',
17324     html: false,
17325     
17326     placement : 'right',
17327     trigger : 'hover', // hover
17328     
17329     delay : 0,
17330     
17331     over: 'parent',
17332     
17333     can_build_overlaid : false,
17334     
17335     getChildContainer : function()
17336     {
17337         return this.el.select('.popover-content',true).first();
17338     },
17339     
17340     getAutoCreate : function(){
17341          
17342         var cfg = {
17343            cls : 'popover roo-dynamic',
17344            style: 'display:block',
17345            cn : [
17346                 {
17347                     cls : 'arrow'
17348                 },
17349                 {
17350                     cls : 'popover-inner',
17351                     cn : [
17352                         {
17353                             tag: 'h3',
17354                             cls: 'popover-title',
17355                             html : this.title
17356                         },
17357                         {
17358                             cls : 'popover-content',
17359                             html : this.html
17360                         }
17361                     ]
17362                     
17363                 }
17364            ]
17365         };
17366         
17367         return cfg;
17368     },
17369     setTitle: function(str)
17370     {
17371         this.title = str;
17372         this.el.select('.popover-title',true).first().dom.innerHTML = str;
17373     },
17374     setContent: function(str)
17375     {
17376         this.html = str;
17377         this.el.select('.popover-content',true).first().dom.innerHTML = str;
17378     },
17379     // as it get's added to the bottom of the page.
17380     onRender : function(ct, position)
17381     {
17382         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17383         if(!this.el){
17384             var cfg = Roo.apply({},  this.getAutoCreate());
17385             cfg.id = Roo.id();
17386             
17387             if (this.cls) {
17388                 cfg.cls += ' ' + this.cls;
17389             }
17390             if (this.style) {
17391                 cfg.style = this.style;
17392             }
17393             //Roo.log("adding to ");
17394             this.el = Roo.get(document.body).createChild(cfg, position);
17395 //            Roo.log(this.el);
17396         }
17397         this.initEvents();
17398     },
17399     
17400     initEvents : function()
17401     {
17402         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17403         this.el.enableDisplayMode('block');
17404         this.el.hide();
17405         if (this.over === false) {
17406             return; 
17407         }
17408         if (this.triggers === false) {
17409             return;
17410         }
17411         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17412         var triggers = this.trigger ? this.trigger.split(' ') : [];
17413         Roo.each(triggers, function(trigger) {
17414         
17415             if (trigger == 'click') {
17416                 on_el.on('click', this.toggle, this);
17417             } else if (trigger != 'manual') {
17418                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
17419                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17420       
17421                 on_el.on(eventIn  ,this.enter, this);
17422                 on_el.on(eventOut, this.leave, this);
17423             }
17424         }, this);
17425         
17426     },
17427     
17428     
17429     // private
17430     timeout : null,
17431     hoverState : null,
17432     
17433     toggle : function () {
17434         this.hoverState == 'in' ? this.leave() : this.enter();
17435     },
17436     
17437     enter : function () {
17438         
17439         clearTimeout(this.timeout);
17440     
17441         this.hoverState = 'in';
17442     
17443         if (!this.delay || !this.delay.show) {
17444             this.show();
17445             return;
17446         }
17447         var _t = this;
17448         this.timeout = setTimeout(function () {
17449             if (_t.hoverState == 'in') {
17450                 _t.show();
17451             }
17452         }, this.delay.show)
17453     },
17454     
17455     leave : function() {
17456         clearTimeout(this.timeout);
17457     
17458         this.hoverState = 'out';
17459     
17460         if (!this.delay || !this.delay.hide) {
17461             this.hide();
17462             return;
17463         }
17464         var _t = this;
17465         this.timeout = setTimeout(function () {
17466             if (_t.hoverState == 'out') {
17467                 _t.hide();
17468             }
17469         }, this.delay.hide)
17470     },
17471     
17472     show : function (on_el)
17473     {
17474         if (!on_el) {
17475             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17476         }
17477         
17478         // set content.
17479         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17480         if (this.html !== false) {
17481             this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17482         }
17483         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17484         if (!this.title.length) {
17485             this.el.select('.popover-title',true).hide();
17486         }
17487         
17488         var placement = typeof this.placement == 'function' ?
17489             this.placement.call(this, this.el, on_el) :
17490             this.placement;
17491             
17492         var autoToken = /\s?auto?\s?/i;
17493         var autoPlace = autoToken.test(placement);
17494         if (autoPlace) {
17495             placement = placement.replace(autoToken, '') || 'top';
17496         }
17497         
17498         //this.el.detach()
17499         //this.el.setXY([0,0]);
17500         this.el.show();
17501         this.el.dom.style.display='block';
17502         this.el.addClass(placement);
17503         
17504         //this.el.appendTo(on_el);
17505         
17506         var p = this.getPosition();
17507         var box = this.el.getBox();
17508         
17509         if (autoPlace) {
17510             // fixme..
17511         }
17512         var align = Roo.bootstrap.Popover.alignment[placement];
17513         
17514 //        Roo.log(align);
17515         this.el.alignTo(on_el, align[0],align[1]);
17516         //var arrow = this.el.select('.arrow',true).first();
17517         //arrow.set(align[2], 
17518         
17519         this.el.addClass('in');
17520         
17521         
17522         if (this.el.hasClass('fade')) {
17523             // fade it?
17524         }
17525         
17526         this.hoverState = 'in';
17527         
17528         this.fireEvent('show', this);
17529         
17530     },
17531     hide : function()
17532     {
17533         this.el.setXY([0,0]);
17534         this.el.removeClass('in');
17535         this.el.hide();
17536         this.hoverState = null;
17537         
17538         this.fireEvent('hide', this);
17539     }
17540     
17541 });
17542
17543 Roo.bootstrap.Popover.alignment = {
17544     'left' : ['r-l', [-10,0], 'right'],
17545     'right' : ['l-r', [10,0], 'left'],
17546     'bottom' : ['t-b', [0,10], 'top'],
17547     'top' : [ 'b-t', [0,-10], 'bottom']
17548 };
17549
17550  /*
17551  * - LGPL
17552  *
17553  * Progress
17554  * 
17555  */
17556
17557 /**
17558  * @class Roo.bootstrap.Progress
17559  * @extends Roo.bootstrap.Component
17560  * Bootstrap Progress class
17561  * @cfg {Boolean} striped striped of the progress bar
17562  * @cfg {Boolean} active animated of the progress bar
17563  * 
17564  * 
17565  * @constructor
17566  * Create a new Progress
17567  * @param {Object} config The config object
17568  */
17569
17570 Roo.bootstrap.Progress = function(config){
17571     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17572 };
17573
17574 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
17575     
17576     striped : false,
17577     active: false,
17578     
17579     getAutoCreate : function(){
17580         var cfg = {
17581             tag: 'div',
17582             cls: 'progress'
17583         };
17584         
17585         
17586         if(this.striped){
17587             cfg.cls += ' progress-striped';
17588         }
17589       
17590         if(this.active){
17591             cfg.cls += ' active';
17592         }
17593         
17594         
17595         return cfg;
17596     }
17597    
17598 });
17599
17600  
17601
17602  /*
17603  * - LGPL
17604  *
17605  * ProgressBar
17606  * 
17607  */
17608
17609 /**
17610  * @class Roo.bootstrap.ProgressBar
17611  * @extends Roo.bootstrap.Component
17612  * Bootstrap ProgressBar class
17613  * @cfg {Number} aria_valuenow aria-value now
17614  * @cfg {Number} aria_valuemin aria-value min
17615  * @cfg {Number} aria_valuemax aria-value max
17616  * @cfg {String} label label for the progress bar
17617  * @cfg {String} panel (success | info | warning | danger )
17618  * @cfg {String} role role of the progress bar
17619  * @cfg {String} sr_only text
17620  * 
17621  * 
17622  * @constructor
17623  * Create a new ProgressBar
17624  * @param {Object} config The config object
17625  */
17626
17627 Roo.bootstrap.ProgressBar = function(config){
17628     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17629 };
17630
17631 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
17632     
17633     aria_valuenow : 0,
17634     aria_valuemin : 0,
17635     aria_valuemax : 100,
17636     label : false,
17637     panel : false,
17638     role : false,
17639     sr_only: false,
17640     
17641     getAutoCreate : function()
17642     {
17643         
17644         var cfg = {
17645             tag: 'div',
17646             cls: 'progress-bar',
17647             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17648         };
17649         
17650         if(this.sr_only){
17651             cfg.cn = {
17652                 tag: 'span',
17653                 cls: 'sr-only',
17654                 html: this.sr_only
17655             }
17656         }
17657         
17658         if(this.role){
17659             cfg.role = this.role;
17660         }
17661         
17662         if(this.aria_valuenow){
17663             cfg['aria-valuenow'] = this.aria_valuenow;
17664         }
17665         
17666         if(this.aria_valuemin){
17667             cfg['aria-valuemin'] = this.aria_valuemin;
17668         }
17669         
17670         if(this.aria_valuemax){
17671             cfg['aria-valuemax'] = this.aria_valuemax;
17672         }
17673         
17674         if(this.label && !this.sr_only){
17675             cfg.html = this.label;
17676         }
17677         
17678         if(this.panel){
17679             cfg.cls += ' progress-bar-' + this.panel;
17680         }
17681         
17682         return cfg;
17683     },
17684     
17685     update : function(aria_valuenow)
17686     {
17687         this.aria_valuenow = aria_valuenow;
17688         
17689         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17690     }
17691    
17692 });
17693
17694  
17695
17696  /*
17697  * - LGPL
17698  *
17699  * column
17700  * 
17701  */
17702
17703 /**
17704  * @class Roo.bootstrap.TabGroup
17705  * @extends Roo.bootstrap.Column
17706  * Bootstrap Column class
17707  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17708  * @cfg {Boolean} carousel true to make the group behave like a carousel
17709  * @cfg {Boolean} bullets show bullets for the panels
17710  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17711  * @cfg {Number} timer auto slide timer .. default 0 millisecond
17712  * @cfg {Boolean} showarrow (true|false) show arrow default true
17713  * 
17714  * @constructor
17715  * Create a new TabGroup
17716  * @param {Object} config The config object
17717  */
17718
17719 Roo.bootstrap.TabGroup = function(config){
17720     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17721     if (!this.navId) {
17722         this.navId = Roo.id();
17723     }
17724     this.tabs = [];
17725     Roo.bootstrap.TabGroup.register(this);
17726     
17727 };
17728
17729 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
17730     
17731     carousel : false,
17732     transition : false,
17733     bullets : 0,
17734     timer : 0,
17735     autoslide : false,
17736     slideFn : false,
17737     slideOnTouch : false,
17738     showarrow : true,
17739     
17740     getAutoCreate : function()
17741     {
17742         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17743         
17744         cfg.cls += ' tab-content';
17745         
17746         if (this.carousel) {
17747             cfg.cls += ' carousel slide';
17748             
17749             cfg.cn = [{
17750                cls : 'carousel-inner',
17751                cn : []
17752             }];
17753         
17754             if(this.bullets  && !Roo.isTouch){
17755                 
17756                 var bullets = {
17757                     cls : 'carousel-bullets',
17758                     cn : []
17759                 };
17760                
17761                 if(this.bullets_cls){
17762                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17763                 }
17764                 
17765                 bullets.cn.push({
17766                     cls : 'clear'
17767                 });
17768                 
17769                 cfg.cn[0].cn.push(bullets);
17770             }
17771             
17772             if(this.showarrow){
17773                 cfg.cn[0].cn.push({
17774                     tag : 'div',
17775                     class : 'carousel-arrow',
17776                     cn : [
17777                         {
17778                             tag : 'div',
17779                             class : 'carousel-prev',
17780                             cn : [
17781                                 {
17782                                     tag : 'i',
17783                                     class : 'fa fa-chevron-left'
17784                                 }
17785                             ]
17786                         },
17787                         {
17788                             tag : 'div',
17789                             class : 'carousel-next',
17790                             cn : [
17791                                 {
17792                                     tag : 'i',
17793                                     class : 'fa fa-chevron-right'
17794                                 }
17795                             ]
17796                         }
17797                     ]
17798                 });
17799             }
17800             
17801         }
17802         
17803         return cfg;
17804     },
17805     
17806     initEvents:  function()
17807     {
17808 //        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17809 //            this.el.on("touchstart", this.onTouchStart, this);
17810 //        }
17811         
17812         if(this.autoslide){
17813             var _this = this;
17814             
17815             this.slideFn = window.setInterval(function() {
17816                 _this.showPanelNext();
17817             }, this.timer);
17818         }
17819         
17820         if(this.showarrow){
17821             this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17822             this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17823         }
17824         
17825         
17826     },
17827     
17828 //    onTouchStart : function(e, el, o)
17829 //    {
17830 //        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17831 //            return;
17832 //        }
17833 //        
17834 //        this.showPanelNext();
17835 //    },
17836     
17837     
17838     getChildContainer : function()
17839     {
17840         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17841     },
17842     
17843     /**
17844     * register a Navigation item
17845     * @param {Roo.bootstrap.NavItem} the navitem to add
17846     */
17847     register : function(item)
17848     {
17849         this.tabs.push( item);
17850         item.navId = this.navId; // not really needed..
17851         this.addBullet();
17852     
17853     },
17854     
17855     getActivePanel : function()
17856     {
17857         var r = false;
17858         Roo.each(this.tabs, function(t) {
17859             if (t.active) {
17860                 r = t;
17861                 return false;
17862             }
17863             return null;
17864         });
17865         return r;
17866         
17867     },
17868     getPanelByName : function(n)
17869     {
17870         var r = false;
17871         Roo.each(this.tabs, function(t) {
17872             if (t.tabId == n) {
17873                 r = t;
17874                 return false;
17875             }
17876             return null;
17877         });
17878         return r;
17879     },
17880     indexOfPanel : function(p)
17881     {
17882         var r = false;
17883         Roo.each(this.tabs, function(t,i) {
17884             if (t.tabId == p.tabId) {
17885                 r = i;
17886                 return false;
17887             }
17888             return null;
17889         });
17890         return r;
17891     },
17892     /**
17893      * show a specific panel
17894      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17895      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17896      */
17897     showPanel : function (pan)
17898     {
17899         if(this.transition || typeof(pan) == 'undefined'){
17900             Roo.log("waiting for the transitionend");
17901             return;
17902         }
17903         
17904         if (typeof(pan) == 'number') {
17905             pan = this.tabs[pan];
17906         }
17907         
17908         if (typeof(pan) == 'string') {
17909             pan = this.getPanelByName(pan);
17910         }
17911         
17912         var cur = this.getActivePanel();
17913         
17914         if(!pan || !cur){
17915             Roo.log('pan or acitve pan is undefined');
17916             return false;
17917         }
17918         
17919         if (pan.tabId == this.getActivePanel().tabId) {
17920             return true;
17921         }
17922         
17923         if (false === cur.fireEvent('beforedeactivate')) {
17924             return false;
17925         }
17926         
17927         if(this.bullets > 0 && !Roo.isTouch){
17928             this.setActiveBullet(this.indexOfPanel(pan));
17929         }
17930         
17931         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17932             
17933             this.transition = true;
17934             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
17935             var lr = dir == 'next' ? 'left' : 'right';
17936             pan.el.addClass(dir); // or prev
17937             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17938             cur.el.addClass(lr); // or right
17939             pan.el.addClass(lr);
17940             
17941             var _this = this;
17942             cur.el.on('transitionend', function() {
17943                 Roo.log("trans end?");
17944                 
17945                 pan.el.removeClass([lr,dir]);
17946                 pan.setActive(true);
17947                 
17948                 cur.el.removeClass([lr]);
17949                 cur.setActive(false);
17950                 
17951                 _this.transition = false;
17952                 
17953             }, this, { single:  true } );
17954             
17955             return true;
17956         }
17957         
17958         cur.setActive(false);
17959         pan.setActive(true);
17960         
17961         return true;
17962         
17963     },
17964     showPanelNext : function()
17965     {
17966         var i = this.indexOfPanel(this.getActivePanel());
17967         
17968         if (i >= this.tabs.length - 1 && !this.autoslide) {
17969             return;
17970         }
17971         
17972         if (i >= this.tabs.length - 1 && this.autoslide) {
17973             i = -1;
17974         }
17975         
17976         this.showPanel(this.tabs[i+1]);
17977     },
17978     
17979     showPanelPrev : function()
17980     {
17981         var i = this.indexOfPanel(this.getActivePanel());
17982         
17983         if (i  < 1 && !this.autoslide) {
17984             return;
17985         }
17986         
17987         if (i < 1 && this.autoslide) {
17988             i = this.tabs.length;
17989         }
17990         
17991         this.showPanel(this.tabs[i-1]);
17992     },
17993     
17994     
17995     addBullet: function()
17996     {
17997         if(!this.bullets || Roo.isTouch){
17998             return;
17999         }
18000         var ctr = this.el.select('.carousel-bullets',true).first();
18001         var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18002         var bullet = ctr.createChild({
18003             cls : 'bullet bullet-' + i
18004         },ctr.dom.lastChild);
18005         
18006         
18007         var _this = this;
18008         
18009         bullet.on('click', (function(e, el, o, ii, t){
18010
18011             e.preventDefault();
18012
18013             this.showPanel(ii);
18014
18015             if(this.autoslide && this.slideFn){
18016                 clearInterval(this.slideFn);
18017                 this.slideFn = window.setInterval(function() {
18018                     _this.showPanelNext();
18019                 }, this.timer);
18020             }
18021
18022         }).createDelegate(this, [i, bullet], true));
18023                 
18024         
18025     },
18026      
18027     setActiveBullet : function(i)
18028     {
18029         if(Roo.isTouch){
18030             return;
18031         }
18032         
18033         Roo.each(this.el.select('.bullet', true).elements, function(el){
18034             el.removeClass('selected');
18035         });
18036
18037         var bullet = this.el.select('.bullet-' + i, true).first();
18038         
18039         if(!bullet){
18040             return;
18041         }
18042         
18043         bullet.addClass('selected');
18044     }
18045     
18046     
18047   
18048 });
18049
18050  
18051
18052  
18053  
18054 Roo.apply(Roo.bootstrap.TabGroup, {
18055     
18056     groups: {},
18057      /**
18058     * register a Navigation Group
18059     * @param {Roo.bootstrap.NavGroup} the navgroup to add
18060     */
18061     register : function(navgrp)
18062     {
18063         this.groups[navgrp.navId] = navgrp;
18064         
18065     },
18066     /**
18067     * fetch a Navigation Group based on the navigation ID
18068     * if one does not exist , it will get created.
18069     * @param {string} the navgroup to add
18070     * @returns {Roo.bootstrap.NavGroup} the navgroup 
18071     */
18072     get: function(navId) {
18073         if (typeof(this.groups[navId]) == 'undefined') {
18074             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18075         }
18076         return this.groups[navId] ;
18077     }
18078     
18079     
18080     
18081 });
18082
18083  /*
18084  * - LGPL
18085  *
18086  * TabPanel
18087  * 
18088  */
18089
18090 /**
18091  * @class Roo.bootstrap.TabPanel
18092  * @extends Roo.bootstrap.Component
18093  * Bootstrap TabPanel class
18094  * @cfg {Boolean} active panel active
18095  * @cfg {String} html panel content
18096  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18097  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18098  * @cfg {String} href click to link..
18099  * 
18100  * 
18101  * @constructor
18102  * Create a new TabPanel
18103  * @param {Object} config The config object
18104  */
18105
18106 Roo.bootstrap.TabPanel = function(config){
18107     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18108     this.addEvents({
18109         /**
18110              * @event changed
18111              * Fires when the active status changes
18112              * @param {Roo.bootstrap.TabPanel} this
18113              * @param {Boolean} state the new state
18114             
18115          */
18116         'changed': true,
18117         /**
18118              * @event beforedeactivate
18119              * Fires before a tab is de-activated - can be used to do validation on a form.
18120              * @param {Roo.bootstrap.TabPanel} this
18121              * @return {Boolean} false if there is an error
18122             
18123          */
18124         'beforedeactivate': true
18125      });
18126     
18127     this.tabId = this.tabId || Roo.id();
18128   
18129 };
18130
18131 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
18132     
18133     active: false,
18134     html: false,
18135     tabId: false,
18136     navId : false,
18137     href : '',
18138     
18139     getAutoCreate : function(){
18140         var cfg = {
18141             tag: 'div',
18142             // item is needed for carousel - not sure if it has any effect otherwise
18143             cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18144             html: this.html || ''
18145         };
18146         
18147         if(this.active){
18148             cfg.cls += ' active';
18149         }
18150         
18151         if(this.tabId){
18152             cfg.tabId = this.tabId;
18153         }
18154         
18155         
18156         return cfg;
18157     },
18158     
18159     initEvents:  function()
18160     {
18161         var p = this.parent();
18162         
18163         this.navId = this.navId || p.navId;
18164         
18165         if (typeof(this.navId) != 'undefined') {
18166             // not really needed.. but just in case.. parent should be a NavGroup.
18167             var tg = Roo.bootstrap.TabGroup.get(this.navId);
18168             
18169             tg.register(this);
18170             
18171             var i = tg.tabs.length - 1;
18172             
18173             if(this.active && tg.bullets > 0 && i < tg.bullets){
18174                 tg.setActiveBullet(i);
18175             }
18176         }
18177         
18178         this.el.on('click', this.onClick, this);
18179         
18180         if(Roo.isTouch){
18181             this.el.on("touchstart", this.onTouchStart, this);
18182             this.el.on("touchmove", this.onTouchMove, this);
18183             this.el.on("touchend", this.onTouchEnd, this);
18184         }
18185         
18186     },
18187     
18188     onRender : function(ct, position)
18189     {
18190         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18191     },
18192     
18193     setActive : function(state)
18194     {
18195         Roo.log("panel - set active " + this.tabId + "=" + state);
18196         
18197         this.active = state;
18198         if (!state) {
18199             this.el.removeClass('active');
18200             
18201         } else  if (!this.el.hasClass('active')) {
18202             this.el.addClass('active');
18203         }
18204         
18205         this.fireEvent('changed', this, state);
18206     },
18207     
18208     onClick : function(e)
18209     {
18210         e.preventDefault();
18211         
18212         if(!this.href.length){
18213             return;
18214         }
18215         
18216         window.location.href = this.href;
18217     },
18218     
18219     startX : 0,
18220     startY : 0,
18221     endX : 0,
18222     endY : 0,
18223     swiping : false,
18224     
18225     onTouchStart : function(e)
18226     {
18227         this.swiping = false;
18228         
18229         this.startX = e.browserEvent.touches[0].clientX;
18230         this.startY = e.browserEvent.touches[0].clientY;
18231     },
18232     
18233     onTouchMove : function(e)
18234     {
18235         this.swiping = true;
18236         
18237         this.endX = e.browserEvent.touches[0].clientX;
18238         this.endY = e.browserEvent.touches[0].clientY;
18239     },
18240     
18241     onTouchEnd : function(e)
18242     {
18243         if(!this.swiping){
18244             this.onClick(e);
18245             return;
18246         }
18247         
18248         var tabGroup = this.parent();
18249         
18250         if(this.endX > this.startX){ // swiping right
18251             tabGroup.showPanelPrev();
18252             return;
18253         }
18254         
18255         if(this.startX > this.endX){ // swiping left
18256             tabGroup.showPanelNext();
18257             return;
18258         }
18259     }
18260     
18261     
18262 });
18263  
18264
18265  
18266
18267  /*
18268  * - LGPL
18269  *
18270  * DateField
18271  * 
18272  */
18273
18274 /**
18275  * @class Roo.bootstrap.DateField
18276  * @extends Roo.bootstrap.Input
18277  * Bootstrap DateField class
18278  * @cfg {Number} weekStart default 0
18279  * @cfg {String} viewMode default empty, (months|years)
18280  * @cfg {String} minViewMode default empty, (months|years)
18281  * @cfg {Number} startDate default -Infinity
18282  * @cfg {Number} endDate default Infinity
18283  * @cfg {Boolean} todayHighlight default false
18284  * @cfg {Boolean} todayBtn default false
18285  * @cfg {Boolean} calendarWeeks default false
18286  * @cfg {Object} daysOfWeekDisabled default empty
18287  * @cfg {Boolean} singleMode default false (true | false)
18288  * 
18289  * @cfg {Boolean} keyboardNavigation default true
18290  * @cfg {String} language default en
18291  * 
18292  * @constructor
18293  * Create a new DateField
18294  * @param {Object} config The config object
18295  */
18296
18297 Roo.bootstrap.DateField = function(config){
18298     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18299      this.addEvents({
18300             /**
18301              * @event show
18302              * Fires when this field show.
18303              * @param {Roo.bootstrap.DateField} this
18304              * @param {Mixed} date The date value
18305              */
18306             show : true,
18307             /**
18308              * @event show
18309              * Fires when this field hide.
18310              * @param {Roo.bootstrap.DateField} this
18311              * @param {Mixed} date The date value
18312              */
18313             hide : true,
18314             /**
18315              * @event select
18316              * Fires when select a date.
18317              * @param {Roo.bootstrap.DateField} this
18318              * @param {Mixed} date The date value
18319              */
18320             select : true,
18321             /**
18322              * @event beforeselect
18323              * Fires when before select a date.
18324              * @param {Roo.bootstrap.DateField} this
18325              * @param {Mixed} date The date value
18326              */
18327             beforeselect : true
18328         });
18329 };
18330
18331 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
18332     
18333     /**
18334      * @cfg {String} format
18335      * The default date format string which can be overriden for localization support.  The format must be
18336      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18337      */
18338     format : "m/d/y",
18339     /**
18340      * @cfg {String} altFormats
18341      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18342      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18343      */
18344     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18345     
18346     weekStart : 0,
18347     
18348     viewMode : '',
18349     
18350     minViewMode : '',
18351     
18352     todayHighlight : false,
18353     
18354     todayBtn: false,
18355     
18356     language: 'en',
18357     
18358     keyboardNavigation: true,
18359     
18360     calendarWeeks: false,
18361     
18362     startDate: -Infinity,
18363     
18364     endDate: Infinity,
18365     
18366     daysOfWeekDisabled: [],
18367     
18368     _events: [],
18369     
18370     singleMode : false,
18371     
18372     UTCDate: function()
18373     {
18374         return new Date(Date.UTC.apply(Date, arguments));
18375     },
18376     
18377     UTCToday: function()
18378     {
18379         var today = new Date();
18380         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18381     },
18382     
18383     getDate: function() {
18384             var d = this.getUTCDate();
18385             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18386     },
18387     
18388     getUTCDate: function() {
18389             return this.date;
18390     },
18391     
18392     setDate: function(d) {
18393             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18394     },
18395     
18396     setUTCDate: function(d) {
18397             this.date = d;
18398             this.setValue(this.formatDate(this.date));
18399     },
18400         
18401     onRender: function(ct, position)
18402     {
18403         
18404         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18405         
18406         this.language = this.language || 'en';
18407         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18408         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18409         
18410         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18411         this.format = this.format || 'm/d/y';
18412         this.isInline = false;
18413         this.isInput = true;
18414         this.component = this.el.select('.add-on', true).first() || false;
18415         this.component = (this.component && this.component.length === 0) ? false : this.component;
18416         this.hasInput = this.component && this.inputEl().length;
18417         
18418         if (typeof(this.minViewMode === 'string')) {
18419             switch (this.minViewMode) {
18420                 case 'months':
18421                     this.minViewMode = 1;
18422                     break;
18423                 case 'years':
18424                     this.minViewMode = 2;
18425                     break;
18426                 default:
18427                     this.minViewMode = 0;
18428                     break;
18429             }
18430         }
18431         
18432         if (typeof(this.viewMode === 'string')) {
18433             switch (this.viewMode) {
18434                 case 'months':
18435                     this.viewMode = 1;
18436                     break;
18437                 case 'years':
18438                     this.viewMode = 2;
18439                     break;
18440                 default:
18441                     this.viewMode = 0;
18442                     break;
18443             }
18444         }
18445                 
18446         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18447         
18448 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18449         
18450         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18451         
18452         this.picker().on('mousedown', this.onMousedown, this);
18453         this.picker().on('click', this.onClick, this);
18454         
18455         this.picker().addClass('datepicker-dropdown');
18456         
18457         this.startViewMode = this.viewMode;
18458         
18459         if(this.singleMode){
18460             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18461                 v.setVisibilityMode(Roo.Element.DISPLAY);
18462                 v.hide();
18463             });
18464             
18465             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18466                 v.setStyle('width', '189px');
18467             });
18468         }
18469         
18470         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18471             if(!this.calendarWeeks){
18472                 v.remove();
18473                 return;
18474             }
18475             
18476             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18477             v.attr('colspan', function(i, val){
18478                 return parseInt(val) + 1;
18479             });
18480         });
18481                         
18482         
18483         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18484         
18485         this.setStartDate(this.startDate);
18486         this.setEndDate(this.endDate);
18487         
18488         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18489         
18490         this.fillDow();
18491         this.fillMonths();
18492         this.update();
18493         this.showMode();
18494         
18495         if(this.isInline) {
18496             this.show();
18497         }
18498     },
18499     
18500     picker : function()
18501     {
18502         return this.pickerEl;
18503 //        return this.el.select('.datepicker', true).first();
18504     },
18505     
18506     fillDow: function()
18507     {
18508         var dowCnt = this.weekStart;
18509         
18510         var dow = {
18511             tag: 'tr',
18512             cn: [
18513                 
18514             ]
18515         };
18516         
18517         if(this.calendarWeeks){
18518             dow.cn.push({
18519                 tag: 'th',
18520                 cls: 'cw',
18521                 html: '&nbsp;'
18522             })
18523         }
18524         
18525         while (dowCnt < this.weekStart + 7) {
18526             dow.cn.push({
18527                 tag: 'th',
18528                 cls: 'dow',
18529                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18530             });
18531         }
18532         
18533         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18534     },
18535     
18536     fillMonths: function()
18537     {    
18538         var i = 0;
18539         var months = this.picker().select('>.datepicker-months td', true).first();
18540         
18541         months.dom.innerHTML = '';
18542         
18543         while (i < 12) {
18544             var month = {
18545                 tag: 'span',
18546                 cls: 'month',
18547                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18548             };
18549             
18550             months.createChild(month);
18551         }
18552         
18553     },
18554     
18555     update: function()
18556     {
18557         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;
18558         
18559         if (this.date < this.startDate) {
18560             this.viewDate = new Date(this.startDate);
18561         } else if (this.date > this.endDate) {
18562             this.viewDate = new Date(this.endDate);
18563         } else {
18564             this.viewDate = new Date(this.date);
18565         }
18566         
18567         this.fill();
18568     },
18569     
18570     fill: function() 
18571     {
18572         var d = new Date(this.viewDate),
18573                 year = d.getUTCFullYear(),
18574                 month = d.getUTCMonth(),
18575                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18576                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18577                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18578                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18579                 currentDate = this.date && this.date.valueOf(),
18580                 today = this.UTCToday();
18581         
18582         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18583         
18584 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18585         
18586 //        this.picker.select('>tfoot th.today').
18587 //                                              .text(dates[this.language].today)
18588 //                                              .toggle(this.todayBtn !== false);
18589     
18590         this.updateNavArrows();
18591         this.fillMonths();
18592                                                 
18593         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18594         
18595         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18596          
18597         prevMonth.setUTCDate(day);
18598         
18599         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18600         
18601         var nextMonth = new Date(prevMonth);
18602         
18603         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18604         
18605         nextMonth = nextMonth.valueOf();
18606         
18607         var fillMonths = false;
18608         
18609         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18610         
18611         while(prevMonth.valueOf() < nextMonth) {
18612             var clsName = '';
18613             
18614             if (prevMonth.getUTCDay() === this.weekStart) {
18615                 if(fillMonths){
18616                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18617                 }
18618                     
18619                 fillMonths = {
18620                     tag: 'tr',
18621                     cn: []
18622                 };
18623                 
18624                 if(this.calendarWeeks){
18625                     // ISO 8601: First week contains first thursday.
18626                     // ISO also states week starts on Monday, but we can be more abstract here.
18627                     var
18628                     // Start of current week: based on weekstart/current date
18629                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18630                     // Thursday of this week
18631                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18632                     // First Thursday of year, year from thursday
18633                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18634                     // Calendar week: ms between thursdays, div ms per day, div 7 days
18635                     calWeek =  (th - yth) / 864e5 / 7 + 1;
18636                     
18637                     fillMonths.cn.push({
18638                         tag: 'td',
18639                         cls: 'cw',
18640                         html: calWeek
18641                     });
18642                 }
18643             }
18644             
18645             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18646                 clsName += ' old';
18647             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18648                 clsName += ' new';
18649             }
18650             if (this.todayHighlight &&
18651                 prevMonth.getUTCFullYear() == today.getFullYear() &&
18652                 prevMonth.getUTCMonth() == today.getMonth() &&
18653                 prevMonth.getUTCDate() == today.getDate()) {
18654                 clsName += ' today';
18655             }
18656             
18657             if (currentDate && prevMonth.valueOf() === currentDate) {
18658                 clsName += ' active';
18659             }
18660             
18661             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18662                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18663                     clsName += ' disabled';
18664             }
18665             
18666             fillMonths.cn.push({
18667                 tag: 'td',
18668                 cls: 'day ' + clsName,
18669                 html: prevMonth.getDate()
18670             });
18671             
18672             prevMonth.setDate(prevMonth.getDate()+1);
18673         }
18674           
18675         var currentYear = this.date && this.date.getUTCFullYear();
18676         var currentMonth = this.date && this.date.getUTCMonth();
18677         
18678         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18679         
18680         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18681             v.removeClass('active');
18682             
18683             if(currentYear === year && k === currentMonth){
18684                 v.addClass('active');
18685             }
18686             
18687             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18688                 v.addClass('disabled');
18689             }
18690             
18691         });
18692         
18693         
18694         year = parseInt(year/10, 10) * 10;
18695         
18696         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18697         
18698         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18699         
18700         year -= 1;
18701         for (var i = -1; i < 11; i++) {
18702             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18703                 tag: 'span',
18704                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18705                 html: year
18706             });
18707             
18708             year += 1;
18709         }
18710     },
18711     
18712     showMode: function(dir) 
18713     {
18714         if (dir) {
18715             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18716         }
18717         
18718         Roo.each(this.picker().select('>div',true).elements, function(v){
18719             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18720             v.hide();
18721         });
18722         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18723     },
18724     
18725     place: function()
18726     {
18727         if(this.isInline) {
18728             return;
18729         }
18730         
18731         this.picker().removeClass(['bottom', 'top']);
18732         
18733         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18734             /*
18735              * place to the top of element!
18736              *
18737              */
18738             
18739             this.picker().addClass('top');
18740             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18741             
18742             return;
18743         }
18744         
18745         this.picker().addClass('bottom');
18746         
18747         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18748     },
18749     
18750     parseDate : function(value)
18751     {
18752         if(!value || value instanceof Date){
18753             return value;
18754         }
18755         var v = Date.parseDate(value, this.format);
18756         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18757             v = Date.parseDate(value, 'Y-m-d');
18758         }
18759         if(!v && this.altFormats){
18760             if(!this.altFormatsArray){
18761                 this.altFormatsArray = this.altFormats.split("|");
18762             }
18763             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18764                 v = Date.parseDate(value, this.altFormatsArray[i]);
18765             }
18766         }
18767         return v;
18768     },
18769     
18770     formatDate : function(date, fmt)
18771     {   
18772         return (!date || !(date instanceof Date)) ?
18773         date : date.dateFormat(fmt || this.format);
18774     },
18775     
18776     onFocus : function()
18777     {
18778         Roo.bootstrap.DateField.superclass.onFocus.call(this);
18779         this.show();
18780     },
18781     
18782     onBlur : function()
18783     {
18784         Roo.bootstrap.DateField.superclass.onBlur.call(this);
18785         
18786         var d = this.inputEl().getValue();
18787         
18788         this.setValue(d);
18789                 
18790         this.hide();
18791     },
18792     
18793     show : function()
18794     {
18795         this.picker().show();
18796         this.update();
18797         this.place();
18798         
18799         this.fireEvent('show', this, this.date);
18800     },
18801     
18802     hide : function()
18803     {
18804         if(this.isInline) {
18805             return;
18806         }
18807         this.picker().hide();
18808         this.viewMode = this.startViewMode;
18809         this.showMode();
18810         
18811         this.fireEvent('hide', this, this.date);
18812         
18813     },
18814     
18815     onMousedown: function(e)
18816     {
18817         e.stopPropagation();
18818         e.preventDefault();
18819     },
18820     
18821     keyup: function(e)
18822     {
18823         Roo.bootstrap.DateField.superclass.keyup.call(this);
18824         this.update();
18825     },
18826
18827     setValue: function(v)
18828     {
18829         if(this.fireEvent('beforeselect', this, v) !== false){
18830             var d = new Date(this.parseDate(v) ).clearTime();
18831         
18832             if(isNaN(d.getTime())){
18833                 this.date = this.viewDate = '';
18834                 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18835                 return;
18836             }
18837
18838             v = this.formatDate(d);
18839
18840             Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18841
18842             this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18843
18844             this.update();
18845
18846             this.fireEvent('select', this, this.date);
18847         }
18848     },
18849     
18850     getValue: function()
18851     {
18852         return this.formatDate(this.date);
18853     },
18854     
18855     fireKey: function(e)
18856     {
18857         if (!this.picker().isVisible()){
18858             if (e.keyCode == 27) { // allow escape to hide and re-show picker
18859                 this.show();
18860             }
18861             return;
18862         }
18863         
18864         var dateChanged = false,
18865         dir, day, month,
18866         newDate, newViewDate;
18867         
18868         switch(e.keyCode){
18869             case 27: // escape
18870                 this.hide();
18871                 e.preventDefault();
18872                 break;
18873             case 37: // left
18874             case 39: // right
18875                 if (!this.keyboardNavigation) {
18876                     break;
18877                 }
18878                 dir = e.keyCode == 37 ? -1 : 1;
18879                 
18880                 if (e.ctrlKey){
18881                     newDate = this.moveYear(this.date, dir);
18882                     newViewDate = this.moveYear(this.viewDate, dir);
18883                 } else if (e.shiftKey){
18884                     newDate = this.moveMonth(this.date, dir);
18885                     newViewDate = this.moveMonth(this.viewDate, dir);
18886                 } else {
18887                     newDate = new Date(this.date);
18888                     newDate.setUTCDate(this.date.getUTCDate() + dir);
18889                     newViewDate = new Date(this.viewDate);
18890                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18891                 }
18892                 if (this.dateWithinRange(newDate)){
18893                     this.date = newDate;
18894                     this.viewDate = newViewDate;
18895                     this.setValue(this.formatDate(this.date));
18896 //                    this.update();
18897                     e.preventDefault();
18898                     dateChanged = true;
18899                 }
18900                 break;
18901             case 38: // up
18902             case 40: // down
18903                 if (!this.keyboardNavigation) {
18904                     break;
18905                 }
18906                 dir = e.keyCode == 38 ? -1 : 1;
18907                 if (e.ctrlKey){
18908                     newDate = this.moveYear(this.date, dir);
18909                     newViewDate = this.moveYear(this.viewDate, dir);
18910                 } else if (e.shiftKey){
18911                     newDate = this.moveMonth(this.date, dir);
18912                     newViewDate = this.moveMonth(this.viewDate, dir);
18913                 } else {
18914                     newDate = new Date(this.date);
18915                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18916                     newViewDate = new Date(this.viewDate);
18917                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18918                 }
18919                 if (this.dateWithinRange(newDate)){
18920                     this.date = newDate;
18921                     this.viewDate = newViewDate;
18922                     this.setValue(this.formatDate(this.date));
18923 //                    this.update();
18924                     e.preventDefault();
18925                     dateChanged = true;
18926                 }
18927                 break;
18928             case 13: // enter
18929                 this.setValue(this.formatDate(this.date));
18930                 this.hide();
18931                 e.preventDefault();
18932                 break;
18933             case 9: // tab
18934                 this.setValue(this.formatDate(this.date));
18935                 this.hide();
18936                 break;
18937             case 16: // shift
18938             case 17: // ctrl
18939             case 18: // alt
18940                 break;
18941             default :
18942                 this.hide();
18943                 
18944         }
18945     },
18946     
18947     
18948     onClick: function(e) 
18949     {
18950         e.stopPropagation();
18951         e.preventDefault();
18952         
18953         var target = e.getTarget();
18954         
18955         if(target.nodeName.toLowerCase() === 'i'){
18956             target = Roo.get(target).dom.parentNode;
18957         }
18958         
18959         var nodeName = target.nodeName;
18960         var className = target.className;
18961         var html = target.innerHTML;
18962         //Roo.log(nodeName);
18963         
18964         switch(nodeName.toLowerCase()) {
18965             case 'th':
18966                 switch(className) {
18967                     case 'switch':
18968                         this.showMode(1);
18969                         break;
18970                     case 'prev':
18971                     case 'next':
18972                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18973                         switch(this.viewMode){
18974                                 case 0:
18975                                         this.viewDate = this.moveMonth(this.viewDate, dir);
18976                                         break;
18977                                 case 1:
18978                                 case 2:
18979                                         this.viewDate = this.moveYear(this.viewDate, dir);
18980                                         break;
18981                         }
18982                         this.fill();
18983                         break;
18984                     case 'today':
18985                         var date = new Date();
18986                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18987 //                        this.fill()
18988                         this.setValue(this.formatDate(this.date));
18989                         
18990                         this.hide();
18991                         break;
18992                 }
18993                 break;
18994             case 'span':
18995                 if (className.indexOf('disabled') < 0) {
18996                     this.viewDate.setUTCDate(1);
18997                     if (className.indexOf('month') > -1) {
18998                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18999                     } else {
19000                         var year = parseInt(html, 10) || 0;
19001                         this.viewDate.setUTCFullYear(year);
19002                         
19003                     }
19004                     
19005                     if(this.singleMode){
19006                         this.setValue(this.formatDate(this.viewDate));
19007                         this.hide();
19008                         return;
19009                     }
19010                     
19011                     this.showMode(-1);
19012                     this.fill();
19013                 }
19014                 break;
19015                 
19016             case 'td':
19017                 //Roo.log(className);
19018                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19019                     var day = parseInt(html, 10) || 1;
19020                     var year = this.viewDate.getUTCFullYear(),
19021                         month = this.viewDate.getUTCMonth();
19022
19023                     if (className.indexOf('old') > -1) {
19024                         if(month === 0 ){
19025                             month = 11;
19026                             year -= 1;
19027                         }else{
19028                             month -= 1;
19029                         }
19030                     } else if (className.indexOf('new') > -1) {
19031                         if (month == 11) {
19032                             month = 0;
19033                             year += 1;
19034                         } else {
19035                             month += 1;
19036                         }
19037                     }
19038                     //Roo.log([year,month,day]);
19039                     this.date = this.UTCDate(year, month, day,0,0,0,0);
19040                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19041 //                    this.fill();
19042                     //Roo.log(this.formatDate(this.date));
19043                     this.setValue(this.formatDate(this.date));
19044                     this.hide();
19045                 }
19046                 break;
19047         }
19048     },
19049     
19050     setStartDate: function(startDate)
19051     {
19052         this.startDate = startDate || -Infinity;
19053         if (this.startDate !== -Infinity) {
19054             this.startDate = this.parseDate(this.startDate);
19055         }
19056         this.update();
19057         this.updateNavArrows();
19058     },
19059
19060     setEndDate: function(endDate)
19061     {
19062         this.endDate = endDate || Infinity;
19063         if (this.endDate !== Infinity) {
19064             this.endDate = this.parseDate(this.endDate);
19065         }
19066         this.update();
19067         this.updateNavArrows();
19068     },
19069     
19070     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19071     {
19072         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19073         if (typeof(this.daysOfWeekDisabled) !== 'object') {
19074             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19075         }
19076         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19077             return parseInt(d, 10);
19078         });
19079         this.update();
19080         this.updateNavArrows();
19081     },
19082     
19083     updateNavArrows: function() 
19084     {
19085         if(this.singleMode){
19086             return;
19087         }
19088         
19089         var d = new Date(this.viewDate),
19090         year = d.getUTCFullYear(),
19091         month = d.getUTCMonth();
19092         
19093         Roo.each(this.picker().select('.prev', true).elements, function(v){
19094             v.show();
19095             switch (this.viewMode) {
19096                 case 0:
19097
19098                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19099                         v.hide();
19100                     }
19101                     break;
19102                 case 1:
19103                 case 2:
19104                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19105                         v.hide();
19106                     }
19107                     break;
19108             }
19109         });
19110         
19111         Roo.each(this.picker().select('.next', true).elements, function(v){
19112             v.show();
19113             switch (this.viewMode) {
19114                 case 0:
19115
19116                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19117                         v.hide();
19118                     }
19119                     break;
19120                 case 1:
19121                 case 2:
19122                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19123                         v.hide();
19124                     }
19125                     break;
19126             }
19127         })
19128     },
19129     
19130     moveMonth: function(date, dir)
19131     {
19132         if (!dir) {
19133             return date;
19134         }
19135         var new_date = new Date(date.valueOf()),
19136         day = new_date.getUTCDate(),
19137         month = new_date.getUTCMonth(),
19138         mag = Math.abs(dir),
19139         new_month, test;
19140         dir = dir > 0 ? 1 : -1;
19141         if (mag == 1){
19142             test = dir == -1
19143             // If going back one month, make sure month is not current month
19144             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19145             ? function(){
19146                 return new_date.getUTCMonth() == month;
19147             }
19148             // If going forward one month, make sure month is as expected
19149             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19150             : function(){
19151                 return new_date.getUTCMonth() != new_month;
19152             };
19153             new_month = month + dir;
19154             new_date.setUTCMonth(new_month);
19155             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19156             if (new_month < 0 || new_month > 11) {
19157                 new_month = (new_month + 12) % 12;
19158             }
19159         } else {
19160             // For magnitudes >1, move one month at a time...
19161             for (var i=0; i<mag; i++) {
19162                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19163                 new_date = this.moveMonth(new_date, dir);
19164             }
19165             // ...then reset the day, keeping it in the new month
19166             new_month = new_date.getUTCMonth();
19167             new_date.setUTCDate(day);
19168             test = function(){
19169                 return new_month != new_date.getUTCMonth();
19170             };
19171         }
19172         // Common date-resetting loop -- if date is beyond end of month, make it
19173         // end of month
19174         while (test()){
19175             new_date.setUTCDate(--day);
19176             new_date.setUTCMonth(new_month);
19177         }
19178         return new_date;
19179     },
19180
19181     moveYear: function(date, dir)
19182     {
19183         return this.moveMonth(date, dir*12);
19184     },
19185
19186     dateWithinRange: function(date)
19187     {
19188         return date >= this.startDate && date <= this.endDate;
19189     },
19190
19191     
19192     remove: function() 
19193     {
19194         this.picker().remove();
19195     },
19196     
19197     validateValue : function(value)
19198     {
19199         if(this.getVisibilityEl().hasClass('hidden')){
19200             return true;
19201         }
19202         
19203         if(value.length < 1)  {
19204             if(this.allowBlank){
19205                 return true;
19206             }
19207             return false;
19208         }
19209         
19210         if(value.length < this.minLength){
19211             return false;
19212         }
19213         if(value.length > this.maxLength){
19214             return false;
19215         }
19216         if(this.vtype){
19217             var vt = Roo.form.VTypes;
19218             if(!vt[this.vtype](value, this)){
19219                 return false;
19220             }
19221         }
19222         if(typeof this.validator == "function"){
19223             var msg = this.validator(value);
19224             if(msg !== true){
19225                 return false;
19226             }
19227         }
19228         
19229         if(this.regex && !this.regex.test(value)){
19230             return false;
19231         }
19232         
19233         if(typeof(this.parseDate(value)) == 'undefined'){
19234             return false;
19235         }
19236         
19237         if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19238             return false;
19239         }      
19240         
19241         if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19242             return false;
19243         } 
19244         
19245         
19246         return true;
19247     },
19248     
19249     setVisible : function(visible)
19250     {
19251         if(!this.getEl()){
19252             return;
19253         }
19254         
19255         this.getEl().removeClass('hidden');
19256         
19257         if(visible){
19258             return;
19259         }
19260         
19261         this.getEl().addClass('hidden');
19262     }
19263    
19264 });
19265
19266 Roo.apply(Roo.bootstrap.DateField,  {
19267     
19268     head : {
19269         tag: 'thead',
19270         cn: [
19271         {
19272             tag: 'tr',
19273             cn: [
19274             {
19275                 tag: 'th',
19276                 cls: 'prev',
19277                 html: '<i class="fa fa-arrow-left"/>'
19278             },
19279             {
19280                 tag: 'th',
19281                 cls: 'switch',
19282                 colspan: '5'
19283             },
19284             {
19285                 tag: 'th',
19286                 cls: 'next',
19287                 html: '<i class="fa fa-arrow-right"/>'
19288             }
19289
19290             ]
19291         }
19292         ]
19293     },
19294     
19295     content : {
19296         tag: 'tbody',
19297         cn: [
19298         {
19299             tag: 'tr',
19300             cn: [
19301             {
19302                 tag: 'td',
19303                 colspan: '7'
19304             }
19305             ]
19306         }
19307         ]
19308     },
19309     
19310     footer : {
19311         tag: 'tfoot',
19312         cn: [
19313         {
19314             tag: 'tr',
19315             cn: [
19316             {
19317                 tag: 'th',
19318                 colspan: '7',
19319                 cls: 'today'
19320             }
19321                     
19322             ]
19323         }
19324         ]
19325     },
19326     
19327     dates:{
19328         en: {
19329             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19330             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19331             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19332             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19333             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19334             today: "Today"
19335         }
19336     },
19337     
19338     modes: [
19339     {
19340         clsName: 'days',
19341         navFnc: 'Month',
19342         navStep: 1
19343     },
19344     {
19345         clsName: 'months',
19346         navFnc: 'FullYear',
19347         navStep: 1
19348     },
19349     {
19350         clsName: 'years',
19351         navFnc: 'FullYear',
19352         navStep: 10
19353     }]
19354 });
19355
19356 Roo.apply(Roo.bootstrap.DateField,  {
19357   
19358     template : {
19359         tag: 'div',
19360         cls: 'datepicker dropdown-menu roo-dynamic',
19361         cn: [
19362         {
19363             tag: 'div',
19364             cls: 'datepicker-days',
19365             cn: [
19366             {
19367                 tag: 'table',
19368                 cls: 'table-condensed',
19369                 cn:[
19370                 Roo.bootstrap.DateField.head,
19371                 {
19372                     tag: 'tbody'
19373                 },
19374                 Roo.bootstrap.DateField.footer
19375                 ]
19376             }
19377             ]
19378         },
19379         {
19380             tag: 'div',
19381             cls: 'datepicker-months',
19382             cn: [
19383             {
19384                 tag: 'table',
19385                 cls: 'table-condensed',
19386                 cn:[
19387                 Roo.bootstrap.DateField.head,
19388                 Roo.bootstrap.DateField.content,
19389                 Roo.bootstrap.DateField.footer
19390                 ]
19391             }
19392             ]
19393         },
19394         {
19395             tag: 'div',
19396             cls: 'datepicker-years',
19397             cn: [
19398             {
19399                 tag: 'table',
19400                 cls: 'table-condensed',
19401                 cn:[
19402                 Roo.bootstrap.DateField.head,
19403                 Roo.bootstrap.DateField.content,
19404                 Roo.bootstrap.DateField.footer
19405                 ]
19406             }
19407             ]
19408         }
19409         ]
19410     }
19411 });
19412
19413  
19414
19415  /*
19416  * - LGPL
19417  *
19418  * TimeField
19419  * 
19420  */
19421
19422 /**
19423  * @class Roo.bootstrap.TimeField
19424  * @extends Roo.bootstrap.Input
19425  * Bootstrap DateField class
19426  * 
19427  * 
19428  * @constructor
19429  * Create a new TimeField
19430  * @param {Object} config The config object
19431  */
19432
19433 Roo.bootstrap.TimeField = function(config){
19434     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19435     this.addEvents({
19436             /**
19437              * @event show
19438              * Fires when this field show.
19439              * @param {Roo.bootstrap.DateField} thisthis
19440              * @param {Mixed} date The date value
19441              */
19442             show : true,
19443             /**
19444              * @event show
19445              * Fires when this field hide.
19446              * @param {Roo.bootstrap.DateField} this
19447              * @param {Mixed} date The date value
19448              */
19449             hide : true,
19450             /**
19451              * @event select
19452              * Fires when select a date.
19453              * @param {Roo.bootstrap.DateField} this
19454              * @param {Mixed} date The date value
19455              */
19456             select : true
19457         });
19458 };
19459
19460 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
19461     
19462     /**
19463      * @cfg {String} format
19464      * The default time format string which can be overriden for localization support.  The format must be
19465      * valid according to {@link Date#parseDate} (defaults to 'H:i').
19466      */
19467     format : "H:i",
19468        
19469     onRender: function(ct, position)
19470     {
19471         
19472         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19473                 
19474         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19475         
19476         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19477         
19478         this.pop = this.picker().select('>.datepicker-time',true).first();
19479         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19480         
19481         this.picker().on('mousedown', this.onMousedown, this);
19482         this.picker().on('click', this.onClick, this);
19483         
19484         this.picker().addClass('datepicker-dropdown');
19485     
19486         this.fillTime();
19487         this.update();
19488             
19489         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19490         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19491         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19492         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19493         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19494         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19495
19496     },
19497     
19498     fireKey: function(e){
19499         if (!this.picker().isVisible()){
19500             if (e.keyCode == 27) { // allow escape to hide and re-show picker
19501                 this.show();
19502             }
19503             return;
19504         }
19505
19506         e.preventDefault();
19507         
19508         switch(e.keyCode){
19509             case 27: // escape
19510                 this.hide();
19511                 break;
19512             case 37: // left
19513             case 39: // right
19514                 this.onTogglePeriod();
19515                 break;
19516             case 38: // up
19517                 this.onIncrementMinutes();
19518                 break;
19519             case 40: // down
19520                 this.onDecrementMinutes();
19521                 break;
19522             case 13: // enter
19523             case 9: // tab
19524                 this.setTime();
19525                 break;
19526         }
19527     },
19528     
19529     onClick: function(e) {
19530         e.stopPropagation();
19531         e.preventDefault();
19532     },
19533     
19534     picker : function()
19535     {
19536         return this.el.select('.datepicker', true).first();
19537     },
19538     
19539     fillTime: function()
19540     {    
19541         var time = this.pop.select('tbody', true).first();
19542         
19543         time.dom.innerHTML = '';
19544         
19545         time.createChild({
19546             tag: 'tr',
19547             cn: [
19548                 {
19549                     tag: 'td',
19550                     cn: [
19551                         {
19552                             tag: 'a',
19553                             href: '#',
19554                             cls: 'btn',
19555                             cn: [
19556                                 {
19557                                     tag: 'span',
19558                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
19559                                 }
19560                             ]
19561                         } 
19562                     ]
19563                 },
19564                 {
19565                     tag: 'td',
19566                     cls: 'separator'
19567                 },
19568                 {
19569                     tag: 'td',
19570                     cn: [
19571                         {
19572                             tag: 'a',
19573                             href: '#',
19574                             cls: 'btn',
19575                             cn: [
19576                                 {
19577                                     tag: 'span',
19578                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
19579                                 }
19580                             ]
19581                         }
19582                     ]
19583                 },
19584                 {
19585                     tag: 'td',
19586                     cls: 'separator'
19587                 }
19588             ]
19589         });
19590         
19591         time.createChild({
19592             tag: 'tr',
19593             cn: [
19594                 {
19595                     tag: 'td',
19596                     cn: [
19597                         {
19598                             tag: 'span',
19599                             cls: 'timepicker-hour',
19600                             html: '00'
19601                         }  
19602                     ]
19603                 },
19604                 {
19605                     tag: 'td',
19606                     cls: 'separator',
19607                     html: ':'
19608                 },
19609                 {
19610                     tag: 'td',
19611                     cn: [
19612                         {
19613                             tag: 'span',
19614                             cls: 'timepicker-minute',
19615                             html: '00'
19616                         }  
19617                     ]
19618                 },
19619                 {
19620                     tag: 'td',
19621                     cls: 'separator'
19622                 },
19623                 {
19624                     tag: 'td',
19625                     cn: [
19626                         {
19627                             tag: 'button',
19628                             type: 'button',
19629                             cls: 'btn btn-primary period',
19630                             html: 'AM'
19631                             
19632                         }
19633                     ]
19634                 }
19635             ]
19636         });
19637         
19638         time.createChild({
19639             tag: 'tr',
19640             cn: [
19641                 {
19642                     tag: 'td',
19643                     cn: [
19644                         {
19645                             tag: 'a',
19646                             href: '#',
19647                             cls: 'btn',
19648                             cn: [
19649                                 {
19650                                     tag: 'span',
19651                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
19652                                 }
19653                             ]
19654                         }
19655                     ]
19656                 },
19657                 {
19658                     tag: 'td',
19659                     cls: 'separator'
19660                 },
19661                 {
19662                     tag: 'td',
19663                     cn: [
19664                         {
19665                             tag: 'a',
19666                             href: '#',
19667                             cls: 'btn',
19668                             cn: [
19669                                 {
19670                                     tag: 'span',
19671                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
19672                                 }
19673                             ]
19674                         }
19675                     ]
19676                 },
19677                 {
19678                     tag: 'td',
19679                     cls: 'separator'
19680                 }
19681             ]
19682         });
19683         
19684     },
19685     
19686     update: function()
19687     {
19688         
19689         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19690         
19691         this.fill();
19692     },
19693     
19694     fill: function() 
19695     {
19696         var hours = this.time.getHours();
19697         var minutes = this.time.getMinutes();
19698         var period = 'AM';
19699         
19700         if(hours > 11){
19701             period = 'PM';
19702         }
19703         
19704         if(hours == 0){
19705             hours = 12;
19706         }
19707         
19708         
19709         if(hours > 12){
19710             hours = hours - 12;
19711         }
19712         
19713         if(hours < 10){
19714             hours = '0' + hours;
19715         }
19716         
19717         if(minutes < 10){
19718             minutes = '0' + minutes;
19719         }
19720         
19721         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19722         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19723         this.pop.select('button', true).first().dom.innerHTML = period;
19724         
19725     },
19726     
19727     place: function()
19728     {   
19729         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19730         
19731         var cls = ['bottom'];
19732         
19733         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19734             cls.pop();
19735             cls.push('top');
19736         }
19737         
19738         cls.push('right');
19739         
19740         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19741             cls.pop();
19742             cls.push('left');
19743         }
19744         
19745         this.picker().addClass(cls.join('-'));
19746         
19747         var _this = this;
19748         
19749         Roo.each(cls, function(c){
19750             if(c == 'bottom'){
19751                 _this.picker().setTop(_this.inputEl().getHeight());
19752                 return;
19753             }
19754             if(c == 'top'){
19755                 _this.picker().setTop(0 - _this.picker().getHeight());
19756                 return;
19757             }
19758             
19759             if(c == 'left'){
19760                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19761                 return;
19762             }
19763             if(c == 'right'){
19764                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19765                 return;
19766             }
19767         });
19768         
19769     },
19770   
19771     onFocus : function()
19772     {
19773         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19774         this.show();
19775     },
19776     
19777     onBlur : function()
19778     {
19779         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19780         this.hide();
19781     },
19782     
19783     show : function()
19784     {
19785         this.picker().show();
19786         this.pop.show();
19787         this.update();
19788         this.place();
19789         
19790         this.fireEvent('show', this, this.date);
19791     },
19792     
19793     hide : function()
19794     {
19795         this.picker().hide();
19796         this.pop.hide();
19797         
19798         this.fireEvent('hide', this, this.date);
19799     },
19800     
19801     setTime : function()
19802     {
19803         this.hide();
19804         this.setValue(this.time.format(this.format));
19805         
19806         this.fireEvent('select', this, this.date);
19807         
19808         
19809     },
19810     
19811     onMousedown: function(e){
19812         e.stopPropagation();
19813         e.preventDefault();
19814     },
19815     
19816     onIncrementHours: function()
19817     {
19818         Roo.log('onIncrementHours');
19819         this.time = this.time.add(Date.HOUR, 1);
19820         this.update();
19821         
19822     },
19823     
19824     onDecrementHours: function()
19825     {
19826         Roo.log('onDecrementHours');
19827         this.time = this.time.add(Date.HOUR, -1);
19828         this.update();
19829     },
19830     
19831     onIncrementMinutes: function()
19832     {
19833         Roo.log('onIncrementMinutes');
19834         this.time = this.time.add(Date.MINUTE, 1);
19835         this.update();
19836     },
19837     
19838     onDecrementMinutes: function()
19839     {
19840         Roo.log('onDecrementMinutes');
19841         this.time = this.time.add(Date.MINUTE, -1);
19842         this.update();
19843     },
19844     
19845     onTogglePeriod: function()
19846     {
19847         Roo.log('onTogglePeriod');
19848         this.time = this.time.add(Date.HOUR, 12);
19849         this.update();
19850     }
19851     
19852    
19853 });
19854
19855 Roo.apply(Roo.bootstrap.TimeField,  {
19856     
19857     content : {
19858         tag: 'tbody',
19859         cn: [
19860             {
19861                 tag: 'tr',
19862                 cn: [
19863                 {
19864                     tag: 'td',
19865                     colspan: '7'
19866                 }
19867                 ]
19868             }
19869         ]
19870     },
19871     
19872     footer : {
19873         tag: 'tfoot',
19874         cn: [
19875             {
19876                 tag: 'tr',
19877                 cn: [
19878                 {
19879                     tag: 'th',
19880                     colspan: '7',
19881                     cls: '',
19882                     cn: [
19883                         {
19884                             tag: 'button',
19885                             cls: 'btn btn-info ok',
19886                             html: 'OK'
19887                         }
19888                     ]
19889                 }
19890
19891                 ]
19892             }
19893         ]
19894     }
19895 });
19896
19897 Roo.apply(Roo.bootstrap.TimeField,  {
19898   
19899     template : {
19900         tag: 'div',
19901         cls: 'datepicker dropdown-menu',
19902         cn: [
19903             {
19904                 tag: 'div',
19905                 cls: 'datepicker-time',
19906                 cn: [
19907                 {
19908                     tag: 'table',
19909                     cls: 'table-condensed',
19910                     cn:[
19911                     Roo.bootstrap.TimeField.content,
19912                     Roo.bootstrap.TimeField.footer
19913                     ]
19914                 }
19915                 ]
19916             }
19917         ]
19918     }
19919 });
19920
19921  
19922
19923  /*
19924  * - LGPL
19925  *
19926  * MonthField
19927  * 
19928  */
19929
19930 /**
19931  * @class Roo.bootstrap.MonthField
19932  * @extends Roo.bootstrap.Input
19933  * Bootstrap MonthField class
19934  * 
19935  * @cfg {String} language default en
19936  * 
19937  * @constructor
19938  * Create a new MonthField
19939  * @param {Object} config The config object
19940  */
19941
19942 Roo.bootstrap.MonthField = function(config){
19943     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19944     
19945     this.addEvents({
19946         /**
19947          * @event show
19948          * Fires when this field show.
19949          * @param {Roo.bootstrap.MonthField} this
19950          * @param {Mixed} date The date value
19951          */
19952         show : true,
19953         /**
19954          * @event show
19955          * Fires when this field hide.
19956          * @param {Roo.bootstrap.MonthField} this
19957          * @param {Mixed} date The date value
19958          */
19959         hide : true,
19960         /**
19961          * @event select
19962          * Fires when select a date.
19963          * @param {Roo.bootstrap.MonthField} this
19964          * @param {String} oldvalue The old value
19965          * @param {String} newvalue The new value
19966          */
19967         select : true
19968     });
19969 };
19970
19971 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
19972     
19973     onRender: function(ct, position)
19974     {
19975         
19976         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19977         
19978         this.language = this.language || 'en';
19979         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19980         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19981         
19982         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19983         this.isInline = false;
19984         this.isInput = true;
19985         this.component = this.el.select('.add-on', true).first() || false;
19986         this.component = (this.component && this.component.length === 0) ? false : this.component;
19987         this.hasInput = this.component && this.inputEL().length;
19988         
19989         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19990         
19991         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19992         
19993         this.picker().on('mousedown', this.onMousedown, this);
19994         this.picker().on('click', this.onClick, this);
19995         
19996         this.picker().addClass('datepicker-dropdown');
19997         
19998         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19999             v.setStyle('width', '189px');
20000         });
20001         
20002         this.fillMonths();
20003         
20004         this.update();
20005         
20006         if(this.isInline) {
20007             this.show();
20008         }
20009         
20010     },
20011     
20012     setValue: function(v, suppressEvent)
20013     {   
20014         var o = this.getValue();
20015         
20016         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20017         
20018         this.update();
20019
20020         if(suppressEvent !== true){
20021             this.fireEvent('select', this, o, v);
20022         }
20023         
20024     },
20025     
20026     getValue: function()
20027     {
20028         return this.value;
20029     },
20030     
20031     onClick: function(e) 
20032     {
20033         e.stopPropagation();
20034         e.preventDefault();
20035         
20036         var target = e.getTarget();
20037         
20038         if(target.nodeName.toLowerCase() === 'i'){
20039             target = Roo.get(target).dom.parentNode;
20040         }
20041         
20042         var nodeName = target.nodeName;
20043         var className = target.className;
20044         var html = target.innerHTML;
20045         
20046         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20047             return;
20048         }
20049         
20050         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20051         
20052         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20053         
20054         this.hide();
20055                         
20056     },
20057     
20058     picker : function()
20059     {
20060         return this.pickerEl;
20061     },
20062     
20063     fillMonths: function()
20064     {    
20065         var i = 0;
20066         var months = this.picker().select('>.datepicker-months td', true).first();
20067         
20068         months.dom.innerHTML = '';
20069         
20070         while (i < 12) {
20071             var month = {
20072                 tag: 'span',
20073                 cls: 'month',
20074                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20075             };
20076             
20077             months.createChild(month);
20078         }
20079         
20080     },
20081     
20082     update: function()
20083     {
20084         var _this = this;
20085         
20086         if(typeof(this.vIndex) == 'undefined' && this.value.length){
20087             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20088         }
20089         
20090         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20091             e.removeClass('active');
20092             
20093             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20094                 e.addClass('active');
20095             }
20096         })
20097     },
20098     
20099     place: function()
20100     {
20101         if(this.isInline) {
20102             return;
20103         }
20104         
20105         this.picker().removeClass(['bottom', 'top']);
20106         
20107         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20108             /*
20109              * place to the top of element!
20110              *
20111              */
20112             
20113             this.picker().addClass('top');
20114             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20115             
20116             return;
20117         }
20118         
20119         this.picker().addClass('bottom');
20120         
20121         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20122     },
20123     
20124     onFocus : function()
20125     {
20126         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20127         this.show();
20128     },
20129     
20130     onBlur : function()
20131     {
20132         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20133         
20134         var d = this.inputEl().getValue();
20135         
20136         this.setValue(d);
20137                 
20138         this.hide();
20139     },
20140     
20141     show : function()
20142     {
20143         this.picker().show();
20144         this.picker().select('>.datepicker-months', true).first().show();
20145         this.update();
20146         this.place();
20147         
20148         this.fireEvent('show', this, this.date);
20149     },
20150     
20151     hide : function()
20152     {
20153         if(this.isInline) {
20154             return;
20155         }
20156         this.picker().hide();
20157         this.fireEvent('hide', this, this.date);
20158         
20159     },
20160     
20161     onMousedown: function(e)
20162     {
20163         e.stopPropagation();
20164         e.preventDefault();
20165     },
20166     
20167     keyup: function(e)
20168     {
20169         Roo.bootstrap.MonthField.superclass.keyup.call(this);
20170         this.update();
20171     },
20172
20173     fireKey: function(e)
20174     {
20175         if (!this.picker().isVisible()){
20176             if (e.keyCode == 27)   {// allow escape to hide and re-show picker
20177                 this.show();
20178             }
20179             return;
20180         }
20181         
20182         var dir;
20183         
20184         switch(e.keyCode){
20185             case 27: // escape
20186                 this.hide();
20187                 e.preventDefault();
20188                 break;
20189             case 37: // left
20190             case 39: // right
20191                 dir = e.keyCode == 37 ? -1 : 1;
20192                 
20193                 this.vIndex = this.vIndex + dir;
20194                 
20195                 if(this.vIndex < 0){
20196                     this.vIndex = 0;
20197                 }
20198                 
20199                 if(this.vIndex > 11){
20200                     this.vIndex = 11;
20201                 }
20202                 
20203                 if(isNaN(this.vIndex)){
20204                     this.vIndex = 0;
20205                 }
20206                 
20207                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20208                 
20209                 break;
20210             case 38: // up
20211             case 40: // down
20212                 
20213                 dir = e.keyCode == 38 ? -1 : 1;
20214                 
20215                 this.vIndex = this.vIndex + dir * 4;
20216                 
20217                 if(this.vIndex < 0){
20218                     this.vIndex = 0;
20219                 }
20220                 
20221                 if(this.vIndex > 11){
20222                     this.vIndex = 11;
20223                 }
20224                 
20225                 if(isNaN(this.vIndex)){
20226                     this.vIndex = 0;
20227                 }
20228                 
20229                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20230                 break;
20231                 
20232             case 13: // enter
20233                 
20234                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20235                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20236                 }
20237                 
20238                 this.hide();
20239                 e.preventDefault();
20240                 break;
20241             case 9: // tab
20242                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20243                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20244                 }
20245                 this.hide();
20246                 break;
20247             case 16: // shift
20248             case 17: // ctrl
20249             case 18: // alt
20250                 break;
20251             default :
20252                 this.hide();
20253                 
20254         }
20255     },
20256     
20257     remove: function() 
20258     {
20259         this.picker().remove();
20260     }
20261    
20262 });
20263
20264 Roo.apply(Roo.bootstrap.MonthField,  {
20265     
20266     content : {
20267         tag: 'tbody',
20268         cn: [
20269         {
20270             tag: 'tr',
20271             cn: [
20272             {
20273                 tag: 'td',
20274                 colspan: '7'
20275             }
20276             ]
20277         }
20278         ]
20279     },
20280     
20281     dates:{
20282         en: {
20283             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20284             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20285         }
20286     }
20287 });
20288
20289 Roo.apply(Roo.bootstrap.MonthField,  {
20290   
20291     template : {
20292         tag: 'div',
20293         cls: 'datepicker dropdown-menu roo-dynamic',
20294         cn: [
20295             {
20296                 tag: 'div',
20297                 cls: 'datepicker-months',
20298                 cn: [
20299                 {
20300                     tag: 'table',
20301                     cls: 'table-condensed',
20302                     cn:[
20303                         Roo.bootstrap.DateField.content
20304                     ]
20305                 }
20306                 ]
20307             }
20308         ]
20309     }
20310 });
20311
20312  
20313
20314  
20315  /*
20316  * - LGPL
20317  *
20318  * CheckBox
20319  * 
20320  */
20321
20322 /**
20323  * @class Roo.bootstrap.CheckBox
20324  * @extends Roo.bootstrap.Input
20325  * Bootstrap CheckBox class
20326  * 
20327  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20328  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20329  * @cfg {String} boxLabel The text that appears beside the checkbox
20330  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20331  * @cfg {Boolean} checked initnal the element
20332  * @cfg {Boolean} inline inline the element (default false)
20333  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20334  * @cfg {String} tooltip label tooltip
20335  * 
20336  * @constructor
20337  * Create a new CheckBox
20338  * @param {Object} config The config object
20339  */
20340
20341 Roo.bootstrap.CheckBox = function(config){
20342     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20343    
20344     this.addEvents({
20345         /**
20346         * @event check
20347         * Fires when the element is checked or unchecked.
20348         * @param {Roo.bootstrap.CheckBox} this This input
20349         * @param {Boolean} checked The new checked value
20350         */
20351        check : true,
20352        /**
20353         * @event click
20354         * Fires when the element is click.
20355         * @param {Roo.bootstrap.CheckBox} this This input
20356         */
20357        click : true
20358     });
20359     
20360 };
20361
20362 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
20363   
20364     inputType: 'checkbox',
20365     inputValue: 1,
20366     valueOff: 0,
20367     boxLabel: false,
20368     checked: false,
20369     weight : false,
20370     inline: false,
20371     tooltip : '',
20372     
20373     getAutoCreate : function()
20374     {
20375         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20376         
20377         var id = Roo.id();
20378         
20379         var cfg = {};
20380         
20381         cfg.cls = 'form-group ' + this.inputType; //input-group
20382         
20383         if(this.inline){
20384             cfg.cls += ' ' + this.inputType + '-inline';
20385         }
20386         
20387         var input =  {
20388             tag: 'input',
20389             id : id,
20390             type : this.inputType,
20391             value : this.inputValue,
20392             cls : 'roo-' + this.inputType, //'form-box',
20393             placeholder : this.placeholder || ''
20394             
20395         };
20396         
20397         if(this.inputType != 'radio'){
20398             var hidden =  {
20399                 tag: 'input',
20400                 type : 'hidden',
20401                 cls : 'roo-hidden-value',
20402                 value : this.checked ? this.inputValue : this.valueOff
20403             };
20404         }
20405         
20406             
20407         if (this.weight) { // Validity check?
20408             cfg.cls += " " + this.inputType + "-" + this.weight;
20409         }
20410         
20411         if (this.disabled) {
20412             input.disabled=true;
20413         }
20414         
20415         if(this.checked){
20416             input.checked = this.checked;
20417         }
20418         
20419         if (this.name) {
20420             
20421             input.name = this.name;
20422             
20423             if(this.inputType != 'radio'){
20424                 hidden.name = this.name;
20425                 input.name = '_hidden_' + this.name;
20426             }
20427         }
20428         
20429         if (this.size) {
20430             input.cls += ' input-' + this.size;
20431         }
20432         
20433         var settings=this;
20434         
20435         ['xs','sm','md','lg'].map(function(size){
20436             if (settings[size]) {
20437                 cfg.cls += ' col-' + size + '-' + settings[size];
20438             }
20439         });
20440         
20441         var inputblock = input;
20442          
20443         if (this.before || this.after) {
20444             
20445             inputblock = {
20446                 cls : 'input-group',
20447                 cn :  [] 
20448             };
20449             
20450             if (this.before) {
20451                 inputblock.cn.push({
20452                     tag :'span',
20453                     cls : 'input-group-addon',
20454                     html : this.before
20455                 });
20456             }
20457             
20458             inputblock.cn.push(input);
20459             
20460             if(this.inputType != 'radio'){
20461                 inputblock.cn.push(hidden);
20462             }
20463             
20464             if (this.after) {
20465                 inputblock.cn.push({
20466                     tag :'span',
20467                     cls : 'input-group-addon',
20468                     html : this.after
20469                 });
20470             }
20471             
20472         }
20473         
20474         if (align ==='left' && this.fieldLabel.length) {
20475 //                Roo.log("left and has label");
20476             cfg.cn = [
20477                 {
20478                     tag: 'label',
20479                     'for' :  id,
20480                     cls : 'control-label',
20481                     html : this.fieldLabel
20482                 },
20483                 {
20484                     cls : "", 
20485                     cn: [
20486                         inputblock
20487                     ]
20488                 }
20489             ];
20490             
20491             if(this.labelWidth > 12){
20492                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20493             }
20494             
20495             if(this.labelWidth < 13 && this.labelmd == 0){
20496                 this.labelmd = this.labelWidth;
20497             }
20498             
20499             if(this.labellg > 0){
20500                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20501                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20502             }
20503             
20504             if(this.labelmd > 0){
20505                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20506                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20507             }
20508             
20509             if(this.labelsm > 0){
20510                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20511                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20512             }
20513             
20514             if(this.labelxs > 0){
20515                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20516                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20517             }
20518             
20519         } else if ( this.fieldLabel.length) {
20520 //                Roo.log(" label");
20521                 cfg.cn = [
20522                    
20523                     {
20524                         tag: this.boxLabel ? 'span' : 'label',
20525                         'for': id,
20526                         cls: 'control-label box-input-label',
20527                         //cls : 'input-group-addon',
20528                         html : this.fieldLabel
20529                     },
20530                     
20531                     inputblock
20532                     
20533                 ];
20534
20535         } else {
20536             
20537 //                Roo.log(" no label && no align");
20538                 cfg.cn = [  inputblock ] ;
20539                 
20540                 
20541         }
20542         
20543         if(this.boxLabel){
20544              var boxLabelCfg = {
20545                 tag: 'label',
20546                 //'for': id, // box label is handled by onclick - so no for...
20547                 cls: 'box-label',
20548                 html: this.boxLabel
20549             };
20550             
20551             if(this.tooltip){
20552                 boxLabelCfg.tooltip = this.tooltip;
20553             }
20554              
20555             cfg.cn.push(boxLabelCfg);
20556         }
20557         
20558         if(this.inputType != 'radio'){
20559             cfg.cn.push(hidden);
20560         }
20561         
20562         return cfg;
20563         
20564     },
20565     
20566     /**
20567      * return the real input element.
20568      */
20569     inputEl: function ()
20570     {
20571         return this.el.select('input.roo-' + this.inputType,true).first();
20572     },
20573     hiddenEl: function ()
20574     {
20575         return this.el.select('input.roo-hidden-value',true).first();
20576     },
20577     
20578     labelEl: function()
20579     {
20580         return this.el.select('label.control-label',true).first();
20581     },
20582     /* depricated... */
20583     
20584     label: function()
20585     {
20586         return this.labelEl();
20587     },
20588     
20589     boxLabelEl: function()
20590     {
20591         return this.el.select('label.box-label',true).first();
20592     },
20593     
20594     initEvents : function()
20595     {
20596 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20597         
20598         this.inputEl().on('click', this.onClick,  this);
20599         
20600         if (this.boxLabel) { 
20601             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
20602         }
20603         
20604         this.startValue = this.getValue();
20605         
20606         if(this.groupId){
20607             Roo.bootstrap.CheckBox.register(this);
20608         }
20609     },
20610     
20611     onClick : function(e)
20612     {   
20613         if(this.fireEvent('click', this, e) !== false){
20614             this.setChecked(!this.checked);
20615         }
20616         
20617     },
20618     
20619     setChecked : function(state,suppressEvent)
20620     {
20621         this.startValue = this.getValue();
20622
20623         if(this.inputType == 'radio'){
20624             
20625             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20626                 e.dom.checked = false;
20627             });
20628             
20629             this.inputEl().dom.checked = true;
20630             
20631             this.inputEl().dom.value = this.inputValue;
20632             
20633             if(suppressEvent !== true){
20634                 this.fireEvent('check', this, true);
20635             }
20636             
20637             this.validate();
20638             
20639             return;
20640         }
20641         
20642         this.checked = state;
20643         
20644         this.inputEl().dom.checked = state;
20645         
20646         
20647         this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20648         
20649         if(suppressEvent !== true){
20650             this.fireEvent('check', this, state);
20651         }
20652         
20653         this.validate();
20654     },
20655     
20656     getValue : function()
20657     {
20658         if(this.inputType == 'radio'){
20659             return this.getGroupValue();
20660         }
20661         
20662         return this.hiddenEl().dom.value;
20663         
20664     },
20665     
20666     getGroupValue : function()
20667     {
20668         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20669             return '';
20670         }
20671         
20672         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20673     },
20674     
20675     setValue : function(v,suppressEvent)
20676     {
20677         if(this.inputType == 'radio'){
20678             this.setGroupValue(v, suppressEvent);
20679             return;
20680         }
20681         
20682         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20683         
20684         this.validate();
20685     },
20686     
20687     setGroupValue : function(v, suppressEvent)
20688     {
20689         this.startValue = this.getValue();
20690         
20691         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20692             e.dom.checked = false;
20693             
20694             if(e.dom.value == v){
20695                 e.dom.checked = true;
20696             }
20697         });
20698         
20699         if(suppressEvent !== true){
20700             this.fireEvent('check', this, true);
20701         }
20702
20703         this.validate();
20704         
20705         return;
20706     },
20707     
20708     validate : function()
20709     {
20710         if(this.getVisibilityEl().hasClass('hidden')){
20711             return true;
20712         }
20713         
20714         if(
20715                 this.disabled || 
20716                 (this.inputType == 'radio' && this.validateRadio()) ||
20717                 (this.inputType == 'checkbox' && this.validateCheckbox())
20718         ){
20719             this.markValid();
20720             return true;
20721         }
20722         
20723         this.markInvalid();
20724         return false;
20725     },
20726     
20727     validateRadio : function()
20728     {
20729         if(this.getVisibilityEl().hasClass('hidden')){
20730             return true;
20731         }
20732         
20733         if(this.allowBlank){
20734             return true;
20735         }
20736         
20737         var valid = false;
20738         
20739         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20740             if(!e.dom.checked){
20741                 return;
20742             }
20743             
20744             valid = true;
20745             
20746             return false;
20747         });
20748         
20749         return valid;
20750     },
20751     
20752     validateCheckbox : function()
20753     {
20754         if(!this.groupId){
20755             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20756             //return (this.getValue() == this.inputValue) ? true : false;
20757         }
20758         
20759         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20760         
20761         if(!group){
20762             return false;
20763         }
20764         
20765         var r = false;
20766         
20767         for(var i in group){
20768             if(group[i].el.isVisible(true)){
20769                 r = false;
20770                 break;
20771             }
20772             
20773             r = true;
20774         }
20775         
20776         for(var i in group){
20777             if(r){
20778                 break;
20779             }
20780             
20781             r = (group[i].getValue() == group[i].inputValue) ? true : false;
20782         }
20783         
20784         return r;
20785     },
20786     
20787     /**
20788      * Mark this field as valid
20789      */
20790     markValid : function()
20791     {
20792         var _this = this;
20793         
20794         this.fireEvent('valid', this);
20795         
20796         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20797         
20798         if(this.groupId){
20799             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20800         }
20801         
20802         if(label){
20803             label.markValid();
20804         }
20805
20806         if(this.inputType == 'radio'){
20807             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20808                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20809                 e.findParent('.form-group', false, true).addClass(_this.validClass);
20810             });
20811             
20812             return;
20813         }
20814
20815         if(!this.groupId){
20816             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20817             this.el.findParent('.form-group', false, true).addClass(this.validClass);
20818             return;
20819         }
20820         
20821         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20822         
20823         if(!group){
20824             return;
20825         }
20826         
20827         for(var i in group){
20828             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20829             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20830         }
20831     },
20832     
20833      /**
20834      * Mark this field as invalid
20835      * @param {String} msg The validation message
20836      */
20837     markInvalid : function(msg)
20838     {
20839         if(this.allowBlank){
20840             return;
20841         }
20842         
20843         var _this = this;
20844         
20845         this.fireEvent('invalid', this, msg);
20846         
20847         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20848         
20849         if(this.groupId){
20850             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20851         }
20852         
20853         if(label){
20854             label.markInvalid();
20855         }
20856             
20857         if(this.inputType == 'radio'){
20858             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20859                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20860                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20861             });
20862             
20863             return;
20864         }
20865         
20866         if(!this.groupId){
20867             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20868             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20869             return;
20870         }
20871         
20872         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20873         
20874         if(!group){
20875             return;
20876         }
20877         
20878         for(var i in group){
20879             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20880             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20881         }
20882         
20883     },
20884     
20885     clearInvalid : function()
20886     {
20887         Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20888         
20889         // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20890         
20891         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20892         
20893         if (label && label.iconEl) {
20894             label.iconEl.removeClass(label.validClass);
20895             label.iconEl.removeClass(label.invalidClass);
20896         }
20897     },
20898     
20899     disable : function()
20900     {
20901         if(this.inputType != 'radio'){
20902             Roo.bootstrap.CheckBox.superclass.disable.call(this);
20903             return;
20904         }
20905         
20906         var _this = this;
20907         
20908         if(this.rendered){
20909             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20910                 _this.getActionEl().addClass(this.disabledClass);
20911                 e.dom.disabled = true;
20912             });
20913         }
20914         
20915         this.disabled = true;
20916         this.fireEvent("disable", this);
20917         return this;
20918     },
20919
20920     enable : function()
20921     {
20922         if(this.inputType != 'radio'){
20923             Roo.bootstrap.CheckBox.superclass.enable.call(this);
20924             return;
20925         }
20926         
20927         var _this = this;
20928         
20929         if(this.rendered){
20930             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20931                 _this.getActionEl().removeClass(this.disabledClass);
20932                 e.dom.disabled = false;
20933             });
20934         }
20935         
20936         this.disabled = false;
20937         this.fireEvent("enable", this);
20938         return this;
20939     },
20940     
20941     setBoxLabel : function(v)
20942     {
20943         this.boxLabel = v;
20944         
20945         if(this.rendered){
20946             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20947         }
20948     }
20949
20950 });
20951
20952 Roo.apply(Roo.bootstrap.CheckBox, {
20953     
20954     groups: {},
20955     
20956      /**
20957     * register a CheckBox Group
20958     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20959     */
20960     register : function(checkbox)
20961     {
20962         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20963             this.groups[checkbox.groupId] = {};
20964         }
20965         
20966         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20967             return;
20968         }
20969         
20970         this.groups[checkbox.groupId][checkbox.name] = checkbox;
20971         
20972     },
20973     /**
20974     * fetch a CheckBox Group based on the group ID
20975     * @param {string} the group ID
20976     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20977     */
20978     get: function(groupId) {
20979         if (typeof(this.groups[groupId]) == 'undefined') {
20980             return false;
20981         }
20982         
20983         return this.groups[groupId] ;
20984     }
20985     
20986     
20987 });
20988 /*
20989  * - LGPL
20990  *
20991  * RadioItem
20992  * 
20993  */
20994
20995 /**
20996  * @class Roo.bootstrap.Radio
20997  * @extends Roo.bootstrap.Component
20998  * Bootstrap Radio class
20999  * @cfg {String} boxLabel - the label associated
21000  * @cfg {String} value - the value of radio
21001  * 
21002  * @constructor
21003  * Create a new Radio
21004  * @param {Object} config The config object
21005  */
21006 Roo.bootstrap.Radio = function(config){
21007     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21008     
21009 };
21010
21011 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21012     
21013     boxLabel : '',
21014     
21015     value : '',
21016     
21017     getAutoCreate : function()
21018     {
21019         var cfg = {
21020             tag : 'div',
21021             cls : 'form-group radio',
21022             cn : [
21023                 {
21024                     tag : 'label',
21025                     cls : 'box-label',
21026                     html : this.boxLabel
21027                 }
21028             ]
21029         };
21030         
21031         return cfg;
21032     },
21033     
21034     initEvents : function() 
21035     {
21036         this.parent().register(this);
21037         
21038         this.el.on('click', this.onClick, this);
21039         
21040     },
21041     
21042     onClick : function(e)
21043     {
21044         if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21045             this.setChecked(true);
21046         }
21047     },
21048     
21049     setChecked : function(state, suppressEvent)
21050     {
21051         this.parent().setValue(this.value, suppressEvent);
21052         
21053     },
21054     
21055     setBoxLabel : function(v)
21056     {
21057         this.boxLabel = v;
21058         
21059         if(this.rendered){
21060             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21061         }
21062     }
21063     
21064 });
21065  
21066
21067  /*
21068  * - LGPL
21069  *
21070  * Input
21071  * 
21072  */
21073
21074 /**
21075  * @class Roo.bootstrap.SecurePass
21076  * @extends Roo.bootstrap.Input
21077  * Bootstrap SecurePass class
21078  *
21079  * 
21080  * @constructor
21081  * Create a new SecurePass
21082  * @param {Object} config The config object
21083  */
21084  
21085 Roo.bootstrap.SecurePass = function (config) {
21086     // these go here, so the translation tool can replace them..
21087     this.errors = {
21088         PwdEmpty: "Please type a password, and then retype it to confirm.",
21089         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21090         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21091         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21092         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21093         FNInPwd: "Your password can't contain your first name. Please type a different password.",
21094         LNInPwd: "Your password can't contain your last name. Please type a different password.",
21095         TooWeak: "Your password is Too Weak."
21096     },
21097     this.meterLabel = "Password strength:";
21098     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21099     this.meterClass = [
21100         "roo-password-meter-tooweak", 
21101         "roo-password-meter-weak", 
21102         "roo-password-meter-medium", 
21103         "roo-password-meter-strong", 
21104         "roo-password-meter-grey"
21105     ];
21106     
21107     this.errors = {};
21108     
21109     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21110 }
21111
21112 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21113     /**
21114      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21115      * {
21116      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
21117      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21118      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21119      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21120      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21121      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
21122      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
21123      * })
21124      */
21125     // private
21126     
21127     meterWidth: 300,
21128     errorMsg :'',    
21129     errors: false,
21130     imageRoot: '/',
21131     /**
21132      * @cfg {String/Object} Label for the strength meter (defaults to
21133      * 'Password strength:')
21134      */
21135     // private
21136     meterLabel: '',
21137     /**
21138      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21139      * ['Weak', 'Medium', 'Strong'])
21140      */
21141     // private    
21142     pwdStrengths: false,    
21143     // private
21144     strength: 0,
21145     // private
21146     _lastPwd: null,
21147     // private
21148     kCapitalLetter: 0,
21149     kSmallLetter: 1,
21150     kDigit: 2,
21151     kPunctuation: 3,
21152     
21153     insecure: false,
21154     // private
21155     initEvents: function ()
21156     {
21157         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21158
21159         if (this.el.is('input[type=password]') && Roo.isSafari) {
21160             this.el.on('keydown', this.SafariOnKeyDown, this);
21161         }
21162
21163         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21164     },
21165     // private
21166     onRender: function (ct, position)
21167     {
21168         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21169         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21170         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21171
21172         this.trigger.createChild({
21173                    cn: [
21174                     {
21175                     //id: 'PwdMeter',
21176                     tag: 'div',
21177                     cls: 'roo-password-meter-grey col-xs-12',
21178                     style: {
21179                         //width: 0,
21180                         //width: this.meterWidth + 'px'                                                
21181                         }
21182                     },
21183                     {                            
21184                          cls: 'roo-password-meter-text'                          
21185                     }
21186                 ]            
21187         });
21188
21189          
21190         if (this.hideTrigger) {
21191             this.trigger.setDisplayed(false);
21192         }
21193         this.setSize(this.width || '', this.height || '');
21194     },
21195     // private
21196     onDestroy: function ()
21197     {
21198         if (this.trigger) {
21199             this.trigger.removeAllListeners();
21200             this.trigger.remove();
21201         }
21202         if (this.wrap) {
21203             this.wrap.remove();
21204         }
21205         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21206     },
21207     // private
21208     checkStrength: function ()
21209     {
21210         var pwd = this.inputEl().getValue();
21211         if (pwd == this._lastPwd) {
21212             return;
21213         }
21214
21215         var strength;
21216         if (this.ClientSideStrongPassword(pwd)) {
21217             strength = 3;
21218         } else if (this.ClientSideMediumPassword(pwd)) {
21219             strength = 2;
21220         } else if (this.ClientSideWeakPassword(pwd)) {
21221             strength = 1;
21222         } else {
21223             strength = 0;
21224         }
21225         
21226         Roo.log('strength1: ' + strength);
21227         
21228         //var pm = this.trigger.child('div/div/div').dom;
21229         var pm = this.trigger.child('div/div');
21230         pm.removeClass(this.meterClass);
21231         pm.addClass(this.meterClass[strength]);
21232                 
21233         
21234         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21235                 
21236         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21237         
21238         this._lastPwd = pwd;
21239     },
21240     reset: function ()
21241     {
21242         Roo.bootstrap.SecurePass.superclass.reset.call(this);
21243         
21244         this._lastPwd = '';
21245         
21246         var pm = this.trigger.child('div/div');
21247         pm.removeClass(this.meterClass);
21248         pm.addClass('roo-password-meter-grey');        
21249         
21250         
21251         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21252         
21253         pt.innerHTML = '';
21254         this.inputEl().dom.type='password';
21255     },
21256     // private
21257     validateValue: function (value)
21258     {
21259         
21260         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21261             return false;
21262         }
21263         if (value.length == 0) {
21264             if (this.allowBlank) {
21265                 this.clearInvalid();
21266                 return true;
21267             }
21268
21269             this.markInvalid(this.errors.PwdEmpty);
21270             this.errorMsg = this.errors.PwdEmpty;
21271             return false;
21272         }
21273         
21274         if(this.insecure){
21275             return true;
21276         }
21277         
21278         if ('[\x21-\x7e]*'.match(value)) {
21279             this.markInvalid(this.errors.PwdBadChar);
21280             this.errorMsg = this.errors.PwdBadChar;
21281             return false;
21282         }
21283         if (value.length < 6) {
21284             this.markInvalid(this.errors.PwdShort);
21285             this.errorMsg = this.errors.PwdShort;
21286             return false;
21287         }
21288         if (value.length > 16) {
21289             this.markInvalid(this.errors.PwdLong);
21290             this.errorMsg = this.errors.PwdLong;
21291             return false;
21292         }
21293         var strength;
21294         if (this.ClientSideStrongPassword(value)) {
21295             strength = 3;
21296         } else if (this.ClientSideMediumPassword(value)) {
21297             strength = 2;
21298         } else if (this.ClientSideWeakPassword(value)) {
21299             strength = 1;
21300         } else {
21301             strength = 0;
21302         }
21303
21304         
21305         if (strength < 2) {
21306             //this.markInvalid(this.errors.TooWeak);
21307             this.errorMsg = this.errors.TooWeak;
21308             //return false;
21309         }
21310         
21311         
21312         console.log('strength2: ' + strength);
21313         
21314         //var pm = this.trigger.child('div/div/div').dom;
21315         
21316         var pm = this.trigger.child('div/div');
21317         pm.removeClass(this.meterClass);
21318         pm.addClass(this.meterClass[strength]);
21319                 
21320         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21321                 
21322         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21323         
21324         this.errorMsg = ''; 
21325         return true;
21326     },
21327     // private
21328     CharacterSetChecks: function (type)
21329     {
21330         this.type = type;
21331         this.fResult = false;
21332     },
21333     // private
21334     isctype: function (character, type)
21335     {
21336         switch (type) {  
21337             case this.kCapitalLetter:
21338                 if (character >= 'A' && character <= 'Z') {
21339                     return true;
21340                 }
21341                 break;
21342             
21343             case this.kSmallLetter:
21344                 if (character >= 'a' && character <= 'z') {
21345                     return true;
21346                 }
21347                 break;
21348             
21349             case this.kDigit:
21350                 if (character >= '0' && character <= '9') {
21351                     return true;
21352                 }
21353                 break;
21354             
21355             case this.kPunctuation:
21356                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21357                     return true;
21358                 }
21359                 break;
21360             
21361             default:
21362                 return false;
21363         }
21364
21365     },
21366     // private
21367     IsLongEnough: function (pwd, size)
21368     {
21369         return !(pwd == null || isNaN(size) || pwd.length < size);
21370     },
21371     // private
21372     SpansEnoughCharacterSets: function (word, nb)
21373     {
21374         if (!this.IsLongEnough(word, nb))
21375         {
21376             return false;
21377         }
21378
21379         var characterSetChecks = new Array(
21380             new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21381             new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21382         );
21383         
21384         for (var index = 0; index < word.length; ++index) {
21385             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21386                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21387                     characterSetChecks[nCharSet].fResult = true;
21388                     break;
21389                 }
21390             }
21391         }
21392
21393         var nCharSets = 0;
21394         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21395             if (characterSetChecks[nCharSet].fResult) {
21396                 ++nCharSets;
21397             }
21398         }
21399
21400         if (nCharSets < nb) {
21401             return false;
21402         }
21403         return true;
21404     },
21405     // private
21406     ClientSideStrongPassword: function (pwd)
21407     {
21408         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21409     },
21410     // private
21411     ClientSideMediumPassword: function (pwd)
21412     {
21413         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21414     },
21415     // private
21416     ClientSideWeakPassword: function (pwd)
21417     {
21418         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21419     }
21420           
21421 })//<script type="text/javascript">
21422
21423 /*
21424  * Based  Ext JS Library 1.1.1
21425  * Copyright(c) 2006-2007, Ext JS, LLC.
21426  * LGPL
21427  *
21428  */
21429  
21430 /**
21431  * @class Roo.HtmlEditorCore
21432  * @extends Roo.Component
21433  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21434  *
21435  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21436  */
21437
21438 Roo.HtmlEditorCore = function(config){
21439     
21440     
21441     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21442     
21443     
21444     this.addEvents({
21445         /**
21446          * @event initialize
21447          * Fires when the editor is fully initialized (including the iframe)
21448          * @param {Roo.HtmlEditorCore} this
21449          */
21450         initialize: true,
21451         /**
21452          * @event activate
21453          * Fires when the editor is first receives the focus. Any insertion must wait
21454          * until after this event.
21455          * @param {Roo.HtmlEditorCore} this
21456          */
21457         activate: true,
21458          /**
21459          * @event beforesync
21460          * Fires before the textarea is updated with content from the editor iframe. Return false
21461          * to cancel the sync.
21462          * @param {Roo.HtmlEditorCore} this
21463          * @param {String} html
21464          */
21465         beforesync: true,
21466          /**
21467          * @event beforepush
21468          * Fires before the iframe editor is updated with content from the textarea. Return false
21469          * to cancel the push.
21470          * @param {Roo.HtmlEditorCore} this
21471          * @param {String} html
21472          */
21473         beforepush: true,
21474          /**
21475          * @event sync
21476          * Fires when the textarea is updated with content from the editor iframe.
21477          * @param {Roo.HtmlEditorCore} this
21478          * @param {String} html
21479          */
21480         sync: true,
21481          /**
21482          * @event push
21483          * Fires when the iframe editor is updated with content from the textarea.
21484          * @param {Roo.HtmlEditorCore} this
21485          * @param {String} html
21486          */
21487         push: true,
21488         
21489         /**
21490          * @event editorevent
21491          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21492          * @param {Roo.HtmlEditorCore} this
21493          */
21494         editorevent: true
21495         
21496     });
21497     
21498     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21499     
21500     // defaults : white / black...
21501     this.applyBlacklists();
21502     
21503     
21504     
21505 };
21506
21507
21508 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
21509
21510
21511      /**
21512      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
21513      */
21514     
21515     owner : false,
21516     
21517      /**
21518      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
21519      *                        Roo.resizable.
21520      */
21521     resizable : false,
21522      /**
21523      * @cfg {Number} height (in pixels)
21524      */   
21525     height: 300,
21526    /**
21527      * @cfg {Number} width (in pixels)
21528      */   
21529     width: 500,
21530     
21531     /**
21532      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21533      * 
21534      */
21535     stylesheets: false,
21536     
21537     // id of frame..
21538     frameId: false,
21539     
21540     // private properties
21541     validationEvent : false,
21542     deferHeight: true,
21543     initialized : false,
21544     activated : false,
21545     sourceEditMode : false,
21546     onFocus : Roo.emptyFn,
21547     iframePad:3,
21548     hideMode:'offsets',
21549     
21550     clearUp: true,
21551     
21552     // blacklist + whitelisted elements..
21553     black: false,
21554     white: false,
21555      
21556     bodyCls : '',
21557
21558     /**
21559      * Protected method that will not generally be called directly. It
21560      * is called when the editor initializes the iframe with HTML contents. Override this method if you
21561      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21562      */
21563     getDocMarkup : function(){
21564         // body styles..
21565         var st = '';
21566         
21567         // inherit styels from page...?? 
21568         if (this.stylesheets === false) {
21569             
21570             Roo.get(document.head).select('style').each(function(node) {
21571                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21572             });
21573             
21574             Roo.get(document.head).select('link').each(function(node) { 
21575                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21576             });
21577             
21578         } else if (!this.stylesheets.length) {
21579                 // simple..
21580                 st = '<style type="text/css">' +
21581                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21582                    '</style>';
21583         } else { 
21584             st = '<style type="text/css">' +
21585                     this.stylesheets +
21586                 '</style>';
21587         }
21588         
21589         st +=  '<style type="text/css">' +
21590             'IMG { cursor: pointer } ' +
21591         '</style>';
21592
21593         var cls = 'roo-htmleditor-body';
21594         
21595         if(this.bodyCls.length){
21596             cls += ' ' + this.bodyCls;
21597         }
21598         
21599         return '<html><head>' + st  +
21600             //<style type="text/css">' +
21601             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21602             //'</style>' +
21603             ' </head><body class="' +  cls + '"></body></html>';
21604     },
21605
21606     // private
21607     onRender : function(ct, position)
21608     {
21609         var _t = this;
21610         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21611         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21612         
21613         
21614         this.el.dom.style.border = '0 none';
21615         this.el.dom.setAttribute('tabIndex', -1);
21616         this.el.addClass('x-hidden hide');
21617         
21618         
21619         
21620         if(Roo.isIE){ // fix IE 1px bogus margin
21621             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21622         }
21623        
21624         
21625         this.frameId = Roo.id();
21626         
21627          
21628         
21629         var iframe = this.owner.wrap.createChild({
21630             tag: 'iframe',
21631             cls: 'form-control', // bootstrap..
21632             id: this.frameId,
21633             name: this.frameId,
21634             frameBorder : 'no',
21635             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
21636         }, this.el
21637         );
21638         
21639         
21640         this.iframe = iframe.dom;
21641
21642          this.assignDocWin();
21643         
21644         this.doc.designMode = 'on';
21645        
21646         this.doc.open();
21647         this.doc.write(this.getDocMarkup());
21648         this.doc.close();
21649
21650         
21651         var task = { // must defer to wait for browser to be ready
21652             run : function(){
21653                 //console.log("run task?" + this.doc.readyState);
21654                 this.assignDocWin();
21655                 if(this.doc.body || this.doc.readyState == 'complete'){
21656                     try {
21657                         this.doc.designMode="on";
21658                     } catch (e) {
21659                         return;
21660                     }
21661                     Roo.TaskMgr.stop(task);
21662                     this.initEditor.defer(10, this);
21663                 }
21664             },
21665             interval : 10,
21666             duration: 10000,
21667             scope: this
21668         };
21669         Roo.TaskMgr.start(task);
21670
21671     },
21672
21673     // private
21674     onResize : function(w, h)
21675     {
21676          Roo.log('resize: ' +w + ',' + h );
21677         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21678         if(!this.iframe){
21679             return;
21680         }
21681         if(typeof w == 'number'){
21682             
21683             this.iframe.style.width = w + 'px';
21684         }
21685         if(typeof h == 'number'){
21686             
21687             this.iframe.style.height = h + 'px';
21688             if(this.doc){
21689                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21690             }
21691         }
21692         
21693     },
21694
21695     /**
21696      * Toggles the editor between standard and source edit mode.
21697      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21698      */
21699     toggleSourceEdit : function(sourceEditMode){
21700         
21701         this.sourceEditMode = sourceEditMode === true;
21702         
21703         if(this.sourceEditMode){
21704  
21705             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
21706             
21707         }else{
21708             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21709             //this.iframe.className = '';
21710             this.deferFocus();
21711         }
21712         //this.setSize(this.owner.wrap.getSize());
21713         //this.fireEvent('editmodechange', this, this.sourceEditMode);
21714     },
21715
21716     
21717   
21718
21719     /**
21720      * Protected method that will not generally be called directly. If you need/want
21721      * custom HTML cleanup, this is the method you should override.
21722      * @param {String} html The HTML to be cleaned
21723      * return {String} The cleaned HTML
21724      */
21725     cleanHtml : function(html){
21726         html = String(html);
21727         if(html.length > 5){
21728             if(Roo.isSafari){ // strip safari nonsense
21729                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21730             }
21731         }
21732         if(html == '&nbsp;'){
21733             html = '';
21734         }
21735         return html;
21736     },
21737
21738     /**
21739      * HTML Editor -> Textarea
21740      * Protected method that will not generally be called directly. Syncs the contents
21741      * of the editor iframe with the textarea.
21742      */
21743     syncValue : function(){
21744         if(this.initialized){
21745             var bd = (this.doc.body || this.doc.documentElement);
21746             //this.cleanUpPaste(); -- this is done else where and causes havoc..
21747             var html = bd.innerHTML;
21748             if(Roo.isSafari){
21749                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21750                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21751                 if(m && m[1]){
21752                     html = '<div style="'+m[0]+'">' + html + '</div>';
21753                 }
21754             }
21755             html = this.cleanHtml(html);
21756             // fix up the special chars.. normaly like back quotes in word...
21757             // however we do not want to do this with chinese..
21758             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21759                 var cc = b.charCodeAt();
21760                 if (
21761                     (cc >= 0x4E00 && cc < 0xA000 ) ||
21762                     (cc >= 0x3400 && cc < 0x4E00 ) ||
21763                     (cc >= 0xf900 && cc < 0xfb00 )
21764                 ) {
21765                         return b;
21766                 }
21767                 return "&#"+cc+";" 
21768             });
21769             if(this.owner.fireEvent('beforesync', this, html) !== false){
21770                 this.el.dom.value = html;
21771                 this.owner.fireEvent('sync', this, html);
21772             }
21773         }
21774     },
21775
21776     /**
21777      * Protected method that will not generally be called directly. Pushes the value of the textarea
21778      * into the iframe editor.
21779      */
21780     pushValue : function(){
21781         if(this.initialized){
21782             var v = this.el.dom.value.trim();
21783             
21784 //            if(v.length < 1){
21785 //                v = '&#160;';
21786 //            }
21787             
21788             if(this.owner.fireEvent('beforepush', this, v) !== false){
21789                 var d = (this.doc.body || this.doc.documentElement);
21790                 d.innerHTML = v;
21791                 this.cleanUpPaste();
21792                 this.el.dom.value = d.innerHTML;
21793                 this.owner.fireEvent('push', this, v);
21794             }
21795         }
21796     },
21797
21798     // private
21799     deferFocus : function(){
21800         this.focus.defer(10, this);
21801     },
21802
21803     // doc'ed in Field
21804     focus : function(){
21805         if(this.win && !this.sourceEditMode){
21806             this.win.focus();
21807         }else{
21808             this.el.focus();
21809         }
21810     },
21811     
21812     assignDocWin: function()
21813     {
21814         var iframe = this.iframe;
21815         
21816          if(Roo.isIE){
21817             this.doc = iframe.contentWindow.document;
21818             this.win = iframe.contentWindow;
21819         } else {
21820 //            if (!Roo.get(this.frameId)) {
21821 //                return;
21822 //            }
21823 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21824 //            this.win = Roo.get(this.frameId).dom.contentWindow;
21825             
21826             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21827                 return;
21828             }
21829             
21830             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21831             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21832         }
21833     },
21834     
21835     // private
21836     initEditor : function(){
21837         //console.log("INIT EDITOR");
21838         this.assignDocWin();
21839         
21840         
21841         
21842         this.doc.designMode="on";
21843         this.doc.open();
21844         this.doc.write(this.getDocMarkup());
21845         this.doc.close();
21846         
21847         var dbody = (this.doc.body || this.doc.documentElement);
21848         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21849         // this copies styles from the containing element into thsi one..
21850         // not sure why we need all of this..
21851         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21852         
21853         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21854         //ss['background-attachment'] = 'fixed'; // w3c
21855         dbody.bgProperties = 'fixed'; // ie
21856         //Roo.DomHelper.applyStyles(dbody, ss);
21857         Roo.EventManager.on(this.doc, {
21858             //'mousedown': this.onEditorEvent,
21859             'mouseup': this.onEditorEvent,
21860             'dblclick': this.onEditorEvent,
21861             'click': this.onEditorEvent,
21862             'keyup': this.onEditorEvent,
21863             buffer:100,
21864             scope: this
21865         });
21866         if(Roo.isGecko){
21867             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21868         }
21869         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21870             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21871         }
21872         this.initialized = true;
21873
21874         this.owner.fireEvent('initialize', this);
21875         this.pushValue();
21876     },
21877
21878     // private
21879     onDestroy : function(){
21880         
21881         
21882         
21883         if(this.rendered){
21884             
21885             //for (var i =0; i < this.toolbars.length;i++) {
21886             //    // fixme - ask toolbars for heights?
21887             //    this.toolbars[i].onDestroy();
21888            // }
21889             
21890             //this.wrap.dom.innerHTML = '';
21891             //this.wrap.remove();
21892         }
21893     },
21894
21895     // private
21896     onFirstFocus : function(){
21897         
21898         this.assignDocWin();
21899         
21900         
21901         this.activated = true;
21902          
21903     
21904         if(Roo.isGecko){ // prevent silly gecko errors
21905             this.win.focus();
21906             var s = this.win.getSelection();
21907             if(!s.focusNode || s.focusNode.nodeType != 3){
21908                 var r = s.getRangeAt(0);
21909                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21910                 r.collapse(true);
21911                 this.deferFocus();
21912             }
21913             try{
21914                 this.execCmd('useCSS', true);
21915                 this.execCmd('styleWithCSS', false);
21916             }catch(e){}
21917         }
21918         this.owner.fireEvent('activate', this);
21919     },
21920
21921     // private
21922     adjustFont: function(btn){
21923         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21924         //if(Roo.isSafari){ // safari
21925         //    adjust *= 2;
21926        // }
21927         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21928         if(Roo.isSafari){ // safari
21929             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21930             v =  (v < 10) ? 10 : v;
21931             v =  (v > 48) ? 48 : v;
21932             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21933             
21934         }
21935         
21936         
21937         v = Math.max(1, v+adjust);
21938         
21939         this.execCmd('FontSize', v  );
21940     },
21941
21942     onEditorEvent : function(e)
21943     {
21944         this.owner.fireEvent('editorevent', this, e);
21945       //  this.updateToolbar();
21946         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21947     },
21948
21949     insertTag : function(tg)
21950     {
21951         // could be a bit smarter... -> wrap the current selected tRoo..
21952         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21953             
21954             range = this.createRange(this.getSelection());
21955             var wrappingNode = this.doc.createElement(tg.toLowerCase());
21956             wrappingNode.appendChild(range.extractContents());
21957             range.insertNode(wrappingNode);
21958
21959             return;
21960             
21961             
21962             
21963         }
21964         this.execCmd("formatblock",   tg);
21965         
21966     },
21967     
21968     insertText : function(txt)
21969     {
21970         
21971         
21972         var range = this.createRange();
21973         range.deleteContents();
21974                //alert(Sender.getAttribute('label'));
21975                
21976         range.insertNode(this.doc.createTextNode(txt));
21977     } ,
21978     
21979      
21980
21981     /**
21982      * Executes a Midas editor command on the editor document and performs necessary focus and
21983      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21984      * @param {String} cmd The Midas command
21985      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21986      */
21987     relayCmd : function(cmd, value){
21988         this.win.focus();
21989         this.execCmd(cmd, value);
21990         this.owner.fireEvent('editorevent', this);
21991         //this.updateToolbar();
21992         this.owner.deferFocus();
21993     },
21994
21995     /**
21996      * Executes a Midas editor command directly on the editor document.
21997      * For visual commands, you should use {@link #relayCmd} instead.
21998      * <b>This should only be called after the editor is initialized.</b>
21999      * @param {String} cmd The Midas command
22000      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22001      */
22002     execCmd : function(cmd, value){
22003         this.doc.execCommand(cmd, false, value === undefined ? null : value);
22004         this.syncValue();
22005     },
22006  
22007  
22008    
22009     /**
22010      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22011      * to insert tRoo.
22012      * @param {String} text | dom node.. 
22013      */
22014     insertAtCursor : function(text)
22015     {
22016         
22017         if(!this.activated){
22018             return;
22019         }
22020         /*
22021         if(Roo.isIE){
22022             this.win.focus();
22023             var r = this.doc.selection.createRange();
22024             if(r){
22025                 r.collapse(true);
22026                 r.pasteHTML(text);
22027                 this.syncValue();
22028                 this.deferFocus();
22029             
22030             }
22031             return;
22032         }
22033         */
22034         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22035             this.win.focus();
22036             
22037             
22038             // from jquery ui (MIT licenced)
22039             var range, node;
22040             var win = this.win;
22041             
22042             if (win.getSelection && win.getSelection().getRangeAt) {
22043                 range = win.getSelection().getRangeAt(0);
22044                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22045                 range.insertNode(node);
22046             } else if (win.document.selection && win.document.selection.createRange) {
22047                 // no firefox support
22048                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22049                 win.document.selection.createRange().pasteHTML(txt);
22050             } else {
22051                 // no firefox support
22052                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22053                 this.execCmd('InsertHTML', txt);
22054             } 
22055             
22056             this.syncValue();
22057             
22058             this.deferFocus();
22059         }
22060     },
22061  // private
22062     mozKeyPress : function(e){
22063         if(e.ctrlKey){
22064             var c = e.getCharCode(), cmd;
22065           
22066             if(c > 0){
22067                 c = String.fromCharCode(c).toLowerCase();
22068                 switch(c){
22069                     case 'b':
22070                         cmd = 'bold';
22071                         break;
22072                     case 'i':
22073                         cmd = 'italic';
22074                         break;
22075                     
22076                     case 'u':
22077                         cmd = 'underline';
22078                         break;
22079                     
22080                     case 'v':
22081                         this.cleanUpPaste.defer(100, this);
22082                         return;
22083                         
22084                 }
22085                 if(cmd){
22086                     this.win.focus();
22087                     this.execCmd(cmd);
22088                     this.deferFocus();
22089                     e.preventDefault();
22090                 }
22091                 
22092             }
22093         }
22094     },
22095
22096     // private
22097     fixKeys : function(){ // load time branching for fastest keydown performance
22098         if(Roo.isIE){
22099             return function(e){
22100                 var k = e.getKey(), r;
22101                 if(k == e.TAB){
22102                     e.stopEvent();
22103                     r = this.doc.selection.createRange();
22104                     if(r){
22105                         r.collapse(true);
22106                         r.pasteHTML('&#160;&#160;&#160;&#160;');
22107                         this.deferFocus();
22108                     }
22109                     return;
22110                 }
22111                 
22112                 if(k == e.ENTER){
22113                     r = this.doc.selection.createRange();
22114                     if(r){
22115                         var target = r.parentElement();
22116                         if(!target || target.tagName.toLowerCase() != 'li'){
22117                             e.stopEvent();
22118                             r.pasteHTML('<br />');
22119                             r.collapse(false);
22120                             r.select();
22121                         }
22122                     }
22123                 }
22124                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22125                     this.cleanUpPaste.defer(100, this);
22126                     return;
22127                 }
22128                 
22129                 
22130             };
22131         }else if(Roo.isOpera){
22132             return function(e){
22133                 var k = e.getKey();
22134                 if(k == e.TAB){
22135                     e.stopEvent();
22136                     this.win.focus();
22137                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
22138                     this.deferFocus();
22139                 }
22140                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22141                     this.cleanUpPaste.defer(100, this);
22142                     return;
22143                 }
22144                 
22145             };
22146         }else if(Roo.isSafari){
22147             return function(e){
22148                 var k = e.getKey();
22149                 
22150                 if(k == e.TAB){
22151                     e.stopEvent();
22152                     this.execCmd('InsertText','\t');
22153                     this.deferFocus();
22154                     return;
22155                 }
22156                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22157                     this.cleanUpPaste.defer(100, this);
22158                     return;
22159                 }
22160                 
22161              };
22162         }
22163     }(),
22164     
22165     getAllAncestors: function()
22166     {
22167         var p = this.getSelectedNode();
22168         var a = [];
22169         if (!p) {
22170             a.push(p); // push blank onto stack..
22171             p = this.getParentElement();
22172         }
22173         
22174         
22175         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22176             a.push(p);
22177             p = p.parentNode;
22178         }
22179         a.push(this.doc.body);
22180         return a;
22181     },
22182     lastSel : false,
22183     lastSelNode : false,
22184     
22185     
22186     getSelection : function() 
22187     {
22188         this.assignDocWin();
22189         return Roo.isIE ? this.doc.selection : this.win.getSelection();
22190     },
22191     
22192     getSelectedNode: function() 
22193     {
22194         // this may only work on Gecko!!!
22195         
22196         // should we cache this!!!!
22197         
22198         
22199         
22200          
22201         var range = this.createRange(this.getSelection()).cloneRange();
22202         
22203         if (Roo.isIE) {
22204             var parent = range.parentElement();
22205             while (true) {
22206                 var testRange = range.duplicate();
22207                 testRange.moveToElementText(parent);
22208                 if (testRange.inRange(range)) {
22209                     break;
22210                 }
22211                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22212                     break;
22213                 }
22214                 parent = parent.parentElement;
22215             }
22216             return parent;
22217         }
22218         
22219         // is ancestor a text element.
22220         var ac =  range.commonAncestorContainer;
22221         if (ac.nodeType == 3) {
22222             ac = ac.parentNode;
22223         }
22224         
22225         var ar = ac.childNodes;
22226          
22227         var nodes = [];
22228         var other_nodes = [];
22229         var has_other_nodes = false;
22230         for (var i=0;i<ar.length;i++) {
22231             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
22232                 continue;
22233             }
22234             // fullly contained node.
22235             
22236             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22237                 nodes.push(ar[i]);
22238                 continue;
22239             }
22240             
22241             // probably selected..
22242             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22243                 other_nodes.push(ar[i]);
22244                 continue;
22245             }
22246             // outer..
22247             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
22248                 continue;
22249             }
22250             
22251             
22252             has_other_nodes = true;
22253         }
22254         if (!nodes.length && other_nodes.length) {
22255             nodes= other_nodes;
22256         }
22257         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22258             return false;
22259         }
22260         
22261         return nodes[0];
22262     },
22263     createRange: function(sel)
22264     {
22265         // this has strange effects when using with 
22266         // top toolbar - not sure if it's a great idea.
22267         //this.editor.contentWindow.focus();
22268         if (typeof sel != "undefined") {
22269             try {
22270                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22271             } catch(e) {
22272                 return this.doc.createRange();
22273             }
22274         } else {
22275             return this.doc.createRange();
22276         }
22277     },
22278     getParentElement: function()
22279     {
22280         
22281         this.assignDocWin();
22282         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22283         
22284         var range = this.createRange(sel);
22285          
22286         try {
22287             var p = range.commonAncestorContainer;
22288             while (p.nodeType == 3) { // text node
22289                 p = p.parentNode;
22290             }
22291             return p;
22292         } catch (e) {
22293             return null;
22294         }
22295     
22296     },
22297     /***
22298      *
22299      * Range intersection.. the hard stuff...
22300      *  '-1' = before
22301      *  '0' = hits..
22302      *  '1' = after.
22303      *         [ -- selected range --- ]
22304      *   [fail]                        [fail]
22305      *
22306      *    basically..
22307      *      if end is before start or  hits it. fail.
22308      *      if start is after end or hits it fail.
22309      *
22310      *   if either hits (but other is outside. - then it's not 
22311      *   
22312      *    
22313      **/
22314     
22315     
22316     // @see http://www.thismuchiknow.co.uk/?p=64.
22317     rangeIntersectsNode : function(range, node)
22318     {
22319         var nodeRange = node.ownerDocument.createRange();
22320         try {
22321             nodeRange.selectNode(node);
22322         } catch (e) {
22323             nodeRange.selectNodeContents(node);
22324         }
22325     
22326         var rangeStartRange = range.cloneRange();
22327         rangeStartRange.collapse(true);
22328     
22329         var rangeEndRange = range.cloneRange();
22330         rangeEndRange.collapse(false);
22331     
22332         var nodeStartRange = nodeRange.cloneRange();
22333         nodeStartRange.collapse(true);
22334     
22335         var nodeEndRange = nodeRange.cloneRange();
22336         nodeEndRange.collapse(false);
22337     
22338         return rangeStartRange.compareBoundaryPoints(
22339                  Range.START_TO_START, nodeEndRange) == -1 &&
22340                rangeEndRange.compareBoundaryPoints(
22341                  Range.START_TO_START, nodeStartRange) == 1;
22342         
22343          
22344     },
22345     rangeCompareNode : function(range, node)
22346     {
22347         var nodeRange = node.ownerDocument.createRange();
22348         try {
22349             nodeRange.selectNode(node);
22350         } catch (e) {
22351             nodeRange.selectNodeContents(node);
22352         }
22353         
22354         
22355         range.collapse(true);
22356     
22357         nodeRange.collapse(true);
22358      
22359         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22360         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
22361          
22362         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22363         
22364         var nodeIsBefore   =  ss == 1;
22365         var nodeIsAfter    = ee == -1;
22366         
22367         if (nodeIsBefore && nodeIsAfter) {
22368             return 0; // outer
22369         }
22370         if (!nodeIsBefore && nodeIsAfter) {
22371             return 1; //right trailed.
22372         }
22373         
22374         if (nodeIsBefore && !nodeIsAfter) {
22375             return 2;  // left trailed.
22376         }
22377         // fully contined.
22378         return 3;
22379     },
22380
22381     // private? - in a new class?
22382     cleanUpPaste :  function()
22383     {
22384         // cleans up the whole document..
22385         Roo.log('cleanuppaste');
22386         
22387         this.cleanUpChildren(this.doc.body);
22388         var clean = this.cleanWordChars(this.doc.body.innerHTML);
22389         if (clean != this.doc.body.innerHTML) {
22390             this.doc.body.innerHTML = clean;
22391         }
22392         
22393     },
22394     
22395     cleanWordChars : function(input) {// change the chars to hex code
22396         var he = Roo.HtmlEditorCore;
22397         
22398         var output = input;
22399         Roo.each(he.swapCodes, function(sw) { 
22400             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22401             
22402             output = output.replace(swapper, sw[1]);
22403         });
22404         
22405         return output;
22406     },
22407     
22408     
22409     cleanUpChildren : function (n)
22410     {
22411         if (!n.childNodes.length) {
22412             return;
22413         }
22414         for (var i = n.childNodes.length-1; i > -1 ; i--) {
22415            this.cleanUpChild(n.childNodes[i]);
22416         }
22417     },
22418     
22419     
22420         
22421     
22422     cleanUpChild : function (node)
22423     {
22424         var ed = this;
22425         //console.log(node);
22426         if (node.nodeName == "#text") {
22427             // clean up silly Windows -- stuff?
22428             return; 
22429         }
22430         if (node.nodeName == "#comment") {
22431             node.parentNode.removeChild(node);
22432             // clean up silly Windows -- stuff?
22433             return; 
22434         }
22435         var lcname = node.tagName.toLowerCase();
22436         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22437         // whitelist of tags..
22438         
22439         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22440             // remove node.
22441             node.parentNode.removeChild(node);
22442             return;
22443             
22444         }
22445         
22446         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22447         
22448         // remove <a name=....> as rendering on yahoo mailer is borked with this.
22449         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22450         
22451         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22452         //    remove_keep_children = true;
22453         //}
22454         
22455         if (remove_keep_children) {
22456             this.cleanUpChildren(node);
22457             // inserts everything just before this node...
22458             while (node.childNodes.length) {
22459                 var cn = node.childNodes[0];
22460                 node.removeChild(cn);
22461                 node.parentNode.insertBefore(cn, node);
22462             }
22463             node.parentNode.removeChild(node);
22464             return;
22465         }
22466         
22467         if (!node.attributes || !node.attributes.length) {
22468             this.cleanUpChildren(node);
22469             return;
22470         }
22471         
22472         function cleanAttr(n,v)
22473         {
22474             
22475             if (v.match(/^\./) || v.match(/^\//)) {
22476                 return;
22477             }
22478             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22479                 return;
22480             }
22481             if (v.match(/^#/)) {
22482                 return;
22483             }
22484 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22485             node.removeAttribute(n);
22486             
22487         }
22488         
22489         var cwhite = this.cwhite;
22490         var cblack = this.cblack;
22491             
22492         function cleanStyle(n,v)
22493         {
22494             if (v.match(/expression/)) { //XSS?? should we even bother..
22495                 node.removeAttribute(n);
22496                 return;
22497             }
22498             
22499             var parts = v.split(/;/);
22500             var clean = [];
22501             
22502             Roo.each(parts, function(p) {
22503                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22504                 if (!p.length) {
22505                     return true;
22506                 }
22507                 var l = p.split(':').shift().replace(/\s+/g,'');
22508                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22509                 
22510                 if ( cwhite.length && cblack.indexOf(l) > -1) {
22511 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22512                     //node.removeAttribute(n);
22513                     return true;
22514                 }
22515                 //Roo.log()
22516                 // only allow 'c whitelisted system attributes'
22517                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
22518 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22519                     //node.removeAttribute(n);
22520                     return true;
22521                 }
22522                 
22523                 
22524                  
22525                 
22526                 clean.push(p);
22527                 return true;
22528             });
22529             if (clean.length) { 
22530                 node.setAttribute(n, clean.join(';'));
22531             } else {
22532                 node.removeAttribute(n);
22533             }
22534             
22535         }
22536         
22537         
22538         for (var i = node.attributes.length-1; i > -1 ; i--) {
22539             var a = node.attributes[i];
22540             //console.log(a);
22541             
22542             if (a.name.toLowerCase().substr(0,2)=='on')  {
22543                 node.removeAttribute(a.name);
22544                 continue;
22545             }
22546             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22547                 node.removeAttribute(a.name);
22548                 continue;
22549             }
22550             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22551                 cleanAttr(a.name,a.value); // fixme..
22552                 continue;
22553             }
22554             if (a.name == 'style') {
22555                 cleanStyle(a.name,a.value);
22556                 continue;
22557             }
22558             /// clean up MS crap..
22559             // tecnically this should be a list of valid class'es..
22560             
22561             
22562             if (a.name == 'class') {
22563                 if (a.value.match(/^Mso/)) {
22564                     node.className = '';
22565                 }
22566                 
22567                 if (a.value.match(/^body$/)) {
22568                     node.className = '';
22569                 }
22570                 continue;
22571             }
22572             
22573             // style cleanup!?
22574             // class cleanup?
22575             
22576         }
22577         
22578         
22579         this.cleanUpChildren(node);
22580         
22581         
22582     },
22583     
22584     /**
22585      * Clean up MS wordisms...
22586      */
22587     cleanWord : function(node)
22588     {
22589         
22590         
22591         if (!node) {
22592             this.cleanWord(this.doc.body);
22593             return;
22594         }
22595         if (node.nodeName == "#text") {
22596             // clean up silly Windows -- stuff?
22597             return; 
22598         }
22599         if (node.nodeName == "#comment") {
22600             node.parentNode.removeChild(node);
22601             // clean up silly Windows -- stuff?
22602             return; 
22603         }
22604         
22605         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22606             node.parentNode.removeChild(node);
22607             return;
22608         }
22609         
22610         // remove - but keep children..
22611         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22612             while (node.childNodes.length) {
22613                 var cn = node.childNodes[0];
22614                 node.removeChild(cn);
22615                 node.parentNode.insertBefore(cn, node);
22616             }
22617             node.parentNode.removeChild(node);
22618             this.iterateChildren(node, this.cleanWord);
22619             return;
22620         }
22621         // clean styles
22622         if (node.className.length) {
22623             
22624             var cn = node.className.split(/\W+/);
22625             var cna = [];
22626             Roo.each(cn, function(cls) {
22627                 if (cls.match(/Mso[a-zA-Z]+/)) {
22628                     return;
22629                 }
22630                 cna.push(cls);
22631             });
22632             node.className = cna.length ? cna.join(' ') : '';
22633             if (!cna.length) {
22634                 node.removeAttribute("class");
22635             }
22636         }
22637         
22638         if (node.hasAttribute("lang")) {
22639             node.removeAttribute("lang");
22640         }
22641         
22642         if (node.hasAttribute("style")) {
22643             
22644             var styles = node.getAttribute("style").split(";");
22645             var nstyle = [];
22646             Roo.each(styles, function(s) {
22647                 if (!s.match(/:/)) {
22648                     return;
22649                 }
22650                 var kv = s.split(":");
22651                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22652                     return;
22653                 }
22654                 // what ever is left... we allow.
22655                 nstyle.push(s);
22656             });
22657             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22658             if (!nstyle.length) {
22659                 node.removeAttribute('style');
22660             }
22661         }
22662         this.iterateChildren(node, this.cleanWord);
22663         
22664         
22665         
22666     },
22667     /**
22668      * iterateChildren of a Node, calling fn each time, using this as the scole..
22669      * @param {DomNode} node node to iterate children of.
22670      * @param {Function} fn method of this class to call on each item.
22671      */
22672     iterateChildren : function(node, fn)
22673     {
22674         if (!node.childNodes.length) {
22675                 return;
22676         }
22677         for (var i = node.childNodes.length-1; i > -1 ; i--) {
22678            fn.call(this, node.childNodes[i])
22679         }
22680     },
22681     
22682     
22683     /**
22684      * cleanTableWidths.
22685      *
22686      * Quite often pasting from word etc.. results in tables with column and widths.
22687      * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22688      *
22689      */
22690     cleanTableWidths : function(node)
22691     {
22692          
22693          
22694         if (!node) {
22695             this.cleanTableWidths(this.doc.body);
22696             return;
22697         }
22698         
22699         // ignore list...
22700         if (node.nodeName == "#text" || node.nodeName == "#comment") {
22701             return; 
22702         }
22703         Roo.log(node.tagName);
22704         if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22705             this.iterateChildren(node, this.cleanTableWidths);
22706             return;
22707         }
22708         if (node.hasAttribute('width')) {
22709             node.removeAttribute('width');
22710         }
22711         
22712          
22713         if (node.hasAttribute("style")) {
22714             // pretty basic...
22715             
22716             var styles = node.getAttribute("style").split(";");
22717             var nstyle = [];
22718             Roo.each(styles, function(s) {
22719                 if (!s.match(/:/)) {
22720                     return;
22721                 }
22722                 var kv = s.split(":");
22723                 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22724                     return;
22725                 }
22726                 // what ever is left... we allow.
22727                 nstyle.push(s);
22728             });
22729             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22730             if (!nstyle.length) {
22731                 node.removeAttribute('style');
22732             }
22733         }
22734         
22735         this.iterateChildren(node, this.cleanTableWidths);
22736         
22737         
22738     },
22739     
22740     
22741     
22742     
22743     domToHTML : function(currentElement, depth, nopadtext) {
22744         
22745         depth = depth || 0;
22746         nopadtext = nopadtext || false;
22747     
22748         if (!currentElement) {
22749             return this.domToHTML(this.doc.body);
22750         }
22751         
22752         //Roo.log(currentElement);
22753         var j;
22754         var allText = false;
22755         var nodeName = currentElement.nodeName;
22756         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22757         
22758         if  (nodeName == '#text') {
22759             
22760             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22761         }
22762         
22763         
22764         var ret = '';
22765         if (nodeName != 'BODY') {
22766              
22767             var i = 0;
22768             // Prints the node tagName, such as <A>, <IMG>, etc
22769             if (tagName) {
22770                 var attr = [];
22771                 for(i = 0; i < currentElement.attributes.length;i++) {
22772                     // quoting?
22773                     var aname = currentElement.attributes.item(i).name;
22774                     if (!currentElement.attributes.item(i).value.length) {
22775                         continue;
22776                     }
22777                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22778                 }
22779                 
22780                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22781             } 
22782             else {
22783                 
22784                 // eack
22785             }
22786         } else {
22787             tagName = false;
22788         }
22789         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22790             return ret;
22791         }
22792         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22793             nopadtext = true;
22794         }
22795         
22796         
22797         // Traverse the tree
22798         i = 0;
22799         var currentElementChild = currentElement.childNodes.item(i);
22800         var allText = true;
22801         var innerHTML  = '';
22802         lastnode = '';
22803         while (currentElementChild) {
22804             // Formatting code (indent the tree so it looks nice on the screen)
22805             var nopad = nopadtext;
22806             if (lastnode == 'SPAN') {
22807                 nopad  = true;
22808             }
22809             // text
22810             if  (currentElementChild.nodeName == '#text') {
22811                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22812                 toadd = nopadtext ? toadd : toadd.trim();
22813                 if (!nopad && toadd.length > 80) {
22814                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
22815                 }
22816                 innerHTML  += toadd;
22817                 
22818                 i++;
22819                 currentElementChild = currentElement.childNodes.item(i);
22820                 lastNode = '';
22821                 continue;
22822             }
22823             allText = false;
22824             
22825             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
22826                 
22827             // Recursively traverse the tree structure of the child node
22828             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
22829             lastnode = currentElementChild.nodeName;
22830             i++;
22831             currentElementChild=currentElement.childNodes.item(i);
22832         }
22833         
22834         ret += innerHTML;
22835         
22836         if (!allText) {
22837                 // The remaining code is mostly for formatting the tree
22838             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
22839         }
22840         
22841         
22842         if (tagName) {
22843             ret+= "</"+tagName+">";
22844         }
22845         return ret;
22846         
22847     },
22848         
22849     applyBlacklists : function()
22850     {
22851         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
22852         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
22853         
22854         this.white = [];
22855         this.black = [];
22856         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22857             if (b.indexOf(tag) > -1) {
22858                 return;
22859             }
22860             this.white.push(tag);
22861             
22862         }, this);
22863         
22864         Roo.each(w, function(tag) {
22865             if (b.indexOf(tag) > -1) {
22866                 return;
22867             }
22868             if (this.white.indexOf(tag) > -1) {
22869                 return;
22870             }
22871             this.white.push(tag);
22872             
22873         }, this);
22874         
22875         
22876         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22877             if (w.indexOf(tag) > -1) {
22878                 return;
22879             }
22880             this.black.push(tag);
22881             
22882         }, this);
22883         
22884         Roo.each(b, function(tag) {
22885             if (w.indexOf(tag) > -1) {
22886                 return;
22887             }
22888             if (this.black.indexOf(tag) > -1) {
22889                 return;
22890             }
22891             this.black.push(tag);
22892             
22893         }, this);
22894         
22895         
22896         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
22897         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
22898         
22899         this.cwhite = [];
22900         this.cblack = [];
22901         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22902             if (b.indexOf(tag) > -1) {
22903                 return;
22904             }
22905             this.cwhite.push(tag);
22906             
22907         }, this);
22908         
22909         Roo.each(w, function(tag) {
22910             if (b.indexOf(tag) > -1) {
22911                 return;
22912             }
22913             if (this.cwhite.indexOf(tag) > -1) {
22914                 return;
22915             }
22916             this.cwhite.push(tag);
22917             
22918         }, this);
22919         
22920         
22921         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22922             if (w.indexOf(tag) > -1) {
22923                 return;
22924             }
22925             this.cblack.push(tag);
22926             
22927         }, this);
22928         
22929         Roo.each(b, function(tag) {
22930             if (w.indexOf(tag) > -1) {
22931                 return;
22932             }
22933             if (this.cblack.indexOf(tag) > -1) {
22934                 return;
22935             }
22936             this.cblack.push(tag);
22937             
22938         }, this);
22939     },
22940     
22941     setStylesheets : function(stylesheets)
22942     {
22943         if(typeof(stylesheets) == 'string'){
22944             Roo.get(this.iframe.contentDocument.head).createChild({
22945                 tag : 'link',
22946                 rel : 'stylesheet',
22947                 type : 'text/css',
22948                 href : stylesheets
22949             });
22950             
22951             return;
22952         }
22953         var _this = this;
22954      
22955         Roo.each(stylesheets, function(s) {
22956             if(!s.length){
22957                 return;
22958             }
22959             
22960             Roo.get(_this.iframe.contentDocument.head).createChild({
22961                 tag : 'link',
22962                 rel : 'stylesheet',
22963                 type : 'text/css',
22964                 href : s
22965             });
22966         });
22967
22968         
22969     },
22970     
22971     removeStylesheets : function()
22972     {
22973         var _this = this;
22974         
22975         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22976             s.remove();
22977         });
22978     },
22979     
22980     setStyle : function(style)
22981     {
22982         Roo.get(this.iframe.contentDocument.head).createChild({
22983             tag : 'style',
22984             type : 'text/css',
22985             html : style
22986         });
22987
22988         return;
22989     }
22990     
22991     // hide stuff that is not compatible
22992     /**
22993      * @event blur
22994      * @hide
22995      */
22996     /**
22997      * @event change
22998      * @hide
22999      */
23000     /**
23001      * @event focus
23002      * @hide
23003      */
23004     /**
23005      * @event specialkey
23006      * @hide
23007      */
23008     /**
23009      * @cfg {String} fieldClass @hide
23010      */
23011     /**
23012      * @cfg {String} focusClass @hide
23013      */
23014     /**
23015      * @cfg {String} autoCreate @hide
23016      */
23017     /**
23018      * @cfg {String} inputType @hide
23019      */
23020     /**
23021      * @cfg {String} invalidClass @hide
23022      */
23023     /**
23024      * @cfg {String} invalidText @hide
23025      */
23026     /**
23027      * @cfg {String} msgFx @hide
23028      */
23029     /**
23030      * @cfg {String} validateOnBlur @hide
23031      */
23032 });
23033
23034 Roo.HtmlEditorCore.white = [
23035         'area', 'br', 'img', 'input', 'hr', 'wbr',
23036         
23037        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
23038        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
23039        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
23040        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
23041        'table',   'ul',         'xmp', 
23042        
23043        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
23044       'thead',   'tr', 
23045      
23046       'dir', 'menu', 'ol', 'ul', 'dl',
23047        
23048       'embed',  'object'
23049 ];
23050
23051
23052 Roo.HtmlEditorCore.black = [
23053     //    'embed',  'object', // enable - backend responsiblity to clean thiese
23054         'applet', // 
23055         'base',   'basefont', 'bgsound', 'blink',  'body', 
23056         'frame',  'frameset', 'head',    'html',   'ilayer', 
23057         'iframe', 'layer',  'link',     'meta',    'object',   
23058         'script', 'style' ,'title',  'xml' // clean later..
23059 ];
23060 Roo.HtmlEditorCore.clean = [
23061     'script', 'style', 'title', 'xml'
23062 ];
23063 Roo.HtmlEditorCore.remove = [
23064     'font'
23065 ];
23066 // attributes..
23067
23068 Roo.HtmlEditorCore.ablack = [
23069     'on'
23070 ];
23071     
23072 Roo.HtmlEditorCore.aclean = [ 
23073     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
23074 ];
23075
23076 // protocols..
23077 Roo.HtmlEditorCore.pwhite= [
23078         'http',  'https',  'mailto'
23079 ];
23080
23081 // white listed style attributes.
23082 Roo.HtmlEditorCore.cwhite= [
23083       //  'text-align', /// default is to allow most things..
23084       
23085          
23086 //        'font-size'//??
23087 ];
23088
23089 // black listed style attributes.
23090 Roo.HtmlEditorCore.cblack= [
23091       //  'font-size' -- this can be set by the project 
23092 ];
23093
23094
23095 Roo.HtmlEditorCore.swapCodes   =[ 
23096     [    8211, "--" ], 
23097     [    8212, "--" ], 
23098     [    8216,  "'" ],  
23099     [    8217, "'" ],  
23100     [    8220, '"' ],  
23101     [    8221, '"' ],  
23102     [    8226, "*" ],  
23103     [    8230, "..." ]
23104 ]; 
23105
23106     /*
23107  * - LGPL
23108  *
23109  * HtmlEditor
23110  * 
23111  */
23112
23113 /**
23114  * @class Roo.bootstrap.HtmlEditor
23115  * @extends Roo.bootstrap.TextArea
23116  * Bootstrap HtmlEditor class
23117
23118  * @constructor
23119  * Create a new HtmlEditor
23120  * @param {Object} config The config object
23121  */
23122
23123 Roo.bootstrap.HtmlEditor = function(config){
23124     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23125     if (!this.toolbars) {
23126         this.toolbars = [];
23127     }
23128     
23129     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23130     this.addEvents({
23131             /**
23132              * @event initialize
23133              * Fires when the editor is fully initialized (including the iframe)
23134              * @param {HtmlEditor} this
23135              */
23136             initialize: true,
23137             /**
23138              * @event activate
23139              * Fires when the editor is first receives the focus. Any insertion must wait
23140              * until after this event.
23141              * @param {HtmlEditor} this
23142              */
23143             activate: true,
23144              /**
23145              * @event beforesync
23146              * Fires before the textarea is updated with content from the editor iframe. Return false
23147              * to cancel the sync.
23148              * @param {HtmlEditor} this
23149              * @param {String} html
23150              */
23151             beforesync: true,
23152              /**
23153              * @event beforepush
23154              * Fires before the iframe editor is updated with content from the textarea. Return false
23155              * to cancel the push.
23156              * @param {HtmlEditor} this
23157              * @param {String} html
23158              */
23159             beforepush: true,
23160              /**
23161              * @event sync
23162              * Fires when the textarea is updated with content from the editor iframe.
23163              * @param {HtmlEditor} this
23164              * @param {String} html
23165              */
23166             sync: true,
23167              /**
23168              * @event push
23169              * Fires when the iframe editor is updated with content from the textarea.
23170              * @param {HtmlEditor} this
23171              * @param {String} html
23172              */
23173             push: true,
23174              /**
23175              * @event editmodechange
23176              * Fires when the editor switches edit modes
23177              * @param {HtmlEditor} this
23178              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23179              */
23180             editmodechange: true,
23181             /**
23182              * @event editorevent
23183              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23184              * @param {HtmlEditor} this
23185              */
23186             editorevent: true,
23187             /**
23188              * @event firstfocus
23189              * Fires when on first focus - needed by toolbars..
23190              * @param {HtmlEditor} this
23191              */
23192             firstfocus: true,
23193             /**
23194              * @event autosave
23195              * Auto save the htmlEditor value as a file into Events
23196              * @param {HtmlEditor} this
23197              */
23198             autosave: true,
23199             /**
23200              * @event savedpreview
23201              * preview the saved version of htmlEditor
23202              * @param {HtmlEditor} this
23203              */
23204             savedpreview: true
23205         });
23206 };
23207
23208
23209 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
23210     
23211     
23212       /**
23213      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23214      */
23215     toolbars : false,
23216     
23217      /**
23218     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23219     */
23220     btns : [],
23221    
23222      /**
23223      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
23224      *                        Roo.resizable.
23225      */
23226     resizable : false,
23227      /**
23228      * @cfg {Number} height (in pixels)
23229      */   
23230     height: 300,
23231    /**
23232      * @cfg {Number} width (in pixels)
23233      */   
23234     width: false,
23235     
23236     /**
23237      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23238      * 
23239      */
23240     stylesheets: false,
23241     
23242     // id of frame..
23243     frameId: false,
23244     
23245     // private properties
23246     validationEvent : false,
23247     deferHeight: true,
23248     initialized : false,
23249     activated : false,
23250     
23251     onFocus : Roo.emptyFn,
23252     iframePad:3,
23253     hideMode:'offsets',
23254     
23255     tbContainer : false,
23256     
23257     bodyCls : '',
23258     
23259     toolbarContainer :function() {
23260         return this.wrap.select('.x-html-editor-tb',true).first();
23261     },
23262
23263     /**
23264      * Protected method that will not generally be called directly. It
23265      * is called when the editor creates its toolbar. Override this method if you need to
23266      * add custom toolbar buttons.
23267      * @param {HtmlEditor} editor
23268      */
23269     createToolbar : function(){
23270         Roo.log('renewing');
23271         Roo.log("create toolbars");
23272         
23273         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23274         this.toolbars[0].render(this.toolbarContainer());
23275         
23276         return;
23277         
23278 //        if (!editor.toolbars || !editor.toolbars.length) {
23279 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23280 //        }
23281 //        
23282 //        for (var i =0 ; i < editor.toolbars.length;i++) {
23283 //            editor.toolbars[i] = Roo.factory(
23284 //                    typeof(editor.toolbars[i]) == 'string' ?
23285 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
23286 //                Roo.bootstrap.HtmlEditor);
23287 //            editor.toolbars[i].init(editor);
23288 //        }
23289     },
23290
23291      
23292     // private
23293     onRender : function(ct, position)
23294     {
23295        // Roo.log("Call onRender: " + this.xtype);
23296         var _t = this;
23297         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23298       
23299         this.wrap = this.inputEl().wrap({
23300             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23301         });
23302         
23303         this.editorcore.onRender(ct, position);
23304          
23305         if (this.resizable) {
23306             this.resizeEl = new Roo.Resizable(this.wrap, {
23307                 pinned : true,
23308                 wrap: true,
23309                 dynamic : true,
23310                 minHeight : this.height,
23311                 height: this.height,
23312                 handles : this.resizable,
23313                 width: this.width,
23314                 listeners : {
23315                     resize : function(r, w, h) {
23316                         _t.onResize(w,h); // -something
23317                     }
23318                 }
23319             });
23320             
23321         }
23322         this.createToolbar(this);
23323        
23324         
23325         if(!this.width && this.resizable){
23326             this.setSize(this.wrap.getSize());
23327         }
23328         if (this.resizeEl) {
23329             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23330             // should trigger onReize..
23331         }
23332         
23333     },
23334
23335     // private
23336     onResize : function(w, h)
23337     {
23338         Roo.log('resize: ' +w + ',' + h );
23339         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23340         var ew = false;
23341         var eh = false;
23342         
23343         if(this.inputEl() ){
23344             if(typeof w == 'number'){
23345                 var aw = w - this.wrap.getFrameWidth('lr');
23346                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23347                 ew = aw;
23348             }
23349             if(typeof h == 'number'){
23350                  var tbh = -11;  // fixme it needs to tool bar size!
23351                 for (var i =0; i < this.toolbars.length;i++) {
23352                     // fixme - ask toolbars for heights?
23353                     tbh += this.toolbars[i].el.getHeight();
23354                     //if (this.toolbars[i].footer) {
23355                     //    tbh += this.toolbars[i].footer.el.getHeight();
23356                     //}
23357                 }
23358               
23359                 
23360                 
23361                 
23362                 
23363                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23364                 ah -= 5; // knock a few pixes off for look..
23365                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23366                 var eh = ah;
23367             }
23368         }
23369         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23370         this.editorcore.onResize(ew,eh);
23371         
23372     },
23373
23374     /**
23375      * Toggles the editor between standard and source edit mode.
23376      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23377      */
23378     toggleSourceEdit : function(sourceEditMode)
23379     {
23380         this.editorcore.toggleSourceEdit(sourceEditMode);
23381         
23382         if(this.editorcore.sourceEditMode){
23383             Roo.log('editor - showing textarea');
23384             
23385 //            Roo.log('in');
23386 //            Roo.log(this.syncValue());
23387             this.syncValue();
23388             this.inputEl().removeClass(['hide', 'x-hidden']);
23389             this.inputEl().dom.removeAttribute('tabIndex');
23390             this.inputEl().focus();
23391         }else{
23392             Roo.log('editor - hiding textarea');
23393 //            Roo.log('out')
23394 //            Roo.log(this.pushValue()); 
23395             this.pushValue();
23396             
23397             this.inputEl().addClass(['hide', 'x-hidden']);
23398             this.inputEl().dom.setAttribute('tabIndex', -1);
23399             //this.deferFocus();
23400         }
23401          
23402         if(this.resizable){
23403             this.setSize(this.wrap.getSize());
23404         }
23405         
23406         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23407     },
23408  
23409     // private (for BoxComponent)
23410     adjustSize : Roo.BoxComponent.prototype.adjustSize,
23411
23412     // private (for BoxComponent)
23413     getResizeEl : function(){
23414         return this.wrap;
23415     },
23416
23417     // private (for BoxComponent)
23418     getPositionEl : function(){
23419         return this.wrap;
23420     },
23421
23422     // private
23423     initEvents : function(){
23424         this.originalValue = this.getValue();
23425     },
23426
23427 //    /**
23428 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23429 //     * @method
23430 //     */
23431 //    markInvalid : Roo.emptyFn,
23432 //    /**
23433 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23434 //     * @method
23435 //     */
23436 //    clearInvalid : Roo.emptyFn,
23437
23438     setValue : function(v){
23439         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23440         this.editorcore.pushValue();
23441     },
23442
23443      
23444     // private
23445     deferFocus : function(){
23446         this.focus.defer(10, this);
23447     },
23448
23449     // doc'ed in Field
23450     focus : function(){
23451         this.editorcore.focus();
23452         
23453     },
23454       
23455
23456     // private
23457     onDestroy : function(){
23458         
23459         
23460         
23461         if(this.rendered){
23462             
23463             for (var i =0; i < this.toolbars.length;i++) {
23464                 // fixme - ask toolbars for heights?
23465                 this.toolbars[i].onDestroy();
23466             }
23467             
23468             this.wrap.dom.innerHTML = '';
23469             this.wrap.remove();
23470         }
23471     },
23472
23473     // private
23474     onFirstFocus : function(){
23475         //Roo.log("onFirstFocus");
23476         this.editorcore.onFirstFocus();
23477          for (var i =0; i < this.toolbars.length;i++) {
23478             this.toolbars[i].onFirstFocus();
23479         }
23480         
23481     },
23482     
23483     // private
23484     syncValue : function()
23485     {   
23486         this.editorcore.syncValue();
23487     },
23488     
23489     pushValue : function()
23490     {   
23491         this.editorcore.pushValue();
23492     }
23493      
23494     
23495     // hide stuff that is not compatible
23496     /**
23497      * @event blur
23498      * @hide
23499      */
23500     /**
23501      * @event change
23502      * @hide
23503      */
23504     /**
23505      * @event focus
23506      * @hide
23507      */
23508     /**
23509      * @event specialkey
23510      * @hide
23511      */
23512     /**
23513      * @cfg {String} fieldClass @hide
23514      */
23515     /**
23516      * @cfg {String} focusClass @hide
23517      */
23518     /**
23519      * @cfg {String} autoCreate @hide
23520      */
23521     /**
23522      * @cfg {String} inputType @hide
23523      */
23524     /**
23525      * @cfg {String} invalidClass @hide
23526      */
23527     /**
23528      * @cfg {String} invalidText @hide
23529      */
23530     /**
23531      * @cfg {String} msgFx @hide
23532      */
23533     /**
23534      * @cfg {String} validateOnBlur @hide
23535      */
23536 });
23537  
23538     
23539    
23540    
23541    
23542       
23543 Roo.namespace('Roo.bootstrap.htmleditor');
23544 /**
23545  * @class Roo.bootstrap.HtmlEditorToolbar1
23546  * Basic Toolbar
23547  * 
23548  * Usage:
23549  *
23550  new Roo.bootstrap.HtmlEditor({
23551     ....
23552     toolbars : [
23553         new Roo.bootstrap.HtmlEditorToolbar1({
23554             disable : { fonts: 1 , format: 1, ..., ... , ...],
23555             btns : [ .... ]
23556         })
23557     }
23558      
23559  * 
23560  * @cfg {Object} disable List of elements to disable..
23561  * @cfg {Array} btns List of additional buttons.
23562  * 
23563  * 
23564  * NEEDS Extra CSS? 
23565  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23566  */
23567  
23568 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23569 {
23570     
23571     Roo.apply(this, config);
23572     
23573     // default disabled, based on 'good practice'..
23574     this.disable = this.disable || {};
23575     Roo.applyIf(this.disable, {
23576         fontSize : true,
23577         colors : true,
23578         specialElements : true
23579     });
23580     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23581     
23582     this.editor = config.editor;
23583     this.editorcore = config.editor.editorcore;
23584     
23585     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23586     
23587     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23588     // dont call parent... till later.
23589 }
23590 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
23591      
23592     bar : true,
23593     
23594     editor : false,
23595     editorcore : false,
23596     
23597     
23598     formats : [
23599         "p" ,  
23600         "h1","h2","h3","h4","h5","h6", 
23601         "pre", "code", 
23602         "abbr", "acronym", "address", "cite", "samp", "var",
23603         'div','span'
23604     ],
23605     
23606     onRender : function(ct, position)
23607     {
23608        // Roo.log("Call onRender: " + this.xtype);
23609         
23610        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23611        Roo.log(this.el);
23612        this.el.dom.style.marginBottom = '0';
23613        var _this = this;
23614        var editorcore = this.editorcore;
23615        var editor= this.editor;
23616        
23617        var children = [];
23618        var btn = function(id,cmd , toggle, handler, html){
23619        
23620             var  event = toggle ? 'toggle' : 'click';
23621        
23622             var a = {
23623                 size : 'sm',
23624                 xtype: 'Button',
23625                 xns: Roo.bootstrap,
23626                 glyphicon : id,
23627                 cmd : id || cmd,
23628                 enableToggle:toggle !== false,
23629                 html : html || '',
23630                 pressed : toggle ? false : null,
23631                 listeners : {}
23632             };
23633             a.listeners[toggle ? 'toggle' : 'click'] = function() {
23634                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
23635             };
23636             children.push(a);
23637             return a;
23638        }
23639        
23640     //    var cb_box = function...
23641         
23642         var style = {
23643                 xtype: 'Button',
23644                 size : 'sm',
23645                 xns: Roo.bootstrap,
23646                 glyphicon : 'font',
23647                 //html : 'submit'
23648                 menu : {
23649                     xtype: 'Menu',
23650                     xns: Roo.bootstrap,
23651                     items:  []
23652                 }
23653         };
23654         Roo.each(this.formats, function(f) {
23655             style.menu.items.push({
23656                 xtype :'MenuItem',
23657                 xns: Roo.bootstrap,
23658                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23659                 tagname : f,
23660                 listeners : {
23661                     click : function()
23662                     {
23663                         editorcore.insertTag(this.tagname);
23664                         editor.focus();
23665                     }
23666                 }
23667                 
23668             });
23669         });
23670         children.push(style);   
23671         
23672         btn('bold',false,true);
23673         btn('italic',false,true);
23674         btn('align-left', 'justifyleft',true);
23675         btn('align-center', 'justifycenter',true);
23676         btn('align-right' , 'justifyright',true);
23677         btn('link', false, false, function(btn) {
23678             //Roo.log("create link?");
23679             var url = prompt(this.createLinkText, this.defaultLinkValue);
23680             if(url && url != 'http:/'+'/'){
23681                 this.editorcore.relayCmd('createlink', url);
23682             }
23683         }),
23684         btn('list','insertunorderedlist',true);
23685         btn('pencil', false,true, function(btn){
23686                 Roo.log(this);
23687                 this.toggleSourceEdit(btn.pressed);
23688         });
23689         
23690         if (this.editor.btns.length > 0) {
23691             for (var i = 0; i<this.editor.btns.length; i++) {
23692                 children.push(this.editor.btns[i]);
23693             }
23694         }
23695         
23696         /*
23697         var cog = {
23698                 xtype: 'Button',
23699                 size : 'sm',
23700                 xns: Roo.bootstrap,
23701                 glyphicon : 'cog',
23702                 //html : 'submit'
23703                 menu : {
23704                     xtype: 'Menu',
23705                     xns: Roo.bootstrap,
23706                     items:  []
23707                 }
23708         };
23709         
23710         cog.menu.items.push({
23711             xtype :'MenuItem',
23712             xns: Roo.bootstrap,
23713             html : Clean styles,
23714             tagname : f,
23715             listeners : {
23716                 click : function()
23717                 {
23718                     editorcore.insertTag(this.tagname);
23719                     editor.focus();
23720                 }
23721             }
23722             
23723         });
23724        */
23725         
23726          
23727        this.xtype = 'NavSimplebar';
23728         
23729         for(var i=0;i< children.length;i++) {
23730             
23731             this.buttons.add(this.addxtypeChild(children[i]));
23732             
23733         }
23734         
23735         editor.on('editorevent', this.updateToolbar, this);
23736     },
23737     onBtnClick : function(id)
23738     {
23739        this.editorcore.relayCmd(id);
23740        this.editorcore.focus();
23741     },
23742     
23743     /**
23744      * Protected method that will not generally be called directly. It triggers
23745      * a toolbar update by reading the markup state of the current selection in the editor.
23746      */
23747     updateToolbar: function(){
23748
23749         if(!this.editorcore.activated){
23750             this.editor.onFirstFocus(); // is this neeed?
23751             return;
23752         }
23753
23754         var btns = this.buttons; 
23755         var doc = this.editorcore.doc;
23756         btns.get('bold').setActive(doc.queryCommandState('bold'));
23757         btns.get('italic').setActive(doc.queryCommandState('italic'));
23758         //btns.get('underline').setActive(doc.queryCommandState('underline'));
23759         
23760         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23761         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23762         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23763         
23764         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23765         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23766          /*
23767         
23768         var ans = this.editorcore.getAllAncestors();
23769         if (this.formatCombo) {
23770             
23771             
23772             var store = this.formatCombo.store;
23773             this.formatCombo.setValue("");
23774             for (var i =0; i < ans.length;i++) {
23775                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23776                     // select it..
23777                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23778                     break;
23779                 }
23780             }
23781         }
23782         
23783         
23784         
23785         // hides menus... - so this cant be on a menu...
23786         Roo.bootstrap.MenuMgr.hideAll();
23787         */
23788         Roo.bootstrap.MenuMgr.hideAll();
23789         //this.editorsyncValue();
23790     },
23791     onFirstFocus: function() {
23792         this.buttons.each(function(item){
23793            item.enable();
23794         });
23795     },
23796     toggleSourceEdit : function(sourceEditMode){
23797         
23798           
23799         if(sourceEditMode){
23800             Roo.log("disabling buttons");
23801            this.buttons.each( function(item){
23802                 if(item.cmd != 'pencil'){
23803                     item.disable();
23804                 }
23805             });
23806           
23807         }else{
23808             Roo.log("enabling buttons");
23809             if(this.editorcore.initialized){
23810                 this.buttons.each( function(item){
23811                     item.enable();
23812                 });
23813             }
23814             
23815         }
23816         Roo.log("calling toggole on editor");
23817         // tell the editor that it's been pressed..
23818         this.editor.toggleSourceEdit(sourceEditMode);
23819        
23820     }
23821 });
23822
23823
23824
23825
23826
23827 /**
23828  * @class Roo.bootstrap.Table.AbstractSelectionModel
23829  * @extends Roo.util.Observable
23830  * Abstract base class for grid SelectionModels.  It provides the interface that should be
23831  * implemented by descendant classes.  This class should not be directly instantiated.
23832  * @constructor
23833  */
23834 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23835     this.locked = false;
23836     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23837 };
23838
23839
23840 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
23841     /** @ignore Called by the grid automatically. Do not call directly. */
23842     init : function(grid){
23843         this.grid = grid;
23844         this.initEvents();
23845     },
23846
23847     /**
23848      * Locks the selections.
23849      */
23850     lock : function(){
23851         this.locked = true;
23852     },
23853
23854     /**
23855      * Unlocks the selections.
23856      */
23857     unlock : function(){
23858         this.locked = false;
23859     },
23860
23861     /**
23862      * Returns true if the selections are locked.
23863      * @return {Boolean}
23864      */
23865     isLocked : function(){
23866         return this.locked;
23867     }
23868 });
23869 /**
23870  * @extends Roo.bootstrap.Table.AbstractSelectionModel
23871  * @class Roo.bootstrap.Table.RowSelectionModel
23872  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23873  * It supports multiple selections and keyboard selection/navigation. 
23874  * @constructor
23875  * @param {Object} config
23876  */
23877
23878 Roo.bootstrap.Table.RowSelectionModel = function(config){
23879     Roo.apply(this, config);
23880     this.selections = new Roo.util.MixedCollection(false, function(o){
23881         return o.id;
23882     });
23883
23884     this.last = false;
23885     this.lastActive = false;
23886
23887     this.addEvents({
23888         /**
23889              * @event selectionchange
23890              * Fires when the selection changes
23891              * @param {SelectionModel} this
23892              */
23893             "selectionchange" : true,
23894         /**
23895              * @event afterselectionchange
23896              * Fires after the selection changes (eg. by key press or clicking)
23897              * @param {SelectionModel} this
23898              */
23899             "afterselectionchange" : true,
23900         /**
23901              * @event beforerowselect
23902              * Fires when a row is selected being selected, return false to cancel.
23903              * @param {SelectionModel} this
23904              * @param {Number} rowIndex The selected index
23905              * @param {Boolean} keepExisting False if other selections will be cleared
23906              */
23907             "beforerowselect" : true,
23908         /**
23909              * @event rowselect
23910              * Fires when a row is selected.
23911              * @param {SelectionModel} this
23912              * @param {Number} rowIndex The selected index
23913              * @param {Roo.data.Record} r The record
23914              */
23915             "rowselect" : true,
23916         /**
23917              * @event rowdeselect
23918              * Fires when a row is deselected.
23919              * @param {SelectionModel} this
23920              * @param {Number} rowIndex The selected index
23921              */
23922         "rowdeselect" : true
23923     });
23924     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23925     this.locked = false;
23926  };
23927
23928 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
23929     /**
23930      * @cfg {Boolean} singleSelect
23931      * True to allow selection of only one row at a time (defaults to false)
23932      */
23933     singleSelect : false,
23934
23935     // private
23936     initEvents : function()
23937     {
23938
23939         //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23940         //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
23941         //}else{ // allow click to work like normal
23942          //   this.grid.on("rowclick", this.handleDragableRowClick, this);
23943         //}
23944         //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23945         this.grid.on("rowclick", this.handleMouseDown, this);
23946         
23947         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23948             "up" : function(e){
23949                 if(!e.shiftKey){
23950                     this.selectPrevious(e.shiftKey);
23951                 }else if(this.last !== false && this.lastActive !== false){
23952                     var last = this.last;
23953                     this.selectRange(this.last,  this.lastActive-1);
23954                     this.grid.getView().focusRow(this.lastActive);
23955                     if(last !== false){
23956                         this.last = last;
23957                     }
23958                 }else{
23959                     this.selectFirstRow();
23960                 }
23961                 this.fireEvent("afterselectionchange", this);
23962             },
23963             "down" : function(e){
23964                 if(!e.shiftKey){
23965                     this.selectNext(e.shiftKey);
23966                 }else if(this.last !== false && this.lastActive !== false){
23967                     var last = this.last;
23968                     this.selectRange(this.last,  this.lastActive+1);
23969                     this.grid.getView().focusRow(this.lastActive);
23970                     if(last !== false){
23971                         this.last = last;
23972                     }
23973                 }else{
23974                     this.selectFirstRow();
23975                 }
23976                 this.fireEvent("afterselectionchange", this);
23977             },
23978             scope: this
23979         });
23980         this.grid.store.on('load', function(){
23981             this.selections.clear();
23982         },this);
23983         /*
23984         var view = this.grid.view;
23985         view.on("refresh", this.onRefresh, this);
23986         view.on("rowupdated", this.onRowUpdated, this);
23987         view.on("rowremoved", this.onRemove, this);
23988         */
23989     },
23990
23991     // private
23992     onRefresh : function()
23993     {
23994         var ds = this.grid.store, i, v = this.grid.view;
23995         var s = this.selections;
23996         s.each(function(r){
23997             if((i = ds.indexOfId(r.id)) != -1){
23998                 v.onRowSelect(i);
23999             }else{
24000                 s.remove(r);
24001             }
24002         });
24003     },
24004
24005     // private
24006     onRemove : function(v, index, r){
24007         this.selections.remove(r);
24008     },
24009
24010     // private
24011     onRowUpdated : function(v, index, r){
24012         if(this.isSelected(r)){
24013             v.onRowSelect(index);
24014         }
24015     },
24016
24017     /**
24018      * Select records.
24019      * @param {Array} records The records to select
24020      * @param {Boolean} keepExisting (optional) True to keep existing selections
24021      */
24022     selectRecords : function(records, keepExisting)
24023     {
24024         if(!keepExisting){
24025             this.clearSelections();
24026         }
24027             var ds = this.grid.store;
24028         for(var i = 0, len = records.length; i < len; i++){
24029             this.selectRow(ds.indexOf(records[i]), true);
24030         }
24031     },
24032
24033     /**
24034      * Gets the number of selected rows.
24035      * @return {Number}
24036      */
24037     getCount : function(){
24038         return this.selections.length;
24039     },
24040
24041     /**
24042      * Selects the first row in the grid.
24043      */
24044     selectFirstRow : function(){
24045         this.selectRow(0);
24046     },
24047
24048     /**
24049      * Select the last row.
24050      * @param {Boolean} keepExisting (optional) True to keep existing selections
24051      */
24052     selectLastRow : function(keepExisting){
24053         //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24054         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24055     },
24056
24057     /**
24058      * Selects the row immediately following the last selected row.
24059      * @param {Boolean} keepExisting (optional) True to keep existing selections
24060      */
24061     selectNext : function(keepExisting)
24062     {
24063             if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24064             this.selectRow(this.last+1, keepExisting);
24065             this.grid.getView().focusRow(this.last);
24066         }
24067     },
24068
24069     /**
24070      * Selects the row that precedes the last selected row.
24071      * @param {Boolean} keepExisting (optional) True to keep existing selections
24072      */
24073     selectPrevious : function(keepExisting){
24074         if(this.last){
24075             this.selectRow(this.last-1, keepExisting);
24076             this.grid.getView().focusRow(this.last);
24077         }
24078     },
24079
24080     /**
24081      * Returns the selected records
24082      * @return {Array} Array of selected records
24083      */
24084     getSelections : function(){
24085         return [].concat(this.selections.items);
24086     },
24087
24088     /**
24089      * Returns the first selected record.
24090      * @return {Record}
24091      */
24092     getSelected : function(){
24093         return this.selections.itemAt(0);
24094     },
24095
24096
24097     /**
24098      * Clears all selections.
24099      */
24100     clearSelections : function(fast)
24101     {
24102         if(this.locked) {
24103             return;
24104         }
24105         if(fast !== true){
24106                 var ds = this.grid.store;
24107             var s = this.selections;
24108             s.each(function(r){
24109                 this.deselectRow(ds.indexOfId(r.id));
24110             }, this);
24111             s.clear();
24112         }else{
24113             this.selections.clear();
24114         }
24115         this.last = false;
24116     },
24117
24118
24119     /**
24120      * Selects all rows.
24121      */
24122     selectAll : function(){
24123         if(this.locked) {
24124             return;
24125         }
24126         this.selections.clear();
24127         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24128             this.selectRow(i, true);
24129         }
24130     },
24131
24132     /**
24133      * Returns True if there is a selection.
24134      * @return {Boolean}
24135      */
24136     hasSelection : function(){
24137         return this.selections.length > 0;
24138     },
24139
24140     /**
24141      * Returns True if the specified row is selected.
24142      * @param {Number/Record} record The record or index of the record to check
24143      * @return {Boolean}
24144      */
24145     isSelected : function(index){
24146             var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24147         return (r && this.selections.key(r.id) ? true : false);
24148     },
24149
24150     /**
24151      * Returns True if the specified record id is selected.
24152      * @param {String} id The id of record to check
24153      * @return {Boolean}
24154      */
24155     isIdSelected : function(id){
24156         return (this.selections.key(id) ? true : false);
24157     },
24158
24159
24160     // private
24161     handleMouseDBClick : function(e, t){
24162         
24163     },
24164     // private
24165     handleMouseDown : function(e, t)
24166     {
24167             var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24168         if(this.isLocked() || rowIndex < 0 ){
24169             return;
24170         };
24171         if(e.shiftKey && this.last !== false){
24172             var last = this.last;
24173             this.selectRange(last, rowIndex, e.ctrlKey);
24174             this.last = last; // reset the last
24175             t.focus();
24176     
24177         }else{
24178             var isSelected = this.isSelected(rowIndex);
24179             //Roo.log("select row:" + rowIndex);
24180             if(isSelected){
24181                 this.deselectRow(rowIndex);
24182             } else {
24183                         this.selectRow(rowIndex, true);
24184             }
24185     
24186             /*
24187                 if(e.button !== 0 && isSelected){
24188                 alert('rowIndex 2: ' + rowIndex);
24189                     view.focusRow(rowIndex);
24190                 }else if(e.ctrlKey && isSelected){
24191                     this.deselectRow(rowIndex);
24192                 }else if(!isSelected){
24193                     this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24194                     view.focusRow(rowIndex);
24195                 }
24196             */
24197         }
24198         this.fireEvent("afterselectionchange", this);
24199     },
24200     // private
24201     handleDragableRowClick :  function(grid, rowIndex, e) 
24202     {
24203         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24204             this.selectRow(rowIndex, false);
24205             grid.view.focusRow(rowIndex);
24206              this.fireEvent("afterselectionchange", this);
24207         }
24208     },
24209     
24210     /**
24211      * Selects multiple rows.
24212      * @param {Array} rows Array of the indexes of the row to select
24213      * @param {Boolean} keepExisting (optional) True to keep existing selections
24214      */
24215     selectRows : function(rows, keepExisting){
24216         if(!keepExisting){
24217             this.clearSelections();
24218         }
24219         for(var i = 0, len = rows.length; i < len; i++){
24220             this.selectRow(rows[i], true);
24221         }
24222     },
24223
24224     /**
24225      * Selects a range of rows. All rows in between startRow and endRow are also selected.
24226      * @param {Number} startRow The index of the first row in the range
24227      * @param {Number} endRow The index of the last row in the range
24228      * @param {Boolean} keepExisting (optional) True to retain existing selections
24229      */
24230     selectRange : function(startRow, endRow, keepExisting){
24231         if(this.locked) {
24232             return;
24233         }
24234         if(!keepExisting){
24235             this.clearSelections();
24236         }
24237         if(startRow <= endRow){
24238             for(var i = startRow; i <= endRow; i++){
24239                 this.selectRow(i, true);
24240             }
24241         }else{
24242             for(var i = startRow; i >= endRow; i--){
24243                 this.selectRow(i, true);
24244             }
24245         }
24246     },
24247
24248     /**
24249      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24250      * @param {Number} startRow The index of the first row in the range
24251      * @param {Number} endRow The index of the last row in the range
24252      */
24253     deselectRange : function(startRow, endRow, preventViewNotify){
24254         if(this.locked) {
24255             return;
24256         }
24257         for(var i = startRow; i <= endRow; i++){
24258             this.deselectRow(i, preventViewNotify);
24259         }
24260     },
24261
24262     /**
24263      * Selects a row.
24264      * @param {Number} row The index of the row to select
24265      * @param {Boolean} keepExisting (optional) True to keep existing selections
24266      */
24267     selectRow : function(index, keepExisting, preventViewNotify)
24268     {
24269             if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24270             return;
24271         }
24272         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24273             if(!keepExisting || this.singleSelect){
24274                 this.clearSelections();
24275             }
24276             
24277             var r = this.grid.store.getAt(index);
24278             //console.log('selectRow - record id :' + r.id);
24279             
24280             this.selections.add(r);
24281             this.last = this.lastActive = index;
24282             if(!preventViewNotify){
24283                 var proxy = new Roo.Element(
24284                                 this.grid.getRowDom(index)
24285                 );
24286                 proxy.addClass('bg-info info');
24287             }
24288             this.fireEvent("rowselect", this, index, r);
24289             this.fireEvent("selectionchange", this);
24290         }
24291     },
24292
24293     /**
24294      * Deselects a row.
24295      * @param {Number} row The index of the row to deselect
24296      */
24297     deselectRow : function(index, preventViewNotify)
24298     {
24299         if(this.locked) {
24300             return;
24301         }
24302         if(this.last == index){
24303             this.last = false;
24304         }
24305         if(this.lastActive == index){
24306             this.lastActive = false;
24307         }
24308         
24309         var r = this.grid.store.getAt(index);
24310         if (!r) {
24311             return;
24312         }
24313         
24314         this.selections.remove(r);
24315         //.console.log('deselectRow - record id :' + r.id);
24316         if(!preventViewNotify){
24317         
24318             var proxy = new Roo.Element(
24319                 this.grid.getRowDom(index)
24320             );
24321             proxy.removeClass('bg-info info');
24322         }
24323         this.fireEvent("rowdeselect", this, index);
24324         this.fireEvent("selectionchange", this);
24325     },
24326
24327     // private
24328     restoreLast : function(){
24329         if(this._last){
24330             this.last = this._last;
24331         }
24332     },
24333
24334     // private
24335     acceptsNav : function(row, col, cm){
24336         return !cm.isHidden(col) && cm.isCellEditable(col, row);
24337     },
24338
24339     // private
24340     onEditorKey : function(field, e){
24341         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24342         if(k == e.TAB){
24343             e.stopEvent();
24344             ed.completeEdit();
24345             if(e.shiftKey){
24346                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24347             }else{
24348                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24349             }
24350         }else if(k == e.ENTER && !e.ctrlKey){
24351             e.stopEvent();
24352             ed.completeEdit();
24353             if(e.shiftKey){
24354                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24355             }else{
24356                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24357             }
24358         }else if(k == e.ESC){
24359             ed.cancelEdit();
24360         }
24361         if(newCell){
24362             g.startEditing(newCell[0], newCell[1]);
24363         }
24364     }
24365 });
24366 /*
24367  * Based on:
24368  * Ext JS Library 1.1.1
24369  * Copyright(c) 2006-2007, Ext JS, LLC.
24370  *
24371  * Originally Released Under LGPL - original licence link has changed is not relivant.
24372  *
24373  * Fork - LGPL
24374  * <script type="text/javascript">
24375  */
24376  
24377 /**
24378  * @class Roo.bootstrap.PagingToolbar
24379  * @extends Roo.bootstrap.NavSimplebar
24380  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24381  * @constructor
24382  * Create a new PagingToolbar
24383  * @param {Object} config The config object
24384  * @param {Roo.data.Store} store
24385  */
24386 Roo.bootstrap.PagingToolbar = function(config)
24387 {
24388     // old args format still supported... - xtype is prefered..
24389         // created from xtype...
24390     
24391     this.ds = config.dataSource;
24392     
24393     if (config.store && !this.ds) {
24394         this.store= Roo.factory(config.store, Roo.data);
24395         this.ds = this.store;
24396         this.ds.xmodule = this.xmodule || false;
24397     }
24398     
24399     this.toolbarItems = [];
24400     if (config.items) {
24401         this.toolbarItems = config.items;
24402     }
24403     
24404     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24405     
24406     this.cursor = 0;
24407     
24408     if (this.ds) { 
24409         this.bind(this.ds);
24410     }
24411     
24412     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24413     
24414 };
24415
24416 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24417     /**
24418      * @cfg {Roo.data.Store} dataSource
24419      * The underlying data store providing the paged data
24420      */
24421     /**
24422      * @cfg {String/HTMLElement/Element} container
24423      * container The id or element that will contain the toolbar
24424      */
24425     /**
24426      * @cfg {Boolean} displayInfo
24427      * True to display the displayMsg (defaults to false)
24428      */
24429     /**
24430      * @cfg {Number} pageSize
24431      * The number of records to display per page (defaults to 20)
24432      */
24433     pageSize: 20,
24434     /**
24435      * @cfg {String} displayMsg
24436      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24437      */
24438     displayMsg : 'Displaying {0} - {1} of {2}',
24439     /**
24440      * @cfg {String} emptyMsg
24441      * The message to display when no records are found (defaults to "No data to display")
24442      */
24443     emptyMsg : 'No data to display',
24444     /**
24445      * Customizable piece of the default paging text (defaults to "Page")
24446      * @type String
24447      */
24448     beforePageText : "Page",
24449     /**
24450      * Customizable piece of the default paging text (defaults to "of %0")
24451      * @type String
24452      */
24453     afterPageText : "of {0}",
24454     /**
24455      * Customizable piece of the default paging text (defaults to "First Page")
24456      * @type String
24457      */
24458     firstText : "First Page",
24459     /**
24460      * Customizable piece of the default paging text (defaults to "Previous Page")
24461      * @type String
24462      */
24463     prevText : "Previous Page",
24464     /**
24465      * Customizable piece of the default paging text (defaults to "Next Page")
24466      * @type String
24467      */
24468     nextText : "Next Page",
24469     /**
24470      * Customizable piece of the default paging text (defaults to "Last Page")
24471      * @type String
24472      */
24473     lastText : "Last Page",
24474     /**
24475      * Customizable piece of the default paging text (defaults to "Refresh")
24476      * @type String
24477      */
24478     refreshText : "Refresh",
24479
24480     buttons : false,
24481     // private
24482     onRender : function(ct, position) 
24483     {
24484         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24485         this.navgroup.parentId = this.id;
24486         this.navgroup.onRender(this.el, null);
24487         // add the buttons to the navgroup
24488         
24489         if(this.displayInfo){
24490             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24491             this.displayEl = this.el.select('.x-paging-info', true).first();
24492 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24493 //            this.displayEl = navel.el.select('span',true).first();
24494         }
24495         
24496         var _this = this;
24497         
24498         if(this.buttons){
24499             Roo.each(_this.buttons, function(e){ // this might need to use render????
24500                Roo.factory(e).onRender(_this.el, null);
24501             });
24502         }
24503             
24504         Roo.each(_this.toolbarItems, function(e) {
24505             _this.navgroup.addItem(e);
24506         });
24507         
24508         
24509         this.first = this.navgroup.addItem({
24510             tooltip: this.firstText,
24511             cls: "prev",
24512             icon : 'fa fa-backward',
24513             disabled: true,
24514             preventDefault: true,
24515             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24516         });
24517         
24518         this.prev =  this.navgroup.addItem({
24519             tooltip: this.prevText,
24520             cls: "prev",
24521             icon : 'fa fa-step-backward',
24522             disabled: true,
24523             preventDefault: true,
24524             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
24525         });
24526     //this.addSeparator();
24527         
24528         
24529         var field = this.navgroup.addItem( {
24530             tagtype : 'span',
24531             cls : 'x-paging-position',
24532             
24533             html : this.beforePageText  +
24534                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24535                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
24536          } ); //?? escaped?
24537         
24538         this.field = field.el.select('input', true).first();
24539         this.field.on("keydown", this.onPagingKeydown, this);
24540         this.field.on("focus", function(){this.dom.select();});
24541     
24542     
24543         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
24544         //this.field.setHeight(18);
24545         //this.addSeparator();
24546         this.next = this.navgroup.addItem({
24547             tooltip: this.nextText,
24548             cls: "next",
24549             html : ' <i class="fa fa-step-forward">',
24550             disabled: true,
24551             preventDefault: true,
24552             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
24553         });
24554         this.last = this.navgroup.addItem({
24555             tooltip: this.lastText,
24556             icon : 'fa fa-forward',
24557             cls: "next",
24558             disabled: true,
24559             preventDefault: true,
24560             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
24561         });
24562     //this.addSeparator();
24563         this.loading = this.navgroup.addItem({
24564             tooltip: this.refreshText,
24565             icon: 'fa fa-refresh',
24566             preventDefault: true,
24567             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24568         });
24569         
24570     },
24571
24572     // private
24573     updateInfo : function(){
24574         if(this.displayEl){
24575             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24576             var msg = count == 0 ?
24577                 this.emptyMsg :
24578                 String.format(
24579                     this.displayMsg,
24580                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
24581                 );
24582             this.displayEl.update(msg);
24583         }
24584     },
24585
24586     // private
24587     onLoad : function(ds, r, o)
24588     {
24589         this.cursor = o.params.start ? o.params.start : 0;
24590         
24591         var d = this.getPageData(),
24592             ap = d.activePage,
24593             ps = d.pages;
24594         
24595         
24596         this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24597         this.field.dom.value = ap;
24598         this.first.setDisabled(ap == 1);
24599         this.prev.setDisabled(ap == 1);
24600         this.next.setDisabled(ap == ps);
24601         this.last.setDisabled(ap == ps);
24602         this.loading.enable();
24603         this.updateInfo();
24604     },
24605
24606     // private
24607     getPageData : function(){
24608         var total = this.ds.getTotalCount();
24609         return {
24610             total : total,
24611             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24612             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24613         };
24614     },
24615
24616     // private
24617     onLoadError : function(){
24618         this.loading.enable();
24619     },
24620
24621     // private
24622     onPagingKeydown : function(e){
24623         var k = e.getKey();
24624         var d = this.getPageData();
24625         if(k == e.RETURN){
24626             var v = this.field.dom.value, pageNum;
24627             if(!v || isNaN(pageNum = parseInt(v, 10))){
24628                 this.field.dom.value = d.activePage;
24629                 return;
24630             }
24631             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24632             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24633             e.stopEvent();
24634         }
24635         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))
24636         {
24637           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24638           this.field.dom.value = pageNum;
24639           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24640           e.stopEvent();
24641         }
24642         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24643         {
24644           var v = this.field.dom.value, pageNum; 
24645           var increment = (e.shiftKey) ? 10 : 1;
24646           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24647                 increment *= -1;
24648           }
24649           if(!v || isNaN(pageNum = parseInt(v, 10))) {
24650             this.field.dom.value = d.activePage;
24651             return;
24652           }
24653           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24654           {
24655             this.field.dom.value = parseInt(v, 10) + increment;
24656             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24657             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24658           }
24659           e.stopEvent();
24660         }
24661     },
24662
24663     // private
24664     beforeLoad : function(){
24665         if(this.loading){
24666             this.loading.disable();
24667         }
24668     },
24669
24670     // private
24671     onClick : function(which){
24672         
24673         var ds = this.ds;
24674         if (!ds) {
24675             return;
24676         }
24677         
24678         switch(which){
24679             case "first":
24680                 ds.load({params:{start: 0, limit: this.pageSize}});
24681             break;
24682             case "prev":
24683                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24684             break;
24685             case "next":
24686                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24687             break;
24688             case "last":
24689                 var total = ds.getTotalCount();
24690                 var extra = total % this.pageSize;
24691                 var lastStart = extra ? (total - extra) : total-this.pageSize;
24692                 ds.load({params:{start: lastStart, limit: this.pageSize}});
24693             break;
24694             case "refresh":
24695                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24696             break;
24697         }
24698     },
24699
24700     /**
24701      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24702      * @param {Roo.data.Store} store The data store to unbind
24703      */
24704     unbind : function(ds){
24705         ds.un("beforeload", this.beforeLoad, this);
24706         ds.un("load", this.onLoad, this);
24707         ds.un("loadexception", this.onLoadError, this);
24708         ds.un("remove", this.updateInfo, this);
24709         ds.un("add", this.updateInfo, this);
24710         this.ds = undefined;
24711     },
24712
24713     /**
24714      * Binds the paging toolbar to the specified {@link Roo.data.Store}
24715      * @param {Roo.data.Store} store The data store to bind
24716      */
24717     bind : function(ds){
24718         ds.on("beforeload", this.beforeLoad, this);
24719         ds.on("load", this.onLoad, this);
24720         ds.on("loadexception", this.onLoadError, this);
24721         ds.on("remove", this.updateInfo, this);
24722         ds.on("add", this.updateInfo, this);
24723         this.ds = ds;
24724     }
24725 });/*
24726  * - LGPL
24727  *
24728  * element
24729  * 
24730  */
24731
24732 /**
24733  * @class Roo.bootstrap.MessageBar
24734  * @extends Roo.bootstrap.Component
24735  * Bootstrap MessageBar class
24736  * @cfg {String} html contents of the MessageBar
24737  * @cfg {String} weight (info | success | warning | danger) default info
24738  * @cfg {String} beforeClass insert the bar before the given class
24739  * @cfg {Boolean} closable (true | false) default false
24740  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24741  * 
24742  * @constructor
24743  * Create a new Element
24744  * @param {Object} config The config object
24745  */
24746
24747 Roo.bootstrap.MessageBar = function(config){
24748     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24749 };
24750
24751 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
24752     
24753     html: '',
24754     weight: 'info',
24755     closable: false,
24756     fixed: false,
24757     beforeClass: 'bootstrap-sticky-wrap',
24758     
24759     getAutoCreate : function(){
24760         
24761         var cfg = {
24762             tag: 'div',
24763             cls: 'alert alert-dismissable alert-' + this.weight,
24764             cn: [
24765                 {
24766                     tag: 'span',
24767                     cls: 'message',
24768                     html: this.html || ''
24769                 }
24770             ]
24771         };
24772         
24773         if(this.fixed){
24774             cfg.cls += ' alert-messages-fixed';
24775         }
24776         
24777         if(this.closable){
24778             cfg.cn.push({
24779                 tag: 'button',
24780                 cls: 'close',
24781                 html: 'x'
24782             });
24783         }
24784         
24785         return cfg;
24786     },
24787     
24788     onRender : function(ct, position)
24789     {
24790         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24791         
24792         if(!this.el){
24793             var cfg = Roo.apply({},  this.getAutoCreate());
24794             cfg.id = Roo.id();
24795             
24796             if (this.cls) {
24797                 cfg.cls += ' ' + this.cls;
24798             }
24799             if (this.style) {
24800                 cfg.style = this.style;
24801             }
24802             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24803             
24804             this.el.setVisibilityMode(Roo.Element.DISPLAY);
24805         }
24806         
24807         this.el.select('>button.close').on('click', this.hide, this);
24808         
24809     },
24810     
24811     show : function()
24812     {
24813         if (!this.rendered) {
24814             this.render();
24815         }
24816         
24817         this.el.show();
24818         
24819         this.fireEvent('show', this);
24820         
24821     },
24822     
24823     hide : function()
24824     {
24825         if (!this.rendered) {
24826             this.render();
24827         }
24828         
24829         this.el.hide();
24830         
24831         this.fireEvent('hide', this);
24832     },
24833     
24834     update : function()
24835     {
24836 //        var e = this.el.dom.firstChild;
24837 //        
24838 //        if(this.closable){
24839 //            e = e.nextSibling;
24840 //        }
24841 //        
24842 //        e.data = this.html || '';
24843
24844         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24845     }
24846    
24847 });
24848
24849  
24850
24851      /*
24852  * - LGPL
24853  *
24854  * Graph
24855  * 
24856  */
24857
24858
24859 /**
24860  * @class Roo.bootstrap.Graph
24861  * @extends Roo.bootstrap.Component
24862  * Bootstrap Graph class
24863 > Prameters
24864  -sm {number} sm 4
24865  -md {number} md 5
24866  @cfg {String} graphtype  bar | vbar | pie
24867  @cfg {number} g_x coodinator | centre x (pie)
24868  @cfg {number} g_y coodinator | centre y (pie)
24869  @cfg {number} g_r radius (pie)
24870  @cfg {number} g_height height of the chart (respected by all elements in the set)
24871  @cfg {number} g_width width of the chart (respected by all elements in the set)
24872  @cfg {Object} title The title of the chart
24873     
24874  -{Array}  values
24875  -opts (object) options for the chart 
24876      o {
24877      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24878      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24879      o vgutter (number)
24880      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.
24881      o stacked (boolean) whether or not to tread values as in a stacked bar chart
24882      o to
24883      o stretch (boolean)
24884      o }
24885  -opts (object) options for the pie
24886      o{
24887      o cut
24888      o startAngle (number)
24889      o endAngle (number)
24890      } 
24891  *
24892  * @constructor
24893  * Create a new Input
24894  * @param {Object} config The config object
24895  */
24896
24897 Roo.bootstrap.Graph = function(config){
24898     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24899     
24900     this.addEvents({
24901         // img events
24902         /**
24903          * @event click
24904          * The img click event for the img.
24905          * @param {Roo.EventObject} e
24906          */
24907         "click" : true
24908     });
24909 };
24910
24911 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
24912     
24913     sm: 4,
24914     md: 5,
24915     graphtype: 'bar',
24916     g_height: 250,
24917     g_width: 400,
24918     g_x: 50,
24919     g_y: 50,
24920     g_r: 30,
24921     opts:{
24922         //g_colors: this.colors,
24923         g_type: 'soft',
24924         g_gutter: '20%'
24925
24926     },
24927     title : false,
24928
24929     getAutoCreate : function(){
24930         
24931         var cfg = {
24932             tag: 'div',
24933             html : null
24934         };
24935         
24936         
24937         return  cfg;
24938     },
24939
24940     onRender : function(ct,position){
24941         
24942         
24943         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24944         
24945         if (typeof(Raphael) == 'undefined') {
24946             Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24947             return;
24948         }
24949         
24950         this.raphael = Raphael(this.el.dom);
24951         
24952                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24953                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24954                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24955                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24956                 /*
24957                 r.text(160, 10, "Single Series Chart").attr(txtattr);
24958                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24959                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24960                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24961                 
24962                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24963                 r.barchart(330, 10, 300, 220, data1);
24964                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24965                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24966                 */
24967                 
24968                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24969                 // r.barchart(30, 30, 560, 250,  xdata, {
24970                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24971                 //     axis : "0 0 1 1",
24972                 //     axisxlabels :  xdata
24973                 //     //yvalues : cols,
24974                    
24975                 // });
24976 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24977 //        
24978 //        this.load(null,xdata,{
24979 //                axis : "0 0 1 1",
24980 //                axisxlabels :  xdata
24981 //                });
24982
24983     },
24984
24985     load : function(graphtype,xdata,opts)
24986     {
24987         this.raphael.clear();
24988         if(!graphtype) {
24989             graphtype = this.graphtype;
24990         }
24991         if(!opts){
24992             opts = this.opts;
24993         }
24994         var r = this.raphael,
24995             fin = function () {
24996                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24997             },
24998             fout = function () {
24999                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25000             },
25001             pfin = function() {
25002                 this.sector.stop();
25003                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25004
25005                 if (this.label) {
25006                     this.label[0].stop();
25007                     this.label[0].attr({ r: 7.5 });
25008                     this.label[1].attr({ "font-weight": 800 });
25009                 }
25010             },
25011             pfout = function() {
25012                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25013
25014                 if (this.label) {
25015                     this.label[0].animate({ r: 5 }, 500, "bounce");
25016                     this.label[1].attr({ "font-weight": 400 });
25017                 }
25018             };
25019
25020         switch(graphtype){
25021             case 'bar':
25022                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25023                 break;
25024             case 'hbar':
25025                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25026                 break;
25027             case 'pie':
25028 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
25029 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25030 //            
25031                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25032                 
25033                 break;
25034
25035         }
25036         
25037         if(this.title){
25038             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25039         }
25040         
25041     },
25042     
25043     setTitle: function(o)
25044     {
25045         this.title = o;
25046     },
25047     
25048     initEvents: function() {
25049         
25050         if(!this.href){
25051             this.el.on('click', this.onClick, this);
25052         }
25053     },
25054     
25055     onClick : function(e)
25056     {
25057         Roo.log('img onclick');
25058         this.fireEvent('click', this, e);
25059     }
25060    
25061 });
25062
25063  
25064 /*
25065  * - LGPL
25066  *
25067  * numberBox
25068  * 
25069  */
25070 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25071
25072 /**
25073  * @class Roo.bootstrap.dash.NumberBox
25074  * @extends Roo.bootstrap.Component
25075  * Bootstrap NumberBox class
25076  * @cfg {String} headline Box headline
25077  * @cfg {String} content Box content
25078  * @cfg {String} icon Box icon
25079  * @cfg {String} footer Footer text
25080  * @cfg {String} fhref Footer href
25081  * 
25082  * @constructor
25083  * Create a new NumberBox
25084  * @param {Object} config The config object
25085  */
25086
25087
25088 Roo.bootstrap.dash.NumberBox = function(config){
25089     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25090     
25091 };
25092
25093 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
25094     
25095     headline : '',
25096     content : '',
25097     icon : '',
25098     footer : '',
25099     fhref : '',
25100     ficon : '',
25101     
25102     getAutoCreate : function(){
25103         
25104         var cfg = {
25105             tag : 'div',
25106             cls : 'small-box ',
25107             cn : [
25108                 {
25109                     tag : 'div',
25110                     cls : 'inner',
25111                     cn :[
25112                         {
25113                             tag : 'h3',
25114                             cls : 'roo-headline',
25115                             html : this.headline
25116                         },
25117                         {
25118                             tag : 'p',
25119                             cls : 'roo-content',
25120                             html : this.content
25121                         }
25122                     ]
25123                 }
25124             ]
25125         };
25126         
25127         if(this.icon){
25128             cfg.cn.push({
25129                 tag : 'div',
25130                 cls : 'icon',
25131                 cn :[
25132                     {
25133                         tag : 'i',
25134                         cls : 'ion ' + this.icon
25135                     }
25136                 ]
25137             });
25138         }
25139         
25140         if(this.footer){
25141             var footer = {
25142                 tag : 'a',
25143                 cls : 'small-box-footer',
25144                 href : this.fhref || '#',
25145                 html : this.footer
25146             };
25147             
25148             cfg.cn.push(footer);
25149             
25150         }
25151         
25152         return  cfg;
25153     },
25154
25155     onRender : function(ct,position){
25156         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25157
25158
25159        
25160                 
25161     },
25162
25163     setHeadline: function (value)
25164     {
25165         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25166     },
25167     
25168     setFooter: function (value, href)
25169     {
25170         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25171         
25172         if(href){
25173             this.el.select('a.small-box-footer',true).first().attr('href', href);
25174         }
25175         
25176     },
25177
25178     setContent: function (value)
25179     {
25180         this.el.select('.roo-content',true).first().dom.innerHTML = value;
25181     },
25182
25183     initEvents: function() 
25184     {   
25185         
25186     }
25187     
25188 });
25189
25190  
25191 /*
25192  * - LGPL
25193  *
25194  * TabBox
25195  * 
25196  */
25197 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25198
25199 /**
25200  * @class Roo.bootstrap.dash.TabBox
25201  * @extends Roo.bootstrap.Component
25202  * Bootstrap TabBox class
25203  * @cfg {String} title Title of the TabBox
25204  * @cfg {String} icon Icon of the TabBox
25205  * @cfg {Boolean} showtabs (true|false) show the tabs default true
25206  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25207  * 
25208  * @constructor
25209  * Create a new TabBox
25210  * @param {Object} config The config object
25211  */
25212
25213
25214 Roo.bootstrap.dash.TabBox = function(config){
25215     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25216     this.addEvents({
25217         // raw events
25218         /**
25219          * @event addpane
25220          * When a pane is added
25221          * @param {Roo.bootstrap.dash.TabPane} pane
25222          */
25223         "addpane" : true,
25224         /**
25225          * @event activatepane
25226          * When a pane is activated
25227          * @param {Roo.bootstrap.dash.TabPane} pane
25228          */
25229         "activatepane" : true
25230         
25231          
25232     });
25233     
25234     this.panes = [];
25235 };
25236
25237 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
25238
25239     title : '',
25240     icon : false,
25241     showtabs : true,
25242     tabScrollable : false,
25243     
25244     getChildContainer : function()
25245     {
25246         return this.el.select('.tab-content', true).first();
25247     },
25248     
25249     getAutoCreate : function(){
25250         
25251         var header = {
25252             tag: 'li',
25253             cls: 'pull-left header',
25254             html: this.title,
25255             cn : []
25256         };
25257         
25258         if(this.icon){
25259             header.cn.push({
25260                 tag: 'i',
25261                 cls: 'fa ' + this.icon
25262             });
25263         }
25264         
25265         var h = {
25266             tag: 'ul',
25267             cls: 'nav nav-tabs pull-right',
25268             cn: [
25269                 header
25270             ]
25271         };
25272         
25273         if(this.tabScrollable){
25274             h = {
25275                 tag: 'div',
25276                 cls: 'tab-header',
25277                 cn: [
25278                     {
25279                         tag: 'ul',
25280                         cls: 'nav nav-tabs pull-right',
25281                         cn: [
25282                             header
25283                         ]
25284                     }
25285                 ]
25286             };
25287         }
25288         
25289         var cfg = {
25290             tag: 'div',
25291             cls: 'nav-tabs-custom',
25292             cn: [
25293                 h,
25294                 {
25295                     tag: 'div',
25296                     cls: 'tab-content no-padding',
25297                     cn: []
25298                 }
25299             ]
25300         };
25301
25302         return  cfg;
25303     },
25304     initEvents : function()
25305     {
25306         //Roo.log('add add pane handler');
25307         this.on('addpane', this.onAddPane, this);
25308     },
25309      /**
25310      * Updates the box title
25311      * @param {String} html to set the title to.
25312      */
25313     setTitle : function(value)
25314     {
25315         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25316     },
25317     onAddPane : function(pane)
25318     {
25319         this.panes.push(pane);
25320         //Roo.log('addpane');
25321         //Roo.log(pane);
25322         // tabs are rendere left to right..
25323         if(!this.showtabs){
25324             return;
25325         }
25326         
25327         var ctr = this.el.select('.nav-tabs', true).first();
25328          
25329          
25330         var existing = ctr.select('.nav-tab',true);
25331         var qty = existing.getCount();;
25332         
25333         
25334         var tab = ctr.createChild({
25335             tag : 'li',
25336             cls : 'nav-tab' + (qty ? '' : ' active'),
25337             cn : [
25338                 {
25339                     tag : 'a',
25340                     href:'#',
25341                     html : pane.title
25342                 }
25343             ]
25344         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25345         pane.tab = tab;
25346         
25347         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25348         if (!qty) {
25349             pane.el.addClass('active');
25350         }
25351         
25352                 
25353     },
25354     onTabClick : function(ev,un,ob,pane)
25355     {
25356         //Roo.log('tab - prev default');
25357         ev.preventDefault();
25358         
25359         
25360         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25361         pane.tab.addClass('active');
25362         //Roo.log(pane.title);
25363         this.getChildContainer().select('.tab-pane',true).removeClass('active');
25364         // technically we should have a deactivate event.. but maybe add later.
25365         // and it should not de-activate the selected tab...
25366         this.fireEvent('activatepane', pane);
25367         pane.el.addClass('active');
25368         pane.fireEvent('activate');
25369         
25370         
25371     },
25372     
25373     getActivePane : function()
25374     {
25375         var r = false;
25376         Roo.each(this.panes, function(p) {
25377             if(p.el.hasClass('active')){
25378                 r = p;
25379                 return false;
25380             }
25381             
25382             return;
25383         });
25384         
25385         return r;
25386     }
25387     
25388     
25389 });
25390
25391  
25392 /*
25393  * - LGPL
25394  *
25395  * Tab pane
25396  * 
25397  */
25398 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25399 /**
25400  * @class Roo.bootstrap.TabPane
25401  * @extends Roo.bootstrap.Component
25402  * Bootstrap TabPane class
25403  * @cfg {Boolean} active (false | true) Default false
25404  * @cfg {String} title title of panel
25405
25406  * 
25407  * @constructor
25408  * Create a new TabPane
25409  * @param {Object} config The config object
25410  */
25411
25412 Roo.bootstrap.dash.TabPane = function(config){
25413     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25414     
25415     this.addEvents({
25416         // raw events
25417         /**
25418          * @event activate
25419          * When a pane is activated
25420          * @param {Roo.bootstrap.dash.TabPane} pane
25421          */
25422         "activate" : true
25423          
25424     });
25425 };
25426
25427 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
25428     
25429     active : false,
25430     title : '',
25431     
25432     // the tabBox that this is attached to.
25433     tab : false,
25434      
25435     getAutoCreate : function() 
25436     {
25437         var cfg = {
25438             tag: 'div',
25439             cls: 'tab-pane'
25440         };
25441         
25442         if(this.active){
25443             cfg.cls += ' active';
25444         }
25445         
25446         return cfg;
25447     },
25448     initEvents  : function()
25449     {
25450         //Roo.log('trigger add pane handler');
25451         this.parent().fireEvent('addpane', this)
25452     },
25453     
25454      /**
25455      * Updates the tab title 
25456      * @param {String} html to set the title to.
25457      */
25458     setTitle: function(str)
25459     {
25460         if (!this.tab) {
25461             return;
25462         }
25463         this.title = str;
25464         this.tab.select('a', true).first().dom.innerHTML = str;
25465         
25466     }
25467     
25468     
25469     
25470 });
25471
25472  
25473
25474
25475  /*
25476  * - LGPL
25477  *
25478  * menu
25479  * 
25480  */
25481 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25482
25483 /**
25484  * @class Roo.bootstrap.menu.Menu
25485  * @extends Roo.bootstrap.Component
25486  * Bootstrap Menu class - container for Menu
25487  * @cfg {String} html Text of the menu
25488  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25489  * @cfg {String} icon Font awesome icon
25490  * @cfg {String} pos Menu align to (top | bottom) default bottom
25491  * 
25492  * 
25493  * @constructor
25494  * Create a new Menu
25495  * @param {Object} config The config object
25496  */
25497
25498
25499 Roo.bootstrap.menu.Menu = function(config){
25500     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25501     
25502     this.addEvents({
25503         /**
25504          * @event beforeshow
25505          * Fires before this menu is displayed
25506          * @param {Roo.bootstrap.menu.Menu} this
25507          */
25508         beforeshow : true,
25509         /**
25510          * @event beforehide
25511          * Fires before this menu is hidden
25512          * @param {Roo.bootstrap.menu.Menu} this
25513          */
25514         beforehide : true,
25515         /**
25516          * @event show
25517          * Fires after this menu is displayed
25518          * @param {Roo.bootstrap.menu.Menu} this
25519          */
25520         show : true,
25521         /**
25522          * @event hide
25523          * Fires after this menu is hidden
25524          * @param {Roo.bootstrap.menu.Menu} this
25525          */
25526         hide : true,
25527         /**
25528          * @event click
25529          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25530          * @param {Roo.bootstrap.menu.Menu} this
25531          * @param {Roo.EventObject} e
25532          */
25533         click : true
25534     });
25535     
25536 };
25537
25538 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
25539     
25540     submenu : false,
25541     html : '',
25542     weight : 'default',
25543     icon : false,
25544     pos : 'bottom',
25545     
25546     
25547     getChildContainer : function() {
25548         if(this.isSubMenu){
25549             return this.el;
25550         }
25551         
25552         return this.el.select('ul.dropdown-menu', true).first();  
25553     },
25554     
25555     getAutoCreate : function()
25556     {
25557         var text = [
25558             {
25559                 tag : 'span',
25560                 cls : 'roo-menu-text',
25561                 html : this.html
25562             }
25563         ];
25564         
25565         if(this.icon){
25566             text.unshift({
25567                 tag : 'i',
25568                 cls : 'fa ' + this.icon
25569             })
25570         }
25571         
25572         
25573         var cfg = {
25574             tag : 'div',
25575             cls : 'btn-group',
25576             cn : [
25577                 {
25578                     tag : 'button',
25579                     cls : 'dropdown-button btn btn-' + this.weight,
25580                     cn : text
25581                 },
25582                 {
25583                     tag : 'button',
25584                     cls : 'dropdown-toggle btn btn-' + this.weight,
25585                     cn : [
25586                         {
25587                             tag : 'span',
25588                             cls : 'caret'
25589                         }
25590                     ]
25591                 },
25592                 {
25593                     tag : 'ul',
25594                     cls : 'dropdown-menu'
25595                 }
25596             ]
25597             
25598         };
25599         
25600         if(this.pos == 'top'){
25601             cfg.cls += ' dropup';
25602         }
25603         
25604         if(this.isSubMenu){
25605             cfg = {
25606                 tag : 'ul',
25607                 cls : 'dropdown-menu'
25608             }
25609         }
25610         
25611         return cfg;
25612     },
25613     
25614     onRender : function(ct, position)
25615     {
25616         this.isSubMenu = ct.hasClass('dropdown-submenu');
25617         
25618         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25619     },
25620     
25621     initEvents : function() 
25622     {
25623         if(this.isSubMenu){
25624             return;
25625         }
25626         
25627         this.hidden = true;
25628         
25629         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25630         this.triggerEl.on('click', this.onTriggerPress, this);
25631         
25632         this.buttonEl = this.el.select('button.dropdown-button', true).first();
25633         this.buttonEl.on('click', this.onClick, this);
25634         
25635     },
25636     
25637     list : function()
25638     {
25639         if(this.isSubMenu){
25640             return this.el;
25641         }
25642         
25643         return this.el.select('ul.dropdown-menu', true).first();
25644     },
25645     
25646     onClick : function(e)
25647     {
25648         this.fireEvent("click", this, e);
25649     },
25650     
25651     onTriggerPress  : function(e)
25652     {   
25653         if (this.isVisible()) {
25654             this.hide();
25655         } else {
25656             this.show();
25657         }
25658     },
25659     
25660     isVisible : function(){
25661         return !this.hidden;
25662     },
25663     
25664     show : function()
25665     {
25666         this.fireEvent("beforeshow", this);
25667         
25668         this.hidden = false;
25669         this.el.addClass('open');
25670         
25671         Roo.get(document).on("mouseup", this.onMouseUp, this);
25672         
25673         this.fireEvent("show", this);
25674         
25675         
25676     },
25677     
25678     hide : function()
25679     {
25680         this.fireEvent("beforehide", this);
25681         
25682         this.hidden = true;
25683         this.el.removeClass('open');
25684         
25685         Roo.get(document).un("mouseup", this.onMouseUp);
25686         
25687         this.fireEvent("hide", this);
25688     },
25689     
25690     onMouseUp : function()
25691     {
25692         this.hide();
25693     }
25694     
25695 });
25696
25697  
25698  /*
25699  * - LGPL
25700  *
25701  * menu item
25702  * 
25703  */
25704 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25705
25706 /**
25707  * @class Roo.bootstrap.menu.Item
25708  * @extends Roo.bootstrap.Component
25709  * Bootstrap MenuItem class
25710  * @cfg {Boolean} submenu (true | false) default false
25711  * @cfg {String} html text of the item
25712  * @cfg {String} href the link
25713  * @cfg {Boolean} disable (true | false) default false
25714  * @cfg {Boolean} preventDefault (true | false) default true
25715  * @cfg {String} icon Font awesome icon
25716  * @cfg {String} pos Submenu align to (left | right) default right 
25717  * 
25718  * 
25719  * @constructor
25720  * Create a new Item
25721  * @param {Object} config The config object
25722  */
25723
25724
25725 Roo.bootstrap.menu.Item = function(config){
25726     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25727     this.addEvents({
25728         /**
25729          * @event mouseover
25730          * Fires when the mouse is hovering over this menu
25731          * @param {Roo.bootstrap.menu.Item} this
25732          * @param {Roo.EventObject} e
25733          */
25734         mouseover : true,
25735         /**
25736          * @event mouseout
25737          * Fires when the mouse exits this menu
25738          * @param {Roo.bootstrap.menu.Item} this
25739          * @param {Roo.EventObject} e
25740          */
25741         mouseout : true,
25742         // raw events
25743         /**
25744          * @event click
25745          * The raw click event for the entire grid.
25746          * @param {Roo.EventObject} e
25747          */
25748         click : true
25749     });
25750 };
25751
25752 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
25753     
25754     submenu : false,
25755     href : '',
25756     html : '',
25757     preventDefault: true,
25758     disable : false,
25759     icon : false,
25760     pos : 'right',
25761     
25762     getAutoCreate : function()
25763     {
25764         var text = [
25765             {
25766                 tag : 'span',
25767                 cls : 'roo-menu-item-text',
25768                 html : this.html
25769             }
25770         ];
25771         
25772         if(this.icon){
25773             text.unshift({
25774                 tag : 'i',
25775                 cls : 'fa ' + this.icon
25776             })
25777         }
25778         
25779         var cfg = {
25780             tag : 'li',
25781             cn : [
25782                 {
25783                     tag : 'a',
25784                     href : this.href || '#',
25785                     cn : text
25786                 }
25787             ]
25788         };
25789         
25790         if(this.disable){
25791             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25792         }
25793         
25794         if(this.submenu){
25795             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25796             
25797             if(this.pos == 'left'){
25798                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25799             }
25800         }
25801         
25802         return cfg;
25803     },
25804     
25805     initEvents : function() 
25806     {
25807         this.el.on('mouseover', this.onMouseOver, this);
25808         this.el.on('mouseout', this.onMouseOut, this);
25809         
25810         this.el.select('a', true).first().on('click', this.onClick, this);
25811         
25812     },
25813     
25814     onClick : function(e)
25815     {
25816         if(this.preventDefault){
25817             e.preventDefault();
25818         }
25819         
25820         this.fireEvent("click", this, e);
25821     },
25822     
25823     onMouseOver : function(e)
25824     {
25825         if(this.submenu && this.pos == 'left'){
25826             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25827         }
25828         
25829         this.fireEvent("mouseover", this, e);
25830     },
25831     
25832     onMouseOut : function(e)
25833     {
25834         this.fireEvent("mouseout", this, e);
25835     }
25836 });
25837
25838  
25839
25840  /*
25841  * - LGPL
25842  *
25843  * menu separator
25844  * 
25845  */
25846 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25847
25848 /**
25849  * @class Roo.bootstrap.menu.Separator
25850  * @extends Roo.bootstrap.Component
25851  * Bootstrap Separator class
25852  * 
25853  * @constructor
25854  * Create a new Separator
25855  * @param {Object} config The config object
25856  */
25857
25858
25859 Roo.bootstrap.menu.Separator = function(config){
25860     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25861 };
25862
25863 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
25864     
25865     getAutoCreate : function(){
25866         var cfg = {
25867             tag : 'li',
25868             cls: 'divider'
25869         };
25870         
25871         return cfg;
25872     }
25873    
25874 });
25875
25876  
25877
25878  /*
25879  * - LGPL
25880  *
25881  * Tooltip
25882  * 
25883  */
25884
25885 /**
25886  * @class Roo.bootstrap.Tooltip
25887  * Bootstrap Tooltip class
25888  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25889  * to determine which dom element triggers the tooltip.
25890  * 
25891  * It needs to add support for additional attributes like tooltip-position
25892  * 
25893  * @constructor
25894  * Create a new Toolti
25895  * @param {Object} config The config object
25896  */
25897
25898 Roo.bootstrap.Tooltip = function(config){
25899     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25900     
25901     this.alignment = Roo.bootstrap.Tooltip.alignment;
25902     
25903     if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25904         this.alignment = config.alignment;
25905     }
25906     
25907 };
25908
25909 Roo.apply(Roo.bootstrap.Tooltip, {
25910     /**
25911      * @function init initialize tooltip monitoring.
25912      * @static
25913      */
25914     currentEl : false,
25915     currentTip : false,
25916     currentRegion : false,
25917     
25918     //  init : delay?
25919     
25920     init : function()
25921     {
25922         Roo.get(document).on('mouseover', this.enter ,this);
25923         Roo.get(document).on('mouseout', this.leave, this);
25924          
25925         
25926         this.currentTip = new Roo.bootstrap.Tooltip();
25927     },
25928     
25929     enter : function(ev)
25930     {
25931         var dom = ev.getTarget();
25932         
25933         //Roo.log(['enter',dom]);
25934         var el = Roo.fly(dom);
25935         if (this.currentEl) {
25936             //Roo.log(dom);
25937             //Roo.log(this.currentEl);
25938             //Roo.log(this.currentEl.contains(dom));
25939             if (this.currentEl == el) {
25940                 return;
25941             }
25942             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25943                 return;
25944             }
25945
25946         }
25947         
25948         if (this.currentTip.el) {
25949             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25950         }    
25951         //Roo.log(ev);
25952         
25953         if(!el || el.dom == document){
25954             return;
25955         }
25956         
25957         var bindEl = el;
25958         
25959         // you can not look for children, as if el is the body.. then everythign is the child..
25960         if (!el.attr('tooltip')) { //
25961             if (!el.select("[tooltip]").elements.length) {
25962                 return;
25963             }
25964             // is the mouse over this child...?
25965             bindEl = el.select("[tooltip]").first();
25966             var xy = ev.getXY();
25967             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25968                 //Roo.log("not in region.");
25969                 return;
25970             }
25971             //Roo.log("child element over..");
25972             
25973         }
25974         this.currentEl = bindEl;
25975         this.currentTip.bind(bindEl);
25976         this.currentRegion = Roo.lib.Region.getRegion(dom);
25977         this.currentTip.enter();
25978         
25979     },
25980     leave : function(ev)
25981     {
25982         var dom = ev.getTarget();
25983         //Roo.log(['leave',dom]);
25984         if (!this.currentEl) {
25985             return;
25986         }
25987         
25988         
25989         if (dom != this.currentEl.dom) {
25990             return;
25991         }
25992         var xy = ev.getXY();
25993         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
25994             return;
25995         }
25996         // only activate leave if mouse cursor is outside... bounding box..
25997         
25998         
25999         
26000         
26001         if (this.currentTip) {
26002             this.currentTip.leave();
26003         }
26004         //Roo.log('clear currentEl');
26005         this.currentEl = false;
26006         
26007         
26008     },
26009     alignment : {
26010         'left' : ['r-l', [-2,0], 'right'],
26011         'right' : ['l-r', [2,0], 'left'],
26012         'bottom' : ['t-b', [0,2], 'top'],
26013         'top' : [ 'b-t', [0,-2], 'bottom']
26014     }
26015     
26016 });
26017
26018
26019 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
26020     
26021     
26022     bindEl : false,
26023     
26024     delay : null, // can be { show : 300 , hide: 500}
26025     
26026     timeout : null,
26027     
26028     hoverState : null, //???
26029     
26030     placement : 'bottom', 
26031     
26032     alignment : false,
26033     
26034     getAutoCreate : function(){
26035     
26036         var cfg = {
26037            cls : 'tooltip',
26038            role : 'tooltip',
26039            cn : [
26040                 {
26041                     cls : 'tooltip-arrow'
26042                 },
26043                 {
26044                     cls : 'tooltip-inner'
26045                 }
26046            ]
26047         };
26048         
26049         return cfg;
26050     },
26051     bind : function(el)
26052     {
26053         this.bindEl = el;
26054     },
26055       
26056     
26057     enter : function () {
26058        
26059         if (this.timeout != null) {
26060             clearTimeout(this.timeout);
26061         }
26062         
26063         this.hoverState = 'in';
26064          //Roo.log("enter - show");
26065         if (!this.delay || !this.delay.show) {
26066             this.show();
26067             return;
26068         }
26069         var _t = this;
26070         this.timeout = setTimeout(function () {
26071             if (_t.hoverState == 'in') {
26072                 _t.show();
26073             }
26074         }, this.delay.show);
26075     },
26076     leave : function()
26077     {
26078         clearTimeout(this.timeout);
26079     
26080         this.hoverState = 'out';
26081          if (!this.delay || !this.delay.hide) {
26082             this.hide();
26083             return;
26084         }
26085        
26086         var _t = this;
26087         this.timeout = setTimeout(function () {
26088             //Roo.log("leave - timeout");
26089             
26090             if (_t.hoverState == 'out') {
26091                 _t.hide();
26092                 Roo.bootstrap.Tooltip.currentEl = false;
26093             }
26094         }, delay);
26095     },
26096     
26097     show : function (msg)
26098     {
26099         if (!this.el) {
26100             this.render(document.body);
26101         }
26102         // set content.
26103         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26104         
26105         var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26106         
26107         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26108         
26109         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26110         
26111         var placement = typeof this.placement == 'function' ?
26112             this.placement.call(this, this.el, on_el) :
26113             this.placement;
26114             
26115         var autoToken = /\s?auto?\s?/i;
26116         var autoPlace = autoToken.test(placement);
26117         if (autoPlace) {
26118             placement = placement.replace(autoToken, '') || 'top';
26119         }
26120         
26121         //this.el.detach()
26122         //this.el.setXY([0,0]);
26123         this.el.show();
26124         //this.el.dom.style.display='block';
26125         
26126         //this.el.appendTo(on_el);
26127         
26128         var p = this.getPosition();
26129         var box = this.el.getBox();
26130         
26131         if (autoPlace) {
26132             // fixme..
26133         }
26134         
26135         var align = this.alignment[placement];
26136         
26137         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26138         
26139         if(placement == 'top' || placement == 'bottom'){
26140             if(xy[0] < 0){
26141                 placement = 'right';
26142             }
26143             
26144             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26145                 placement = 'left';
26146             }
26147             
26148             var scroll = Roo.select('body', true).first().getScroll();
26149             
26150             if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26151                 placement = 'top';
26152             }
26153             
26154         }
26155         
26156         this.el.alignTo(this.bindEl, align[0],align[1]);
26157         //var arrow = this.el.select('.arrow',true).first();
26158         //arrow.set(align[2], 
26159         
26160         this.el.addClass(placement);
26161         
26162         this.el.addClass('in fade');
26163         
26164         this.hoverState = null;
26165         
26166         if (this.el.hasClass('fade')) {
26167             // fade it?
26168         }
26169         
26170     },
26171     hide : function()
26172     {
26173          
26174         if (!this.el) {
26175             return;
26176         }
26177         //this.el.setXY([0,0]);
26178         this.el.removeClass('in');
26179         //this.el.hide();
26180         
26181     }
26182     
26183 });
26184  
26185
26186  /*
26187  * - LGPL
26188  *
26189  * Location Picker
26190  * 
26191  */
26192
26193 /**
26194  * @class Roo.bootstrap.LocationPicker
26195  * @extends Roo.bootstrap.Component
26196  * Bootstrap LocationPicker class
26197  * @cfg {Number} latitude Position when init default 0
26198  * @cfg {Number} longitude Position when init default 0
26199  * @cfg {Number} zoom default 15
26200  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26201  * @cfg {Boolean} mapTypeControl default false
26202  * @cfg {Boolean} disableDoubleClickZoom default false
26203  * @cfg {Boolean} scrollwheel default true
26204  * @cfg {Boolean} streetViewControl default false
26205  * @cfg {Number} radius default 0
26206  * @cfg {String} locationName
26207  * @cfg {Boolean} draggable default true
26208  * @cfg {Boolean} enableAutocomplete default false
26209  * @cfg {Boolean} enableReverseGeocode default true
26210  * @cfg {String} markerTitle
26211  * 
26212  * @constructor
26213  * Create a new LocationPicker
26214  * @param {Object} config The config object
26215  */
26216
26217
26218 Roo.bootstrap.LocationPicker = function(config){
26219     
26220     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26221     
26222     this.addEvents({
26223         /**
26224          * @event initial
26225          * Fires when the picker initialized.
26226          * @param {Roo.bootstrap.LocationPicker} this
26227          * @param {Google Location} location
26228          */
26229         initial : true,
26230         /**
26231          * @event positionchanged
26232          * Fires when the picker position changed.
26233          * @param {Roo.bootstrap.LocationPicker} this
26234          * @param {Google Location} location
26235          */
26236         positionchanged : true,
26237         /**
26238          * @event resize
26239          * Fires when the map resize.
26240          * @param {Roo.bootstrap.LocationPicker} this
26241          */
26242         resize : true,
26243         /**
26244          * @event show
26245          * Fires when the map show.
26246          * @param {Roo.bootstrap.LocationPicker} this
26247          */
26248         show : true,
26249         /**
26250          * @event hide
26251          * Fires when the map hide.
26252          * @param {Roo.bootstrap.LocationPicker} this
26253          */
26254         hide : true,
26255         /**
26256          * @event mapClick
26257          * Fires when click the map.
26258          * @param {Roo.bootstrap.LocationPicker} this
26259          * @param {Map event} e
26260          */
26261         mapClick : true,
26262         /**
26263          * @event mapRightClick
26264          * Fires when right click the map.
26265          * @param {Roo.bootstrap.LocationPicker} this
26266          * @param {Map event} e
26267          */
26268         mapRightClick : true,
26269         /**
26270          * @event markerClick
26271          * Fires when click the marker.
26272          * @param {Roo.bootstrap.LocationPicker} this
26273          * @param {Map event} e
26274          */
26275         markerClick : true,
26276         /**
26277          * @event markerRightClick
26278          * Fires when right click the marker.
26279          * @param {Roo.bootstrap.LocationPicker} this
26280          * @param {Map event} e
26281          */
26282         markerRightClick : true,
26283         /**
26284          * @event OverlayViewDraw
26285          * Fires when OverlayView Draw
26286          * @param {Roo.bootstrap.LocationPicker} this
26287          */
26288         OverlayViewDraw : true,
26289         /**
26290          * @event OverlayViewOnAdd
26291          * Fires when OverlayView Draw
26292          * @param {Roo.bootstrap.LocationPicker} this
26293          */
26294         OverlayViewOnAdd : true,
26295         /**
26296          * @event OverlayViewOnRemove
26297          * Fires when OverlayView Draw
26298          * @param {Roo.bootstrap.LocationPicker} this
26299          */
26300         OverlayViewOnRemove : true,
26301         /**
26302          * @event OverlayViewShow
26303          * Fires when OverlayView Draw
26304          * @param {Roo.bootstrap.LocationPicker} this
26305          * @param {Pixel} cpx
26306          */
26307         OverlayViewShow : true,
26308         /**
26309          * @event OverlayViewHide
26310          * Fires when OverlayView Draw
26311          * @param {Roo.bootstrap.LocationPicker} this
26312          */
26313         OverlayViewHide : true,
26314         /**
26315          * @event loadexception
26316          * Fires when load google lib failed.
26317          * @param {Roo.bootstrap.LocationPicker} this
26318          */
26319         loadexception : true
26320     });
26321         
26322 };
26323
26324 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
26325     
26326     gMapContext: false,
26327     
26328     latitude: 0,
26329     longitude: 0,
26330     zoom: 15,
26331     mapTypeId: false,
26332     mapTypeControl: false,
26333     disableDoubleClickZoom: false,
26334     scrollwheel: true,
26335     streetViewControl: false,
26336     radius: 0,
26337     locationName: '',
26338     draggable: true,
26339     enableAutocomplete: false,
26340     enableReverseGeocode: true,
26341     markerTitle: '',
26342     
26343     getAutoCreate: function()
26344     {
26345
26346         var cfg = {
26347             tag: 'div',
26348             cls: 'roo-location-picker'
26349         };
26350         
26351         return cfg
26352     },
26353     
26354     initEvents: function(ct, position)
26355     {       
26356         if(!this.el.getWidth() || this.isApplied()){
26357             return;
26358         }
26359         
26360         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26361         
26362         this.initial();
26363     },
26364     
26365     initial: function()
26366     {
26367         if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26368             this.fireEvent('loadexception', this);
26369             return;
26370         }
26371         
26372         if(!this.mapTypeId){
26373             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26374         }
26375         
26376         this.gMapContext = this.GMapContext();
26377         
26378         this.initOverlayView();
26379         
26380         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26381         
26382         var _this = this;
26383                 
26384         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26385             _this.setPosition(_this.gMapContext.marker.position);
26386         });
26387         
26388         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26389             _this.fireEvent('mapClick', this, event);
26390             
26391         });
26392
26393         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26394             _this.fireEvent('mapRightClick', this, event);
26395             
26396         });
26397         
26398         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26399             _this.fireEvent('markerClick', this, event);
26400             
26401         });
26402
26403         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26404             _this.fireEvent('markerRightClick', this, event);
26405             
26406         });
26407         
26408         this.setPosition(this.gMapContext.location);
26409         
26410         this.fireEvent('initial', this, this.gMapContext.location);
26411     },
26412     
26413     initOverlayView: function()
26414     {
26415         var _this = this;
26416         
26417         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26418             
26419             draw: function()
26420             {
26421                 _this.fireEvent('OverlayViewDraw', _this);
26422             },
26423             
26424             onAdd: function()
26425             {
26426                 _this.fireEvent('OverlayViewOnAdd', _this);
26427             },
26428             
26429             onRemove: function()
26430             {
26431                 _this.fireEvent('OverlayViewOnRemove', _this);
26432             },
26433             
26434             show: function(cpx)
26435             {
26436                 _this.fireEvent('OverlayViewShow', _this, cpx);
26437             },
26438             
26439             hide: function()
26440             {
26441                 _this.fireEvent('OverlayViewHide', _this);
26442             }
26443             
26444         });
26445     },
26446     
26447     fromLatLngToContainerPixel: function(event)
26448     {
26449         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26450     },
26451     
26452     isApplied: function() 
26453     {
26454         return this.getGmapContext() == false ? false : true;
26455     },
26456     
26457     getGmapContext: function() 
26458     {
26459         return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26460     },
26461     
26462     GMapContext: function() 
26463     {
26464         var position = new google.maps.LatLng(this.latitude, this.longitude);
26465         
26466         var _map = new google.maps.Map(this.el.dom, {
26467             center: position,
26468             zoom: this.zoom,
26469             mapTypeId: this.mapTypeId,
26470             mapTypeControl: this.mapTypeControl,
26471             disableDoubleClickZoom: this.disableDoubleClickZoom,
26472             scrollwheel: this.scrollwheel,
26473             streetViewControl: this.streetViewControl,
26474             locationName: this.locationName,
26475             draggable: this.draggable,
26476             enableAutocomplete: this.enableAutocomplete,
26477             enableReverseGeocode: this.enableReverseGeocode
26478         });
26479         
26480         var _marker = new google.maps.Marker({
26481             position: position,
26482             map: _map,
26483             title: this.markerTitle,
26484             draggable: this.draggable
26485         });
26486         
26487         return {
26488             map: _map,
26489             marker: _marker,
26490             circle: null,
26491             location: position,
26492             radius: this.radius,
26493             locationName: this.locationName,
26494             addressComponents: {
26495                 formatted_address: null,
26496                 addressLine1: null,
26497                 addressLine2: null,
26498                 streetName: null,
26499                 streetNumber: null,
26500                 city: null,
26501                 district: null,
26502                 state: null,
26503                 stateOrProvince: null
26504             },
26505             settings: this,
26506             domContainer: this.el.dom,
26507             geodecoder: new google.maps.Geocoder()
26508         };
26509     },
26510     
26511     drawCircle: function(center, radius, options) 
26512     {
26513         if (this.gMapContext.circle != null) {
26514             this.gMapContext.circle.setMap(null);
26515         }
26516         if (radius > 0) {
26517             radius *= 1;
26518             options = Roo.apply({}, options, {
26519                 strokeColor: "#0000FF",
26520                 strokeOpacity: .35,
26521                 strokeWeight: 2,
26522                 fillColor: "#0000FF",
26523                 fillOpacity: .2
26524             });
26525             
26526             options.map = this.gMapContext.map;
26527             options.radius = radius;
26528             options.center = center;
26529             this.gMapContext.circle = new google.maps.Circle(options);
26530             return this.gMapContext.circle;
26531         }
26532         
26533         return null;
26534     },
26535     
26536     setPosition: function(location) 
26537     {
26538         this.gMapContext.location = location;
26539         this.gMapContext.marker.setPosition(location);
26540         this.gMapContext.map.panTo(location);
26541         this.drawCircle(location, this.gMapContext.radius, {});
26542         
26543         var _this = this;
26544         
26545         if (this.gMapContext.settings.enableReverseGeocode) {
26546             this.gMapContext.geodecoder.geocode({
26547                 latLng: this.gMapContext.location
26548             }, function(results, status) {
26549                 
26550                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26551                     _this.gMapContext.locationName = results[0].formatted_address;
26552                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26553                     
26554                     _this.fireEvent('positionchanged', this, location);
26555                 }
26556             });
26557             
26558             return;
26559         }
26560         
26561         this.fireEvent('positionchanged', this, location);
26562     },
26563     
26564     resize: function()
26565     {
26566         google.maps.event.trigger(this.gMapContext.map, "resize");
26567         
26568         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26569         
26570         this.fireEvent('resize', this);
26571     },
26572     
26573     setPositionByLatLng: function(latitude, longitude)
26574     {
26575         this.setPosition(new google.maps.LatLng(latitude, longitude));
26576     },
26577     
26578     getCurrentPosition: function() 
26579     {
26580         return {
26581             latitude: this.gMapContext.location.lat(),
26582             longitude: this.gMapContext.location.lng()
26583         };
26584     },
26585     
26586     getAddressName: function() 
26587     {
26588         return this.gMapContext.locationName;
26589     },
26590     
26591     getAddressComponents: function() 
26592     {
26593         return this.gMapContext.addressComponents;
26594     },
26595     
26596     address_component_from_google_geocode: function(address_components) 
26597     {
26598         var result = {};
26599         
26600         for (var i = 0; i < address_components.length; i++) {
26601             var component = address_components[i];
26602             if (component.types.indexOf("postal_code") >= 0) {
26603                 result.postalCode = component.short_name;
26604             } else if (component.types.indexOf("street_number") >= 0) {
26605                 result.streetNumber = component.short_name;
26606             } else if (component.types.indexOf("route") >= 0) {
26607                 result.streetName = component.short_name;
26608             } else if (component.types.indexOf("neighborhood") >= 0) {
26609                 result.city = component.short_name;
26610             } else if (component.types.indexOf("locality") >= 0) {
26611                 result.city = component.short_name;
26612             } else if (component.types.indexOf("sublocality") >= 0) {
26613                 result.district = component.short_name;
26614             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26615                 result.stateOrProvince = component.short_name;
26616             } else if (component.types.indexOf("country") >= 0) {
26617                 result.country = component.short_name;
26618             }
26619         }
26620         
26621         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26622         result.addressLine2 = "";
26623         return result;
26624     },
26625     
26626     setZoomLevel: function(zoom)
26627     {
26628         this.gMapContext.map.setZoom(zoom);
26629     },
26630     
26631     show: function()
26632     {
26633         if(!this.el){
26634             return;
26635         }
26636         
26637         this.el.show();
26638         
26639         this.resize();
26640         
26641         this.fireEvent('show', this);
26642     },
26643     
26644     hide: function()
26645     {
26646         if(!this.el){
26647             return;
26648         }
26649         
26650         this.el.hide();
26651         
26652         this.fireEvent('hide', this);
26653     }
26654     
26655 });
26656
26657 Roo.apply(Roo.bootstrap.LocationPicker, {
26658     
26659     OverlayView : function(map, options)
26660     {
26661         options = options || {};
26662         
26663         this.setMap(map);
26664     }
26665     
26666     
26667 });/*
26668  * - LGPL
26669  *
26670  * Alert
26671  * 
26672  */
26673
26674 /**
26675  * @class Roo.bootstrap.Alert
26676  * @extends Roo.bootstrap.Component
26677  * Bootstrap Alert class
26678  * @cfg {String} title The title of alert
26679  * @cfg {String} html The content of alert
26680  * @cfg {String} weight (  success | info | warning | danger )
26681  * @cfg {String} faicon font-awesomeicon
26682  * 
26683  * @constructor
26684  * Create a new alert
26685  * @param {Object} config The config object
26686  */
26687
26688
26689 Roo.bootstrap.Alert = function(config){
26690     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26691     
26692 };
26693
26694 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
26695     
26696     title: '',
26697     html: '',
26698     weight: false,
26699     faicon: false,
26700     
26701     getAutoCreate : function()
26702     {
26703         
26704         var cfg = {
26705             tag : 'div',
26706             cls : 'alert',
26707             cn : [
26708                 {
26709                     tag : 'i',
26710                     cls : 'roo-alert-icon'
26711                     
26712                 },
26713                 {
26714                     tag : 'b',
26715                     cls : 'roo-alert-title',
26716                     html : this.title
26717                 },
26718                 {
26719                     tag : 'span',
26720                     cls : 'roo-alert-text',
26721                     html : this.html
26722                 }
26723             ]
26724         };
26725         
26726         if(this.faicon){
26727             cfg.cn[0].cls += ' fa ' + this.faicon;
26728         }
26729         
26730         if(this.weight){
26731             cfg.cls += ' alert-' + this.weight;
26732         }
26733         
26734         return cfg;
26735     },
26736     
26737     initEvents: function() 
26738     {
26739         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26740     },
26741     
26742     setTitle : function(str)
26743     {
26744         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26745     },
26746     
26747     setText : function(str)
26748     {
26749         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26750     },
26751     
26752     setWeight : function(weight)
26753     {
26754         if(this.weight){
26755             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26756         }
26757         
26758         this.weight = weight;
26759         
26760         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26761     },
26762     
26763     setIcon : function(icon)
26764     {
26765         if(this.faicon){
26766             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26767         }
26768         
26769         this.faicon = icon;
26770         
26771         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26772     },
26773     
26774     hide: function() 
26775     {
26776         this.el.hide();   
26777     },
26778     
26779     show: function() 
26780     {  
26781         this.el.show();   
26782     }
26783     
26784 });
26785
26786  
26787 /*
26788 * Licence: LGPL
26789 */
26790
26791 /**
26792  * @class Roo.bootstrap.UploadCropbox
26793  * @extends Roo.bootstrap.Component
26794  * Bootstrap UploadCropbox class
26795  * @cfg {String} emptyText show when image has been loaded
26796  * @cfg {String} rotateNotify show when image too small to rotate
26797  * @cfg {Number} errorTimeout default 3000
26798  * @cfg {Number} minWidth default 300
26799  * @cfg {Number} minHeight default 300
26800  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26801  * @cfg {Boolean} isDocument (true|false) default false
26802  * @cfg {String} url action url
26803  * @cfg {String} paramName default 'imageUpload'
26804  * @cfg {String} method default POST
26805  * @cfg {Boolean} loadMask (true|false) default true
26806  * @cfg {Boolean} loadingText default 'Loading...'
26807  * 
26808  * @constructor
26809  * Create a new UploadCropbox
26810  * @param {Object} config The config object
26811  */
26812
26813 Roo.bootstrap.UploadCropbox = function(config){
26814     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26815     
26816     this.addEvents({
26817         /**
26818          * @event beforeselectfile
26819          * Fire before select file
26820          * @param {Roo.bootstrap.UploadCropbox} this
26821          */
26822         "beforeselectfile" : true,
26823         /**
26824          * @event initial
26825          * Fire after initEvent
26826          * @param {Roo.bootstrap.UploadCropbox} this
26827          */
26828         "initial" : true,
26829         /**
26830          * @event crop
26831          * Fire after initEvent
26832          * @param {Roo.bootstrap.UploadCropbox} this
26833          * @param {String} data
26834          */
26835         "crop" : true,
26836         /**
26837          * @event prepare
26838          * Fire when preparing the file data
26839          * @param {Roo.bootstrap.UploadCropbox} this
26840          * @param {Object} file
26841          */
26842         "prepare" : true,
26843         /**
26844          * @event exception
26845          * Fire when get exception
26846          * @param {Roo.bootstrap.UploadCropbox} this
26847          * @param {XMLHttpRequest} xhr
26848          */
26849         "exception" : true,
26850         /**
26851          * @event beforeloadcanvas
26852          * Fire before load the canvas
26853          * @param {Roo.bootstrap.UploadCropbox} this
26854          * @param {String} src
26855          */
26856         "beforeloadcanvas" : true,
26857         /**
26858          * @event trash
26859          * Fire when trash image
26860          * @param {Roo.bootstrap.UploadCropbox} this
26861          */
26862         "trash" : true,
26863         /**
26864          * @event download
26865          * Fire when download the image
26866          * @param {Roo.bootstrap.UploadCropbox} this
26867          */
26868         "download" : true,
26869         /**
26870          * @event footerbuttonclick
26871          * Fire when footerbuttonclick
26872          * @param {Roo.bootstrap.UploadCropbox} this
26873          * @param {String} type
26874          */
26875         "footerbuttonclick" : true,
26876         /**
26877          * @event resize
26878          * Fire when resize
26879          * @param {Roo.bootstrap.UploadCropbox} this
26880          */
26881         "resize" : true,
26882         /**
26883          * @event rotate
26884          * Fire when rotate the image
26885          * @param {Roo.bootstrap.UploadCropbox} this
26886          * @param {String} pos
26887          */
26888         "rotate" : true,
26889         /**
26890          * @event inspect
26891          * Fire when inspect the file
26892          * @param {Roo.bootstrap.UploadCropbox} this
26893          * @param {Object} file
26894          */
26895         "inspect" : true,
26896         /**
26897          * @event upload
26898          * Fire when xhr upload the file
26899          * @param {Roo.bootstrap.UploadCropbox} this
26900          * @param {Object} data
26901          */
26902         "upload" : true,
26903         /**
26904          * @event arrange
26905          * Fire when arrange the file data
26906          * @param {Roo.bootstrap.UploadCropbox} this
26907          * @param {Object} formData
26908          */
26909         "arrange" : true
26910     });
26911     
26912     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26913 };
26914
26915 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
26916     
26917     emptyText : 'Click to upload image',
26918     rotateNotify : 'Image is too small to rotate',
26919     errorTimeout : 3000,
26920     scale : 0,
26921     baseScale : 1,
26922     rotate : 0,
26923     dragable : false,
26924     pinching : false,
26925     mouseX : 0,
26926     mouseY : 0,
26927     cropData : false,
26928     minWidth : 300,
26929     minHeight : 300,
26930     file : false,
26931     exif : {},
26932     baseRotate : 1,
26933     cropType : 'image/jpeg',
26934     buttons : false,
26935     canvasLoaded : false,
26936     isDocument : false,
26937     method : 'POST',
26938     paramName : 'imageUpload',
26939     loadMask : true,
26940     loadingText : 'Loading...',
26941     maskEl : false,
26942     
26943     getAutoCreate : function()
26944     {
26945         var cfg = {
26946             tag : 'div',
26947             cls : 'roo-upload-cropbox',
26948             cn : [
26949                 {
26950                     tag : 'input',
26951                     cls : 'roo-upload-cropbox-selector',
26952                     type : 'file'
26953                 },
26954                 {
26955                     tag : 'div',
26956                     cls : 'roo-upload-cropbox-body',
26957                     style : 'cursor:pointer',
26958                     cn : [
26959                         {
26960                             tag : 'div',
26961                             cls : 'roo-upload-cropbox-preview'
26962                         },
26963                         {
26964                             tag : 'div',
26965                             cls : 'roo-upload-cropbox-thumb'
26966                         },
26967                         {
26968                             tag : 'div',
26969                             cls : 'roo-upload-cropbox-empty-notify',
26970                             html : this.emptyText
26971                         },
26972                         {
26973                             tag : 'div',
26974                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26975                             html : this.rotateNotify
26976                         }
26977                     ]
26978                 },
26979                 {
26980                     tag : 'div',
26981                     cls : 'roo-upload-cropbox-footer',
26982                     cn : {
26983                         tag : 'div',
26984                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26985                         cn : []
26986                     }
26987                 }
26988             ]
26989         };
26990         
26991         return cfg;
26992     },
26993     
26994     onRender : function(ct, position)
26995     {
26996         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26997         
26998         if (this.buttons.length) {
26999             
27000             Roo.each(this.buttons, function(bb) {
27001                 
27002                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27003                 
27004                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27005                 
27006             }, this);
27007         }
27008         
27009         if(this.loadMask){
27010             this.maskEl = this.el;
27011         }
27012     },
27013     
27014     initEvents : function()
27015     {
27016         this.urlAPI = (window.createObjectURL && window) || 
27017                                 (window.URL && URL.revokeObjectURL && URL) || 
27018                                 (window.webkitURL && webkitURL);
27019                         
27020         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27021         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27022         
27023         this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27024         this.selectorEl.hide();
27025         
27026         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27027         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27028         
27029         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27030         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27031         this.thumbEl.hide();
27032         
27033         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27034         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27035         
27036         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27037         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27038         this.errorEl.hide();
27039         
27040         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27041         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27042         this.footerEl.hide();
27043         
27044         this.setThumbBoxSize();
27045         
27046         this.bind();
27047         
27048         this.resize();
27049         
27050         this.fireEvent('initial', this);
27051     },
27052
27053     bind : function()
27054     {
27055         var _this = this;
27056         
27057         window.addEventListener("resize", function() { _this.resize(); } );
27058         
27059         this.bodyEl.on('click', this.beforeSelectFile, this);
27060         
27061         if(Roo.isTouch){
27062             this.bodyEl.on('touchstart', this.onTouchStart, this);
27063             this.bodyEl.on('touchmove', this.onTouchMove, this);
27064             this.bodyEl.on('touchend', this.onTouchEnd, this);
27065         }
27066         
27067         if(!Roo.isTouch){
27068             this.bodyEl.on('mousedown', this.onMouseDown, this);
27069             this.bodyEl.on('mousemove', this.onMouseMove, this);
27070             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27071             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27072             Roo.get(document).on('mouseup', this.onMouseUp, this);
27073         }
27074         
27075         this.selectorEl.on('change', this.onFileSelected, this);
27076     },
27077     
27078     reset : function()
27079     {    
27080         this.scale = 0;
27081         this.baseScale = 1;
27082         this.rotate = 0;
27083         this.baseRotate = 1;
27084         this.dragable = false;
27085         this.pinching = false;
27086         this.mouseX = 0;
27087         this.mouseY = 0;
27088         this.cropData = false;
27089         this.notifyEl.dom.innerHTML = this.emptyText;
27090         
27091         this.selectorEl.dom.value = '';
27092         
27093     },
27094     
27095     resize : function()
27096     {
27097         if(this.fireEvent('resize', this) != false){
27098             this.setThumbBoxPosition();
27099             this.setCanvasPosition();
27100         }
27101     },
27102     
27103     onFooterButtonClick : function(e, el, o, type)
27104     {
27105         switch (type) {
27106             case 'rotate-left' :
27107                 this.onRotateLeft(e);
27108                 break;
27109             case 'rotate-right' :
27110                 this.onRotateRight(e);
27111                 break;
27112             case 'picture' :
27113                 this.beforeSelectFile(e);
27114                 break;
27115             case 'trash' :
27116                 this.trash(e);
27117                 break;
27118             case 'crop' :
27119                 this.crop(e);
27120                 break;
27121             case 'download' :
27122                 this.download(e);
27123                 break;
27124             default :
27125                 break;
27126         }
27127         
27128         this.fireEvent('footerbuttonclick', this, type);
27129     },
27130     
27131     beforeSelectFile : function(e)
27132     {
27133         e.preventDefault();
27134         
27135         if(this.fireEvent('beforeselectfile', this) != false){
27136             this.selectorEl.dom.click();
27137         }
27138     },
27139     
27140     onFileSelected : function(e)
27141     {
27142         e.preventDefault();
27143         
27144         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27145             return;
27146         }
27147         
27148         var file = this.selectorEl.dom.files[0];
27149         
27150         if(this.fireEvent('inspect', this, file) != false){
27151             this.prepare(file);
27152         }
27153         
27154     },
27155     
27156     trash : function(e)
27157     {
27158         this.fireEvent('trash', this);
27159     },
27160     
27161     download : function(e)
27162     {
27163         this.fireEvent('download', this);
27164     },
27165     
27166     loadCanvas : function(src)
27167     {   
27168         if(this.fireEvent('beforeloadcanvas', this, src) != false){
27169             
27170             this.reset();
27171             
27172             this.imageEl = document.createElement('img');
27173             
27174             var _this = this;
27175             
27176             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27177             
27178             this.imageEl.src = src;
27179         }
27180     },
27181     
27182     onLoadCanvas : function()
27183     {   
27184         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27185         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27186         
27187         this.bodyEl.un('click', this.beforeSelectFile, this);
27188         
27189         this.notifyEl.hide();
27190         this.thumbEl.show();
27191         this.footerEl.show();
27192         
27193         this.baseRotateLevel();
27194         
27195         if(this.isDocument){
27196             this.setThumbBoxSize();
27197         }
27198         
27199         this.setThumbBoxPosition();
27200         
27201         this.baseScaleLevel();
27202         
27203         this.draw();
27204         
27205         this.resize();
27206         
27207         this.canvasLoaded = true;
27208         
27209         if(this.loadMask){
27210             this.maskEl.unmask();
27211         }
27212         
27213     },
27214     
27215     setCanvasPosition : function()
27216     {   
27217         if(!this.canvasEl){
27218             return;
27219         }
27220         
27221         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27222         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27223         
27224         this.previewEl.setLeft(pw);
27225         this.previewEl.setTop(ph);
27226         
27227     },
27228     
27229     onMouseDown : function(e)
27230     {   
27231         e.stopEvent();
27232         
27233         this.dragable = true;
27234         this.pinching = false;
27235         
27236         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27237             this.dragable = false;
27238             return;
27239         }
27240         
27241         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27242         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27243         
27244     },
27245     
27246     onMouseMove : function(e)
27247     {   
27248         e.stopEvent();
27249         
27250         if(!this.canvasLoaded){
27251             return;
27252         }
27253         
27254         if (!this.dragable){
27255             return;
27256         }
27257         
27258         var minX = Math.ceil(this.thumbEl.getLeft(true));
27259         var minY = Math.ceil(this.thumbEl.getTop(true));
27260         
27261         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27262         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27263         
27264         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27265         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27266         
27267         x = x - this.mouseX;
27268         y = y - this.mouseY;
27269         
27270         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27271         var bgY = Math.ceil(y + this.previewEl.getTop(true));
27272         
27273         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27274         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27275         
27276         this.previewEl.setLeft(bgX);
27277         this.previewEl.setTop(bgY);
27278         
27279         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27280         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27281     },
27282     
27283     onMouseUp : function(e)
27284     {   
27285         e.stopEvent();
27286         
27287         this.dragable = false;
27288     },
27289     
27290     onMouseWheel : function(e)
27291     {   
27292         e.stopEvent();
27293         
27294         this.startScale = this.scale;
27295         
27296         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27297         
27298         if(!this.zoomable()){
27299             this.scale = this.startScale;
27300             return;
27301         }
27302         
27303         this.draw();
27304         
27305         return;
27306     },
27307     
27308     zoomable : function()
27309     {
27310         var minScale = this.thumbEl.getWidth() / this.minWidth;
27311         
27312         if(this.minWidth < this.minHeight){
27313             minScale = this.thumbEl.getHeight() / this.minHeight;
27314         }
27315         
27316         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27317         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27318         
27319         if(
27320                 this.isDocument &&
27321                 (this.rotate == 0 || this.rotate == 180) && 
27322                 (
27323                     width > this.imageEl.OriginWidth || 
27324                     height > this.imageEl.OriginHeight ||
27325                     (width < this.minWidth && height < this.minHeight)
27326                 )
27327         ){
27328             return false;
27329         }
27330         
27331         if(
27332                 this.isDocument &&
27333                 (this.rotate == 90 || this.rotate == 270) && 
27334                 (
27335                     width > this.imageEl.OriginWidth || 
27336                     height > this.imageEl.OriginHeight ||
27337                     (width < this.minHeight && height < this.minWidth)
27338                 )
27339         ){
27340             return false;
27341         }
27342         
27343         if(
27344                 !this.isDocument &&
27345                 (this.rotate == 0 || this.rotate == 180) && 
27346                 (
27347                     width < this.minWidth || 
27348                     width > this.imageEl.OriginWidth || 
27349                     height < this.minHeight || 
27350                     height > this.imageEl.OriginHeight
27351                 )
27352         ){
27353             return false;
27354         }
27355         
27356         if(
27357                 !this.isDocument &&
27358                 (this.rotate == 90 || this.rotate == 270) && 
27359                 (
27360                     width < this.minHeight || 
27361                     width > this.imageEl.OriginWidth || 
27362                     height < this.minWidth || 
27363                     height > this.imageEl.OriginHeight
27364                 )
27365         ){
27366             return false;
27367         }
27368         
27369         return true;
27370         
27371     },
27372     
27373     onRotateLeft : function(e)
27374     {   
27375         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27376             
27377             var minScale = this.thumbEl.getWidth() / this.minWidth;
27378             
27379             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27380             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27381             
27382             this.startScale = this.scale;
27383             
27384             while (this.getScaleLevel() < minScale){
27385             
27386                 this.scale = this.scale + 1;
27387                 
27388                 if(!this.zoomable()){
27389                     break;
27390                 }
27391                 
27392                 if(
27393                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27394                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27395                 ){
27396                     continue;
27397                 }
27398                 
27399                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27400
27401                 this.draw();
27402                 
27403                 return;
27404             }
27405             
27406             this.scale = this.startScale;
27407             
27408             this.onRotateFail();
27409             
27410             return false;
27411         }
27412         
27413         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27414
27415         if(this.isDocument){
27416             this.setThumbBoxSize();
27417             this.setThumbBoxPosition();
27418             this.setCanvasPosition();
27419         }
27420         
27421         this.draw();
27422         
27423         this.fireEvent('rotate', this, 'left');
27424         
27425     },
27426     
27427     onRotateRight : function(e)
27428     {
27429         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27430             
27431             var minScale = this.thumbEl.getWidth() / this.minWidth;
27432         
27433             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27434             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27435             
27436             this.startScale = this.scale;
27437             
27438             while (this.getScaleLevel() < minScale){
27439             
27440                 this.scale = this.scale + 1;
27441                 
27442                 if(!this.zoomable()){
27443                     break;
27444                 }
27445                 
27446                 if(
27447                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27448                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27449                 ){
27450                     continue;
27451                 }
27452                 
27453                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27454
27455                 this.draw();
27456                 
27457                 return;
27458             }
27459             
27460             this.scale = this.startScale;
27461             
27462             this.onRotateFail();
27463             
27464             return false;
27465         }
27466         
27467         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27468
27469         if(this.isDocument){
27470             this.setThumbBoxSize();
27471             this.setThumbBoxPosition();
27472             this.setCanvasPosition();
27473         }
27474         
27475         this.draw();
27476         
27477         this.fireEvent('rotate', this, 'right');
27478     },
27479     
27480     onRotateFail : function()
27481     {
27482         this.errorEl.show(true);
27483         
27484         var _this = this;
27485         
27486         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27487     },
27488     
27489     draw : function()
27490     {
27491         this.previewEl.dom.innerHTML = '';
27492         
27493         var canvasEl = document.createElement("canvas");
27494         
27495         var contextEl = canvasEl.getContext("2d");
27496         
27497         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27498         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27499         var center = this.imageEl.OriginWidth / 2;
27500         
27501         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27502             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27503             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27504             center = this.imageEl.OriginHeight / 2;
27505         }
27506         
27507         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27508         
27509         contextEl.translate(center, center);
27510         contextEl.rotate(this.rotate * Math.PI / 180);
27511
27512         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27513         
27514         this.canvasEl = document.createElement("canvas");
27515         
27516         this.contextEl = this.canvasEl.getContext("2d");
27517         
27518         switch (this.rotate) {
27519             case 0 :
27520                 
27521                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27522                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27523                 
27524                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27525                 
27526                 break;
27527             case 90 : 
27528                 
27529                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27530                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27531                 
27532                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27533                     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);
27534                     break;
27535                 }
27536                 
27537                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27538                 
27539                 break;
27540             case 180 :
27541                 
27542                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27543                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27544                 
27545                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27546                     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);
27547                     break;
27548                 }
27549                 
27550                 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);
27551                 
27552                 break;
27553             case 270 :
27554                 
27555                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27556                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27557         
27558                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27559                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27560                     break;
27561                 }
27562                 
27563                 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);
27564                 
27565                 break;
27566             default : 
27567                 break;
27568         }
27569         
27570         this.previewEl.appendChild(this.canvasEl);
27571         
27572         this.setCanvasPosition();
27573     },
27574     
27575     crop : function()
27576     {
27577         if(!this.canvasLoaded){
27578             return;
27579         }
27580         
27581         var imageCanvas = document.createElement("canvas");
27582         
27583         var imageContext = imageCanvas.getContext("2d");
27584         
27585         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27586         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27587         
27588         var center = imageCanvas.width / 2;
27589         
27590         imageContext.translate(center, center);
27591         
27592         imageContext.rotate(this.rotate * Math.PI / 180);
27593         
27594         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27595         
27596         var canvas = document.createElement("canvas");
27597         
27598         var context = canvas.getContext("2d");
27599                 
27600         canvas.width = this.minWidth;
27601         canvas.height = this.minHeight;
27602
27603         switch (this.rotate) {
27604             case 0 :
27605                 
27606                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27607                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27608                 
27609                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27610                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27611                 
27612                 var targetWidth = this.minWidth - 2 * x;
27613                 var targetHeight = this.minHeight - 2 * y;
27614                 
27615                 var scale = 1;
27616                 
27617                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27618                     scale = targetWidth / width;
27619                 }
27620                 
27621                 if(x > 0 && y == 0){
27622                     scale = targetHeight / height;
27623                 }
27624                 
27625                 if(x > 0 && y > 0){
27626                     scale = targetWidth / width;
27627                     
27628                     if(width < height){
27629                         scale = targetHeight / height;
27630                     }
27631                 }
27632                 
27633                 context.scale(scale, scale);
27634                 
27635                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27636                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27637
27638                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27639                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27640
27641                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27642                 
27643                 break;
27644             case 90 : 
27645                 
27646                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27647                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27648                 
27649                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27650                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27651                 
27652                 var targetWidth = this.minWidth - 2 * x;
27653                 var targetHeight = this.minHeight - 2 * y;
27654                 
27655                 var scale = 1;
27656                 
27657                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27658                     scale = targetWidth / width;
27659                 }
27660                 
27661                 if(x > 0 && y == 0){
27662                     scale = targetHeight / height;
27663                 }
27664                 
27665                 if(x > 0 && y > 0){
27666                     scale = targetWidth / width;
27667                     
27668                     if(width < height){
27669                         scale = targetHeight / height;
27670                     }
27671                 }
27672                 
27673                 context.scale(scale, scale);
27674                 
27675                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27676                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27677
27678                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27679                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27680                 
27681                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27682                 
27683                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27684                 
27685                 break;
27686             case 180 :
27687                 
27688                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27689                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27690                 
27691                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27692                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27693                 
27694                 var targetWidth = this.minWidth - 2 * x;
27695                 var targetHeight = this.minHeight - 2 * y;
27696                 
27697                 var scale = 1;
27698                 
27699                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27700                     scale = targetWidth / width;
27701                 }
27702                 
27703                 if(x > 0 && y == 0){
27704                     scale = targetHeight / height;
27705                 }
27706                 
27707                 if(x > 0 && y > 0){
27708                     scale = targetWidth / width;
27709                     
27710                     if(width < height){
27711                         scale = targetHeight / height;
27712                     }
27713                 }
27714                 
27715                 context.scale(scale, scale);
27716                 
27717                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27718                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27719
27720                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27721                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27722
27723                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27724                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27725                 
27726                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27727                 
27728                 break;
27729             case 270 :
27730                 
27731                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27732                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27733                 
27734                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27735                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27736                 
27737                 var targetWidth = this.minWidth - 2 * x;
27738                 var targetHeight = this.minHeight - 2 * y;
27739                 
27740                 var scale = 1;
27741                 
27742                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27743                     scale = targetWidth / width;
27744                 }
27745                 
27746                 if(x > 0 && y == 0){
27747                     scale = targetHeight / height;
27748                 }
27749                 
27750                 if(x > 0 && y > 0){
27751                     scale = targetWidth / width;
27752                     
27753                     if(width < height){
27754                         scale = targetHeight / height;
27755                     }
27756                 }
27757                 
27758                 context.scale(scale, scale);
27759                 
27760                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27761                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27762
27763                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27764                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27765                 
27766                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27767                 
27768                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27769                 
27770                 break;
27771             default : 
27772                 break;
27773         }
27774         
27775         this.cropData = canvas.toDataURL(this.cropType);
27776         
27777         if(this.fireEvent('crop', this, this.cropData) !== false){
27778             this.process(this.file, this.cropData);
27779         }
27780         
27781         return;
27782         
27783     },
27784     
27785     setThumbBoxSize : function()
27786     {
27787         var width, height;
27788         
27789         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27790             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27791             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27792             
27793             this.minWidth = width;
27794             this.minHeight = height;
27795             
27796             if(this.rotate == 90 || this.rotate == 270){
27797                 this.minWidth = height;
27798                 this.minHeight = width;
27799             }
27800         }
27801         
27802         height = 300;
27803         width = Math.ceil(this.minWidth * height / this.minHeight);
27804         
27805         if(this.minWidth > this.minHeight){
27806             width = 300;
27807             height = Math.ceil(this.minHeight * width / this.minWidth);
27808         }
27809         
27810         this.thumbEl.setStyle({
27811             width : width + 'px',
27812             height : height + 'px'
27813         });
27814
27815         return;
27816             
27817     },
27818     
27819     setThumbBoxPosition : function()
27820     {
27821         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27822         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27823         
27824         this.thumbEl.setLeft(x);
27825         this.thumbEl.setTop(y);
27826         
27827     },
27828     
27829     baseRotateLevel : function()
27830     {
27831         this.baseRotate = 1;
27832         
27833         if(
27834                 typeof(this.exif) != 'undefined' &&
27835                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27836                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27837         ){
27838             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27839         }
27840         
27841         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27842         
27843     },
27844     
27845     baseScaleLevel : function()
27846     {
27847         var width, height;
27848         
27849         if(this.isDocument){
27850             
27851             if(this.baseRotate == 6 || this.baseRotate == 8){
27852             
27853                 height = this.thumbEl.getHeight();
27854                 this.baseScale = height / this.imageEl.OriginWidth;
27855
27856                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27857                     width = this.thumbEl.getWidth();
27858                     this.baseScale = width / this.imageEl.OriginHeight;
27859                 }
27860
27861                 return;
27862             }
27863
27864             height = this.thumbEl.getHeight();
27865             this.baseScale = height / this.imageEl.OriginHeight;
27866
27867             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27868                 width = this.thumbEl.getWidth();
27869                 this.baseScale = width / this.imageEl.OriginWidth;
27870             }
27871
27872             return;
27873         }
27874         
27875         if(this.baseRotate == 6 || this.baseRotate == 8){
27876             
27877             width = this.thumbEl.getHeight();
27878             this.baseScale = width / this.imageEl.OriginHeight;
27879             
27880             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27881                 height = this.thumbEl.getWidth();
27882                 this.baseScale = height / this.imageEl.OriginHeight;
27883             }
27884             
27885             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27886                 height = this.thumbEl.getWidth();
27887                 this.baseScale = height / this.imageEl.OriginHeight;
27888                 
27889                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27890                     width = this.thumbEl.getHeight();
27891                     this.baseScale = width / this.imageEl.OriginWidth;
27892                 }
27893             }
27894             
27895             return;
27896         }
27897         
27898         width = this.thumbEl.getWidth();
27899         this.baseScale = width / this.imageEl.OriginWidth;
27900         
27901         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27902             height = this.thumbEl.getHeight();
27903             this.baseScale = height / this.imageEl.OriginHeight;
27904         }
27905         
27906         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27907             
27908             height = this.thumbEl.getHeight();
27909             this.baseScale = height / this.imageEl.OriginHeight;
27910             
27911             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27912                 width = this.thumbEl.getWidth();
27913                 this.baseScale = width / this.imageEl.OriginWidth;
27914             }
27915             
27916         }
27917         
27918         return;
27919     },
27920     
27921     getScaleLevel : function()
27922     {
27923         return this.baseScale * Math.pow(1.1, this.scale);
27924     },
27925     
27926     onTouchStart : function(e)
27927     {
27928         if(!this.canvasLoaded){
27929             this.beforeSelectFile(e);
27930             return;
27931         }
27932         
27933         var touches = e.browserEvent.touches;
27934         
27935         if(!touches){
27936             return;
27937         }
27938         
27939         if(touches.length == 1){
27940             this.onMouseDown(e);
27941             return;
27942         }
27943         
27944         if(touches.length != 2){
27945             return;
27946         }
27947         
27948         var coords = [];
27949         
27950         for(var i = 0, finger; finger = touches[i]; i++){
27951             coords.push(finger.pageX, finger.pageY);
27952         }
27953         
27954         var x = Math.pow(coords[0] - coords[2], 2);
27955         var y = Math.pow(coords[1] - coords[3], 2);
27956         
27957         this.startDistance = Math.sqrt(x + y);
27958         
27959         this.startScale = this.scale;
27960         
27961         this.pinching = true;
27962         this.dragable = false;
27963         
27964     },
27965     
27966     onTouchMove : function(e)
27967     {
27968         if(!this.pinching && !this.dragable){
27969             return;
27970         }
27971         
27972         var touches = e.browserEvent.touches;
27973         
27974         if(!touches){
27975             return;
27976         }
27977         
27978         if(this.dragable){
27979             this.onMouseMove(e);
27980             return;
27981         }
27982         
27983         var coords = [];
27984         
27985         for(var i = 0, finger; finger = touches[i]; i++){
27986             coords.push(finger.pageX, finger.pageY);
27987         }
27988         
27989         var x = Math.pow(coords[0] - coords[2], 2);
27990         var y = Math.pow(coords[1] - coords[3], 2);
27991         
27992         this.endDistance = Math.sqrt(x + y);
27993         
27994         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27995         
27996         if(!this.zoomable()){
27997             this.scale = this.startScale;
27998             return;
27999         }
28000         
28001         this.draw();
28002         
28003     },
28004     
28005     onTouchEnd : function(e)
28006     {
28007         this.pinching = false;
28008         this.dragable = false;
28009         
28010     },
28011     
28012     process : function(file, crop)
28013     {
28014         if(this.loadMask){
28015             this.maskEl.mask(this.loadingText);
28016         }
28017         
28018         this.xhr = new XMLHttpRequest();
28019         
28020         file.xhr = this.xhr;
28021
28022         this.xhr.open(this.method, this.url, true);
28023         
28024         var headers = {
28025             "Accept": "application/json",
28026             "Cache-Control": "no-cache",
28027             "X-Requested-With": "XMLHttpRequest"
28028         };
28029         
28030         for (var headerName in headers) {
28031             var headerValue = headers[headerName];
28032             if (headerValue) {
28033                 this.xhr.setRequestHeader(headerName, headerValue);
28034             }
28035         }
28036         
28037         var _this = this;
28038         
28039         this.xhr.onload = function()
28040         {
28041             _this.xhrOnLoad(_this.xhr);
28042         }
28043         
28044         this.xhr.onerror = function()
28045         {
28046             _this.xhrOnError(_this.xhr);
28047         }
28048         
28049         var formData = new FormData();
28050
28051         formData.append('returnHTML', 'NO');
28052         
28053         if(crop){
28054             formData.append('crop', crop);
28055         }
28056         
28057         if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28058             formData.append(this.paramName, file, file.name);
28059         }
28060         
28061         if(typeof(file.filename) != 'undefined'){
28062             formData.append('filename', file.filename);
28063         }
28064         
28065         if(typeof(file.mimetype) != 'undefined'){
28066             formData.append('mimetype', file.mimetype);
28067         }
28068         
28069         if(this.fireEvent('arrange', this, formData) != false){
28070             this.xhr.send(formData);
28071         };
28072     },
28073     
28074     xhrOnLoad : function(xhr)
28075     {
28076         if(this.loadMask){
28077             this.maskEl.unmask();
28078         }
28079         
28080         if (xhr.readyState !== 4) {
28081             this.fireEvent('exception', this, xhr);
28082             return;
28083         }
28084
28085         var response = Roo.decode(xhr.responseText);
28086         
28087         if(!response.success){
28088             this.fireEvent('exception', this, xhr);
28089             return;
28090         }
28091         
28092         var response = Roo.decode(xhr.responseText);
28093         
28094         this.fireEvent('upload', this, response);
28095         
28096     },
28097     
28098     xhrOnError : function()
28099     {
28100         if(this.loadMask){
28101             this.maskEl.unmask();
28102         }
28103         
28104         Roo.log('xhr on error');
28105         
28106         var response = Roo.decode(xhr.responseText);
28107           
28108         Roo.log(response);
28109         
28110     },
28111     
28112     prepare : function(file)
28113     {   
28114         if(this.loadMask){
28115             this.maskEl.mask(this.loadingText);
28116         }
28117         
28118         this.file = false;
28119         this.exif = {};
28120         
28121         if(typeof(file) === 'string'){
28122             this.loadCanvas(file);
28123             return;
28124         }
28125         
28126         if(!file || !this.urlAPI){
28127             return;
28128         }
28129         
28130         this.file = file;
28131         this.cropType = file.type;
28132         
28133         var _this = this;
28134         
28135         if(this.fireEvent('prepare', this, this.file) != false){
28136             
28137             var reader = new FileReader();
28138             
28139             reader.onload = function (e) {
28140                 if (e.target.error) {
28141                     Roo.log(e.target.error);
28142                     return;
28143                 }
28144                 
28145                 var buffer = e.target.result,
28146                     dataView = new DataView(buffer),
28147                     offset = 2,
28148                     maxOffset = dataView.byteLength - 4,
28149                     markerBytes,
28150                     markerLength;
28151                 
28152                 if (dataView.getUint16(0) === 0xffd8) {
28153                     while (offset < maxOffset) {
28154                         markerBytes = dataView.getUint16(offset);
28155                         
28156                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28157                             markerLength = dataView.getUint16(offset + 2) + 2;
28158                             if (offset + markerLength > dataView.byteLength) {
28159                                 Roo.log('Invalid meta data: Invalid segment size.');
28160                                 break;
28161                             }
28162                             
28163                             if(markerBytes == 0xffe1){
28164                                 _this.parseExifData(
28165                                     dataView,
28166                                     offset,
28167                                     markerLength
28168                                 );
28169                             }
28170                             
28171                             offset += markerLength;
28172                             
28173                             continue;
28174                         }
28175                         
28176                         break;
28177                     }
28178                     
28179                 }
28180                 
28181                 var url = _this.urlAPI.createObjectURL(_this.file);
28182                 
28183                 _this.loadCanvas(url);
28184                 
28185                 return;
28186             }
28187             
28188             reader.readAsArrayBuffer(this.file);
28189             
28190         }
28191         
28192     },
28193     
28194     parseExifData : function(dataView, offset, length)
28195     {
28196         var tiffOffset = offset + 10,
28197             littleEndian,
28198             dirOffset;
28199     
28200         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28201             // No Exif data, might be XMP data instead
28202             return;
28203         }
28204         
28205         // Check for the ASCII code for "Exif" (0x45786966):
28206         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28207             // No Exif data, might be XMP data instead
28208             return;
28209         }
28210         if (tiffOffset + 8 > dataView.byteLength) {
28211             Roo.log('Invalid Exif data: Invalid segment size.');
28212             return;
28213         }
28214         // Check for the two null bytes:
28215         if (dataView.getUint16(offset + 8) !== 0x0000) {
28216             Roo.log('Invalid Exif data: Missing byte alignment offset.');
28217             return;
28218         }
28219         // Check the byte alignment:
28220         switch (dataView.getUint16(tiffOffset)) {
28221         case 0x4949:
28222             littleEndian = true;
28223             break;
28224         case 0x4D4D:
28225             littleEndian = false;
28226             break;
28227         default:
28228             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28229             return;
28230         }
28231         // Check for the TIFF tag marker (0x002A):
28232         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28233             Roo.log('Invalid Exif data: Missing TIFF marker.');
28234             return;
28235         }
28236         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28237         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28238         
28239         this.parseExifTags(
28240             dataView,
28241             tiffOffset,
28242             tiffOffset + dirOffset,
28243             littleEndian
28244         );
28245     },
28246     
28247     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28248     {
28249         var tagsNumber,
28250             dirEndOffset,
28251             i;
28252         if (dirOffset + 6 > dataView.byteLength) {
28253             Roo.log('Invalid Exif data: Invalid directory offset.');
28254             return;
28255         }
28256         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28257         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28258         if (dirEndOffset + 4 > dataView.byteLength) {
28259             Roo.log('Invalid Exif data: Invalid directory size.');
28260             return;
28261         }
28262         for (i = 0; i < tagsNumber; i += 1) {
28263             this.parseExifTag(
28264                 dataView,
28265                 tiffOffset,
28266                 dirOffset + 2 + 12 * i, // tag offset
28267                 littleEndian
28268             );
28269         }
28270         // Return the offset to the next directory:
28271         return dataView.getUint32(dirEndOffset, littleEndian);
28272     },
28273     
28274     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
28275     {
28276         var tag = dataView.getUint16(offset, littleEndian);
28277         
28278         this.exif[tag] = this.getExifValue(
28279             dataView,
28280             tiffOffset,
28281             offset,
28282             dataView.getUint16(offset + 2, littleEndian), // tag type
28283             dataView.getUint32(offset + 4, littleEndian), // tag length
28284             littleEndian
28285         );
28286     },
28287     
28288     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28289     {
28290         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28291             tagSize,
28292             dataOffset,
28293             values,
28294             i,
28295             str,
28296             c;
28297     
28298         if (!tagType) {
28299             Roo.log('Invalid Exif data: Invalid tag type.');
28300             return;
28301         }
28302         
28303         tagSize = tagType.size * length;
28304         // Determine if the value is contained in the dataOffset bytes,
28305         // or if the value at the dataOffset is a pointer to the actual data:
28306         dataOffset = tagSize > 4 ?
28307                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28308         if (dataOffset + tagSize > dataView.byteLength) {
28309             Roo.log('Invalid Exif data: Invalid data offset.');
28310             return;
28311         }
28312         if (length === 1) {
28313             return tagType.getValue(dataView, dataOffset, littleEndian);
28314         }
28315         values = [];
28316         for (i = 0; i < length; i += 1) {
28317             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28318         }
28319         
28320         if (tagType.ascii) {
28321             str = '';
28322             // Concatenate the chars:
28323             for (i = 0; i < values.length; i += 1) {
28324                 c = values[i];
28325                 // Ignore the terminating NULL byte(s):
28326                 if (c === '\u0000') {
28327                     break;
28328                 }
28329                 str += c;
28330             }
28331             return str;
28332         }
28333         return values;
28334     }
28335     
28336 });
28337
28338 Roo.apply(Roo.bootstrap.UploadCropbox, {
28339     tags : {
28340         'Orientation': 0x0112
28341     },
28342     
28343     Orientation: {
28344             1: 0, //'top-left',
28345 //            2: 'top-right',
28346             3: 180, //'bottom-right',
28347 //            4: 'bottom-left',
28348 //            5: 'left-top',
28349             6: 90, //'right-top',
28350 //            7: 'right-bottom',
28351             8: 270 //'left-bottom'
28352     },
28353     
28354     exifTagTypes : {
28355         // byte, 8-bit unsigned int:
28356         1: {
28357             getValue: function (dataView, dataOffset) {
28358                 return dataView.getUint8(dataOffset);
28359             },
28360             size: 1
28361         },
28362         // ascii, 8-bit byte:
28363         2: {
28364             getValue: function (dataView, dataOffset) {
28365                 return String.fromCharCode(dataView.getUint8(dataOffset));
28366             },
28367             size: 1,
28368             ascii: true
28369         },
28370         // short, 16 bit int:
28371         3: {
28372             getValue: function (dataView, dataOffset, littleEndian) {
28373                 return dataView.getUint16(dataOffset, littleEndian);
28374             },
28375             size: 2
28376         },
28377         // long, 32 bit int:
28378         4: {
28379             getValue: function (dataView, dataOffset, littleEndian) {
28380                 return dataView.getUint32(dataOffset, littleEndian);
28381             },
28382             size: 4
28383         },
28384         // rational = two long values, first is numerator, second is denominator:
28385         5: {
28386             getValue: function (dataView, dataOffset, littleEndian) {
28387                 return dataView.getUint32(dataOffset, littleEndian) /
28388                     dataView.getUint32(dataOffset + 4, littleEndian);
28389             },
28390             size: 8
28391         },
28392         // slong, 32 bit signed int:
28393         9: {
28394             getValue: function (dataView, dataOffset, littleEndian) {
28395                 return dataView.getInt32(dataOffset, littleEndian);
28396             },
28397             size: 4
28398         },
28399         // srational, two slongs, first is numerator, second is denominator:
28400         10: {
28401             getValue: function (dataView, dataOffset, littleEndian) {
28402                 return dataView.getInt32(dataOffset, littleEndian) /
28403                     dataView.getInt32(dataOffset + 4, littleEndian);
28404             },
28405             size: 8
28406         }
28407     },
28408     
28409     footer : {
28410         STANDARD : [
28411             {
28412                 tag : 'div',
28413                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28414                 action : 'rotate-left',
28415                 cn : [
28416                     {
28417                         tag : 'button',
28418                         cls : 'btn btn-default',
28419                         html : '<i class="fa fa-undo"></i>'
28420                     }
28421                 ]
28422             },
28423             {
28424                 tag : 'div',
28425                 cls : 'btn-group roo-upload-cropbox-picture',
28426                 action : 'picture',
28427                 cn : [
28428                     {
28429                         tag : 'button',
28430                         cls : 'btn btn-default',
28431                         html : '<i class="fa fa-picture-o"></i>'
28432                     }
28433                 ]
28434             },
28435             {
28436                 tag : 'div',
28437                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28438                 action : 'rotate-right',
28439                 cn : [
28440                     {
28441                         tag : 'button',
28442                         cls : 'btn btn-default',
28443                         html : '<i class="fa fa-repeat"></i>'
28444                     }
28445                 ]
28446             }
28447         ],
28448         DOCUMENT : [
28449             {
28450                 tag : 'div',
28451                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28452                 action : 'rotate-left',
28453                 cn : [
28454                     {
28455                         tag : 'button',
28456                         cls : 'btn btn-default',
28457                         html : '<i class="fa fa-undo"></i>'
28458                     }
28459                 ]
28460             },
28461             {
28462                 tag : 'div',
28463                 cls : 'btn-group roo-upload-cropbox-download',
28464                 action : 'download',
28465                 cn : [
28466                     {
28467                         tag : 'button',
28468                         cls : 'btn btn-default',
28469                         html : '<i class="fa fa-download"></i>'
28470                     }
28471                 ]
28472             },
28473             {
28474                 tag : 'div',
28475                 cls : 'btn-group roo-upload-cropbox-crop',
28476                 action : 'crop',
28477                 cn : [
28478                     {
28479                         tag : 'button',
28480                         cls : 'btn btn-default',
28481                         html : '<i class="fa fa-crop"></i>'
28482                     }
28483                 ]
28484             },
28485             {
28486                 tag : 'div',
28487                 cls : 'btn-group roo-upload-cropbox-trash',
28488                 action : 'trash',
28489                 cn : [
28490                     {
28491                         tag : 'button',
28492                         cls : 'btn btn-default',
28493                         html : '<i class="fa fa-trash"></i>'
28494                     }
28495                 ]
28496             },
28497             {
28498                 tag : 'div',
28499                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28500                 action : 'rotate-right',
28501                 cn : [
28502                     {
28503                         tag : 'button',
28504                         cls : 'btn btn-default',
28505                         html : '<i class="fa fa-repeat"></i>'
28506                     }
28507                 ]
28508             }
28509         ],
28510         ROTATOR : [
28511             {
28512                 tag : 'div',
28513                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28514                 action : 'rotate-left',
28515                 cn : [
28516                     {
28517                         tag : 'button',
28518                         cls : 'btn btn-default',
28519                         html : '<i class="fa fa-undo"></i>'
28520                     }
28521                 ]
28522             },
28523             {
28524                 tag : 'div',
28525                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28526                 action : 'rotate-right',
28527                 cn : [
28528                     {
28529                         tag : 'button',
28530                         cls : 'btn btn-default',
28531                         html : '<i class="fa fa-repeat"></i>'
28532                     }
28533                 ]
28534             }
28535         ]
28536     }
28537 });
28538
28539 /*
28540 * Licence: LGPL
28541 */
28542
28543 /**
28544  * @class Roo.bootstrap.DocumentManager
28545  * @extends Roo.bootstrap.Component
28546  * Bootstrap DocumentManager class
28547  * @cfg {String} paramName default 'imageUpload'
28548  * @cfg {String} toolTipName default 'filename'
28549  * @cfg {String} method default POST
28550  * @cfg {String} url action url
28551  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28552  * @cfg {Boolean} multiple multiple upload default true
28553  * @cfg {Number} thumbSize default 300
28554  * @cfg {String} fieldLabel
28555  * @cfg {Number} labelWidth default 4
28556  * @cfg {String} labelAlign (left|top) default left
28557  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28558 * @cfg {Number} labellg set the width of label (1-12)
28559  * @cfg {Number} labelmd set the width of label (1-12)
28560  * @cfg {Number} labelsm set the width of label (1-12)
28561  * @cfg {Number} labelxs set the width of label (1-12)
28562  * 
28563  * @constructor
28564  * Create a new DocumentManager
28565  * @param {Object} config The config object
28566  */
28567
28568 Roo.bootstrap.DocumentManager = function(config){
28569     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28570     
28571     this.files = [];
28572     this.delegates = [];
28573     
28574     this.addEvents({
28575         /**
28576          * @event initial
28577          * Fire when initial the DocumentManager
28578          * @param {Roo.bootstrap.DocumentManager} this
28579          */
28580         "initial" : true,
28581         /**
28582          * @event inspect
28583          * inspect selected file
28584          * @param {Roo.bootstrap.DocumentManager} this
28585          * @param {File} file
28586          */
28587         "inspect" : true,
28588         /**
28589          * @event exception
28590          * Fire when xhr load exception
28591          * @param {Roo.bootstrap.DocumentManager} this
28592          * @param {XMLHttpRequest} xhr
28593          */
28594         "exception" : true,
28595         /**
28596          * @event afterupload
28597          * Fire when xhr load exception
28598          * @param {Roo.bootstrap.DocumentManager} this
28599          * @param {XMLHttpRequest} xhr
28600          */
28601         "afterupload" : true,
28602         /**
28603          * @event prepare
28604          * prepare the form data
28605          * @param {Roo.bootstrap.DocumentManager} this
28606          * @param {Object} formData
28607          */
28608         "prepare" : true,
28609         /**
28610          * @event remove
28611          * Fire when remove the file
28612          * @param {Roo.bootstrap.DocumentManager} this
28613          * @param {Object} file
28614          */
28615         "remove" : true,
28616         /**
28617          * @event refresh
28618          * Fire after refresh the file
28619          * @param {Roo.bootstrap.DocumentManager} this
28620          */
28621         "refresh" : true,
28622         /**
28623          * @event click
28624          * Fire after click the image
28625          * @param {Roo.bootstrap.DocumentManager} this
28626          * @param {Object} file
28627          */
28628         "click" : true,
28629         /**
28630          * @event edit
28631          * Fire when upload a image and editable set to true
28632          * @param {Roo.bootstrap.DocumentManager} this
28633          * @param {Object} file
28634          */
28635         "edit" : true,
28636         /**
28637          * @event beforeselectfile
28638          * Fire before select file
28639          * @param {Roo.bootstrap.DocumentManager} this
28640          */
28641         "beforeselectfile" : true,
28642         /**
28643          * @event process
28644          * Fire before process file
28645          * @param {Roo.bootstrap.DocumentManager} this
28646          * @param {Object} file
28647          */
28648         "process" : true,
28649         /**
28650          * @event previewrendered
28651          * Fire when preview rendered
28652          * @param {Roo.bootstrap.DocumentManager} this
28653          * @param {Object} file
28654          */
28655         "previewrendered" : true
28656         
28657     });
28658 };
28659
28660 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
28661     
28662     boxes : 0,
28663     inputName : '',
28664     thumbSize : 300,
28665     multiple : true,
28666     files : false,
28667     method : 'POST',
28668     url : '',
28669     paramName : 'imageUpload',
28670     toolTipName : 'filename',
28671     fieldLabel : '',
28672     labelWidth : 4,
28673     labelAlign : 'left',
28674     editable : true,
28675     delegates : false,
28676     xhr : false, 
28677     
28678     labellg : 0,
28679     labelmd : 0,
28680     labelsm : 0,
28681     labelxs : 0,
28682     
28683     getAutoCreate : function()
28684     {   
28685         var managerWidget = {
28686             tag : 'div',
28687             cls : 'roo-document-manager',
28688             cn : [
28689                 {
28690                     tag : 'input',
28691                     cls : 'roo-document-manager-selector',
28692                     type : 'file'
28693                 },
28694                 {
28695                     tag : 'div',
28696                     cls : 'roo-document-manager-uploader',
28697                     cn : [
28698                         {
28699                             tag : 'div',
28700                             cls : 'roo-document-manager-upload-btn',
28701                             html : '<i class="fa fa-plus"></i>'
28702                         }
28703                     ]
28704                     
28705                 }
28706             ]
28707         };
28708         
28709         var content = [
28710             {
28711                 tag : 'div',
28712                 cls : 'column col-md-12',
28713                 cn : managerWidget
28714             }
28715         ];
28716         
28717         if(this.fieldLabel.length){
28718             
28719             content = [
28720                 {
28721                     tag : 'div',
28722                     cls : 'column col-md-12',
28723                     html : this.fieldLabel
28724                 },
28725                 {
28726                     tag : 'div',
28727                     cls : 'column col-md-12',
28728                     cn : managerWidget
28729                 }
28730             ];
28731
28732             if(this.labelAlign == 'left'){
28733                 content = [
28734                     {
28735                         tag : 'div',
28736                         cls : 'column',
28737                         html : this.fieldLabel
28738                     },
28739                     {
28740                         tag : 'div',
28741                         cls : 'column',
28742                         cn : managerWidget
28743                     }
28744                 ];
28745                 
28746                 if(this.labelWidth > 12){
28747                     content[0].style = "width: " + this.labelWidth + 'px';
28748                 }
28749
28750                 if(this.labelWidth < 13 && this.labelmd == 0){
28751                     this.labelmd = this.labelWidth;
28752                 }
28753
28754                 if(this.labellg > 0){
28755                     content[0].cls += ' col-lg-' + this.labellg;
28756                     content[1].cls += ' col-lg-' + (12 - this.labellg);
28757                 }
28758
28759                 if(this.labelmd > 0){
28760                     content[0].cls += ' col-md-' + this.labelmd;
28761                     content[1].cls += ' col-md-' + (12 - this.labelmd);
28762                 }
28763
28764                 if(this.labelsm > 0){
28765                     content[0].cls += ' col-sm-' + this.labelsm;
28766                     content[1].cls += ' col-sm-' + (12 - this.labelsm);
28767                 }
28768
28769                 if(this.labelxs > 0){
28770                     content[0].cls += ' col-xs-' + this.labelxs;
28771                     content[1].cls += ' col-xs-' + (12 - this.labelxs);
28772                 }
28773                 
28774             }
28775         }
28776         
28777         var cfg = {
28778             tag : 'div',
28779             cls : 'row clearfix',
28780             cn : content
28781         };
28782         
28783         return cfg;
28784         
28785     },
28786     
28787     initEvents : function()
28788     {
28789         this.managerEl = this.el.select('.roo-document-manager', true).first();
28790         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28791         
28792         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28793         this.selectorEl.hide();
28794         
28795         if(this.multiple){
28796             this.selectorEl.attr('multiple', 'multiple');
28797         }
28798         
28799         this.selectorEl.on('change', this.onFileSelected, this);
28800         
28801         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28802         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28803         
28804         this.uploader.on('click', this.onUploaderClick, this);
28805         
28806         this.renderProgressDialog();
28807         
28808         var _this = this;
28809         
28810         window.addEventListener("resize", function() { _this.refresh(); } );
28811         
28812         this.fireEvent('initial', this);
28813     },
28814     
28815     renderProgressDialog : function()
28816     {
28817         var _this = this;
28818         
28819         this.progressDialog = new Roo.bootstrap.Modal({
28820             cls : 'roo-document-manager-progress-dialog',
28821             allow_close : false,
28822             title : '',
28823             buttons : [
28824                 {
28825                     name  :'cancel',
28826                     weight : 'danger',
28827                     html : 'Cancel'
28828                 }
28829             ], 
28830             listeners : { 
28831                 btnclick : function() {
28832                     _this.uploadCancel();
28833                     this.hide();
28834                 }
28835             }
28836         });
28837          
28838         this.progressDialog.render(Roo.get(document.body));
28839          
28840         this.progress = new Roo.bootstrap.Progress({
28841             cls : 'roo-document-manager-progress',
28842             active : true,
28843             striped : true
28844         });
28845         
28846         this.progress.render(this.progressDialog.getChildContainer());
28847         
28848         this.progressBar = new Roo.bootstrap.ProgressBar({
28849             cls : 'roo-document-manager-progress-bar',
28850             aria_valuenow : 0,
28851             aria_valuemin : 0,
28852             aria_valuemax : 12,
28853             panel : 'success'
28854         });
28855         
28856         this.progressBar.render(this.progress.getChildContainer());
28857     },
28858     
28859     onUploaderClick : function(e)
28860     {
28861         e.preventDefault();
28862      
28863         if(this.fireEvent('beforeselectfile', this) != false){
28864             this.selectorEl.dom.click();
28865         }
28866         
28867     },
28868     
28869     onFileSelected : function(e)
28870     {
28871         e.preventDefault();
28872         
28873         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28874             return;
28875         }
28876         
28877         Roo.each(this.selectorEl.dom.files, function(file){
28878             if(this.fireEvent('inspect', this, file) != false){
28879                 this.files.push(file);
28880             }
28881         }, this);
28882         
28883         this.queue();
28884         
28885     },
28886     
28887     queue : function()
28888     {
28889         this.selectorEl.dom.value = '';
28890         
28891         if(!this.files || !this.files.length){
28892             return;
28893         }
28894         
28895         if(this.boxes > 0 && this.files.length > this.boxes){
28896             this.files = this.files.slice(0, this.boxes);
28897         }
28898         
28899         this.uploader.show();
28900         
28901         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28902             this.uploader.hide();
28903         }
28904         
28905         var _this = this;
28906         
28907         var files = [];
28908         
28909         var docs = [];
28910         
28911         Roo.each(this.files, function(file){
28912             
28913             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28914                 var f = this.renderPreview(file);
28915                 files.push(f);
28916                 return;
28917             }
28918             
28919             if(file.type.indexOf('image') != -1){
28920                 this.delegates.push(
28921                     (function(){
28922                         _this.process(file);
28923                     }).createDelegate(this)
28924                 );
28925         
28926                 return;
28927             }
28928             
28929             docs.push(
28930                 (function(){
28931                     _this.process(file);
28932                 }).createDelegate(this)
28933             );
28934             
28935         }, this);
28936         
28937         this.files = files;
28938         
28939         this.delegates = this.delegates.concat(docs);
28940         
28941         if(!this.delegates.length){
28942             this.refresh();
28943             return;
28944         }
28945         
28946         this.progressBar.aria_valuemax = this.delegates.length;
28947         
28948         this.arrange();
28949         
28950         return;
28951     },
28952     
28953     arrange : function()
28954     {
28955         if(!this.delegates.length){
28956             this.progressDialog.hide();
28957             this.refresh();
28958             return;
28959         }
28960         
28961         var delegate = this.delegates.shift();
28962         
28963         this.progressDialog.show();
28964         
28965         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28966         
28967         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28968         
28969         delegate();
28970     },
28971     
28972     refresh : function()
28973     {
28974         this.uploader.show();
28975         
28976         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28977             this.uploader.hide();
28978         }
28979         
28980         Roo.isTouch ? this.closable(false) : this.closable(true);
28981         
28982         this.fireEvent('refresh', this);
28983     },
28984     
28985     onRemove : function(e, el, o)
28986     {
28987         e.preventDefault();
28988         
28989         this.fireEvent('remove', this, o);
28990         
28991     },
28992     
28993     remove : function(o)
28994     {
28995         var files = [];
28996         
28997         Roo.each(this.files, function(file){
28998             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28999                 files.push(file);
29000                 return;
29001             }
29002
29003             o.target.remove();
29004
29005         }, this);
29006         
29007         this.files = files;
29008         
29009         this.refresh();
29010     },
29011     
29012     clear : function()
29013     {
29014         Roo.each(this.files, function(file){
29015             if(!file.target){
29016                 return;
29017             }
29018             
29019             file.target.remove();
29020
29021         }, this);
29022         
29023         this.files = [];
29024         
29025         this.refresh();
29026     },
29027     
29028     onClick : function(e, el, o)
29029     {
29030         e.preventDefault();
29031         
29032         this.fireEvent('click', this, o);
29033         
29034     },
29035     
29036     closable : function(closable)
29037     {
29038         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29039             
29040             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29041             
29042             if(closable){
29043                 el.show();
29044                 return;
29045             }
29046             
29047             el.hide();
29048             
29049         }, this);
29050     },
29051     
29052     xhrOnLoad : function(xhr)
29053     {
29054         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29055             el.remove();
29056         }, this);
29057         
29058         if (xhr.readyState !== 4) {
29059             this.arrange();
29060             this.fireEvent('exception', this, xhr);
29061             return;
29062         }
29063
29064         var response = Roo.decode(xhr.responseText);
29065         
29066         if(!response.success){
29067             this.arrange();
29068             this.fireEvent('exception', this, xhr);
29069             return;
29070         }
29071         
29072         var file = this.renderPreview(response.data);
29073         
29074         this.files.push(file);
29075         
29076         this.arrange();
29077         
29078         this.fireEvent('afterupload', this, xhr);
29079         
29080     },
29081     
29082     xhrOnError : function(xhr)
29083     {
29084         Roo.log('xhr on error');
29085         
29086         var response = Roo.decode(xhr.responseText);
29087           
29088         Roo.log(response);
29089         
29090         this.arrange();
29091     },
29092     
29093     process : function(file)
29094     {
29095         if(this.fireEvent('process', this, file) !== false){
29096             if(this.editable && file.type.indexOf('image') != -1){
29097                 this.fireEvent('edit', this, file);
29098                 return;
29099             }
29100
29101             this.uploadStart(file, false);
29102
29103             return;
29104         }
29105         
29106     },
29107     
29108     uploadStart : function(file, crop)
29109     {
29110         this.xhr = new XMLHttpRequest();
29111         
29112         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29113             this.arrange();
29114             return;
29115         }
29116         
29117         file.xhr = this.xhr;
29118             
29119         this.managerEl.createChild({
29120             tag : 'div',
29121             cls : 'roo-document-manager-loading',
29122             cn : [
29123                 {
29124                     tag : 'div',
29125                     tooltip : file.name,
29126                     cls : 'roo-document-manager-thumb',
29127                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29128                 }
29129             ]
29130
29131         });
29132
29133         this.xhr.open(this.method, this.url, true);
29134         
29135         var headers = {
29136             "Accept": "application/json",
29137             "Cache-Control": "no-cache",
29138             "X-Requested-With": "XMLHttpRequest"
29139         };
29140         
29141         for (var headerName in headers) {
29142             var headerValue = headers[headerName];
29143             if (headerValue) {
29144                 this.xhr.setRequestHeader(headerName, headerValue);
29145             }
29146         }
29147         
29148         var _this = this;
29149         
29150         this.xhr.onload = function()
29151         {
29152             _this.xhrOnLoad(_this.xhr);
29153         }
29154         
29155         this.xhr.onerror = function()
29156         {
29157             _this.xhrOnError(_this.xhr);
29158         }
29159         
29160         var formData = new FormData();
29161
29162         formData.append('returnHTML', 'NO');
29163         
29164         if(crop){
29165             formData.append('crop', crop);
29166         }
29167         
29168         formData.append(this.paramName, file, file.name);
29169         
29170         var options = {
29171             file : file, 
29172             manually : false
29173         };
29174         
29175         if(this.fireEvent('prepare', this, formData, options) != false){
29176             
29177             if(options.manually){
29178                 return;
29179             }
29180             
29181             this.xhr.send(formData);
29182             return;
29183         };
29184         
29185         this.uploadCancel();
29186     },
29187     
29188     uploadCancel : function()
29189     {
29190         if (this.xhr) {
29191             this.xhr.abort();
29192         }
29193         
29194         this.delegates = [];
29195         
29196         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29197             el.remove();
29198         }, this);
29199         
29200         this.arrange();
29201     },
29202     
29203     renderPreview : function(file)
29204     {
29205         if(typeof(file.target) != 'undefined' && file.target){
29206             return file;
29207         }
29208         
29209         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29210         
29211         var previewEl = this.managerEl.createChild({
29212             tag : 'div',
29213             cls : 'roo-document-manager-preview',
29214             cn : [
29215                 {
29216                     tag : 'div',
29217                     tooltip : file[this.toolTipName],
29218                     cls : 'roo-document-manager-thumb',
29219                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29220                 },
29221                 {
29222                     tag : 'button',
29223                     cls : 'close',
29224                     html : '<i class="fa fa-times-circle"></i>'
29225                 }
29226             ]
29227         });
29228
29229         var close = previewEl.select('button.close', true).first();
29230
29231         close.on('click', this.onRemove, this, file);
29232
29233         file.target = previewEl;
29234
29235         var image = previewEl.select('img', true).first();
29236         
29237         var _this = this;
29238         
29239         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29240         
29241         image.on('click', this.onClick, this, file);
29242         
29243         this.fireEvent('previewrendered', this, file);
29244         
29245         return file;
29246         
29247     },
29248     
29249     onPreviewLoad : function(file, image)
29250     {
29251         if(typeof(file.target) == 'undefined' || !file.target){
29252             return;
29253         }
29254         
29255         var width = image.dom.naturalWidth || image.dom.width;
29256         var height = image.dom.naturalHeight || image.dom.height;
29257         
29258         if(width > height){
29259             file.target.addClass('wide');
29260             return;
29261         }
29262         
29263         file.target.addClass('tall');
29264         return;
29265         
29266     },
29267     
29268     uploadFromSource : function(file, crop)
29269     {
29270         this.xhr = new XMLHttpRequest();
29271         
29272         this.managerEl.createChild({
29273             tag : 'div',
29274             cls : 'roo-document-manager-loading',
29275             cn : [
29276                 {
29277                     tag : 'div',
29278                     tooltip : file.name,
29279                     cls : 'roo-document-manager-thumb',
29280                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29281                 }
29282             ]
29283
29284         });
29285
29286         this.xhr.open(this.method, this.url, true);
29287         
29288         var headers = {
29289             "Accept": "application/json",
29290             "Cache-Control": "no-cache",
29291             "X-Requested-With": "XMLHttpRequest"
29292         };
29293         
29294         for (var headerName in headers) {
29295             var headerValue = headers[headerName];
29296             if (headerValue) {
29297                 this.xhr.setRequestHeader(headerName, headerValue);
29298             }
29299         }
29300         
29301         var _this = this;
29302         
29303         this.xhr.onload = function()
29304         {
29305             _this.xhrOnLoad(_this.xhr);
29306         }
29307         
29308         this.xhr.onerror = function()
29309         {
29310             _this.xhrOnError(_this.xhr);
29311         }
29312         
29313         var formData = new FormData();
29314
29315         formData.append('returnHTML', 'NO');
29316         
29317         formData.append('crop', crop);
29318         
29319         if(typeof(file.filename) != 'undefined'){
29320             formData.append('filename', file.filename);
29321         }
29322         
29323         if(typeof(file.mimetype) != 'undefined'){
29324             formData.append('mimetype', file.mimetype);
29325         }
29326         
29327         Roo.log(formData);
29328         
29329         if(this.fireEvent('prepare', this, formData) != false){
29330             this.xhr.send(formData);
29331         };
29332     }
29333 });
29334
29335 /*
29336 * Licence: LGPL
29337 */
29338
29339 /**
29340  * @class Roo.bootstrap.DocumentViewer
29341  * @extends Roo.bootstrap.Component
29342  * Bootstrap DocumentViewer class
29343  * @cfg {Boolean} showDownload (true|false) show download button (default true)
29344  * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29345  * 
29346  * @constructor
29347  * Create a new DocumentViewer
29348  * @param {Object} config The config object
29349  */
29350
29351 Roo.bootstrap.DocumentViewer = function(config){
29352     Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29353     
29354     this.addEvents({
29355         /**
29356          * @event initial
29357          * Fire after initEvent
29358          * @param {Roo.bootstrap.DocumentViewer} this
29359          */
29360         "initial" : true,
29361         /**
29362          * @event click
29363          * Fire after click
29364          * @param {Roo.bootstrap.DocumentViewer} this
29365          */
29366         "click" : true,
29367         /**
29368          * @event download
29369          * Fire after download button
29370          * @param {Roo.bootstrap.DocumentViewer} this
29371          */
29372         "download" : true,
29373         /**
29374          * @event trash
29375          * Fire after trash button
29376          * @param {Roo.bootstrap.DocumentViewer} this
29377          */
29378         "trash" : true
29379         
29380     });
29381 };
29382
29383 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
29384     
29385     showDownload : true,
29386     
29387     showTrash : true,
29388     
29389     getAutoCreate : function()
29390     {
29391         var cfg = {
29392             tag : 'div',
29393             cls : 'roo-document-viewer',
29394             cn : [
29395                 {
29396                     tag : 'div',
29397                     cls : 'roo-document-viewer-body',
29398                     cn : [
29399                         {
29400                             tag : 'div',
29401                             cls : 'roo-document-viewer-thumb',
29402                             cn : [
29403                                 {
29404                                     tag : 'img',
29405                                     cls : 'roo-document-viewer-image'
29406                                 }
29407                             ]
29408                         }
29409                     ]
29410                 },
29411                 {
29412                     tag : 'div',
29413                     cls : 'roo-document-viewer-footer',
29414                     cn : {
29415                         tag : 'div',
29416                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29417                         cn : [
29418                             {
29419                                 tag : 'div',
29420                                 cls : 'btn-group roo-document-viewer-download',
29421                                 cn : [
29422                                     {
29423                                         tag : 'button',
29424                                         cls : 'btn btn-default',
29425                                         html : '<i class="fa fa-download"></i>'
29426                                     }
29427                                 ]
29428                             },
29429                             {
29430                                 tag : 'div',
29431                                 cls : 'btn-group roo-document-viewer-trash',
29432                                 cn : [
29433                                     {
29434                                         tag : 'button',
29435                                         cls : 'btn btn-default',
29436                                         html : '<i class="fa fa-trash"></i>'
29437                                     }
29438                                 ]
29439                             }
29440                         ]
29441                     }
29442                 }
29443             ]
29444         };
29445         
29446         return cfg;
29447     },
29448     
29449     initEvents : function()
29450     {
29451         this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29452         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29453         
29454         this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29455         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29456         
29457         this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29458         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29459         
29460         this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29461         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29462         
29463         this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29464         this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29465         
29466         this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29467         this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29468         
29469         this.bodyEl.on('click', this.onClick, this);
29470         this.downloadBtn.on('click', this.onDownload, this);
29471         this.trashBtn.on('click', this.onTrash, this);
29472         
29473         this.downloadBtn.hide();
29474         this.trashBtn.hide();
29475         
29476         if(this.showDownload){
29477             this.downloadBtn.show();
29478         }
29479         
29480         if(this.showTrash){
29481             this.trashBtn.show();
29482         }
29483         
29484         if(!this.showDownload && !this.showTrash) {
29485             this.footerEl.hide();
29486         }
29487         
29488     },
29489     
29490     initial : function()
29491     {
29492         this.fireEvent('initial', this);
29493         
29494     },
29495     
29496     onClick : function(e)
29497     {
29498         e.preventDefault();
29499         
29500         this.fireEvent('click', this);
29501     },
29502     
29503     onDownload : function(e)
29504     {
29505         e.preventDefault();
29506         
29507         this.fireEvent('download', this);
29508     },
29509     
29510     onTrash : function(e)
29511     {
29512         e.preventDefault();
29513         
29514         this.fireEvent('trash', this);
29515     }
29516     
29517 });
29518 /*
29519  * - LGPL
29520  *
29521  * nav progress bar
29522  * 
29523  */
29524
29525 /**
29526  * @class Roo.bootstrap.NavProgressBar
29527  * @extends Roo.bootstrap.Component
29528  * Bootstrap NavProgressBar class
29529  * 
29530  * @constructor
29531  * Create a new nav progress bar
29532  * @param {Object} config The config object
29533  */
29534
29535 Roo.bootstrap.NavProgressBar = function(config){
29536     Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29537
29538     this.bullets = this.bullets || [];
29539    
29540 //    Roo.bootstrap.NavProgressBar.register(this);
29541      this.addEvents({
29542         /**
29543              * @event changed
29544              * Fires when the active item changes
29545              * @param {Roo.bootstrap.NavProgressBar} this
29546              * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29547              * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
29548          */
29549         'changed': true
29550      });
29551     
29552 };
29553
29554 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
29555     
29556     bullets : [],
29557     barItems : [],
29558     
29559     getAutoCreate : function()
29560     {
29561         var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29562         
29563         cfg = {
29564             tag : 'div',
29565             cls : 'roo-navigation-bar-group',
29566             cn : [
29567                 {
29568                     tag : 'div',
29569                     cls : 'roo-navigation-top-bar'
29570                 },
29571                 {
29572                     tag : 'div',
29573                     cls : 'roo-navigation-bullets-bar',
29574                     cn : [
29575                         {
29576                             tag : 'ul',
29577                             cls : 'roo-navigation-bar'
29578                         }
29579                     ]
29580                 },
29581                 
29582                 {
29583                     tag : 'div',
29584                     cls : 'roo-navigation-bottom-bar'
29585                 }
29586             ]
29587             
29588         };
29589         
29590         return cfg;
29591         
29592     },
29593     
29594     initEvents: function() 
29595     {
29596         
29597     },
29598     
29599     onRender : function(ct, position) 
29600     {
29601         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29602         
29603         if(this.bullets.length){
29604             Roo.each(this.bullets, function(b){
29605                this.addItem(b);
29606             }, this);
29607         }
29608         
29609         this.format();
29610         
29611     },
29612     
29613     addItem : function(cfg)
29614     {
29615         var item = new Roo.bootstrap.NavProgressItem(cfg);
29616         
29617         item.parentId = this.id;
29618         item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29619         
29620         if(cfg.html){
29621             var top = new Roo.bootstrap.Element({
29622                 tag : 'div',
29623                 cls : 'roo-navigation-bar-text'
29624             });
29625             
29626             var bottom = new Roo.bootstrap.Element({
29627                 tag : 'div',
29628                 cls : 'roo-navigation-bar-text'
29629             });
29630             
29631             top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29632             bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29633             
29634             var topText = new Roo.bootstrap.Element({
29635                 tag : 'span',
29636                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29637             });
29638             
29639             var bottomText = new Roo.bootstrap.Element({
29640                 tag : 'span',
29641                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29642             });
29643             
29644             topText.onRender(top.el, null);
29645             bottomText.onRender(bottom.el, null);
29646             
29647             item.topEl = top;
29648             item.bottomEl = bottom;
29649         }
29650         
29651         this.barItems.push(item);
29652         
29653         return item;
29654     },
29655     
29656     getActive : function()
29657     {
29658         var active = false;
29659         
29660         Roo.each(this.barItems, function(v){
29661             
29662             if (!v.isActive()) {
29663                 return;
29664             }
29665             
29666             active = v;
29667             return false;
29668             
29669         });
29670         
29671         return active;
29672     },
29673     
29674     setActiveItem : function(item)
29675     {
29676         var prev = false;
29677         
29678         Roo.each(this.barItems, function(v){
29679             if (v.rid == item.rid) {
29680                 return ;
29681             }
29682             
29683             if (v.isActive()) {
29684                 v.setActive(false);
29685                 prev = v;
29686             }
29687         });
29688
29689         item.setActive(true);
29690         
29691         this.fireEvent('changed', this, item, prev);
29692     },
29693     
29694     getBarItem: function(rid)
29695     {
29696         var ret = false;
29697         
29698         Roo.each(this.barItems, function(e) {
29699             if (e.rid != rid) {
29700                 return;
29701             }
29702             
29703             ret =  e;
29704             return false;
29705         });
29706         
29707         return ret;
29708     },
29709     
29710     indexOfItem : function(item)
29711     {
29712         var index = false;
29713         
29714         Roo.each(this.barItems, function(v, i){
29715             
29716             if (v.rid != item.rid) {
29717                 return;
29718             }
29719             
29720             index = i;
29721             return false
29722         });
29723         
29724         return index;
29725     },
29726     
29727     setActiveNext : function()
29728     {
29729         var i = this.indexOfItem(this.getActive());
29730         
29731         if (i > this.barItems.length) {
29732             return;
29733         }
29734         
29735         this.setActiveItem(this.barItems[i+1]);
29736     },
29737     
29738     setActivePrev : function()
29739     {
29740         var i = this.indexOfItem(this.getActive());
29741         
29742         if (i  < 1) {
29743             return;
29744         }
29745         
29746         this.setActiveItem(this.barItems[i-1]);
29747     },
29748     
29749     format : function()
29750     {
29751         if(!this.barItems.length){
29752             return;
29753         }
29754      
29755         var width = 100 / this.barItems.length;
29756         
29757         Roo.each(this.barItems, function(i){
29758             i.el.setStyle('width', width + '%');
29759             i.topEl.el.setStyle('width', width + '%');
29760             i.bottomEl.el.setStyle('width', width + '%');
29761         }, this);
29762         
29763     }
29764     
29765 });
29766 /*
29767  * - LGPL
29768  *
29769  * Nav Progress Item
29770  * 
29771  */
29772
29773 /**
29774  * @class Roo.bootstrap.NavProgressItem
29775  * @extends Roo.bootstrap.Component
29776  * Bootstrap NavProgressItem class
29777  * @cfg {String} rid the reference id
29778  * @cfg {Boolean} active (true|false) Is item active default false
29779  * @cfg {Boolean} disabled (true|false) Is item active default false
29780  * @cfg {String} html
29781  * @cfg {String} position (top|bottom) text position default bottom
29782  * @cfg {String} icon show icon instead of number
29783  * 
29784  * @constructor
29785  * Create a new NavProgressItem
29786  * @param {Object} config The config object
29787  */
29788 Roo.bootstrap.NavProgressItem = function(config){
29789     Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29790     this.addEvents({
29791         // raw events
29792         /**
29793          * @event click
29794          * The raw click event for the entire grid.
29795          * @param {Roo.bootstrap.NavProgressItem} this
29796          * @param {Roo.EventObject} e
29797          */
29798         "click" : true
29799     });
29800    
29801 };
29802
29803 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
29804     
29805     rid : '',
29806     active : false,
29807     disabled : false,
29808     html : '',
29809     position : 'bottom',
29810     icon : false,
29811     
29812     getAutoCreate : function()
29813     {
29814         var iconCls = 'roo-navigation-bar-item-icon';
29815         
29816         iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29817         
29818         var cfg = {
29819             tag: 'li',
29820             cls: 'roo-navigation-bar-item',
29821             cn : [
29822                 {
29823                     tag : 'i',
29824                     cls : iconCls
29825                 }
29826             ]
29827         };
29828         
29829         if(this.active){
29830             cfg.cls += ' active';
29831         }
29832         if(this.disabled){
29833             cfg.cls += ' disabled';
29834         }
29835         
29836         return cfg;
29837     },
29838     
29839     disable : function()
29840     {
29841         this.setDisabled(true);
29842     },
29843     
29844     enable : function()
29845     {
29846         this.setDisabled(false);
29847     },
29848     
29849     initEvents: function() 
29850     {
29851         this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29852         
29853         this.iconEl.on('click', this.onClick, this);
29854     },
29855     
29856     onClick : function(e)
29857     {
29858         e.preventDefault();
29859         
29860         if(this.disabled){
29861             return;
29862         }
29863         
29864         if(this.fireEvent('click', this, e) === false){
29865             return;
29866         };
29867         
29868         this.parent().setActiveItem(this);
29869     },
29870     
29871     isActive: function () 
29872     {
29873         return this.active;
29874     },
29875     
29876     setActive : function(state)
29877     {
29878         if(this.active == state){
29879             return;
29880         }
29881         
29882         this.active = state;
29883         
29884         if (state) {
29885             this.el.addClass('active');
29886             return;
29887         }
29888         
29889         this.el.removeClass('active');
29890         
29891         return;
29892     },
29893     
29894     setDisabled : function(state)
29895     {
29896         if(this.disabled == state){
29897             return;
29898         }
29899         
29900         this.disabled = state;
29901         
29902         if (state) {
29903             this.el.addClass('disabled');
29904             return;
29905         }
29906         
29907         this.el.removeClass('disabled');
29908     },
29909     
29910     tooltipEl : function()
29911     {
29912         return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29913     }
29914 });
29915  
29916
29917  /*
29918  * - LGPL
29919  *
29920  * FieldLabel
29921  * 
29922  */
29923
29924 /**
29925  * @class Roo.bootstrap.FieldLabel
29926  * @extends Roo.bootstrap.Component
29927  * Bootstrap FieldLabel class
29928  * @cfg {String} html contents of the element
29929  * @cfg {String} tag tag of the element default label
29930  * @cfg {String} cls class of the element
29931  * @cfg {String} target label target 
29932  * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29933  * @cfg {String} invalidClass default "text-warning"
29934  * @cfg {String} validClass default "text-success"
29935  * @cfg {String} iconTooltip default "This field is required"
29936  * @cfg {String} indicatorpos (left|right) default left
29937  * 
29938  * @constructor
29939  * Create a new FieldLabel
29940  * @param {Object} config The config object
29941  */
29942
29943 Roo.bootstrap.FieldLabel = function(config){
29944     Roo.bootstrap.Element.superclass.constructor.call(this, config);
29945     
29946     this.addEvents({
29947             /**
29948              * @event invalid
29949              * Fires after the field has been marked as invalid.
29950              * @param {Roo.form.FieldLabel} this
29951              * @param {String} msg The validation message
29952              */
29953             invalid : true,
29954             /**
29955              * @event valid
29956              * Fires after the field has been validated with no errors.
29957              * @param {Roo.form.FieldLabel} this
29958              */
29959             valid : true
29960         });
29961 };
29962
29963 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
29964     
29965     tag: 'label',
29966     cls: '',
29967     html: '',
29968     target: '',
29969     allowBlank : true,
29970     invalidClass : 'has-warning',
29971     validClass : 'has-success',
29972     iconTooltip : 'This field is required',
29973     indicatorpos : 'left',
29974     
29975     getAutoCreate : function(){
29976         
29977         var cfg = {
29978             tag : this.tag,
29979             cls : 'roo-bootstrap-field-label ' + this.cls,
29980             for : this.target,
29981             cn : [
29982                 {
29983                     tag : 'i',
29984                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29985                     tooltip : this.iconTooltip
29986                 },
29987                 {
29988                     tag : 'span',
29989                     html : this.html
29990                 }
29991             ] 
29992         };
29993         
29994         if(this.indicatorpos == 'right'){
29995             var cfg = {
29996                 tag : this.tag,
29997                 cls : 'roo-bootstrap-field-label ' + this.cls,
29998                 for : this.target,
29999                 cn : [
30000                     {
30001                         tag : 'span',
30002                         html : this.html
30003                     },
30004                     {
30005                         tag : 'i',
30006                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30007                         tooltip : this.iconTooltip
30008                     }
30009                 ] 
30010             };
30011         }
30012         
30013         return cfg;
30014     },
30015     
30016     initEvents: function() 
30017     {
30018         Roo.bootstrap.Element.superclass.initEvents.call(this);
30019         
30020         this.indicator = this.indicatorEl();
30021         
30022         if(this.indicator){
30023             this.indicator.removeClass('visible');
30024             this.indicator.addClass('invisible');
30025         }
30026         
30027         Roo.bootstrap.FieldLabel.register(this);
30028     },
30029     
30030     indicatorEl : function()
30031     {
30032         var indicator = this.el.select('i.roo-required-indicator',true).first();
30033         
30034         if(!indicator){
30035             return false;
30036         }
30037         
30038         return indicator;
30039         
30040     },
30041     
30042     /**
30043      * Mark this field as valid
30044      */
30045     markValid : function()
30046     {
30047         if(this.indicator){
30048             this.indicator.removeClass('visible');
30049             this.indicator.addClass('invisible');
30050         }
30051         
30052         this.el.removeClass(this.invalidClass);
30053         
30054         this.el.addClass(this.validClass);
30055         
30056         this.fireEvent('valid', this);
30057     },
30058     
30059     /**
30060      * Mark this field as invalid
30061      * @param {String} msg The validation message
30062      */
30063     markInvalid : function(msg)
30064     {
30065         if(this.indicator){
30066             this.indicator.removeClass('invisible');
30067             this.indicator.addClass('visible');
30068         }
30069         
30070         this.el.removeClass(this.validClass);
30071         
30072         this.el.addClass(this.invalidClass);
30073         
30074         this.fireEvent('invalid', this, msg);
30075     }
30076     
30077    
30078 });
30079
30080 Roo.apply(Roo.bootstrap.FieldLabel, {
30081     
30082     groups: {},
30083     
30084      /**
30085     * register a FieldLabel Group
30086     * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30087     */
30088     register : function(label)
30089     {
30090         if(this.groups.hasOwnProperty(label.target)){
30091             return;
30092         }
30093      
30094         this.groups[label.target] = label;
30095         
30096     },
30097     /**
30098     * fetch a FieldLabel Group based on the target
30099     * @param {string} target
30100     * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30101     */
30102     get: function(target) {
30103         if (typeof(this.groups[target]) == 'undefined') {
30104             return false;
30105         }
30106         
30107         return this.groups[target] ;
30108     }
30109 });
30110
30111  
30112
30113  /*
30114  * - LGPL
30115  *
30116  * page DateSplitField.
30117  * 
30118  */
30119
30120
30121 /**
30122  * @class Roo.bootstrap.DateSplitField
30123  * @extends Roo.bootstrap.Component
30124  * Bootstrap DateSplitField class
30125  * @cfg {string} fieldLabel - the label associated
30126  * @cfg {Number} labelWidth set the width of label (0-12)
30127  * @cfg {String} labelAlign (top|left)
30128  * @cfg {Boolean} dayAllowBlank (true|false) default false
30129  * @cfg {Boolean} monthAllowBlank (true|false) default false
30130  * @cfg {Boolean} yearAllowBlank (true|false) default false
30131  * @cfg {string} dayPlaceholder 
30132  * @cfg {string} monthPlaceholder
30133  * @cfg {string} yearPlaceholder
30134  * @cfg {string} dayFormat default 'd'
30135  * @cfg {string} monthFormat default 'm'
30136  * @cfg {string} yearFormat default 'Y'
30137  * @cfg {Number} labellg set the width of label (1-12)
30138  * @cfg {Number} labelmd set the width of label (1-12)
30139  * @cfg {Number} labelsm set the width of label (1-12)
30140  * @cfg {Number} labelxs set the width of label (1-12)
30141
30142  *     
30143  * @constructor
30144  * Create a new DateSplitField
30145  * @param {Object} config The config object
30146  */
30147
30148 Roo.bootstrap.DateSplitField = function(config){
30149     Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30150     
30151     this.addEvents({
30152         // raw events
30153          /**
30154          * @event years
30155          * getting the data of years
30156          * @param {Roo.bootstrap.DateSplitField} this
30157          * @param {Object} years
30158          */
30159         "years" : true,
30160         /**
30161          * @event days
30162          * getting the data of days
30163          * @param {Roo.bootstrap.DateSplitField} this
30164          * @param {Object} days
30165          */
30166         "days" : true,
30167         /**
30168          * @event invalid
30169          * Fires after the field has been marked as invalid.
30170          * @param {Roo.form.Field} this
30171          * @param {String} msg The validation message
30172          */
30173         invalid : true,
30174        /**
30175          * @event valid
30176          * Fires after the field has been validated with no errors.
30177          * @param {Roo.form.Field} this
30178          */
30179         valid : true
30180     });
30181 };
30182
30183 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
30184     
30185     fieldLabel : '',
30186     labelAlign : 'top',
30187     labelWidth : 3,
30188     dayAllowBlank : false,
30189     monthAllowBlank : false,
30190     yearAllowBlank : false,
30191     dayPlaceholder : '',
30192     monthPlaceholder : '',
30193     yearPlaceholder : '',
30194     dayFormat : 'd',
30195     monthFormat : 'm',
30196     yearFormat : 'Y',
30197     isFormField : true,
30198     labellg : 0,
30199     labelmd : 0,
30200     labelsm : 0,
30201     labelxs : 0,
30202     
30203     getAutoCreate : function()
30204     {
30205         var cfg = {
30206             tag : 'div',
30207             cls : 'row roo-date-split-field-group',
30208             cn : [
30209                 {
30210                     tag : 'input',
30211                     type : 'hidden',
30212                     cls : 'form-hidden-field roo-date-split-field-group-value',
30213                     name : this.name
30214                 }
30215             ]
30216         };
30217         
30218         var labelCls = 'col-md-12';
30219         var contentCls = 'col-md-4';
30220         
30221         if(this.fieldLabel){
30222             
30223             var label = {
30224                 tag : 'div',
30225                 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30226                 cn : [
30227                     {
30228                         tag : 'label',
30229                         html : this.fieldLabel
30230                     }
30231                 ]
30232             };
30233             
30234             if(this.labelAlign == 'left'){
30235             
30236                 if(this.labelWidth > 12){
30237                     label.style = "width: " + this.labelWidth + 'px';
30238                 }
30239
30240                 if(this.labelWidth < 13 && this.labelmd == 0){
30241                     this.labelmd = this.labelWidth;
30242                 }
30243
30244                 if(this.labellg > 0){
30245                     labelCls = ' col-lg-' + this.labellg;
30246                     contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30247                 }
30248
30249                 if(this.labelmd > 0){
30250                     labelCls = ' col-md-' + this.labelmd;
30251                     contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30252                 }
30253
30254                 if(this.labelsm > 0){
30255                     labelCls = ' col-sm-' + this.labelsm;
30256                     contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30257                 }
30258
30259                 if(this.labelxs > 0){
30260                     labelCls = ' col-xs-' + this.labelxs;
30261                     contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30262                 }
30263             }
30264             
30265             label.cls += ' ' + labelCls;
30266             
30267             cfg.cn.push(label);
30268         }
30269         
30270         Roo.each(['day', 'month', 'year'], function(t){
30271             cfg.cn.push({
30272                 tag : 'div',
30273                 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30274             });
30275         }, this);
30276         
30277         return cfg;
30278     },
30279     
30280     inputEl: function ()
30281     {
30282         return this.el.select('.roo-date-split-field-group-value', true).first();
30283     },
30284     
30285     onRender : function(ct, position) 
30286     {
30287         var _this = this;
30288         
30289         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30290         
30291         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30292         
30293         this.dayField = new Roo.bootstrap.ComboBox({
30294             allowBlank : this.dayAllowBlank,
30295             alwaysQuery : true,
30296             displayField : 'value',
30297             editable : false,
30298             fieldLabel : '',
30299             forceSelection : true,
30300             mode : 'local',
30301             placeholder : this.dayPlaceholder,
30302             selectOnFocus : true,
30303             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30304             triggerAction : 'all',
30305             typeAhead : true,
30306             valueField : 'value',
30307             store : new Roo.data.SimpleStore({
30308                 data : (function() {    
30309                     var days = [];
30310                     _this.fireEvent('days', _this, days);
30311                     return days;
30312                 })(),
30313                 fields : [ 'value' ]
30314             }),
30315             listeners : {
30316                 select : function (_self, record, index)
30317                 {
30318                     _this.setValue(_this.getValue());
30319                 }
30320             }
30321         });
30322
30323         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30324         
30325         this.monthField = new Roo.bootstrap.MonthField({
30326             after : '<i class=\"fa fa-calendar\"></i>',
30327             allowBlank : this.monthAllowBlank,
30328             placeholder : this.monthPlaceholder,
30329             readOnly : true,
30330             listeners : {
30331                 render : function (_self)
30332                 {
30333                     this.el.select('span.input-group-addon', true).first().on('click', function(e){
30334                         e.preventDefault();
30335                         _self.focus();
30336                     });
30337                 },
30338                 select : function (_self, oldvalue, newvalue)
30339                 {
30340                     _this.setValue(_this.getValue());
30341                 }
30342             }
30343         });
30344         
30345         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30346         
30347         this.yearField = new Roo.bootstrap.ComboBox({
30348             allowBlank : this.yearAllowBlank,
30349             alwaysQuery : true,
30350             displayField : 'value',
30351             editable : false,
30352             fieldLabel : '',
30353             forceSelection : true,
30354             mode : 'local',
30355             placeholder : this.yearPlaceholder,
30356             selectOnFocus : true,
30357             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30358             triggerAction : 'all',
30359             typeAhead : true,
30360             valueField : 'value',
30361             store : new Roo.data.SimpleStore({
30362                 data : (function() {
30363                     var years = [];
30364                     _this.fireEvent('years', _this, years);
30365                     return years;
30366                 })(),
30367                 fields : [ 'value' ]
30368             }),
30369             listeners : {
30370                 select : function (_self, record, index)
30371                 {
30372                     _this.setValue(_this.getValue());
30373                 }
30374             }
30375         });
30376
30377         this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30378     },
30379     
30380     setValue : function(v, format)
30381     {
30382         this.inputEl.dom.value = v;
30383         
30384         var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30385         
30386         var d = Date.parseDate(v, f);
30387         
30388         if(!d){
30389             this.validate();
30390             return;
30391         }
30392         
30393         this.setDay(d.format(this.dayFormat));
30394         this.setMonth(d.format(this.monthFormat));
30395         this.setYear(d.format(this.yearFormat));
30396         
30397         this.validate();
30398         
30399         return;
30400     },
30401     
30402     setDay : function(v)
30403     {
30404         this.dayField.setValue(v);
30405         this.inputEl.dom.value = this.getValue();
30406         this.validate();
30407         return;
30408     },
30409     
30410     setMonth : function(v)
30411     {
30412         this.monthField.setValue(v, true);
30413         this.inputEl.dom.value = this.getValue();
30414         this.validate();
30415         return;
30416     },
30417     
30418     setYear : function(v)
30419     {
30420         this.yearField.setValue(v);
30421         this.inputEl.dom.value = this.getValue();
30422         this.validate();
30423         return;
30424     },
30425     
30426     getDay : function()
30427     {
30428         return this.dayField.getValue();
30429     },
30430     
30431     getMonth : function()
30432     {
30433         return this.monthField.getValue();
30434     },
30435     
30436     getYear : function()
30437     {
30438         return this.yearField.getValue();
30439     },
30440     
30441     getValue : function()
30442     {
30443         var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30444         
30445         var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30446         
30447         return date;
30448     },
30449     
30450     reset : function()
30451     {
30452         this.setDay('');
30453         this.setMonth('');
30454         this.setYear('');
30455         this.inputEl.dom.value = '';
30456         this.validate();
30457         return;
30458     },
30459     
30460     validate : function()
30461     {
30462         var d = this.dayField.validate();
30463         var m = this.monthField.validate();
30464         var y = this.yearField.validate();
30465         
30466         var valid = true;
30467         
30468         if(
30469                 (!this.dayAllowBlank && !d) ||
30470                 (!this.monthAllowBlank && !m) ||
30471                 (!this.yearAllowBlank && !y)
30472         ){
30473             valid = false;
30474         }
30475         
30476         if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30477             return valid;
30478         }
30479         
30480         if(valid){
30481             this.markValid();
30482             return valid;
30483         }
30484         
30485         this.markInvalid();
30486         
30487         return valid;
30488     },
30489     
30490     markValid : function()
30491     {
30492         
30493         var label = this.el.select('label', true).first();
30494         var icon = this.el.select('i.fa-star', true).first();
30495
30496         if(label && icon){
30497             icon.remove();
30498         }
30499         
30500         this.fireEvent('valid', this);
30501     },
30502     
30503      /**
30504      * Mark this field as invalid
30505      * @param {String} msg The validation message
30506      */
30507     markInvalid : function(msg)
30508     {
30509         
30510         var label = this.el.select('label', true).first();
30511         var icon = this.el.select('i.fa-star', true).first();
30512
30513         if(label && !icon){
30514             this.el.select('.roo-date-split-field-label', true).createChild({
30515                 tag : 'i',
30516                 cls : 'text-danger fa fa-lg fa-star',
30517                 tooltip : 'This field is required',
30518                 style : 'margin-right:5px;'
30519             }, label, true);
30520         }
30521         
30522         this.fireEvent('invalid', this, msg);
30523     },
30524     
30525     clearInvalid : function()
30526     {
30527         var label = this.el.select('label', true).first();
30528         var icon = this.el.select('i.fa-star', true).first();
30529
30530         if(label && icon){
30531             icon.remove();
30532         }
30533         
30534         this.fireEvent('valid', this);
30535     },
30536     
30537     getName: function()
30538     {
30539         return this.name;
30540     }
30541     
30542 });
30543
30544  /**
30545  *
30546  * This is based on 
30547  * http://masonry.desandro.com
30548  *
30549  * The idea is to render all the bricks based on vertical width...
30550  *
30551  * The original code extends 'outlayer' - we might need to use that....
30552  * 
30553  */
30554
30555
30556 /**
30557  * @class Roo.bootstrap.LayoutMasonry
30558  * @extends Roo.bootstrap.Component
30559  * Bootstrap Layout Masonry class
30560  * 
30561  * @constructor
30562  * Create a new Element
30563  * @param {Object} config The config object
30564  */
30565
30566 Roo.bootstrap.LayoutMasonry = function(config){
30567     
30568     Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30569     
30570     this.bricks = [];
30571     
30572     Roo.bootstrap.LayoutMasonry.register(this);
30573     
30574     this.addEvents({
30575         // raw events
30576         /**
30577          * @event layout
30578          * Fire after layout the items
30579          * @param {Roo.bootstrap.LayoutMasonry} this
30580          * @param {Roo.EventObject} e
30581          */
30582         "layout" : true
30583     });
30584     
30585 };
30586
30587 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component,  {
30588     
30589     /**
30590      * @cfg {Boolean} isLayoutInstant = no animation?
30591      */   
30592     isLayoutInstant : false, // needed?
30593    
30594     /**
30595      * @cfg {Number} boxWidth  width of the columns
30596      */   
30597     boxWidth : 450,
30598     
30599       /**
30600      * @cfg {Number} boxHeight  - 0 for square, or fix it at a certian height
30601      */   
30602     boxHeight : 0,
30603     
30604     /**
30605      * @cfg {Number} padWidth padding below box..
30606      */   
30607     padWidth : 10, 
30608     
30609     /**
30610      * @cfg {Number} gutter gutter width..
30611      */   
30612     gutter : 10,
30613     
30614      /**
30615      * @cfg {Number} maxCols maximum number of columns
30616      */   
30617     
30618     maxCols: 0,
30619     
30620     /**
30621      * @cfg {Boolean} isAutoInitial defalut true
30622      */   
30623     isAutoInitial : true, 
30624     
30625     containerWidth: 0,
30626     
30627     /**
30628      * @cfg {Boolean} isHorizontal defalut false
30629      */   
30630     isHorizontal : false, 
30631
30632     currentSize : null,
30633     
30634     tag: 'div',
30635     
30636     cls: '',
30637     
30638     bricks: null, //CompositeElement
30639     
30640     cols : 1,
30641     
30642     _isLayoutInited : false,
30643     
30644 //    isAlternative : false, // only use for vertical layout...
30645     
30646     /**
30647      * @cfg {Number} alternativePadWidth padding below box..
30648      */   
30649     alternativePadWidth : 50,
30650     
30651     selectedBrick : [],
30652     
30653     getAutoCreate : function(){
30654         
30655         var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30656         
30657         var cfg = {
30658             tag: this.tag,
30659             cls: 'blog-masonary-wrapper ' + this.cls,
30660             cn : {
30661                 cls : 'mas-boxes masonary'
30662             }
30663         };
30664         
30665         return cfg;
30666     },
30667     
30668     getChildContainer: function( )
30669     {
30670         if (this.boxesEl) {
30671             return this.boxesEl;
30672         }
30673         
30674         this.boxesEl = this.el.select('.mas-boxes').first();
30675         
30676         return this.boxesEl;
30677     },
30678     
30679     
30680     initEvents : function()
30681     {
30682         var _this = this;
30683         
30684         if(this.isAutoInitial){
30685             Roo.log('hook children rendered');
30686             this.on('childrenrendered', function() {
30687                 Roo.log('children rendered');
30688                 _this.initial();
30689             } ,this);
30690         }
30691     },
30692     
30693     initial : function()
30694     {
30695         this.selectedBrick = [];
30696         
30697         this.currentSize = this.el.getBox(true);
30698         
30699         Roo.EventManager.onWindowResize(this.resize, this); 
30700
30701         if(!this.isAutoInitial){
30702             this.layout();
30703             return;
30704         }
30705         
30706         this.layout();
30707         
30708         return;
30709         //this.layout.defer(500,this);
30710         
30711     },
30712     
30713     resize : function()
30714     {
30715         var cs = this.el.getBox(true);
30716         
30717         if (
30718                 this.currentSize.width == cs.width && 
30719                 this.currentSize.x == cs.x && 
30720                 this.currentSize.height == cs.height && 
30721                 this.currentSize.y == cs.y 
30722         ) {
30723             Roo.log("no change in with or X or Y");
30724             return;
30725         }
30726         
30727         this.currentSize = cs;
30728         
30729         this.layout();
30730         
30731     },
30732     
30733     layout : function()
30734     {   
30735         this._resetLayout();
30736         
30737         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30738         
30739         this.layoutItems( isInstant );
30740       
30741         this._isLayoutInited = true;
30742         
30743         this.fireEvent('layout', this);
30744         
30745     },
30746     
30747     _resetLayout : function()
30748     {
30749         if(this.isHorizontal){
30750             this.horizontalMeasureColumns();
30751             return;
30752         }
30753         
30754         this.verticalMeasureColumns();
30755         
30756     },
30757     
30758     verticalMeasureColumns : function()
30759     {
30760         this.getContainerWidth();
30761         
30762 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30763 //            this.colWidth = Math.floor(this.containerWidth * 0.8);
30764 //            return;
30765 //        }
30766         
30767         var boxWidth = this.boxWidth + this.padWidth;
30768         
30769         if(this.containerWidth < this.boxWidth){
30770             boxWidth = this.containerWidth
30771         }
30772         
30773         var containerWidth = this.containerWidth;
30774         
30775         var cols = Math.floor(containerWidth / boxWidth);
30776         
30777         this.cols = Math.max( cols, 1 );
30778         
30779         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30780         
30781         var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30782         
30783         var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30784         
30785         this.colWidth = boxWidth + avail - this.padWidth;
30786         
30787         this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30788         this.unitHeight = this.boxHeight > 0 ? this.boxHeight  : this.unitWidth;
30789     },
30790     
30791     horizontalMeasureColumns : function()
30792     {
30793         this.getContainerWidth();
30794         
30795         var boxWidth = this.boxWidth;
30796         
30797         if(this.containerWidth < boxWidth){
30798             boxWidth = this.containerWidth;
30799         }
30800         
30801         this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30802         
30803         this.el.setHeight(boxWidth);
30804         
30805     },
30806     
30807     getContainerWidth : function()
30808     {
30809         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
30810     },
30811     
30812     layoutItems : function( isInstant )
30813     {
30814         Roo.log(this.bricks);
30815         
30816         var items = Roo.apply([], this.bricks);
30817         
30818         if(this.isHorizontal){
30819             this._horizontalLayoutItems( items , isInstant );
30820             return;
30821         }
30822         
30823 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30824 //            this._verticalAlternativeLayoutItems( items , isInstant );
30825 //            return;
30826 //        }
30827         
30828         this._verticalLayoutItems( items , isInstant );
30829         
30830     },
30831     
30832     _verticalLayoutItems : function ( items , isInstant)
30833     {
30834         if ( !items || !items.length ) {
30835             return;
30836         }
30837         
30838         var standard = [
30839             ['xs', 'xs', 'xs', 'tall'],
30840             ['xs', 'xs', 'tall'],
30841             ['xs', 'xs', 'sm'],
30842             ['xs', 'xs', 'xs'],
30843             ['xs', 'tall'],
30844             ['xs', 'sm'],
30845             ['xs', 'xs'],
30846             ['xs'],
30847             
30848             ['sm', 'xs', 'xs'],
30849             ['sm', 'xs'],
30850             ['sm'],
30851             
30852             ['tall', 'xs', 'xs', 'xs'],
30853             ['tall', 'xs', 'xs'],
30854             ['tall', 'xs'],
30855             ['tall']
30856             
30857         ];
30858         
30859         var queue = [];
30860         
30861         var boxes = [];
30862         
30863         var box = [];
30864         
30865         Roo.each(items, function(item, k){
30866             
30867             switch (item.size) {
30868                 // these layouts take up a full box,
30869                 case 'md' :
30870                 case 'md-left' :
30871                 case 'md-right' :
30872                 case 'wide' :
30873                     
30874                     if(box.length){
30875                         boxes.push(box);
30876                         box = [];
30877                     }
30878                     
30879                     boxes.push([item]);
30880                     
30881                     break;
30882                     
30883                 case 'xs' :
30884                 case 'sm' :
30885                 case 'tall' :
30886                     
30887                     box.push(item);
30888                     
30889                     break;
30890                 default :
30891                     break;
30892                     
30893             }
30894             
30895         }, this);
30896         
30897         if(box.length){
30898             boxes.push(box);
30899             box = [];
30900         }
30901         
30902         var filterPattern = function(box, length)
30903         {
30904             if(!box.length){
30905                 return;
30906             }
30907             
30908             var match = false;
30909             
30910             var pattern = box.slice(0, length);
30911             
30912             var format = [];
30913             
30914             Roo.each(pattern, function(i){
30915                 format.push(i.size);
30916             }, this);
30917             
30918             Roo.each(standard, function(s){
30919                 
30920                 if(String(s) != String(format)){
30921                     return;
30922                 }
30923                 
30924                 match = true;
30925                 return false;
30926                 
30927             }, this);
30928             
30929             if(!match && length == 1){
30930                 return;
30931             }
30932             
30933             if(!match){
30934                 filterPattern(box, length - 1);
30935                 return;
30936             }
30937                 
30938             queue.push(pattern);
30939
30940             box = box.slice(length, box.length);
30941
30942             filterPattern(box, 4);
30943
30944             return;
30945             
30946         }
30947         
30948         Roo.each(boxes, function(box, k){
30949             
30950             if(!box.length){
30951                 return;
30952             }
30953             
30954             if(box.length == 1){
30955                 queue.push(box);
30956                 return;
30957             }
30958             
30959             filterPattern(box, 4);
30960             
30961         }, this);
30962         
30963         this._processVerticalLayoutQueue( queue, isInstant );
30964         
30965     },
30966     
30967 //    _verticalAlternativeLayoutItems : function( items , isInstant )
30968 //    {
30969 //        if ( !items || !items.length ) {
30970 //            return;
30971 //        }
30972 //
30973 //        this._processVerticalAlternativeLayoutQueue( items, isInstant );
30974 //        
30975 //    },
30976     
30977     _horizontalLayoutItems : function ( items , isInstant)
30978     {
30979         if ( !items || !items.length || items.length < 3) {
30980             return;
30981         }
30982         
30983         items.reverse();
30984         
30985         var eItems = items.slice(0, 3);
30986         
30987         items = items.slice(3, items.length);
30988         
30989         var standard = [
30990             ['xs', 'xs', 'xs', 'wide'],
30991             ['xs', 'xs', 'wide'],
30992             ['xs', 'xs', 'sm'],
30993             ['xs', 'xs', 'xs'],
30994             ['xs', 'wide'],
30995             ['xs', 'sm'],
30996             ['xs', 'xs'],
30997             ['xs'],
30998             
30999             ['sm', 'xs', 'xs'],
31000             ['sm', 'xs'],
31001             ['sm'],
31002             
31003             ['wide', 'xs', 'xs', 'xs'],
31004             ['wide', 'xs', 'xs'],
31005             ['wide', 'xs'],
31006             ['wide'],
31007             
31008             ['wide-thin']
31009         ];
31010         
31011         var queue = [];
31012         
31013         var boxes = [];
31014         
31015         var box = [];
31016         
31017         Roo.each(items, function(item, k){
31018             
31019             switch (item.size) {
31020                 case 'md' :
31021                 case 'md-left' :
31022                 case 'md-right' :
31023                 case 'tall' :
31024                     
31025                     if(box.length){
31026                         boxes.push(box);
31027                         box = [];
31028                     }
31029                     
31030                     boxes.push([item]);
31031                     
31032                     break;
31033                     
31034                 case 'xs' :
31035                 case 'sm' :
31036                 case 'wide' :
31037                 case 'wide-thin' :
31038                     
31039                     box.push(item);
31040                     
31041                     break;
31042                 default :
31043                     break;
31044                     
31045             }
31046             
31047         }, this);
31048         
31049         if(box.length){
31050             boxes.push(box);
31051             box = [];
31052         }
31053         
31054         var filterPattern = function(box, length)
31055         {
31056             if(!box.length){
31057                 return;
31058             }
31059             
31060             var match = false;
31061             
31062             var pattern = box.slice(0, length);
31063             
31064             var format = [];
31065             
31066             Roo.each(pattern, function(i){
31067                 format.push(i.size);
31068             }, this);
31069             
31070             Roo.each(standard, function(s){
31071                 
31072                 if(String(s) != String(format)){
31073                     return;
31074                 }
31075                 
31076                 match = true;
31077                 return false;
31078                 
31079             }, this);
31080             
31081             if(!match && length == 1){
31082                 return;
31083             }
31084             
31085             if(!match){
31086                 filterPattern(box, length - 1);
31087                 return;
31088             }
31089                 
31090             queue.push(pattern);
31091
31092             box = box.slice(length, box.length);
31093
31094             filterPattern(box, 4);
31095
31096             return;
31097             
31098         }
31099         
31100         Roo.each(boxes, function(box, k){
31101             
31102             if(!box.length){
31103                 return;
31104             }
31105             
31106             if(box.length == 1){
31107                 queue.push(box);
31108                 return;
31109             }
31110             
31111             filterPattern(box, 4);
31112             
31113         }, this);
31114         
31115         
31116         var prune = [];
31117         
31118         var pos = this.el.getBox(true);
31119         
31120         var minX = pos.x;
31121         
31122         var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31123         
31124         var hit_end = false;
31125         
31126         Roo.each(queue, function(box){
31127             
31128             if(hit_end){
31129                 
31130                 Roo.each(box, function(b){
31131                 
31132                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31133                     b.el.hide();
31134
31135                 }, this);
31136
31137                 return;
31138             }
31139             
31140             var mx = 0;
31141             
31142             Roo.each(box, function(b){
31143                 
31144                 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31145                 b.el.show();
31146
31147                 mx = Math.max(mx, b.x);
31148                 
31149             }, this);
31150             
31151             maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31152             
31153             if(maxX < minX){
31154                 
31155                 Roo.each(box, function(b){
31156                 
31157                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31158                     b.el.hide();
31159                     
31160                 }, this);
31161                 
31162                 hit_end = true;
31163                 
31164                 return;
31165             }
31166             
31167             prune.push(box);
31168             
31169         }, this);
31170         
31171         this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31172     },
31173     
31174     /** Sets position of item in DOM
31175     * @param {Element} item
31176     * @param {Number} x - horizontal position
31177     * @param {Number} y - vertical position
31178     * @param {Boolean} isInstant - disables transitions
31179     */
31180     _processVerticalLayoutQueue : function( queue, isInstant )
31181     {
31182         var pos = this.el.getBox(true);
31183         var x = pos.x;
31184         var y = pos.y;
31185         var maxY = [];
31186         
31187         for (var i = 0; i < this.cols; i++){
31188             maxY[i] = pos.y;
31189         }
31190         
31191         Roo.each(queue, function(box, k){
31192             
31193             var col = k % this.cols;
31194             
31195             Roo.each(box, function(b,kk){
31196                 
31197                 b.el.position('absolute');
31198                 
31199                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31200                 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31201                 
31202                 if(b.size == 'md-left' || b.size == 'md-right'){
31203                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31204                     height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31205                 }
31206                 
31207                 b.el.setWidth(width);
31208                 b.el.setHeight(height);
31209                 // iframe?
31210                 b.el.select('iframe',true).setSize(width,height);
31211                 
31212             }, this);
31213             
31214             for (var i = 0; i < this.cols; i++){
31215                 
31216                 if(maxY[i] < maxY[col]){
31217                     col = i;
31218                     continue;
31219                 }
31220                 
31221                 col = Math.min(col, i);
31222                 
31223             }
31224             
31225             x = pos.x + col * (this.colWidth + this.padWidth);
31226             
31227             y = maxY[col];
31228             
31229             var positions = [];
31230             
31231             switch (box.length){
31232                 case 1 :
31233                     positions = this.getVerticalOneBoxColPositions(x, y, box);
31234                     break;
31235                 case 2 :
31236                     positions = this.getVerticalTwoBoxColPositions(x, y, box);
31237                     break;
31238                 case 3 :
31239                     positions = this.getVerticalThreeBoxColPositions(x, y, box);
31240                     break;
31241                 case 4 :
31242                     positions = this.getVerticalFourBoxColPositions(x, y, box);
31243                     break;
31244                 default :
31245                     break;
31246             }
31247             
31248             Roo.each(box, function(b,kk){
31249                 
31250                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31251                 
31252                 var sz = b.el.getSize();
31253                 
31254                 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31255                 
31256             }, this);
31257             
31258         }, this);
31259         
31260         var mY = 0;
31261         
31262         for (var i = 0; i < this.cols; i++){
31263             mY = Math.max(mY, maxY[i]);
31264         }
31265         
31266         this.el.setHeight(mY - pos.y);
31267         
31268     },
31269     
31270 //    _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31271 //    {
31272 //        var pos = this.el.getBox(true);
31273 //        var x = pos.x;
31274 //        var y = pos.y;
31275 //        var maxX = pos.right;
31276 //        
31277 //        var maxHeight = 0;
31278 //        
31279 //        Roo.each(items, function(item, k){
31280 //            
31281 //            var c = k % 2;
31282 //            
31283 //            item.el.position('absolute');
31284 //                
31285 //            var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31286 //
31287 //            item.el.setWidth(width);
31288 //
31289 //            var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31290 //
31291 //            item.el.setHeight(height);
31292 //            
31293 //            if(c == 0){
31294 //                item.el.setXY([x, y], isInstant ? false : true);
31295 //            } else {
31296 //                item.el.setXY([maxX - width, y], isInstant ? false : true);
31297 //            }
31298 //            
31299 //            y = y + height + this.alternativePadWidth;
31300 //            
31301 //            maxHeight = maxHeight + height + this.alternativePadWidth;
31302 //            
31303 //        }, this);
31304 //        
31305 //        this.el.setHeight(maxHeight);
31306 //        
31307 //    },
31308     
31309     _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31310     {
31311         var pos = this.el.getBox(true);
31312         
31313         var minX = pos.x;
31314         var minY = pos.y;
31315         
31316         var maxX = pos.right;
31317         
31318         this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31319         
31320         var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31321         
31322         Roo.each(queue, function(box, k){
31323             
31324             Roo.each(box, function(b, kk){
31325                 
31326                 b.el.position('absolute');
31327                 
31328                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31329                 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31330                 
31331                 if(b.size == 'md-left' || b.size == 'md-right'){
31332                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31333                     height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31334                 }
31335                 
31336                 b.el.setWidth(width);
31337                 b.el.setHeight(height);
31338                 
31339             }, this);
31340             
31341             if(!box.length){
31342                 return;
31343             }
31344             
31345             var positions = [];
31346             
31347             switch (box.length){
31348                 case 1 :
31349                     positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31350                     break;
31351                 case 2 :
31352                     positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31353                     break;
31354                 case 3 :
31355                     positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31356                     break;
31357                 case 4 :
31358                     positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31359                     break;
31360                 default :
31361                     break;
31362             }
31363             
31364             Roo.each(box, function(b,kk){
31365                 
31366                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31367                 
31368                 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31369                 
31370             }, this);
31371             
31372         }, this);
31373         
31374     },
31375     
31376     _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31377     {
31378         Roo.each(eItems, function(b,k){
31379             
31380             b.size = (k == 0) ? 'sm' : 'xs';
31381             b.x = (k == 0) ? 2 : 1;
31382             b.y = (k == 0) ? 2 : 1;
31383             
31384             b.el.position('absolute');
31385             
31386             var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31387                 
31388             b.el.setWidth(width);
31389             
31390             var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31391             
31392             b.el.setHeight(height);
31393             
31394         }, this);
31395
31396         var positions = [];
31397         
31398         positions.push({
31399             x : maxX - this.unitWidth * 2 - this.gutter,
31400             y : minY
31401         });
31402         
31403         positions.push({
31404             x : maxX - this.unitWidth,
31405             y : minY + (this.unitWidth + this.gutter) * 2
31406         });
31407         
31408         positions.push({
31409             x : maxX - this.unitWidth * 3 - this.gutter * 2,
31410             y : minY
31411         });
31412         
31413         Roo.each(eItems, function(b,k){
31414             
31415             b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31416
31417         }, this);
31418         
31419     },
31420     
31421     getVerticalOneBoxColPositions : function(x, y, box)
31422     {
31423         var pos = [];
31424         
31425         var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31426         
31427         if(box[0].size == 'md-left'){
31428             rand = 0;
31429         }
31430         
31431         if(box[0].size == 'md-right'){
31432             rand = 1;
31433         }
31434         
31435         pos.push({
31436             x : x + (this.unitWidth + this.gutter) * rand,
31437             y : y
31438         });
31439         
31440         return pos;
31441     },
31442     
31443     getVerticalTwoBoxColPositions : function(x, y, box)
31444     {
31445         var pos = [];
31446         
31447         if(box[0].size == 'xs'){
31448             
31449             pos.push({
31450                 x : x,
31451                 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31452             });
31453
31454             pos.push({
31455                 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31456                 y : y
31457             });
31458             
31459             return pos;
31460             
31461         }
31462         
31463         pos.push({
31464             x : x,
31465             y : y
31466         });
31467
31468         pos.push({
31469             x : x + (this.unitWidth + this.gutter) * 2,
31470             y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31471         });
31472         
31473         return pos;
31474         
31475     },
31476     
31477     getVerticalThreeBoxColPositions : function(x, y, box)
31478     {
31479         var pos = [];
31480         
31481         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31482             
31483             pos.push({
31484                 x : x,
31485                 y : y
31486             });
31487
31488             pos.push({
31489                 x : x + (this.unitWidth + this.gutter) * 1,
31490                 y : y
31491             });
31492             
31493             pos.push({
31494                 x : x + (this.unitWidth + this.gutter) * 2,
31495                 y : y
31496             });
31497             
31498             return pos;
31499             
31500         }
31501         
31502         if(box[0].size == 'xs' && box[1].size == 'xs'){
31503             
31504             pos.push({
31505                 x : x,
31506                 y : y
31507             });
31508
31509             pos.push({
31510                 x : x,
31511                 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31512             });
31513             
31514             pos.push({
31515                 x : x + (this.unitWidth + this.gutter) * 1,
31516                 y : y
31517             });
31518             
31519             return pos;
31520             
31521         }
31522         
31523         pos.push({
31524             x : x,
31525             y : y
31526         });
31527
31528         pos.push({
31529             x : x + (this.unitWidth + this.gutter) * 2,
31530             y : y
31531         });
31532
31533         pos.push({
31534             x : x + (this.unitWidth + this.gutter) * 2,
31535             y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31536         });
31537             
31538         return pos;
31539         
31540     },
31541     
31542     getVerticalFourBoxColPositions : function(x, y, box)
31543     {
31544         var pos = [];
31545         
31546         if(box[0].size == 'xs'){
31547             
31548             pos.push({
31549                 x : x,
31550                 y : y
31551             });
31552
31553             pos.push({
31554                 x : x,
31555                 y : y + (this.unitHeight + this.gutter) * 1
31556             });
31557             
31558             pos.push({
31559                 x : x,
31560                 y : y + (this.unitHeight + this.gutter) * 2
31561             });
31562             
31563             pos.push({
31564                 x : x + (this.unitWidth + this.gutter) * 1,
31565                 y : y
31566             });
31567             
31568             return pos;
31569             
31570         }
31571         
31572         pos.push({
31573             x : x,
31574             y : y
31575         });
31576
31577         pos.push({
31578             x : x + (this.unitWidth + this.gutter) * 2,
31579             y : y
31580         });
31581
31582         pos.push({
31583             x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31584             y : y + (this.unitHeight + this.gutter) * 1
31585         });
31586
31587         pos.push({
31588             x : x + (this.unitWidth + this.gutter) * 2,
31589             y : y + (this.unitWidth + this.gutter) * 2
31590         });
31591
31592         return pos;
31593         
31594     },
31595     
31596     getHorizontalOneBoxColPositions : function(maxX, minY, box)
31597     {
31598         var pos = [];
31599         
31600         if(box[0].size == 'md-left'){
31601             pos.push({
31602                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31603                 y : minY
31604             });
31605             
31606             return pos;
31607         }
31608         
31609         if(box[0].size == 'md-right'){
31610             pos.push({
31611                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31612                 y : minY + (this.unitWidth + this.gutter) * 1
31613             });
31614             
31615             return pos;
31616         }
31617         
31618         var rand = Math.floor(Math.random() * (4 - box[0].y));
31619         
31620         pos.push({
31621             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31622             y : minY + (this.unitWidth + this.gutter) * rand
31623         });
31624         
31625         return pos;
31626         
31627     },
31628     
31629     getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31630     {
31631         var pos = [];
31632         
31633         if(box[0].size == 'xs'){
31634             
31635             pos.push({
31636                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31637                 y : minY
31638             });
31639
31640             pos.push({
31641                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31642                 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31643             });
31644             
31645             return pos;
31646             
31647         }
31648         
31649         pos.push({
31650             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31651             y : minY
31652         });
31653
31654         pos.push({
31655             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31656             y : minY + (this.unitWidth + this.gutter) * 2
31657         });
31658         
31659         return pos;
31660         
31661     },
31662     
31663     getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31664     {
31665         var pos = [];
31666         
31667         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31668             
31669             pos.push({
31670                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31671                 y : minY
31672             });
31673
31674             pos.push({
31675                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31676                 y : minY + (this.unitWidth + this.gutter) * 1
31677             });
31678             
31679             pos.push({
31680                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31681                 y : minY + (this.unitWidth + this.gutter) * 2
31682             });
31683             
31684             return pos;
31685             
31686         }
31687         
31688         if(box[0].size == 'xs' && box[1].size == 'xs'){
31689             
31690             pos.push({
31691                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31692                 y : minY
31693             });
31694
31695             pos.push({
31696                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31697                 y : minY
31698             });
31699             
31700             pos.push({
31701                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31702                 y : minY + (this.unitWidth + this.gutter) * 1
31703             });
31704             
31705             return pos;
31706             
31707         }
31708         
31709         pos.push({
31710             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31711             y : minY
31712         });
31713
31714         pos.push({
31715             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31716             y : minY + (this.unitWidth + this.gutter) * 2
31717         });
31718
31719         pos.push({
31720             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31721             y : minY + (this.unitWidth + this.gutter) * 2
31722         });
31723             
31724         return pos;
31725         
31726     },
31727     
31728     getHorizontalFourBoxColPositions : function(maxX, minY, box)
31729     {
31730         var pos = [];
31731         
31732         if(box[0].size == 'xs'){
31733             
31734             pos.push({
31735                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31736                 y : minY
31737             });
31738
31739             pos.push({
31740                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31741                 y : minY
31742             });
31743             
31744             pos.push({
31745                 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),
31746                 y : minY
31747             });
31748             
31749             pos.push({
31750                 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31751                 y : minY + (this.unitWidth + this.gutter) * 1
31752             });
31753             
31754             return pos;
31755             
31756         }
31757         
31758         pos.push({
31759             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31760             y : minY
31761         });
31762         
31763         pos.push({
31764             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31765             y : minY + (this.unitWidth + this.gutter) * 2
31766         });
31767         
31768         pos.push({
31769             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31770             y : minY + (this.unitWidth + this.gutter) * 2
31771         });
31772         
31773         pos.push({
31774             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),
31775             y : minY + (this.unitWidth + this.gutter) * 2
31776         });
31777
31778         return pos;
31779         
31780     },
31781     
31782     /**
31783     * remove a Masonry Brick
31784     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31785     */
31786     removeBrick : function(brick_id)
31787     {
31788         if (!brick_id) {
31789             return;
31790         }
31791         
31792         for (var i = 0; i<this.bricks.length; i++) {
31793             if (this.bricks[i].id == brick_id) {
31794                 this.bricks.splice(i,1);
31795                 this.el.dom.removeChild(Roo.get(brick_id).dom);
31796                 this.initial();
31797             }
31798         }
31799     },
31800     
31801     /**
31802     * adds a Masonry Brick
31803     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31804     */
31805     addBrick : function(cfg)
31806     {
31807         var cn = new Roo.bootstrap.MasonryBrick(cfg);
31808         //this.register(cn);
31809         cn.parentId = this.id;
31810         cn.onRender(this.el, null);
31811         return cn;
31812     },
31813     
31814     /**
31815     * register a Masonry Brick
31816     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31817     */
31818     
31819     register : function(brick)
31820     {
31821         this.bricks.push(brick);
31822         brick.masonryId = this.id;
31823     },
31824     
31825     /**
31826     * clear all the Masonry Brick
31827     */
31828     clearAll : function()
31829     {
31830         this.bricks = [];
31831         //this.getChildContainer().dom.innerHTML = "";
31832         this.el.dom.innerHTML = '';
31833     },
31834     
31835     getSelected : function()
31836     {
31837         if (!this.selectedBrick) {
31838             return false;
31839         }
31840         
31841         return this.selectedBrick;
31842     }
31843 });
31844
31845 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31846     
31847     groups: {},
31848      /**
31849     * register a Masonry Layout
31850     * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31851     */
31852     
31853     register : function(layout)
31854     {
31855         this.groups[layout.id] = layout;
31856     },
31857     /**
31858     * fetch a  Masonry Layout based on the masonry layout ID
31859     * @param {string} the masonry layout to add
31860     * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31861     */
31862     
31863     get: function(layout_id) {
31864         if (typeof(this.groups[layout_id]) == 'undefined') {
31865             return false;
31866         }
31867         return this.groups[layout_id] ;
31868     }
31869     
31870     
31871     
31872 });
31873
31874  
31875
31876  /**
31877  *
31878  * This is based on 
31879  * http://masonry.desandro.com
31880  *
31881  * The idea is to render all the bricks based on vertical width...
31882  *
31883  * The original code extends 'outlayer' - we might need to use that....
31884  * 
31885  */
31886
31887
31888 /**
31889  * @class Roo.bootstrap.LayoutMasonryAuto
31890  * @extends Roo.bootstrap.Component
31891  * Bootstrap Layout Masonry class
31892  * 
31893  * @constructor
31894  * Create a new Element
31895  * @param {Object} config The config object
31896  */
31897
31898 Roo.bootstrap.LayoutMasonryAuto = function(config){
31899     Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31900 };
31901
31902 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component,  {
31903     
31904       /**
31905      * @cfg {Boolean} isFitWidth  - resize the width..
31906      */   
31907     isFitWidth : false,  // options..
31908     /**
31909      * @cfg {Boolean} isOriginLeft = left align?
31910      */   
31911     isOriginLeft : true,
31912     /**
31913      * @cfg {Boolean} isOriginTop = top align?
31914      */   
31915     isOriginTop : false,
31916     /**
31917      * @cfg {Boolean} isLayoutInstant = no animation?
31918      */   
31919     isLayoutInstant : false, // needed?
31920     /**
31921      * @cfg {Boolean} isResizingContainer = not sure if this is used..
31922      */   
31923     isResizingContainer : true,
31924     /**
31925      * @cfg {Number} columnWidth  width of the columns 
31926      */   
31927     
31928     columnWidth : 0,
31929     
31930     /**
31931      * @cfg {Number} maxCols maximum number of columns
31932      */   
31933     
31934     maxCols: 0,
31935     /**
31936      * @cfg {Number} padHeight padding below box..
31937      */   
31938     
31939     padHeight : 10, 
31940     
31941     /**
31942      * @cfg {Boolean} isAutoInitial defalut true
31943      */   
31944     
31945     isAutoInitial : true, 
31946     
31947     // private?
31948     gutter : 0,
31949     
31950     containerWidth: 0,
31951     initialColumnWidth : 0,
31952     currentSize : null,
31953     
31954     colYs : null, // array.
31955     maxY : 0,
31956     padWidth: 10,
31957     
31958     
31959     tag: 'div',
31960     cls: '',
31961     bricks: null, //CompositeElement
31962     cols : 0, // array?
31963     // element : null, // wrapped now this.el
31964     _isLayoutInited : null, 
31965     
31966     
31967     getAutoCreate : function(){
31968         
31969         var cfg = {
31970             tag: this.tag,
31971             cls: 'blog-masonary-wrapper ' + this.cls,
31972             cn : {
31973                 cls : 'mas-boxes masonary'
31974             }
31975         };
31976         
31977         return cfg;
31978     },
31979     
31980     getChildContainer: function( )
31981     {
31982         if (this.boxesEl) {
31983             return this.boxesEl;
31984         }
31985         
31986         this.boxesEl = this.el.select('.mas-boxes').first();
31987         
31988         return this.boxesEl;
31989     },
31990     
31991     
31992     initEvents : function()
31993     {
31994         var _this = this;
31995         
31996         if(this.isAutoInitial){
31997             Roo.log('hook children rendered');
31998             this.on('childrenrendered', function() {
31999                 Roo.log('children rendered');
32000                 _this.initial();
32001             } ,this);
32002         }
32003         
32004     },
32005     
32006     initial : function()
32007     {
32008         this.reloadItems();
32009
32010         this.currentSize = this.el.getBox(true);
32011
32012         /// was window resize... - let's see if this works..
32013         Roo.EventManager.onWindowResize(this.resize, this); 
32014
32015         if(!this.isAutoInitial){
32016             this.layout();
32017             return;
32018         }
32019         
32020         this.layout.defer(500,this);
32021     },
32022     
32023     reloadItems: function()
32024     {
32025         this.bricks = this.el.select('.masonry-brick', true);
32026         
32027         this.bricks.each(function(b) {
32028             //Roo.log(b.getSize());
32029             if (!b.attr('originalwidth')) {
32030                 b.attr('originalwidth',  b.getSize().width);
32031             }
32032             
32033         });
32034         
32035         Roo.log(this.bricks.elements.length);
32036     },
32037     
32038     resize : function()
32039     {
32040         Roo.log('resize');
32041         var cs = this.el.getBox(true);
32042         
32043         if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32044             Roo.log("no change in with or X");
32045             return;
32046         }
32047         this.currentSize = cs;
32048         this.layout();
32049     },
32050     
32051     layout : function()
32052     {
32053          Roo.log('layout');
32054         this._resetLayout();
32055         //this._manageStamps();
32056       
32057         // don't animate first layout
32058         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32059         this.layoutItems( isInstant );
32060       
32061         // flag for initalized
32062         this._isLayoutInited = true;
32063     },
32064     
32065     layoutItems : function( isInstant )
32066     {
32067         //var items = this._getItemsForLayout( this.items );
32068         // original code supports filtering layout items.. we just ignore it..
32069         
32070         this._layoutItems( this.bricks , isInstant );
32071       
32072         this._postLayout();
32073     },
32074     _layoutItems : function ( items , isInstant)
32075     {
32076        //this.fireEvent( 'layout', this, items );
32077     
32078
32079         if ( !items || !items.elements.length ) {
32080           // no items, emit event with empty array
32081             return;
32082         }
32083
32084         var queue = [];
32085         items.each(function(item) {
32086             Roo.log("layout item");
32087             Roo.log(item);
32088             // get x/y object from method
32089             var position = this._getItemLayoutPosition( item );
32090             // enqueue
32091             position.item = item;
32092             position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32093             queue.push( position );
32094         }, this);
32095       
32096         this._processLayoutQueue( queue );
32097     },
32098     /** Sets position of item in DOM
32099     * @param {Element} item
32100     * @param {Number} x - horizontal position
32101     * @param {Number} y - vertical position
32102     * @param {Boolean} isInstant - disables transitions
32103     */
32104     _processLayoutQueue : function( queue )
32105     {
32106         for ( var i=0, len = queue.length; i < len; i++ ) {
32107             var obj = queue[i];
32108             obj.item.position('absolute');
32109             obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32110         }
32111     },
32112       
32113     
32114     /**
32115     * Any logic you want to do after each layout,
32116     * i.e. size the container
32117     */
32118     _postLayout : function()
32119     {
32120         this.resizeContainer();
32121     },
32122     
32123     resizeContainer : function()
32124     {
32125         if ( !this.isResizingContainer ) {
32126             return;
32127         }
32128         var size = this._getContainerSize();
32129         if ( size ) {
32130             this.el.setSize(size.width,size.height);
32131             this.boxesEl.setSize(size.width,size.height);
32132         }
32133     },
32134     
32135     
32136     
32137     _resetLayout : function()
32138     {
32139         //this.getSize();  // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32140         this.colWidth = this.el.getWidth();
32141         //this.gutter = this.el.getWidth(); 
32142         
32143         this.measureColumns();
32144
32145         // reset column Y
32146         var i = this.cols;
32147         this.colYs = [];
32148         while (i--) {
32149             this.colYs.push( 0 );
32150         }
32151     
32152         this.maxY = 0;
32153     },
32154
32155     measureColumns : function()
32156     {
32157         this.getContainerWidth();
32158       // if columnWidth is 0, default to outerWidth of first item
32159         if ( !this.columnWidth ) {
32160             var firstItem = this.bricks.first();
32161             Roo.log(firstItem);
32162             this.columnWidth  = this.containerWidth;
32163             if (firstItem && firstItem.attr('originalwidth') ) {
32164                 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32165             }
32166             // columnWidth fall back to item of first element
32167             Roo.log("set column width?");
32168                         this.initialColumnWidth = this.columnWidth  ;
32169
32170             // if first elem has no width, default to size of container
32171             
32172         }
32173         
32174         
32175         if (this.initialColumnWidth) {
32176             this.columnWidth = this.initialColumnWidth;
32177         }
32178         
32179         
32180             
32181         // column width is fixed at the top - however if container width get's smaller we should
32182         // reduce it...
32183         
32184         // this bit calcs how man columns..
32185             
32186         var columnWidth = this.columnWidth += this.gutter;
32187       
32188         // calculate columns
32189         var containerWidth = this.containerWidth + this.gutter;
32190         
32191         var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32192         // fix rounding errors, typically with gutters
32193         var excess = columnWidth - containerWidth % columnWidth;
32194         
32195         
32196         // if overshoot is less than a pixel, round up, otherwise floor it
32197         var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32198         cols = Math[ mathMethod ]( cols );
32199         this.cols = Math.max( cols, 1 );
32200         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32201         
32202          // padding positioning..
32203         var totalColWidth = this.cols * this.columnWidth;
32204         var padavail = this.containerWidth - totalColWidth;
32205         // so for 2 columns - we need 3 'pads'
32206         
32207         var padNeeded = (1+this.cols) * this.padWidth;
32208         
32209         var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32210         
32211         this.columnWidth += padExtra
32212         //this.padWidth = Math.floor(padavail /  ( this.cols));
32213         
32214         // adjust colum width so that padding is fixed??
32215         
32216         // we have 3 columns ... total = width * 3
32217         // we have X left over... that should be used by 
32218         
32219         //if (this.expandC) {
32220             
32221         //}
32222         
32223         
32224         
32225     },
32226     
32227     getContainerWidth : function()
32228     {
32229        /* // container is parent if fit width
32230         var container = this.isFitWidth ? this.element.parentNode : this.element;
32231         // check that this.size and size are there
32232         // IE8 triggers resize on body size change, so they might not be
32233         
32234         var size = getSize( container );  //FIXME
32235         this.containerWidth = size && size.innerWidth; //FIXME
32236         */
32237          
32238         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
32239         
32240     },
32241     
32242     _getItemLayoutPosition : function( item )  // what is item?
32243     {
32244         // we resize the item to our columnWidth..
32245       
32246         item.setWidth(this.columnWidth);
32247         item.autoBoxAdjust  = false;
32248         
32249         var sz = item.getSize();
32250  
32251         // how many columns does this brick span
32252         var remainder = this.containerWidth % this.columnWidth;
32253         
32254         var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32255         // round if off by 1 pixel, otherwise use ceil
32256         var colSpan = Math[ mathMethod ]( sz.width  / this.columnWidth );
32257         colSpan = Math.min( colSpan, this.cols );
32258         
32259         // normally this should be '1' as we dont' currently allow multi width columns..
32260         
32261         var colGroup = this._getColGroup( colSpan );
32262         // get the minimum Y value from the columns
32263         var minimumY = Math.min.apply( Math, colGroup );
32264         Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32265         
32266         var shortColIndex = colGroup.indexOf(  minimumY ); // broken on ie8..?? probably...
32267          
32268         // position the brick
32269         var position = {
32270             x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32271             y: this.currentSize.y + minimumY + this.padHeight
32272         };
32273         
32274         Roo.log(position);
32275         // apply setHeight to necessary columns
32276         var setHeight = minimumY + sz.height + this.padHeight;
32277         //Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32278         
32279         var setSpan = this.cols + 1 - colGroup.length;
32280         for ( var i = 0; i < setSpan; i++ ) {
32281           this.colYs[ shortColIndex + i ] = setHeight ;
32282         }
32283       
32284         return position;
32285     },
32286     
32287     /**
32288      * @param {Number} colSpan - number of columns the element spans
32289      * @returns {Array} colGroup
32290      */
32291     _getColGroup : function( colSpan )
32292     {
32293         if ( colSpan < 2 ) {
32294           // if brick spans only one column, use all the column Ys
32295           return this.colYs;
32296         }
32297       
32298         var colGroup = [];
32299         // how many different places could this brick fit horizontally
32300         var groupCount = this.cols + 1 - colSpan;
32301         // for each group potential horizontal position
32302         for ( var i = 0; i < groupCount; i++ ) {
32303           // make an array of colY values for that one group
32304           var groupColYs = this.colYs.slice( i, i + colSpan );
32305           // and get the max value of the array
32306           colGroup[i] = Math.max.apply( Math, groupColYs );
32307         }
32308         return colGroup;
32309     },
32310     /*
32311     _manageStamp : function( stamp )
32312     {
32313         var stampSize =  stamp.getSize();
32314         var offset = stamp.getBox();
32315         // get the columns that this stamp affects
32316         var firstX = this.isOriginLeft ? offset.x : offset.right;
32317         var lastX = firstX + stampSize.width;
32318         var firstCol = Math.floor( firstX / this.columnWidth );
32319         firstCol = Math.max( 0, firstCol );
32320         
32321         var lastCol = Math.floor( lastX / this.columnWidth );
32322         // lastCol should not go over if multiple of columnWidth #425
32323         lastCol -= lastX % this.columnWidth ? 0 : 1;
32324         lastCol = Math.min( this.cols - 1, lastCol );
32325         
32326         // set colYs to bottom of the stamp
32327         var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32328             stampSize.height;
32329             
32330         for ( var i = firstCol; i <= lastCol; i++ ) {
32331           this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32332         }
32333     },
32334     */
32335     
32336     _getContainerSize : function()
32337     {
32338         this.maxY = Math.max.apply( Math, this.colYs );
32339         var size = {
32340             height: this.maxY
32341         };
32342       
32343         if ( this.isFitWidth ) {
32344             size.width = this._getContainerFitWidth();
32345         }
32346       
32347         return size;
32348     },
32349     
32350     _getContainerFitWidth : function()
32351     {
32352         var unusedCols = 0;
32353         // count unused columns
32354         var i = this.cols;
32355         while ( --i ) {
32356           if ( this.colYs[i] !== 0 ) {
32357             break;
32358           }
32359           unusedCols++;
32360         }
32361         // fit container to columns that have been used
32362         return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32363     },
32364     
32365     needsResizeLayout : function()
32366     {
32367         var previousWidth = this.containerWidth;
32368         this.getContainerWidth();
32369         return previousWidth !== this.containerWidth;
32370     }
32371  
32372 });
32373
32374  
32375
32376  /*
32377  * - LGPL
32378  *
32379  * element
32380  * 
32381  */
32382
32383 /**
32384  * @class Roo.bootstrap.MasonryBrick
32385  * @extends Roo.bootstrap.Component
32386  * Bootstrap MasonryBrick class
32387  * 
32388  * @constructor
32389  * Create a new MasonryBrick
32390  * @param {Object} config The config object
32391  */
32392
32393 Roo.bootstrap.MasonryBrick = function(config){
32394     
32395     Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32396     
32397     Roo.bootstrap.MasonryBrick.register(this);
32398     
32399     this.addEvents({
32400         // raw events
32401         /**
32402          * @event click
32403          * When a MasonryBrick is clcik
32404          * @param {Roo.bootstrap.MasonryBrick} this
32405          * @param {Roo.EventObject} e
32406          */
32407         "click" : true
32408     });
32409 };
32410
32411 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component,  {
32412     
32413     /**
32414      * @cfg {String} title
32415      */   
32416     title : '',
32417     /**
32418      * @cfg {String} html
32419      */   
32420     html : '',
32421     /**
32422      * @cfg {String} bgimage
32423      */   
32424     bgimage : '',
32425     /**
32426      * @cfg {String} videourl
32427      */   
32428     videourl : '',
32429     /**
32430      * @cfg {String} cls
32431      */   
32432     cls : '',
32433     /**
32434      * @cfg {String} href
32435      */   
32436     href : '',
32437     /**
32438      * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32439      */   
32440     size : 'xs',
32441     
32442     /**
32443      * @cfg {String} placetitle (center|bottom)
32444      */   
32445     placetitle : '',
32446     
32447     /**
32448      * @cfg {Boolean} isFitContainer defalut true
32449      */   
32450     isFitContainer : true, 
32451     
32452     /**
32453      * @cfg {Boolean} preventDefault defalut false
32454      */   
32455     preventDefault : false, 
32456     
32457     /**
32458      * @cfg {Boolean} inverse defalut false
32459      */   
32460     maskInverse : false, 
32461     
32462     getAutoCreate : function()
32463     {
32464         if(!this.isFitContainer){
32465             return this.getSplitAutoCreate();
32466         }
32467         
32468         var cls = 'masonry-brick masonry-brick-full';
32469         
32470         if(this.href.length){
32471             cls += ' masonry-brick-link';
32472         }
32473         
32474         if(this.bgimage.length){
32475             cls += ' masonry-brick-image';
32476         }
32477         
32478         if(this.maskInverse){
32479             cls += ' mask-inverse';
32480         }
32481         
32482         if(!this.html.length && !this.maskInverse && !this.videourl.length){
32483             cls += ' enable-mask';
32484         }
32485         
32486         if(this.size){
32487             cls += ' masonry-' + this.size + '-brick';
32488         }
32489         
32490         if(this.placetitle.length){
32491             
32492             switch (this.placetitle) {
32493                 case 'center' :
32494                     cls += ' masonry-center-title';
32495                     break;
32496                 case 'bottom' :
32497                     cls += ' masonry-bottom-title';
32498                     break;
32499                 default:
32500                     break;
32501             }
32502             
32503         } else {
32504             if(!this.html.length && !this.bgimage.length){
32505                 cls += ' masonry-center-title';
32506             }
32507
32508             if(!this.html.length && this.bgimage.length){
32509                 cls += ' masonry-bottom-title';
32510             }
32511         }
32512         
32513         if(this.cls){
32514             cls += ' ' + this.cls;
32515         }
32516         
32517         var cfg = {
32518             tag: (this.href.length) ? 'a' : 'div',
32519             cls: cls,
32520             cn: [
32521                 {
32522                     tag: 'div',
32523                     cls: 'masonry-brick-mask'
32524                 },
32525                 {
32526                     tag: 'div',
32527                     cls: 'masonry-brick-paragraph',
32528                     cn: []
32529                 }
32530             ]
32531         };
32532         
32533         if(this.href.length){
32534             cfg.href = this.href;
32535         }
32536         
32537         var cn = cfg.cn[1].cn;
32538         
32539         if(this.title.length){
32540             cn.push({
32541                 tag: 'h4',
32542                 cls: 'masonry-brick-title',
32543                 html: this.title
32544             });
32545         }
32546         
32547         if(this.html.length){
32548             cn.push({
32549                 tag: 'p',
32550                 cls: 'masonry-brick-text',
32551                 html: this.html
32552             });
32553         }
32554         
32555         if (!this.title.length && !this.html.length) {
32556             cfg.cn[1].cls += ' hide';
32557         }
32558         
32559         if(this.bgimage.length){
32560             cfg.cn.push({
32561                 tag: 'img',
32562                 cls: 'masonry-brick-image-view',
32563                 src: this.bgimage
32564             });
32565         }
32566         
32567         if(this.videourl.length){
32568             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32569             // youtube support only?
32570             cfg.cn.push({
32571                 tag: 'iframe',
32572                 cls: 'masonry-brick-image-view',
32573                 src: vurl,
32574                 frameborder : 0,
32575                 allowfullscreen : true
32576             });
32577         }
32578         
32579         return cfg;
32580         
32581     },
32582     
32583     getSplitAutoCreate : function()
32584     {
32585         var cls = 'masonry-brick masonry-brick-split';
32586         
32587         if(this.href.length){
32588             cls += ' masonry-brick-link';
32589         }
32590         
32591         if(this.bgimage.length){
32592             cls += ' masonry-brick-image';
32593         }
32594         
32595         if(this.size){
32596             cls += ' masonry-' + this.size + '-brick';
32597         }
32598         
32599         switch (this.placetitle) {
32600             case 'center' :
32601                 cls += ' masonry-center-title';
32602                 break;
32603             case 'bottom' :
32604                 cls += ' masonry-bottom-title';
32605                 break;
32606             default:
32607                 if(!this.bgimage.length){
32608                     cls += ' masonry-center-title';
32609                 }
32610
32611                 if(this.bgimage.length){
32612                     cls += ' masonry-bottom-title';
32613                 }
32614                 break;
32615         }
32616         
32617         if(this.cls){
32618             cls += ' ' + this.cls;
32619         }
32620         
32621         var cfg = {
32622             tag: (this.href.length) ? 'a' : 'div',
32623             cls: cls,
32624             cn: [
32625                 {
32626                     tag: 'div',
32627                     cls: 'masonry-brick-split-head',
32628                     cn: [
32629                         {
32630                             tag: 'div',
32631                             cls: 'masonry-brick-paragraph',
32632                             cn: []
32633                         }
32634                     ]
32635                 },
32636                 {
32637                     tag: 'div',
32638                     cls: 'masonry-brick-split-body',
32639                     cn: []
32640                 }
32641             ]
32642         };
32643         
32644         if(this.href.length){
32645             cfg.href = this.href;
32646         }
32647         
32648         if(this.title.length){
32649             cfg.cn[0].cn[0].cn.push({
32650                 tag: 'h4',
32651                 cls: 'masonry-brick-title',
32652                 html: this.title
32653             });
32654         }
32655         
32656         if(this.html.length){
32657             cfg.cn[1].cn.push({
32658                 tag: 'p',
32659                 cls: 'masonry-brick-text',
32660                 html: this.html
32661             });
32662         }
32663
32664         if(this.bgimage.length){
32665             cfg.cn[0].cn.push({
32666                 tag: 'img',
32667                 cls: 'masonry-brick-image-view',
32668                 src: this.bgimage
32669             });
32670         }
32671         
32672         if(this.videourl.length){
32673             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32674             // youtube support only?
32675             cfg.cn[0].cn.cn.push({
32676                 tag: 'iframe',
32677                 cls: 'masonry-brick-image-view',
32678                 src: vurl,
32679                 frameborder : 0,
32680                 allowfullscreen : true
32681             });
32682         }
32683         
32684         return cfg;
32685     },
32686     
32687     initEvents: function() 
32688     {
32689         switch (this.size) {
32690             case 'xs' :
32691                 this.x = 1;
32692                 this.y = 1;
32693                 break;
32694             case 'sm' :
32695                 this.x = 2;
32696                 this.y = 2;
32697                 break;
32698             case 'md' :
32699             case 'md-left' :
32700             case 'md-right' :
32701                 this.x = 3;
32702                 this.y = 3;
32703                 break;
32704             case 'tall' :
32705                 this.x = 2;
32706                 this.y = 3;
32707                 break;
32708             case 'wide' :
32709                 this.x = 3;
32710                 this.y = 2;
32711                 break;
32712             case 'wide-thin' :
32713                 this.x = 3;
32714                 this.y = 1;
32715                 break;
32716                         
32717             default :
32718                 break;
32719         }
32720         
32721         if(Roo.isTouch){
32722             this.el.on('touchstart', this.onTouchStart, this);
32723             this.el.on('touchmove', this.onTouchMove, this);
32724             this.el.on('touchend', this.onTouchEnd, this);
32725             this.el.on('contextmenu', this.onContextMenu, this);
32726         } else {
32727             this.el.on('mouseenter'  ,this.enter, this);
32728             this.el.on('mouseleave', this.leave, this);
32729             this.el.on('click', this.onClick, this);
32730         }
32731         
32732         if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32733             this.parent().bricks.push(this);   
32734         }
32735         
32736     },
32737     
32738     onClick: function(e, el)
32739     {
32740         var time = this.endTimer - this.startTimer;
32741         // Roo.log(e.preventDefault());
32742         if(Roo.isTouch){
32743             if(time > 1000){
32744                 e.preventDefault();
32745                 return;
32746             }
32747         }
32748         
32749         if(!this.preventDefault){
32750             return;
32751         }
32752         
32753         e.preventDefault();
32754         
32755         if (this.activeClass != '') {
32756             this.selectBrick();
32757         }
32758         
32759         this.fireEvent('click', this, e);
32760     },
32761     
32762     enter: function(e, el)
32763     {
32764         e.preventDefault();
32765         
32766         if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32767             return;
32768         }
32769         
32770         if(this.bgimage.length && this.html.length){
32771             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32772         }
32773     },
32774     
32775     leave: function(e, el)
32776     {
32777         e.preventDefault();
32778         
32779         if(!this.isFitContainer || this.maskInverse  || this.videourl.length){
32780             return;
32781         }
32782         
32783         if(this.bgimage.length && this.html.length){
32784             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32785         }
32786     },
32787     
32788     onTouchStart: function(e, el)
32789     {
32790 //        e.preventDefault();
32791         
32792         this.touchmoved = false;
32793         
32794         if(!this.isFitContainer){
32795             return;
32796         }
32797         
32798         if(!this.bgimage.length || !this.html.length){
32799             return;
32800         }
32801         
32802         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32803         
32804         this.timer = new Date().getTime();
32805         
32806     },
32807     
32808     onTouchMove: function(e, el)
32809     {
32810         this.touchmoved = true;
32811     },
32812     
32813     onContextMenu : function(e,el)
32814     {
32815         e.preventDefault();
32816         e.stopPropagation();
32817         return false;
32818     },
32819     
32820     onTouchEnd: function(e, el)
32821     {
32822 //        e.preventDefault();
32823         
32824         if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32825         
32826             this.leave(e,el);
32827             
32828             return;
32829         }
32830         
32831         if(!this.bgimage.length || !this.html.length){
32832             
32833             if(this.href.length){
32834                 window.location.href = this.href;
32835             }
32836             
32837             return;
32838         }
32839         
32840         if(!this.isFitContainer){
32841             return;
32842         }
32843         
32844         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32845         
32846         window.location.href = this.href;
32847     },
32848     
32849     //selection on single brick only
32850     selectBrick : function() {
32851         
32852         if (!this.parentId) {
32853             return;
32854         }
32855         
32856         var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32857         var index = m.selectedBrick.indexOf(this.id);
32858         
32859         if ( index > -1) {
32860             m.selectedBrick.splice(index,1);
32861             this.el.removeClass(this.activeClass);
32862             return;
32863         }
32864         
32865         for(var i = 0; i < m.selectedBrick.length; i++) {
32866             var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32867             b.el.removeClass(b.activeClass);
32868         }
32869         
32870         m.selectedBrick = [];
32871         
32872         m.selectedBrick.push(this.id);
32873         this.el.addClass(this.activeClass);
32874         return;
32875     },
32876     
32877     isSelected : function(){
32878         return this.el.hasClass(this.activeClass);
32879         
32880     }
32881 });
32882
32883 Roo.apply(Roo.bootstrap.MasonryBrick, {
32884     
32885     //groups: {},
32886     groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32887      /**
32888     * register a Masonry Brick
32889     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32890     */
32891     
32892     register : function(brick)
32893     {
32894         //this.groups[brick.id] = brick;
32895         this.groups.add(brick.id, brick);
32896     },
32897     /**
32898     * fetch a  masonry brick based on the masonry brick ID
32899     * @param {string} the masonry brick to add
32900     * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32901     */
32902     
32903     get: function(brick_id) 
32904     {
32905         // if (typeof(this.groups[brick_id]) == 'undefined') {
32906         //     return false;
32907         // }
32908         // return this.groups[brick_id] ;
32909         
32910         if(this.groups.key(brick_id)) {
32911             return this.groups.key(brick_id);
32912         }
32913         
32914         return false;
32915     }
32916     
32917     
32918     
32919 });
32920
32921  /*
32922  * - LGPL
32923  *
32924  * element
32925  * 
32926  */
32927
32928 /**
32929  * @class Roo.bootstrap.Brick
32930  * @extends Roo.bootstrap.Component
32931  * Bootstrap Brick class
32932  * 
32933  * @constructor
32934  * Create a new Brick
32935  * @param {Object} config The config object
32936  */
32937
32938 Roo.bootstrap.Brick = function(config){
32939     Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32940     
32941     this.addEvents({
32942         // raw events
32943         /**
32944          * @event click
32945          * When a Brick is click
32946          * @param {Roo.bootstrap.Brick} this
32947          * @param {Roo.EventObject} e
32948          */
32949         "click" : true
32950     });
32951 };
32952
32953 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
32954     
32955     /**
32956      * @cfg {String} title
32957      */   
32958     title : '',
32959     /**
32960      * @cfg {String} html
32961      */   
32962     html : '',
32963     /**
32964      * @cfg {String} bgimage
32965      */   
32966     bgimage : '',
32967     /**
32968      * @cfg {String} cls
32969      */   
32970     cls : '',
32971     /**
32972      * @cfg {String} href
32973      */   
32974     href : '',
32975     /**
32976      * @cfg {String} video
32977      */   
32978     video : '',
32979     /**
32980      * @cfg {Boolean} square
32981      */   
32982     square : true,
32983     
32984     getAutoCreate : function()
32985     {
32986         var cls = 'roo-brick';
32987         
32988         if(this.href.length){
32989             cls += ' roo-brick-link';
32990         }
32991         
32992         if(this.bgimage.length){
32993             cls += ' roo-brick-image';
32994         }
32995         
32996         if(!this.html.length && !this.bgimage.length){
32997             cls += ' roo-brick-center-title';
32998         }
32999         
33000         if(!this.html.length && this.bgimage.length){
33001             cls += ' roo-brick-bottom-title';
33002         }
33003         
33004         if(this.cls){
33005             cls += ' ' + this.cls;
33006         }
33007         
33008         var cfg = {
33009             tag: (this.href.length) ? 'a' : 'div',
33010             cls: cls,
33011             cn: [
33012                 {
33013                     tag: 'div',
33014                     cls: 'roo-brick-paragraph',
33015                     cn: []
33016                 }
33017             ]
33018         };
33019         
33020         if(this.href.length){
33021             cfg.href = this.href;
33022         }
33023         
33024         var cn = cfg.cn[0].cn;
33025         
33026         if(this.title.length){
33027             cn.push({
33028                 tag: 'h4',
33029                 cls: 'roo-brick-title',
33030                 html: this.title
33031             });
33032         }
33033         
33034         if(this.html.length){
33035             cn.push({
33036                 tag: 'p',
33037                 cls: 'roo-brick-text',
33038                 html: this.html
33039             });
33040         } else {
33041             cn.cls += ' hide';
33042         }
33043         
33044         if(this.bgimage.length){
33045             cfg.cn.push({
33046                 tag: 'img',
33047                 cls: 'roo-brick-image-view',
33048                 src: this.bgimage
33049             });
33050         }
33051         
33052         return cfg;
33053     },
33054     
33055     initEvents: function() 
33056     {
33057         if(this.title.length || this.html.length){
33058             this.el.on('mouseenter'  ,this.enter, this);
33059             this.el.on('mouseleave', this.leave, this);
33060         }
33061         
33062         Roo.EventManager.onWindowResize(this.resize, this); 
33063         
33064         if(this.bgimage.length){
33065             this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33066             this.imageEl.on('load', this.onImageLoad, this);
33067             return;
33068         }
33069         
33070         this.resize();
33071     },
33072     
33073     onImageLoad : function()
33074     {
33075         this.resize();
33076     },
33077     
33078     resize : function()
33079     {
33080         var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33081         
33082         paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33083         
33084         if(this.bgimage.length){
33085             var image = this.el.select('.roo-brick-image-view', true).first();
33086             
33087             image.setWidth(paragraph.getWidth());
33088             
33089             if(this.square){
33090                 image.setHeight(paragraph.getWidth());
33091             }
33092             
33093             this.el.setHeight(image.getHeight());
33094             paragraph.setHeight(image.getHeight());
33095             
33096         }
33097         
33098     },
33099     
33100     enter: function(e, el)
33101     {
33102         e.preventDefault();
33103         
33104         if(this.bgimage.length){
33105             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33106             this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33107         }
33108     },
33109     
33110     leave: function(e, el)
33111     {
33112         e.preventDefault();
33113         
33114         if(this.bgimage.length){
33115             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33116             this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33117         }
33118     }
33119     
33120 });
33121
33122  
33123
33124  /*
33125  * - LGPL
33126  *
33127  * Number field 
33128  */
33129
33130 /**
33131  * @class Roo.bootstrap.NumberField
33132  * @extends Roo.bootstrap.Input
33133  * Bootstrap NumberField class
33134  * 
33135  * 
33136  * 
33137  * 
33138  * @constructor
33139  * Create a new NumberField
33140  * @param {Object} config The config object
33141  */
33142
33143 Roo.bootstrap.NumberField = function(config){
33144     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33145 };
33146
33147 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33148     
33149     /**
33150      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33151      */
33152     allowDecimals : true,
33153     /**
33154      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33155      */
33156     decimalSeparator : ".",
33157     /**
33158      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33159      */
33160     decimalPrecision : 2,
33161     /**
33162      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33163      */
33164     allowNegative : true,
33165     
33166     /**
33167      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33168      */
33169     allowZero: true,
33170     /**
33171      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33172      */
33173     minValue : Number.NEGATIVE_INFINITY,
33174     /**
33175      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33176      */
33177     maxValue : Number.MAX_VALUE,
33178     /**
33179      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33180      */
33181     minText : "The minimum value for this field is {0}",
33182     /**
33183      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33184      */
33185     maxText : "The maximum value for this field is {0}",
33186     /**
33187      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
33188      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33189      */
33190     nanText : "{0} is not a valid number",
33191     /**
33192      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33193      */
33194     castInt : true,
33195     /**
33196      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33197      */
33198     thousandsDelimiter : false,
33199     /**
33200      * @cfg {String} valueAlign alignment of value
33201      */
33202     valueAlign : "left",
33203
33204     getAutoCreate : function()
33205     {
33206         var hiddenInput = {
33207             tag: 'input',
33208             type: 'hidden',
33209             id: Roo.id(),
33210             cls: 'hidden-number-input'
33211         };
33212         
33213         if (this.name) {
33214             hiddenInput.name = this.name;
33215         }
33216         
33217         this.name = '';
33218         
33219         var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33220         
33221         this.name = hiddenInput.name;
33222         
33223         if(cfg.cn.length > 0) {
33224             cfg.cn.push(hiddenInput);
33225         }
33226         
33227         return cfg;
33228     },
33229
33230     // private
33231     initEvents : function()
33232     {   
33233         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33234         
33235         var allowed = "0123456789";
33236         
33237         if(this.allowDecimals){
33238             allowed += this.decimalSeparator;
33239         }
33240         
33241         if(this.allowNegative){
33242             allowed += "-";
33243         }
33244         
33245         if(this.thousandsDelimiter) {
33246             allowed += ",";
33247         }
33248         
33249         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33250         
33251         var keyPress = function(e){
33252             
33253             var k = e.getKey();
33254             
33255             var c = e.getCharCode();
33256             
33257             if(
33258                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33259                     allowed.indexOf(String.fromCharCode(c)) === -1
33260             ){
33261                 e.stopEvent();
33262                 return;
33263             }
33264             
33265             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33266                 return;
33267             }
33268             
33269             if(allowed.indexOf(String.fromCharCode(c)) === -1){
33270                 e.stopEvent();
33271             }
33272         };
33273         
33274         this.el.on("keypress", keyPress, this);
33275     },
33276     
33277     validateValue : function(value)
33278     {
33279         
33280         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33281             return false;
33282         }
33283         
33284         var num = this.parseValue(value);
33285         
33286         if(isNaN(num)){
33287             this.markInvalid(String.format(this.nanText, value));
33288             return false;
33289         }
33290         
33291         if(num < this.minValue){
33292             this.markInvalid(String.format(this.minText, this.minValue));
33293             return false;
33294         }
33295         
33296         if(num > this.maxValue){
33297             this.markInvalid(String.format(this.maxText, this.maxValue));
33298             return false;
33299         }
33300         
33301         return true;
33302     },
33303
33304     getValue : function()
33305     {
33306         var v = this.hiddenEl().getValue();
33307         
33308         return this.fixPrecision(this.parseValue(v));
33309     },
33310
33311     parseValue : function(value)
33312     {
33313         if(this.thousandsDelimiter) {
33314             value += "";
33315             r = new RegExp(",", "g");
33316             value = value.replace(r, "");
33317         }
33318         
33319         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33320         return isNaN(value) ? '' : value;
33321     },
33322
33323     fixPrecision : function(value)
33324     {
33325         if(this.thousandsDelimiter) {
33326             value += "";
33327             r = new RegExp(",", "g");
33328             value = value.replace(r, "");
33329         }
33330         
33331         var nan = isNaN(value);
33332         
33333         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33334             return nan ? '' : value;
33335         }
33336         return parseFloat(value).toFixed(this.decimalPrecision);
33337     },
33338
33339     setValue : function(v)
33340     {
33341         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33342         
33343         this.value = v;
33344         
33345         if(this.rendered){
33346             
33347             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33348             
33349             this.inputEl().dom.value = (v == '') ? '' :
33350                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33351             
33352             if(!this.allowZero && v === '0') {
33353                 this.hiddenEl().dom.value = '';
33354                 this.inputEl().dom.value = '';
33355             }
33356             
33357             this.validate();
33358         }
33359     },
33360
33361     decimalPrecisionFcn : function(v)
33362     {
33363         return Math.floor(v);
33364     },
33365
33366     beforeBlur : function()
33367     {
33368         if(!this.castInt){
33369             return;
33370         }
33371         
33372         var v = this.parseValue(this.getRawValue());
33373         
33374         if(v || v === 0){
33375             this.setValue(v);
33376         }
33377     },
33378     
33379     hiddenEl : function()
33380     {
33381         return this.el.select('input.hidden-number-input',true).first();
33382     }
33383     
33384 });
33385
33386  
33387
33388 /*
33389 * Licence: LGPL
33390 */
33391
33392 /**
33393  * @class Roo.bootstrap.DocumentSlider
33394  * @extends Roo.bootstrap.Component
33395  * Bootstrap DocumentSlider class
33396  * 
33397  * @constructor
33398  * Create a new DocumentViewer
33399  * @param {Object} config The config object
33400  */
33401
33402 Roo.bootstrap.DocumentSlider = function(config){
33403     Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33404     
33405     this.files = [];
33406     
33407     this.addEvents({
33408         /**
33409          * @event initial
33410          * Fire after initEvent
33411          * @param {Roo.bootstrap.DocumentSlider} this
33412          */
33413         "initial" : true,
33414         /**
33415          * @event update
33416          * Fire after update
33417          * @param {Roo.bootstrap.DocumentSlider} this
33418          */
33419         "update" : true,
33420         /**
33421          * @event click
33422          * Fire after click
33423          * @param {Roo.bootstrap.DocumentSlider} this
33424          */
33425         "click" : true
33426     });
33427 };
33428
33429 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
33430     
33431     files : false,
33432     
33433     indicator : 0,
33434     
33435     getAutoCreate : function()
33436     {
33437         var cfg = {
33438             tag : 'div',
33439             cls : 'roo-document-slider',
33440             cn : [
33441                 {
33442                     tag : 'div',
33443                     cls : 'roo-document-slider-header',
33444                     cn : [
33445                         {
33446                             tag : 'div',
33447                             cls : 'roo-document-slider-header-title'
33448                         }
33449                     ]
33450                 },
33451                 {
33452                     tag : 'div',
33453                     cls : 'roo-document-slider-body',
33454                     cn : [
33455                         {
33456                             tag : 'div',
33457                             cls : 'roo-document-slider-prev',
33458                             cn : [
33459                                 {
33460                                     tag : 'i',
33461                                     cls : 'fa fa-chevron-left'
33462                                 }
33463                             ]
33464                         },
33465                         {
33466                             tag : 'div',
33467                             cls : 'roo-document-slider-thumb',
33468                             cn : [
33469                                 {
33470                                     tag : 'img',
33471                                     cls : 'roo-document-slider-image'
33472                                 }
33473                             ]
33474                         },
33475                         {
33476                             tag : 'div',
33477                             cls : 'roo-document-slider-next',
33478                             cn : [
33479                                 {
33480                                     tag : 'i',
33481                                     cls : 'fa fa-chevron-right'
33482                                 }
33483                             ]
33484                         }
33485                     ]
33486                 }
33487             ]
33488         };
33489         
33490         return cfg;
33491     },
33492     
33493     initEvents : function()
33494     {
33495         this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33496         this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33497         
33498         this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33499         this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33500         
33501         this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33502         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33503         
33504         this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33505         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33506         
33507         this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33508         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33509         
33510         this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33511         this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33512         
33513         this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33514         this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33515         
33516         this.thumbEl.on('click', this.onClick, this);
33517         
33518         this.prevIndicator.on('click', this.prev, this);
33519         
33520         this.nextIndicator.on('click', this.next, this);
33521         
33522     },
33523     
33524     initial : function()
33525     {
33526         if(this.files.length){
33527             this.indicator = 1;
33528             this.update()
33529         }
33530         
33531         this.fireEvent('initial', this);
33532     },
33533     
33534     update : function()
33535     {
33536         this.imageEl.attr('src', this.files[this.indicator - 1]);
33537         
33538         this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33539         
33540         this.prevIndicator.show();
33541         
33542         if(this.indicator == 1){
33543             this.prevIndicator.hide();
33544         }
33545         
33546         this.nextIndicator.show();
33547         
33548         if(this.indicator == this.files.length){
33549             this.nextIndicator.hide();
33550         }
33551         
33552         this.thumbEl.scrollTo('top');
33553         
33554         this.fireEvent('update', this);
33555     },
33556     
33557     onClick : function(e)
33558     {
33559         e.preventDefault();
33560         
33561         this.fireEvent('click', this);
33562     },
33563     
33564     prev : function(e)
33565     {
33566         e.preventDefault();
33567         
33568         this.indicator = Math.max(1, this.indicator - 1);
33569         
33570         this.update();
33571     },
33572     
33573     next : function(e)
33574     {
33575         e.preventDefault();
33576         
33577         this.indicator = Math.min(this.files.length, this.indicator + 1);
33578         
33579         this.update();
33580     }
33581 });
33582 /*
33583  * - LGPL
33584  *
33585  * RadioSet
33586  *
33587  *
33588  */
33589
33590 /**
33591  * @class Roo.bootstrap.RadioSet
33592  * @extends Roo.bootstrap.Input
33593  * Bootstrap RadioSet class
33594  * @cfg {String} indicatorpos (left|right) default left
33595  * @cfg {Boolean} inline (true|false) inline the element (default true)
33596  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33597  * @constructor
33598  * Create a new RadioSet
33599  * @param {Object} config The config object
33600  */
33601
33602 Roo.bootstrap.RadioSet = function(config){
33603     
33604     Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33605     
33606     this.radioes = [];
33607     
33608     Roo.bootstrap.RadioSet.register(this);
33609     
33610     this.addEvents({
33611         /**
33612         * @event check
33613         * Fires when the element is checked or unchecked.
33614         * @param {Roo.bootstrap.RadioSet} this This radio
33615         * @param {Roo.bootstrap.Radio} item The checked item
33616         */
33617        check : true,
33618        /**
33619         * @event click
33620         * Fires when the element is click.
33621         * @param {Roo.bootstrap.RadioSet} this This radio set
33622         * @param {Roo.bootstrap.Radio} item The checked item
33623         * @param {Roo.EventObject} e The event object
33624         */
33625        click : true
33626     });
33627     
33628 };
33629
33630 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
33631
33632     radioes : false,
33633     
33634     inline : true,
33635     
33636     weight : '',
33637     
33638     indicatorpos : 'left',
33639     
33640     getAutoCreate : function()
33641     {
33642         var label = {
33643             tag : 'label',
33644             cls : 'roo-radio-set-label',
33645             cn : [
33646                 {
33647                     tag : 'span',
33648                     html : this.fieldLabel
33649                 }
33650             ]
33651         };
33652         
33653         if(this.indicatorpos == 'left'){
33654             label.cn.unshift({
33655                 tag : 'i',
33656                 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33657                 tooltip : 'This field is required'
33658             });
33659         } else {
33660             label.cn.push({
33661                 tag : 'i',
33662                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33663                 tooltip : 'This field is required'
33664             });
33665         }
33666         
33667         var items = {
33668             tag : 'div',
33669             cls : 'roo-radio-set-items'
33670         };
33671         
33672         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33673         
33674         if (align === 'left' && this.fieldLabel.length) {
33675             
33676             items = {
33677                 cls : "roo-radio-set-right", 
33678                 cn: [
33679                     items
33680                 ]
33681             };
33682             
33683             if(this.labelWidth > 12){
33684                 label.style = "width: " + this.labelWidth + 'px';
33685             }
33686             
33687             if(this.labelWidth < 13 && this.labelmd == 0){
33688                 this.labelmd = this.labelWidth;
33689             }
33690             
33691             if(this.labellg > 0){
33692                 label.cls += ' col-lg-' + this.labellg;
33693                 items.cls += ' col-lg-' + (12 - this.labellg);
33694             }
33695             
33696             if(this.labelmd > 0){
33697                 label.cls += ' col-md-' + this.labelmd;
33698                 items.cls += ' col-md-' + (12 - this.labelmd);
33699             }
33700             
33701             if(this.labelsm > 0){
33702                 label.cls += ' col-sm-' + this.labelsm;
33703                 items.cls += ' col-sm-' + (12 - this.labelsm);
33704             }
33705             
33706             if(this.labelxs > 0){
33707                 label.cls += ' col-xs-' + this.labelxs;
33708                 items.cls += ' col-xs-' + (12 - this.labelxs);
33709             }
33710         }
33711         
33712         var cfg = {
33713             tag : 'div',
33714             cls : 'roo-radio-set',
33715             cn : [
33716                 {
33717                     tag : 'input',
33718                     cls : 'roo-radio-set-input',
33719                     type : 'hidden',
33720                     name : this.name,
33721                     value : this.value ? this.value :  ''
33722                 },
33723                 label,
33724                 items
33725             ]
33726         };
33727         
33728         if(this.weight.length){
33729             cfg.cls += ' roo-radio-' + this.weight;
33730         }
33731         
33732         if(this.inline) {
33733             cfg.cls += ' roo-radio-set-inline';
33734         }
33735         
33736         var settings=this;
33737         ['xs','sm','md','lg'].map(function(size){
33738             if (settings[size]) {
33739                 cfg.cls += ' col-' + size + '-' + settings[size];
33740             }
33741         });
33742         
33743         return cfg;
33744         
33745     },
33746
33747     initEvents : function()
33748     {
33749         this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33750         this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33751         
33752         if(!this.fieldLabel.length){
33753             this.labelEl.hide();
33754         }
33755         
33756         this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33757         this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33758         
33759         this.indicator = this.indicatorEl();
33760         
33761         if(this.indicator){
33762             this.indicator.addClass('invisible');
33763         }
33764         
33765         this.originalValue = this.getValue();
33766         
33767     },
33768     
33769     inputEl: function ()
33770     {
33771         return this.el.select('.roo-radio-set-input', true).first();
33772     },
33773     
33774     getChildContainer : function()
33775     {
33776         return this.itemsEl;
33777     },
33778     
33779     register : function(item)
33780     {
33781         this.radioes.push(item);
33782         
33783     },
33784     
33785     validate : function()
33786     {   
33787         if(this.getVisibilityEl().hasClass('hidden')){
33788             return true;
33789         }
33790         
33791         var valid = false;
33792         
33793         Roo.each(this.radioes, function(i){
33794             if(!i.checked){
33795                 return;
33796             }
33797             
33798             valid = true;
33799             return false;
33800         });
33801         
33802         if(this.allowBlank) {
33803             return true;
33804         }
33805         
33806         if(this.disabled || valid){
33807             this.markValid();
33808             return true;
33809         }
33810         
33811         this.markInvalid();
33812         return false;
33813         
33814     },
33815     
33816     markValid : function()
33817     {
33818         if(this.labelEl.isVisible(true)){
33819             this.indicatorEl().removeClass('visible');
33820             this.indicatorEl().addClass('invisible');
33821         }
33822         
33823         this.el.removeClass([this.invalidClass, this.validClass]);
33824         this.el.addClass(this.validClass);
33825         
33826         this.fireEvent('valid', this);
33827     },
33828     
33829     markInvalid : function(msg)
33830     {
33831         if(this.allowBlank || this.disabled){
33832             return;
33833         }
33834         
33835         if(this.labelEl.isVisible(true)){
33836             this.indicatorEl().removeClass('invisible');
33837             this.indicatorEl().addClass('visible');
33838         }
33839         
33840         this.el.removeClass([this.invalidClass, this.validClass]);
33841         this.el.addClass(this.invalidClass);
33842         
33843         this.fireEvent('invalid', this, msg);
33844         
33845     },
33846     
33847     setValue : function(v, suppressEvent)
33848     {   
33849         if(this.value === v){
33850             return;
33851         }
33852         
33853         this.value = v;
33854         
33855         if(this.rendered){
33856             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33857         }
33858         
33859         Roo.each(this.radioes, function(i){
33860             i.checked = false;
33861             i.el.removeClass('checked');
33862         });
33863         
33864         Roo.each(this.radioes, function(i){
33865             
33866             if(i.value === v || i.value.toString() === v.toString()){
33867                 i.checked = true;
33868                 i.el.addClass('checked');
33869                 
33870                 if(suppressEvent !== true){
33871                     this.fireEvent('check', this, i);
33872                 }
33873                 
33874                 return false;
33875             }
33876             
33877         }, this);
33878         
33879         this.validate();
33880     },
33881     
33882     clearInvalid : function(){
33883         
33884         if(!this.el || this.preventMark){
33885             return;
33886         }
33887         
33888         this.el.removeClass([this.invalidClass]);
33889         
33890         this.fireEvent('valid', this);
33891     }
33892     
33893 });
33894
33895 Roo.apply(Roo.bootstrap.RadioSet, {
33896     
33897     groups: {},
33898     
33899     register : function(set)
33900     {
33901         this.groups[set.name] = set;
33902     },
33903     
33904     get: function(name) 
33905     {
33906         if (typeof(this.groups[name]) == 'undefined') {
33907             return false;
33908         }
33909         
33910         return this.groups[name] ;
33911     }
33912     
33913 });
33914 /*
33915  * Based on:
33916  * Ext JS Library 1.1.1
33917  * Copyright(c) 2006-2007, Ext JS, LLC.
33918  *
33919  * Originally Released Under LGPL - original licence link has changed is not relivant.
33920  *
33921  * Fork - LGPL
33922  * <script type="text/javascript">
33923  */
33924
33925
33926 /**
33927  * @class Roo.bootstrap.SplitBar
33928  * @extends Roo.util.Observable
33929  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33930  * <br><br>
33931  * Usage:
33932  * <pre><code>
33933 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33934                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33935 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33936 split.minSize = 100;
33937 split.maxSize = 600;
33938 split.animate = true;
33939 split.on('moved', splitterMoved);
33940 </code></pre>
33941  * @constructor
33942  * Create a new SplitBar
33943  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
33944  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
33945  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33946  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
33947                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33948                         position of the SplitBar).
33949  */
33950 Roo.bootstrap.SplitBar = function(cfg){
33951     
33952     /** @private */
33953     
33954     //{
33955     //  dragElement : elm
33956     //  resizingElement: el,
33957         // optional..
33958     //    orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33959     //    placement : Roo.bootstrap.SplitBar.LEFT  ,
33960         // existingProxy ???
33961     //}
33962     
33963     this.el = Roo.get(cfg.dragElement, true);
33964     this.el.dom.unselectable = "on";
33965     /** @private */
33966     this.resizingEl = Roo.get(cfg.resizingElement, true);
33967
33968     /**
33969      * @private
33970      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33971      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33972      * @type Number
33973      */
33974     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33975     
33976     /**
33977      * The minimum size of the resizing element. (Defaults to 0)
33978      * @type Number
33979      */
33980     this.minSize = 0;
33981     
33982     /**
33983      * The maximum size of the resizing element. (Defaults to 2000)
33984      * @type Number
33985      */
33986     this.maxSize = 2000;
33987     
33988     /**
33989      * Whether to animate the transition to the new size
33990      * @type Boolean
33991      */
33992     this.animate = false;
33993     
33994     /**
33995      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33996      * @type Boolean
33997      */
33998     this.useShim = false;
33999     
34000     /** @private */
34001     this.shim = null;
34002     
34003     if(!cfg.existingProxy){
34004         /** @private */
34005         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34006     }else{
34007         this.proxy = Roo.get(cfg.existingProxy).dom;
34008     }
34009     /** @private */
34010     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34011     
34012     /** @private */
34013     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34014     
34015     /** @private */
34016     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34017     
34018     /** @private */
34019     this.dragSpecs = {};
34020     
34021     /**
34022      * @private The adapter to use to positon and resize elements
34023      */
34024     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34025     this.adapter.init(this);
34026     
34027     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34028         /** @private */
34029         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34030         this.el.addClass("roo-splitbar-h");
34031     }else{
34032         /** @private */
34033         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34034         this.el.addClass("roo-splitbar-v");
34035     }
34036     
34037     this.addEvents({
34038         /**
34039          * @event resize
34040          * Fires when the splitter is moved (alias for {@link #event-moved})
34041          * @param {Roo.bootstrap.SplitBar} this
34042          * @param {Number} newSize the new width or height
34043          */
34044         "resize" : true,
34045         /**
34046          * @event moved
34047          * Fires when the splitter is moved
34048          * @param {Roo.bootstrap.SplitBar} this
34049          * @param {Number} newSize the new width or height
34050          */
34051         "moved" : true,
34052         /**
34053          * @event beforeresize
34054          * Fires before the splitter is dragged
34055          * @param {Roo.bootstrap.SplitBar} this
34056          */
34057         "beforeresize" : true,
34058
34059         "beforeapply" : true
34060     });
34061
34062     Roo.util.Observable.call(this);
34063 };
34064
34065 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34066     onStartProxyDrag : function(x, y){
34067         this.fireEvent("beforeresize", this);
34068         if(!this.overlay){
34069             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "roo-drag-overlay", html: "&#160;"}, true);
34070             o.unselectable();
34071             o.enableDisplayMode("block");
34072             // all splitbars share the same overlay
34073             Roo.bootstrap.SplitBar.prototype.overlay = o;
34074         }
34075         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34076         this.overlay.show();
34077         Roo.get(this.proxy).setDisplayed("block");
34078         var size = this.adapter.getElementSize(this);
34079         this.activeMinSize = this.getMinimumSize();;
34080         this.activeMaxSize = this.getMaximumSize();;
34081         var c1 = size - this.activeMinSize;
34082         var c2 = Math.max(this.activeMaxSize - size, 0);
34083         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34084             this.dd.resetConstraints();
34085             this.dd.setXConstraint(
34086                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
34087                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34088             );
34089             this.dd.setYConstraint(0, 0);
34090         }else{
34091             this.dd.resetConstraints();
34092             this.dd.setXConstraint(0, 0);
34093             this.dd.setYConstraint(
34094                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
34095                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34096             );
34097          }
34098         this.dragSpecs.startSize = size;
34099         this.dragSpecs.startPoint = [x, y];
34100         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34101     },
34102     
34103     /** 
34104      * @private Called after the drag operation by the DDProxy
34105      */
34106     onEndProxyDrag : function(e){
34107         Roo.get(this.proxy).setDisplayed(false);
34108         var endPoint = Roo.lib.Event.getXY(e);
34109         if(this.overlay){
34110             this.overlay.hide();
34111         }
34112         var newSize;
34113         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34114             newSize = this.dragSpecs.startSize + 
34115                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34116                     endPoint[0] - this.dragSpecs.startPoint[0] :
34117                     this.dragSpecs.startPoint[0] - endPoint[0]
34118                 );
34119         }else{
34120             newSize = this.dragSpecs.startSize + 
34121                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34122                     endPoint[1] - this.dragSpecs.startPoint[1] :
34123                     this.dragSpecs.startPoint[1] - endPoint[1]
34124                 );
34125         }
34126         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34127         if(newSize != this.dragSpecs.startSize){
34128             if(this.fireEvent('beforeapply', this, newSize) !== false){
34129                 this.adapter.setElementSize(this, newSize);
34130                 this.fireEvent("moved", this, newSize);
34131                 this.fireEvent("resize", this, newSize);
34132             }
34133         }
34134     },
34135     
34136     /**
34137      * Get the adapter this SplitBar uses
34138      * @return The adapter object
34139      */
34140     getAdapter : function(){
34141         return this.adapter;
34142     },
34143     
34144     /**
34145      * Set the adapter this SplitBar uses
34146      * @param {Object} adapter A SplitBar adapter object
34147      */
34148     setAdapter : function(adapter){
34149         this.adapter = adapter;
34150         this.adapter.init(this);
34151     },
34152     
34153     /**
34154      * Gets the minimum size for the resizing element
34155      * @return {Number} The minimum size
34156      */
34157     getMinimumSize : function(){
34158         return this.minSize;
34159     },
34160     
34161     /**
34162      * Sets the minimum size for the resizing element
34163      * @param {Number} minSize The minimum size
34164      */
34165     setMinimumSize : function(minSize){
34166         this.minSize = minSize;
34167     },
34168     
34169     /**
34170      * Gets the maximum size for the resizing element
34171      * @return {Number} The maximum size
34172      */
34173     getMaximumSize : function(){
34174         return this.maxSize;
34175     },
34176     
34177     /**
34178      * Sets the maximum size for the resizing element
34179      * @param {Number} maxSize The maximum size
34180      */
34181     setMaximumSize : function(maxSize){
34182         this.maxSize = maxSize;
34183     },
34184     
34185     /**
34186      * Sets the initialize size for the resizing element
34187      * @param {Number} size The initial size
34188      */
34189     setCurrentSize : function(size){
34190         var oldAnimate = this.animate;
34191         this.animate = false;
34192         this.adapter.setElementSize(this, size);
34193         this.animate = oldAnimate;
34194     },
34195     
34196     /**
34197      * Destroy this splitbar. 
34198      * @param {Boolean} removeEl True to remove the element
34199      */
34200     destroy : function(removeEl){
34201         if(this.shim){
34202             this.shim.remove();
34203         }
34204         this.dd.unreg();
34205         this.proxy.parentNode.removeChild(this.proxy);
34206         if(removeEl){
34207             this.el.remove();
34208         }
34209     }
34210 });
34211
34212 /**
34213  * @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.
34214  */
34215 Roo.bootstrap.SplitBar.createProxy = function(dir){
34216     var proxy = new Roo.Element(document.createElement("div"));
34217     proxy.unselectable();
34218     var cls = 'roo-splitbar-proxy';
34219     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34220     document.body.appendChild(proxy.dom);
34221     return proxy.dom;
34222 };
34223
34224 /** 
34225  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34226  * Default Adapter. It assumes the splitter and resizing element are not positioned
34227  * elements and only gets/sets the width of the element. Generally used for table based layouts.
34228  */
34229 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34230 };
34231
34232 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34233     // do nothing for now
34234     init : function(s){
34235     
34236     },
34237     /**
34238      * Called before drag operations to get the current size of the resizing element. 
34239      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34240      */
34241      getElementSize : function(s){
34242         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34243             return s.resizingEl.getWidth();
34244         }else{
34245             return s.resizingEl.getHeight();
34246         }
34247     },
34248     
34249     /**
34250      * Called after drag operations to set the size of the resizing element.
34251      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34252      * @param {Number} newSize The new size to set
34253      * @param {Function} onComplete A function to be invoked when resizing is complete
34254      */
34255     setElementSize : function(s, newSize, onComplete){
34256         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34257             if(!s.animate){
34258                 s.resizingEl.setWidth(newSize);
34259                 if(onComplete){
34260                     onComplete(s, newSize);
34261                 }
34262             }else{
34263                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34264             }
34265         }else{
34266             
34267             if(!s.animate){
34268                 s.resizingEl.setHeight(newSize);
34269                 if(onComplete){
34270                     onComplete(s, newSize);
34271                 }
34272             }else{
34273                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34274             }
34275         }
34276     }
34277 };
34278
34279 /** 
34280  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34281  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34282  * Adapter that  moves the splitter element to align with the resized sizing element. 
34283  * Used with an absolute positioned SplitBar.
34284  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34285  * document.body, make sure you assign an id to the body element.
34286  */
34287 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34288     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34289     this.container = Roo.get(container);
34290 };
34291
34292 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34293     init : function(s){
34294         this.basic.init(s);
34295     },
34296     
34297     getElementSize : function(s){
34298         return this.basic.getElementSize(s);
34299     },
34300     
34301     setElementSize : function(s, newSize, onComplete){
34302         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34303     },
34304     
34305     moveSplitter : function(s){
34306         var yes = Roo.bootstrap.SplitBar;
34307         switch(s.placement){
34308             case yes.LEFT:
34309                 s.el.setX(s.resizingEl.getRight());
34310                 break;
34311             case yes.RIGHT:
34312                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34313                 break;
34314             case yes.TOP:
34315                 s.el.setY(s.resizingEl.getBottom());
34316                 break;
34317             case yes.BOTTOM:
34318                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34319                 break;
34320         }
34321     }
34322 };
34323
34324 /**
34325  * Orientation constant - Create a vertical SplitBar
34326  * @static
34327  * @type Number
34328  */
34329 Roo.bootstrap.SplitBar.VERTICAL = 1;
34330
34331 /**
34332  * Orientation constant - Create a horizontal SplitBar
34333  * @static
34334  * @type Number
34335  */
34336 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34337
34338 /**
34339  * Placement constant - The resizing element is to the left of the splitter element
34340  * @static
34341  * @type Number
34342  */
34343 Roo.bootstrap.SplitBar.LEFT = 1;
34344
34345 /**
34346  * Placement constant - The resizing element is to the right of the splitter element
34347  * @static
34348  * @type Number
34349  */
34350 Roo.bootstrap.SplitBar.RIGHT = 2;
34351
34352 /**
34353  * Placement constant - The resizing element is positioned above the splitter element
34354  * @static
34355  * @type Number
34356  */
34357 Roo.bootstrap.SplitBar.TOP = 3;
34358
34359 /**
34360  * Placement constant - The resizing element is positioned under splitter element
34361  * @static
34362  * @type Number
34363  */
34364 Roo.bootstrap.SplitBar.BOTTOM = 4;
34365 Roo.namespace("Roo.bootstrap.layout");/*
34366  * Based on:
34367  * Ext JS Library 1.1.1
34368  * Copyright(c) 2006-2007, Ext JS, LLC.
34369  *
34370  * Originally Released Under LGPL - original licence link has changed is not relivant.
34371  *
34372  * Fork - LGPL
34373  * <script type="text/javascript">
34374  */
34375
34376 /**
34377  * @class Roo.bootstrap.layout.Manager
34378  * @extends Roo.bootstrap.Component
34379  * Base class for layout managers.
34380  */
34381 Roo.bootstrap.layout.Manager = function(config)
34382 {
34383     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34384
34385
34386
34387
34388
34389     /** false to disable window resize monitoring @type Boolean */
34390     this.monitorWindowResize = true;
34391     this.regions = {};
34392     this.addEvents({
34393         /**
34394          * @event layout
34395          * Fires when a layout is performed.
34396          * @param {Roo.LayoutManager} this
34397          */
34398         "layout" : true,
34399         /**
34400          * @event regionresized
34401          * Fires when the user resizes a region.
34402          * @param {Roo.LayoutRegion} region The resized region
34403          * @param {Number} newSize The new size (width for east/west, height for north/south)
34404          */
34405         "regionresized" : true,
34406         /**
34407          * @event regioncollapsed
34408          * Fires when a region is collapsed.
34409          * @param {Roo.LayoutRegion} region The collapsed region
34410          */
34411         "regioncollapsed" : true,
34412         /**
34413          * @event regionexpanded
34414          * Fires when a region is expanded.
34415          * @param {Roo.LayoutRegion} region The expanded region
34416          */
34417         "regionexpanded" : true
34418     });
34419     this.updating = false;
34420
34421     if (config.el) {
34422         this.el = Roo.get(config.el);
34423         this.initEvents();
34424     }
34425
34426 };
34427
34428 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34429
34430
34431     regions : null,
34432
34433     monitorWindowResize : true,
34434
34435
34436     updating : false,
34437
34438
34439     onRender : function(ct, position)
34440     {
34441         if(!this.el){
34442             this.el = Roo.get(ct);
34443             this.initEvents();
34444         }
34445         //this.fireEvent('render',this);
34446     },
34447
34448
34449     initEvents: function()
34450     {
34451
34452
34453         // ie scrollbar fix
34454         if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34455             document.body.scroll = "no";
34456         }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34457             this.el.position('relative');
34458         }
34459         this.id = this.el.id;
34460         this.el.addClass("roo-layout-container");
34461         Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34462         if(this.el.dom != document.body ) {
34463             this.el.on('resize', this.layout,this);
34464             this.el.on('show', this.layout,this);
34465         }
34466
34467     },
34468
34469     /**
34470      * Returns true if this layout is currently being updated
34471      * @return {Boolean}
34472      */
34473     isUpdating : function(){
34474         return this.updating;
34475     },
34476
34477     /**
34478      * Suspend the LayoutManager from doing auto-layouts while
34479      * making multiple add or remove calls
34480      */
34481     beginUpdate : function(){
34482         this.updating = true;
34483     },
34484
34485     /**
34486      * Restore auto-layouts and optionally disable the manager from performing a layout
34487      * @param {Boolean} noLayout true to disable a layout update
34488      */
34489     endUpdate : function(noLayout){
34490         this.updating = false;
34491         if(!noLayout){
34492             this.layout();
34493         }
34494     },
34495
34496     layout: function(){
34497         // abstract...
34498     },
34499
34500     onRegionResized : function(region, newSize){
34501         this.fireEvent("regionresized", region, newSize);
34502         this.layout();
34503     },
34504
34505     onRegionCollapsed : function(region){
34506         this.fireEvent("regioncollapsed", region);
34507     },
34508
34509     onRegionExpanded : function(region){
34510         this.fireEvent("regionexpanded", region);
34511     },
34512
34513     /**
34514      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34515      * performs box-model adjustments.
34516      * @return {Object} The size as an object {width: (the width), height: (the height)}
34517      */
34518     getViewSize : function()
34519     {
34520         var size;
34521         if(this.el.dom != document.body){
34522             size = this.el.getSize();
34523         }else{
34524             size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34525         }
34526         size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34527         size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34528         return size;
34529     },
34530
34531     /**
34532      * Returns the Element this layout is bound to.
34533      * @return {Roo.Element}
34534      */
34535     getEl : function(){
34536         return this.el;
34537     },
34538
34539     /**
34540      * Returns the specified region.
34541      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34542      * @return {Roo.LayoutRegion}
34543      */
34544     getRegion : function(target){
34545         return this.regions[target.toLowerCase()];
34546     },
34547
34548     onWindowResize : function(){
34549         if(this.monitorWindowResize){
34550             this.layout();
34551         }
34552     }
34553 });
34554 /*
34555  * Based on:
34556  * Ext JS Library 1.1.1
34557  * Copyright(c) 2006-2007, Ext JS, LLC.
34558  *
34559  * Originally Released Under LGPL - original licence link has changed is not relivant.
34560  *
34561  * Fork - LGPL
34562  * <script type="text/javascript">
34563  */
34564 /**
34565  * @class Roo.bootstrap.layout.Border
34566  * @extends Roo.bootstrap.layout.Manager
34567  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34568  * please see: examples/bootstrap/nested.html<br><br>
34569  
34570 <b>The container the layout is rendered into can be either the body element or any other element.
34571 If it is not the body element, the container needs to either be an absolute positioned element,
34572 or you will need to add "position:relative" to the css of the container.  You will also need to specify
34573 the container size if it is not the body element.</b>
34574
34575 * @constructor
34576 * Create a new Border
34577 * @param {Object} config Configuration options
34578  */
34579 Roo.bootstrap.layout.Border = function(config){
34580     config = config || {};
34581     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34582     
34583     
34584     
34585     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34586         if(config[region]){
34587             config[region].region = region;
34588             this.addRegion(config[region]);
34589         }
34590     },this);
34591     
34592 };
34593
34594 Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
34595
34596 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34597     /**
34598      * Creates and adds a new region if it doesn't already exist.
34599      * @param {String} target The target region key (north, south, east, west or center).
34600      * @param {Object} config The regions config object
34601      * @return {BorderLayoutRegion} The new region
34602      */
34603     addRegion : function(config)
34604     {
34605         if(!this.regions[config.region]){
34606             var r = this.factory(config);
34607             this.bindRegion(r);
34608         }
34609         return this.regions[config.region];
34610     },
34611
34612     // private (kinda)
34613     bindRegion : function(r){
34614         this.regions[r.config.region] = r;
34615         
34616         r.on("visibilitychange",    this.layout, this);
34617         r.on("paneladded",          this.layout, this);
34618         r.on("panelremoved",        this.layout, this);
34619         r.on("invalidated",         this.layout, this);
34620         r.on("resized",             this.onRegionResized, this);
34621         r.on("collapsed",           this.onRegionCollapsed, this);
34622         r.on("expanded",            this.onRegionExpanded, this);
34623     },
34624
34625     /**
34626      * Performs a layout update.
34627      */
34628     layout : function()
34629     {
34630         if(this.updating) {
34631             return;
34632         }
34633         
34634         // render all the rebions if they have not been done alreayd?
34635         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34636             if(this.regions[region] && !this.regions[region].bodyEl){
34637                 this.regions[region].onRender(this.el)
34638             }
34639         },this);
34640         
34641         var size = this.getViewSize();
34642         var w = size.width;
34643         var h = size.height;
34644         var centerW = w;
34645         var centerH = h;
34646         var centerY = 0;
34647         var centerX = 0;
34648         //var x = 0, y = 0;
34649
34650         var rs = this.regions;
34651         var north = rs["north"];
34652         var south = rs["south"]; 
34653         var west = rs["west"];
34654         var east = rs["east"];
34655         var center = rs["center"];
34656         //if(this.hideOnLayout){ // not supported anymore
34657             //c.el.setStyle("display", "none");
34658         //}
34659         if(north && north.isVisible()){
34660             var b = north.getBox();
34661             var m = north.getMargins();
34662             b.width = w - (m.left+m.right);
34663             b.x = m.left;
34664             b.y = m.top;
34665             centerY = b.height + b.y + m.bottom;
34666             centerH -= centerY;
34667             north.updateBox(this.safeBox(b));
34668         }
34669         if(south && south.isVisible()){
34670             var b = south.getBox();
34671             var m = south.getMargins();
34672             b.width = w - (m.left+m.right);
34673             b.x = m.left;
34674             var totalHeight = (b.height + m.top + m.bottom);
34675             b.y = h - totalHeight + m.top;
34676             centerH -= totalHeight;
34677             south.updateBox(this.safeBox(b));
34678         }
34679         if(west && west.isVisible()){
34680             var b = west.getBox();
34681             var m = west.getMargins();
34682             b.height = centerH - (m.top+m.bottom);
34683             b.x = m.left;
34684             b.y = centerY + m.top;
34685             var totalWidth = (b.width + m.left + m.right);
34686             centerX += totalWidth;
34687             centerW -= totalWidth;
34688             west.updateBox(this.safeBox(b));
34689         }
34690         if(east && east.isVisible()){
34691             var b = east.getBox();
34692             var m = east.getMargins();
34693             b.height = centerH - (m.top+m.bottom);
34694             var totalWidth = (b.width + m.left + m.right);
34695             b.x = w - totalWidth + m.left;
34696             b.y = centerY + m.top;
34697             centerW -= totalWidth;
34698             east.updateBox(this.safeBox(b));
34699         }
34700         if(center){
34701             var m = center.getMargins();
34702             var centerBox = {
34703                 x: centerX + m.left,
34704                 y: centerY + m.top,
34705                 width: centerW - (m.left+m.right),
34706                 height: centerH - (m.top+m.bottom)
34707             };
34708             //if(this.hideOnLayout){
34709                 //center.el.setStyle("display", "block");
34710             //}
34711             center.updateBox(this.safeBox(centerBox));
34712         }
34713         this.el.repaint();
34714         this.fireEvent("layout", this);
34715     },
34716
34717     // private
34718     safeBox : function(box){
34719         box.width = Math.max(0, box.width);
34720         box.height = Math.max(0, box.height);
34721         return box;
34722     },
34723
34724     /**
34725      * Adds a ContentPanel (or subclass) to this layout.
34726      * @param {String} target The target region key (north, south, east, west or center).
34727      * @param {Roo.ContentPanel} panel The panel to add
34728      * @return {Roo.ContentPanel} The added panel
34729      */
34730     add : function(target, panel){
34731          
34732         target = target.toLowerCase();
34733         return this.regions[target].add(panel);
34734     },
34735
34736     /**
34737      * Remove a ContentPanel (or subclass) to this layout.
34738      * @param {String} target The target region key (north, south, east, west or center).
34739      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34740      * @return {Roo.ContentPanel} The removed panel
34741      */
34742     remove : function(target, panel){
34743         target = target.toLowerCase();
34744         return this.regions[target].remove(panel);
34745     },
34746
34747     /**
34748      * Searches all regions for a panel with the specified id
34749      * @param {String} panelId
34750      * @return {Roo.ContentPanel} The panel or null if it wasn't found
34751      */
34752     findPanel : function(panelId){
34753         var rs = this.regions;
34754         for(var target in rs){
34755             if(typeof rs[target] != "function"){
34756                 var p = rs[target].getPanel(panelId);
34757                 if(p){
34758                     return p;
34759                 }
34760             }
34761         }
34762         return null;
34763     },
34764
34765     /**
34766      * Searches all regions for a panel with the specified id and activates (shows) it.
34767      * @param {String/ContentPanel} panelId The panels id or the panel itself
34768      * @return {Roo.ContentPanel} The shown panel or null
34769      */
34770     showPanel : function(panelId) {
34771       var rs = this.regions;
34772       for(var target in rs){
34773          var r = rs[target];
34774          if(typeof r != "function"){
34775             if(r.hasPanel(panelId)){
34776                return r.showPanel(panelId);
34777             }
34778          }
34779       }
34780       return null;
34781    },
34782
34783    /**
34784      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34785      * @param {Roo.state.Provider} provider (optional) An alternate state provider
34786      */
34787    /*
34788     restoreState : function(provider){
34789         if(!provider){
34790             provider = Roo.state.Manager;
34791         }
34792         var sm = new Roo.LayoutStateManager();
34793         sm.init(this, provider);
34794     },
34795 */
34796  
34797  
34798     /**
34799      * Adds a xtype elements to the layout.
34800      * <pre><code>
34801
34802 layout.addxtype({
34803        xtype : 'ContentPanel',
34804        region: 'west',
34805        items: [ .... ]
34806    }
34807 );
34808
34809 layout.addxtype({
34810         xtype : 'NestedLayoutPanel',
34811         region: 'west',
34812         layout: {
34813            center: { },
34814            west: { }   
34815         },
34816         items : [ ... list of content panels or nested layout panels.. ]
34817    }
34818 );
34819 </code></pre>
34820      * @param {Object} cfg Xtype definition of item to add.
34821      */
34822     addxtype : function(cfg)
34823     {
34824         // basically accepts a pannel...
34825         // can accept a layout region..!?!?
34826         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34827         
34828         
34829         // theory?  children can only be panels??
34830         
34831         //if (!cfg.xtype.match(/Panel$/)) {
34832         //    return false;
34833         //}
34834         var ret = false;
34835         
34836         if (typeof(cfg.region) == 'undefined') {
34837             Roo.log("Failed to add Panel, region was not set");
34838             Roo.log(cfg);
34839             return false;
34840         }
34841         var region = cfg.region;
34842         delete cfg.region;
34843         
34844           
34845         var xitems = [];
34846         if (cfg.items) {
34847             xitems = cfg.items;
34848             delete cfg.items;
34849         }
34850         var nb = false;
34851         
34852         switch(cfg.xtype) 
34853         {
34854             case 'Content':  // ContentPanel (el, cfg)
34855             case 'Scroll':  // ContentPanel (el, cfg)
34856             case 'View': 
34857                 cfg.autoCreate = true;
34858                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34859                 //} else {
34860                 //    var el = this.el.createChild();
34861                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34862                 //}
34863                 
34864                 this.add(region, ret);
34865                 break;
34866             
34867             /*
34868             case 'TreePanel': // our new panel!
34869                 cfg.el = this.el.createChild();
34870                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34871                 this.add(region, ret);
34872                 break;
34873             */
34874             
34875             case 'Nest': 
34876                 // create a new Layout (which is  a Border Layout...
34877                 
34878                 var clayout = cfg.layout;
34879                 clayout.el  = this.el.createChild();
34880                 clayout.items   = clayout.items  || [];
34881                 
34882                 delete cfg.layout;
34883                 
34884                 // replace this exitems with the clayout ones..
34885                 xitems = clayout.items;
34886                  
34887                 // force background off if it's in center...
34888                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34889                     cfg.background = false;
34890                 }
34891                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
34892                 
34893                 
34894                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34895                 //console.log('adding nested layout panel '  + cfg.toSource());
34896                 this.add(region, ret);
34897                 nb = {}; /// find first...
34898                 break;
34899             
34900             case 'Grid':
34901                 
34902                 // needs grid and region
34903                 
34904                 //var el = this.getRegion(region).el.createChild();
34905                 /*
34906                  *var el = this.el.createChild();
34907                 // create the grid first...
34908                 cfg.grid.container = el;
34909                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34910                 */
34911                 
34912                 if (region == 'center' && this.active ) {
34913                     cfg.background = false;
34914                 }
34915                 
34916                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34917                 
34918                 this.add(region, ret);
34919                 /*
34920                 if (cfg.background) {
34921                     // render grid on panel activation (if panel background)
34922                     ret.on('activate', function(gp) {
34923                         if (!gp.grid.rendered) {
34924                     //        gp.grid.render(el);
34925                         }
34926                     });
34927                 } else {
34928                   //  cfg.grid.render(el);
34929                 }
34930                 */
34931                 break;
34932            
34933            
34934             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34935                 // it was the old xcomponent building that caused this before.
34936                 // espeically if border is the top element in the tree.
34937                 ret = this;
34938                 break; 
34939                 
34940                     
34941                 
34942                 
34943                 
34944             default:
34945                 /*
34946                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34947                     
34948                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34949                     this.add(region, ret);
34950                 } else {
34951                 */
34952                     Roo.log(cfg);
34953                     throw "Can not add '" + cfg.xtype + "' to Border";
34954                     return null;
34955              
34956                                 
34957              
34958         }
34959         this.beginUpdate();
34960         // add children..
34961         var region = '';
34962         var abn = {};
34963         Roo.each(xitems, function(i)  {
34964             region = nb && i.region ? i.region : false;
34965             
34966             var add = ret.addxtype(i);
34967            
34968             if (region) {
34969                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34970                 if (!i.background) {
34971                     abn[region] = nb[region] ;
34972                 }
34973             }
34974             
34975         });
34976         this.endUpdate();
34977
34978         // make the last non-background panel active..
34979         //if (nb) { Roo.log(abn); }
34980         if (nb) {
34981             
34982             for(var r in abn) {
34983                 region = this.getRegion(r);
34984                 if (region) {
34985                     // tried using nb[r], but it does not work..
34986                      
34987                     region.showPanel(abn[r]);
34988                    
34989                 }
34990             }
34991         }
34992         return ret;
34993         
34994     },
34995     
34996     
34997 // private
34998     factory : function(cfg)
34999     {
35000         
35001         var validRegions = Roo.bootstrap.layout.Border.regions;
35002
35003         var target = cfg.region;
35004         cfg.mgr = this;
35005         
35006         var r = Roo.bootstrap.layout;
35007         Roo.log(target);
35008         switch(target){
35009             case "north":
35010                 return new r.North(cfg);
35011             case "south":
35012                 return new r.South(cfg);
35013             case "east":
35014                 return new r.East(cfg);
35015             case "west":
35016                 return new r.West(cfg);
35017             case "center":
35018                 return new r.Center(cfg);
35019         }
35020         throw 'Layout region "'+target+'" not supported.';
35021     }
35022     
35023     
35024 });
35025  /*
35026  * Based on:
35027  * Ext JS Library 1.1.1
35028  * Copyright(c) 2006-2007, Ext JS, LLC.
35029  *
35030  * Originally Released Under LGPL - original licence link has changed is not relivant.
35031  *
35032  * Fork - LGPL
35033  * <script type="text/javascript">
35034  */
35035  
35036 /**
35037  * @class Roo.bootstrap.layout.Basic
35038  * @extends Roo.util.Observable
35039  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35040  * and does not have a titlebar, tabs or any other features. All it does is size and position 
35041  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35042  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35043  * @cfg {string}   region  the region that it inhabits..
35044  * @cfg {bool}   skipConfig skip config?
35045  * 
35046
35047  */
35048 Roo.bootstrap.layout.Basic = function(config){
35049     
35050     this.mgr = config.mgr;
35051     
35052     this.position = config.region;
35053     
35054     var skipConfig = config.skipConfig;
35055     
35056     this.events = {
35057         /**
35058          * @scope Roo.BasicLayoutRegion
35059          */
35060         
35061         /**
35062          * @event beforeremove
35063          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35064          * @param {Roo.LayoutRegion} this
35065          * @param {Roo.ContentPanel} panel The panel
35066          * @param {Object} e The cancel event object
35067          */
35068         "beforeremove" : true,
35069         /**
35070          * @event invalidated
35071          * Fires when the layout for this region is changed.
35072          * @param {Roo.LayoutRegion} this
35073          */
35074         "invalidated" : true,
35075         /**
35076          * @event visibilitychange
35077          * Fires when this region is shown or hidden 
35078          * @param {Roo.LayoutRegion} this
35079          * @param {Boolean} visibility true or false
35080          */
35081         "visibilitychange" : true,
35082         /**
35083          * @event paneladded
35084          * Fires when a panel is added. 
35085          * @param {Roo.LayoutRegion} this
35086          * @param {Roo.ContentPanel} panel The panel
35087          */
35088         "paneladded" : true,
35089         /**
35090          * @event panelremoved
35091          * Fires when a panel is removed. 
35092          * @param {Roo.LayoutRegion} this
35093          * @param {Roo.ContentPanel} panel The panel
35094          */
35095         "panelremoved" : true,
35096         /**
35097          * @event beforecollapse
35098          * Fires when this region before collapse.
35099          * @param {Roo.LayoutRegion} this
35100          */
35101         "beforecollapse" : true,
35102         /**
35103          * @event collapsed
35104          * Fires when this region is collapsed.
35105          * @param {Roo.LayoutRegion} this
35106          */
35107         "collapsed" : true,
35108         /**
35109          * @event expanded
35110          * Fires when this region is expanded.
35111          * @param {Roo.LayoutRegion} this
35112          */
35113         "expanded" : true,
35114         /**
35115          * @event slideshow
35116          * Fires when this region is slid into view.
35117          * @param {Roo.LayoutRegion} this
35118          */
35119         "slideshow" : true,
35120         /**
35121          * @event slidehide
35122          * Fires when this region slides out of view. 
35123          * @param {Roo.LayoutRegion} this
35124          */
35125         "slidehide" : true,
35126         /**
35127          * @event panelactivated
35128          * Fires when a panel is activated. 
35129          * @param {Roo.LayoutRegion} this
35130          * @param {Roo.ContentPanel} panel The activated panel
35131          */
35132         "panelactivated" : true,
35133         /**
35134          * @event resized
35135          * Fires when the user resizes this region. 
35136          * @param {Roo.LayoutRegion} this
35137          * @param {Number} newSize The new size (width for east/west, height for north/south)
35138          */
35139         "resized" : true
35140     };
35141     /** A collection of panels in this region. @type Roo.util.MixedCollection */
35142     this.panels = new Roo.util.MixedCollection();
35143     this.panels.getKey = this.getPanelId.createDelegate(this);
35144     this.box = null;
35145     this.activePanel = null;
35146     // ensure listeners are added...
35147     
35148     if (config.listeners || config.events) {
35149         Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35150             listeners : config.listeners || {},
35151             events : config.events || {}
35152         });
35153     }
35154     
35155     if(skipConfig !== true){
35156         this.applyConfig(config);
35157     }
35158 };
35159
35160 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35161 {
35162     getPanelId : function(p){
35163         return p.getId();
35164     },
35165     
35166     applyConfig : function(config){
35167         this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35168         this.config = config;
35169         
35170     },
35171     
35172     /**
35173      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
35174      * the width, for horizontal (north, south) the height.
35175      * @param {Number} newSize The new width or height
35176      */
35177     resizeTo : function(newSize){
35178         var el = this.el ? this.el :
35179                  (this.activePanel ? this.activePanel.getEl() : null);
35180         if(el){
35181             switch(this.position){
35182                 case "east":
35183                 case "west":
35184                     el.setWidth(newSize);
35185                     this.fireEvent("resized", this, newSize);
35186                 break;
35187                 case "north":
35188                 case "south":
35189                     el.setHeight(newSize);
35190                     this.fireEvent("resized", this, newSize);
35191                 break;                
35192             }
35193         }
35194     },
35195     
35196     getBox : function(){
35197         return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35198     },
35199     
35200     getMargins : function(){
35201         return this.margins;
35202     },
35203     
35204     updateBox : function(box){
35205         this.box = box;
35206         var el = this.activePanel.getEl();
35207         el.dom.style.left = box.x + "px";
35208         el.dom.style.top = box.y + "px";
35209         this.activePanel.setSize(box.width, box.height);
35210     },
35211     
35212     /**
35213      * Returns the container element for this region.
35214      * @return {Roo.Element}
35215      */
35216     getEl : function(){
35217         return this.activePanel;
35218     },
35219     
35220     /**
35221      * Returns true if this region is currently visible.
35222      * @return {Boolean}
35223      */
35224     isVisible : function(){
35225         return this.activePanel ? true : false;
35226     },
35227     
35228     setActivePanel : function(panel){
35229         panel = this.getPanel(panel);
35230         if(this.activePanel && this.activePanel != panel){
35231             this.activePanel.setActiveState(false);
35232             this.activePanel.getEl().setLeftTop(-10000,-10000);
35233         }
35234         this.activePanel = panel;
35235         panel.setActiveState(true);
35236         if(this.box){
35237             panel.setSize(this.box.width, this.box.height);
35238         }
35239         this.fireEvent("panelactivated", this, panel);
35240         this.fireEvent("invalidated");
35241     },
35242     
35243     /**
35244      * Show the specified panel.
35245      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35246      * @return {Roo.ContentPanel} The shown panel or null
35247      */
35248     showPanel : function(panel){
35249         panel = this.getPanel(panel);
35250         if(panel){
35251             this.setActivePanel(panel);
35252         }
35253         return panel;
35254     },
35255     
35256     /**
35257      * Get the active panel for this region.
35258      * @return {Roo.ContentPanel} The active panel or null
35259      */
35260     getActivePanel : function(){
35261         return this.activePanel;
35262     },
35263     
35264     /**
35265      * Add the passed ContentPanel(s)
35266      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35267      * @return {Roo.ContentPanel} The panel added (if only one was added)
35268      */
35269     add : function(panel){
35270         if(arguments.length > 1){
35271             for(var i = 0, len = arguments.length; i < len; i++) {
35272                 this.add(arguments[i]);
35273             }
35274             return null;
35275         }
35276         if(this.hasPanel(panel)){
35277             this.showPanel(panel);
35278             return panel;
35279         }
35280         var el = panel.getEl();
35281         if(el.dom.parentNode != this.mgr.el.dom){
35282             this.mgr.el.dom.appendChild(el.dom);
35283         }
35284         if(panel.setRegion){
35285             panel.setRegion(this);
35286         }
35287         this.panels.add(panel);
35288         el.setStyle("position", "absolute");
35289         if(!panel.background){
35290             this.setActivePanel(panel);
35291             if(this.config.initialSize && this.panels.getCount()==1){
35292                 this.resizeTo(this.config.initialSize);
35293             }
35294         }
35295         this.fireEvent("paneladded", this, panel);
35296         return panel;
35297     },
35298     
35299     /**
35300      * Returns true if the panel is in this region.
35301      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35302      * @return {Boolean}
35303      */
35304     hasPanel : function(panel){
35305         if(typeof panel == "object"){ // must be panel obj
35306             panel = panel.getId();
35307         }
35308         return this.getPanel(panel) ? true : false;
35309     },
35310     
35311     /**
35312      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35313      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35314      * @param {Boolean} preservePanel Overrides the config preservePanel option
35315      * @return {Roo.ContentPanel} The panel that was removed
35316      */
35317     remove : function(panel, preservePanel){
35318         panel = this.getPanel(panel);
35319         if(!panel){
35320             return null;
35321         }
35322         var e = {};
35323         this.fireEvent("beforeremove", this, panel, e);
35324         if(e.cancel === true){
35325             return null;
35326         }
35327         var panelId = panel.getId();
35328         this.panels.removeKey(panelId);
35329         return panel;
35330     },
35331     
35332     /**
35333      * Returns the panel specified or null if it's not in this region.
35334      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35335      * @return {Roo.ContentPanel}
35336      */
35337     getPanel : function(id){
35338         if(typeof id == "object"){ // must be panel obj
35339             return id;
35340         }
35341         return this.panels.get(id);
35342     },
35343     
35344     /**
35345      * Returns this regions position (north/south/east/west/center).
35346      * @return {String} 
35347      */
35348     getPosition: function(){
35349         return this.position;    
35350     }
35351 });/*
35352  * Based on:
35353  * Ext JS Library 1.1.1
35354  * Copyright(c) 2006-2007, Ext JS, LLC.
35355  *
35356  * Originally Released Under LGPL - original licence link has changed is not relivant.
35357  *
35358  * Fork - LGPL
35359  * <script type="text/javascript">
35360  */
35361  
35362 /**
35363  * @class Roo.bootstrap.layout.Region
35364  * @extends Roo.bootstrap.layout.Basic
35365  * This class represents a region in a layout manager.
35366  
35367  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35368  * @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})
35369  * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
35370  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
35371  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
35372  * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
35373  * @cfg {String}    title           The title for the region (overrides panel titles)
35374  * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
35375  * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35376  * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
35377  * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35378  * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
35379  * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35380  *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
35381  * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
35382  * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
35383  * @cfg {String}    overflow       (hidden|visible) if you have menus in the region, then you need to set this to visible.
35384
35385  * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
35386  * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
35387  * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
35388  * @cfg {Number}    width           For East/West panels
35389  * @cfg {Number}    height          For North/South panels
35390  * @cfg {Boolean}   split           To show the splitter
35391  * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
35392  * 
35393  * @cfg {string}   cls             Extra CSS classes to add to region
35394  * 
35395  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35396  * @cfg {string}   region  the region that it inhabits..
35397  *
35398
35399  * @xxxcfg {Boolean}   collapsible     DISABLED False to disable collapsing (defaults to true)
35400  * @xxxcfg {Boolean}   collapsed       DISABLED True to set the initial display to collapsed (defaults to false)
35401
35402  * @xxxcfg {String}    collapsedTitle  DISABLED Optional string message to display in the collapsed block of a north or south region
35403  * @xxxxcfg {Boolean}   floatable       DISABLED False to disable floating (defaults to true)
35404  * @xxxxcfg {Boolean}   showPin         True to show a pin button NOT SUPPORTED YET
35405  */
35406 Roo.bootstrap.layout.Region = function(config)
35407 {
35408     this.applyConfig(config);
35409
35410     var mgr = config.mgr;
35411     var pos = config.region;
35412     config.skipConfig = true;
35413     Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35414     
35415     if (mgr.el) {
35416         this.onRender(mgr.el);   
35417     }
35418      
35419     this.visible = true;
35420     this.collapsed = false;
35421     this.unrendered_panels = [];
35422 };
35423
35424 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35425
35426     position: '', // set by wrapper (eg. north/south etc..)
35427     unrendered_panels : null,  // unrendered panels.
35428     createBody : function(){
35429         /** This region's body element 
35430         * @type Roo.Element */
35431         this.bodyEl = this.el.createChild({
35432                 tag: "div",
35433                 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35434         });
35435     },
35436
35437     onRender: function(ctr, pos)
35438     {
35439         var dh = Roo.DomHelper;
35440         /** This region's container element 
35441         * @type Roo.Element */
35442         this.el = dh.append(ctr.dom, {
35443                 tag: "div",
35444                 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35445             }, true);
35446         /** This region's title element 
35447         * @type Roo.Element */
35448     
35449         this.titleEl = dh.append(this.el.dom,
35450             {
35451                     tag: "div",
35452                     unselectable: "on",
35453                     cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35454                     children:[
35455                         {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
35456                         {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35457                     ]}, true);
35458         
35459         this.titleEl.enableDisplayMode();
35460         /** This region's title text element 
35461         * @type HTMLElement */
35462         this.titleTextEl = this.titleEl.dom.firstChild;
35463         this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35464         /*
35465         this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35466         this.closeBtn.enableDisplayMode();
35467         this.closeBtn.on("click", this.closeClicked, this);
35468         this.closeBtn.hide();
35469     */
35470         this.createBody(this.config);
35471         if(this.config.hideWhenEmpty){
35472             this.hide();
35473             this.on("paneladded", this.validateVisibility, this);
35474             this.on("panelremoved", this.validateVisibility, this);
35475         }
35476         if(this.autoScroll){
35477             this.bodyEl.setStyle("overflow", "auto");
35478         }else{
35479             this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35480         }
35481         //if(c.titlebar !== false){
35482             if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35483                 this.titleEl.hide();
35484             }else{
35485                 this.titleEl.show();
35486                 if(this.config.title){
35487                     this.titleTextEl.innerHTML = this.config.title;
35488                 }
35489             }
35490         //}
35491         if(this.config.collapsed){
35492             this.collapse(true);
35493         }
35494         if(this.config.hidden){
35495             this.hide();
35496         }
35497         
35498         if (this.unrendered_panels && this.unrendered_panels.length) {
35499             for (var i =0;i< this.unrendered_panels.length; i++) {
35500                 this.add(this.unrendered_panels[i]);
35501             }
35502             this.unrendered_panels = null;
35503             
35504         }
35505         
35506     },
35507     
35508     applyConfig : function(c)
35509     {
35510         /*
35511          *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35512             var dh = Roo.DomHelper;
35513             if(c.titlebar !== false){
35514                 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35515                 this.collapseBtn.on("click", this.collapse, this);
35516                 this.collapseBtn.enableDisplayMode();
35517                 /*
35518                 if(c.showPin === true || this.showPin){
35519                     this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35520                     this.stickBtn.enableDisplayMode();
35521                     this.stickBtn.on("click", this.expand, this);
35522                     this.stickBtn.hide();
35523                 }
35524                 
35525             }
35526             */
35527             /** This region's collapsed element
35528             * @type Roo.Element */
35529             /*
35530              *
35531             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35532                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35533             ]}, true);
35534             
35535             if(c.floatable !== false){
35536                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35537                this.collapsedEl.on("click", this.collapseClick, this);
35538             }
35539
35540             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35541                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35542                    id: "message", unselectable: "on", style:{"float":"left"}});
35543                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35544              }
35545             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35546             this.expandBtn.on("click", this.expand, this);
35547             
35548         }
35549         
35550         if(this.collapseBtn){
35551             this.collapseBtn.setVisible(c.collapsible == true);
35552         }
35553         
35554         this.cmargins = c.cmargins || this.cmargins ||
35555                          (this.position == "west" || this.position == "east" ?
35556                              {top: 0, left: 2, right:2, bottom: 0} :
35557                              {top: 2, left: 0, right:0, bottom: 2});
35558         */
35559         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35560         
35561         
35562         this.bottomTabs = c.tabPosition != "top";
35563         
35564         this.autoScroll = c.autoScroll || false;
35565         
35566         
35567        
35568         
35569         this.duration = c.duration || .30;
35570         this.slideDuration = c.slideDuration || .45;
35571         this.config = c;
35572        
35573     },
35574     /**
35575      * Returns true if this region is currently visible.
35576      * @return {Boolean}
35577      */
35578     isVisible : function(){
35579         return this.visible;
35580     },
35581
35582     /**
35583      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35584      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
35585      */
35586     //setCollapsedTitle : function(title){
35587     //    title = title || "&#160;";
35588      //   if(this.collapsedTitleTextEl){
35589       //      this.collapsedTitleTextEl.innerHTML = title;
35590        // }
35591     //},
35592
35593     getBox : function(){
35594         var b;
35595       //  if(!this.collapsed){
35596             b = this.el.getBox(false, true);
35597        // }else{
35598           //  b = this.collapsedEl.getBox(false, true);
35599         //}
35600         return b;
35601     },
35602
35603     getMargins : function(){
35604         return this.margins;
35605         //return this.collapsed ? this.cmargins : this.margins;
35606     },
35607 /*
35608     highlight : function(){
35609         this.el.addClass("x-layout-panel-dragover");
35610     },
35611
35612     unhighlight : function(){
35613         this.el.removeClass("x-layout-panel-dragover");
35614     },
35615 */
35616     updateBox : function(box)
35617     {
35618         if (!this.bodyEl) {
35619             return; // not rendered yet..
35620         }
35621         
35622         this.box = box;
35623         if(!this.collapsed){
35624             this.el.dom.style.left = box.x + "px";
35625             this.el.dom.style.top = box.y + "px";
35626             this.updateBody(box.width, box.height);
35627         }else{
35628             this.collapsedEl.dom.style.left = box.x + "px";
35629             this.collapsedEl.dom.style.top = box.y + "px";
35630             this.collapsedEl.setSize(box.width, box.height);
35631         }
35632         if(this.tabs){
35633             this.tabs.autoSizeTabs();
35634         }
35635     },
35636
35637     updateBody : function(w, h)
35638     {
35639         if(w !== null){
35640             this.el.setWidth(w);
35641             w -= this.el.getBorderWidth("rl");
35642             if(this.config.adjustments){
35643                 w += this.config.adjustments[0];
35644             }
35645         }
35646         if(h !== null && h > 0){
35647             this.el.setHeight(h);
35648             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35649             h -= this.el.getBorderWidth("tb");
35650             if(this.config.adjustments){
35651                 h += this.config.adjustments[1];
35652             }
35653             this.bodyEl.setHeight(h);
35654             if(this.tabs){
35655                 h = this.tabs.syncHeight(h);
35656             }
35657         }
35658         if(this.panelSize){
35659             w = w !== null ? w : this.panelSize.width;
35660             h = h !== null ? h : this.panelSize.height;
35661         }
35662         if(this.activePanel){
35663             var el = this.activePanel.getEl();
35664             w = w !== null ? w : el.getWidth();
35665             h = h !== null ? h : el.getHeight();
35666             this.panelSize = {width: w, height: h};
35667             this.activePanel.setSize(w, h);
35668         }
35669         if(Roo.isIE && this.tabs){
35670             this.tabs.el.repaint();
35671         }
35672     },
35673
35674     /**
35675      * Returns the container element for this region.
35676      * @return {Roo.Element}
35677      */
35678     getEl : function(){
35679         return this.el;
35680     },
35681
35682     /**
35683      * Hides this region.
35684      */
35685     hide : function(){
35686         //if(!this.collapsed){
35687             this.el.dom.style.left = "-2000px";
35688             this.el.hide();
35689         //}else{
35690          //   this.collapsedEl.dom.style.left = "-2000px";
35691          //   this.collapsedEl.hide();
35692        // }
35693         this.visible = false;
35694         this.fireEvent("visibilitychange", this, false);
35695     },
35696
35697     /**
35698      * Shows this region if it was previously hidden.
35699      */
35700     show : function(){
35701         //if(!this.collapsed){
35702             this.el.show();
35703         //}else{
35704         //    this.collapsedEl.show();
35705        // }
35706         this.visible = true;
35707         this.fireEvent("visibilitychange", this, true);
35708     },
35709 /*
35710     closeClicked : function(){
35711         if(this.activePanel){
35712             this.remove(this.activePanel);
35713         }
35714     },
35715
35716     collapseClick : function(e){
35717         if(this.isSlid){
35718            e.stopPropagation();
35719            this.slideIn();
35720         }else{
35721            e.stopPropagation();
35722            this.slideOut();
35723         }
35724     },
35725 */
35726     /**
35727      * Collapses this region.
35728      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35729      */
35730     /*
35731     collapse : function(skipAnim, skipCheck = false){
35732         if(this.collapsed) {
35733             return;
35734         }
35735         
35736         if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35737             
35738             this.collapsed = true;
35739             if(this.split){
35740                 this.split.el.hide();
35741             }
35742             if(this.config.animate && skipAnim !== true){
35743                 this.fireEvent("invalidated", this);
35744                 this.animateCollapse();
35745             }else{
35746                 this.el.setLocation(-20000,-20000);
35747                 this.el.hide();
35748                 this.collapsedEl.show();
35749                 this.fireEvent("collapsed", this);
35750                 this.fireEvent("invalidated", this);
35751             }
35752         }
35753         
35754     },
35755 */
35756     animateCollapse : function(){
35757         // overridden
35758     },
35759
35760     /**
35761      * Expands this region if it was previously collapsed.
35762      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35763      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35764      */
35765     /*
35766     expand : function(e, skipAnim){
35767         if(e) {
35768             e.stopPropagation();
35769         }
35770         if(!this.collapsed || this.el.hasActiveFx()) {
35771             return;
35772         }
35773         if(this.isSlid){
35774             this.afterSlideIn();
35775             skipAnim = true;
35776         }
35777         this.collapsed = false;
35778         if(this.config.animate && skipAnim !== true){
35779             this.animateExpand();
35780         }else{
35781             this.el.show();
35782             if(this.split){
35783                 this.split.el.show();
35784             }
35785             this.collapsedEl.setLocation(-2000,-2000);
35786             this.collapsedEl.hide();
35787             this.fireEvent("invalidated", this);
35788             this.fireEvent("expanded", this);
35789         }
35790     },
35791 */
35792     animateExpand : function(){
35793         // overridden
35794     },
35795
35796     initTabs : function()
35797     {
35798         //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35799         
35800         var ts = new Roo.bootstrap.panel.Tabs({
35801                 el: this.bodyEl.dom,
35802                 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35803                 disableTooltips: this.config.disableTabTips,
35804                 toolbar : this.config.toolbar
35805             });
35806         
35807         if(this.config.hideTabs){
35808             ts.stripWrap.setDisplayed(false);
35809         }
35810         this.tabs = ts;
35811         ts.resizeTabs = this.config.resizeTabs === true;
35812         ts.minTabWidth = this.config.minTabWidth || 40;
35813         ts.maxTabWidth = this.config.maxTabWidth || 250;
35814         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35815         ts.monitorResize = false;
35816         //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35817         ts.bodyEl.addClass('roo-layout-tabs-body');
35818         this.panels.each(this.initPanelAsTab, this);
35819     },
35820
35821     initPanelAsTab : function(panel){
35822         var ti = this.tabs.addTab(
35823             panel.getEl().id,
35824             panel.getTitle(),
35825             null,
35826             this.config.closeOnTab && panel.isClosable(),
35827             panel.tpl
35828         );
35829         if(panel.tabTip !== undefined){
35830             ti.setTooltip(panel.tabTip);
35831         }
35832         ti.on("activate", function(){
35833               this.setActivePanel(panel);
35834         }, this);
35835         
35836         if(this.config.closeOnTab){
35837             ti.on("beforeclose", function(t, e){
35838                 e.cancel = true;
35839                 this.remove(panel);
35840             }, this);
35841         }
35842         
35843         panel.tabItem = ti;
35844         
35845         return ti;
35846     },
35847
35848     updatePanelTitle : function(panel, title)
35849     {
35850         if(this.activePanel == panel){
35851             this.updateTitle(title);
35852         }
35853         if(this.tabs){
35854             var ti = this.tabs.getTab(panel.getEl().id);
35855             ti.setText(title);
35856             if(panel.tabTip !== undefined){
35857                 ti.setTooltip(panel.tabTip);
35858             }
35859         }
35860     },
35861
35862     updateTitle : function(title){
35863         if(this.titleTextEl && !this.config.title){
35864             this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
35865         }
35866     },
35867
35868     setActivePanel : function(panel)
35869     {
35870         panel = this.getPanel(panel);
35871         if(this.activePanel && this.activePanel != panel){
35872             if(this.activePanel.setActiveState(false) === false){
35873                 return;
35874             }
35875         }
35876         this.activePanel = panel;
35877         panel.setActiveState(true);
35878         if(this.panelSize){
35879             panel.setSize(this.panelSize.width, this.panelSize.height);
35880         }
35881         if(this.closeBtn){
35882             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35883         }
35884         this.updateTitle(panel.getTitle());
35885         if(this.tabs){
35886             this.fireEvent("invalidated", this);
35887         }
35888         this.fireEvent("panelactivated", this, panel);
35889     },
35890
35891     /**
35892      * Shows the specified panel.
35893      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35894      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35895      */
35896     showPanel : function(panel)
35897     {
35898         panel = this.getPanel(panel);
35899         if(panel){
35900             if(this.tabs){
35901                 var tab = this.tabs.getTab(panel.getEl().id);
35902                 if(tab.isHidden()){
35903                     this.tabs.unhideTab(tab.id);
35904                 }
35905                 tab.activate();
35906             }else{
35907                 this.setActivePanel(panel);
35908             }
35909         }
35910         return panel;
35911     },
35912
35913     /**
35914      * Get the active panel for this region.
35915      * @return {Roo.ContentPanel} The active panel or null
35916      */
35917     getActivePanel : function(){
35918         return this.activePanel;
35919     },
35920
35921     validateVisibility : function(){
35922         if(this.panels.getCount() < 1){
35923             this.updateTitle("&#160;");
35924             this.closeBtn.hide();
35925             this.hide();
35926         }else{
35927             if(!this.isVisible()){
35928                 this.show();
35929             }
35930         }
35931     },
35932
35933     /**
35934      * Adds the passed ContentPanel(s) to this region.
35935      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35936      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35937      */
35938     add : function(panel)
35939     {
35940         if(arguments.length > 1){
35941             for(var i = 0, len = arguments.length; i < len; i++) {
35942                 this.add(arguments[i]);
35943             }
35944             return null;
35945         }
35946         
35947         // if we have not been rendered yet, then we can not really do much of this..
35948         if (!this.bodyEl) {
35949             this.unrendered_panels.push(panel);
35950             return panel;
35951         }
35952         
35953         
35954         
35955         
35956         if(this.hasPanel(panel)){
35957             this.showPanel(panel);
35958             return panel;
35959         }
35960         panel.setRegion(this);
35961         this.panels.add(panel);
35962        /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35963             // sinle panel - no tab...?? would it not be better to render it with the tabs,
35964             // and hide them... ???
35965             this.bodyEl.dom.appendChild(panel.getEl().dom);
35966             if(panel.background !== true){
35967                 this.setActivePanel(panel);
35968             }
35969             this.fireEvent("paneladded", this, panel);
35970             return panel;
35971         }
35972         */
35973         if(!this.tabs){
35974             this.initTabs();
35975         }else{
35976             this.initPanelAsTab(panel);
35977         }
35978         
35979         
35980         if(panel.background !== true){
35981             this.tabs.activate(panel.getEl().id);
35982         }
35983         this.fireEvent("paneladded", this, panel);
35984         return panel;
35985     },
35986
35987     /**
35988      * Hides the tab for the specified panel.
35989      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35990      */
35991     hidePanel : function(panel){
35992         if(this.tabs && (panel = this.getPanel(panel))){
35993             this.tabs.hideTab(panel.getEl().id);
35994         }
35995     },
35996
35997     /**
35998      * Unhides the tab for a previously hidden panel.
35999      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36000      */
36001     unhidePanel : function(panel){
36002         if(this.tabs && (panel = this.getPanel(panel))){
36003             this.tabs.unhideTab(panel.getEl().id);
36004         }
36005     },
36006
36007     clearPanels : function(){
36008         while(this.panels.getCount() > 0){
36009              this.remove(this.panels.first());
36010         }
36011     },
36012
36013     /**
36014      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36015      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36016      * @param {Boolean} preservePanel Overrides the config preservePanel option
36017      * @return {Roo.ContentPanel} The panel that was removed
36018      */
36019     remove : function(panel, preservePanel)
36020     {
36021         panel = this.getPanel(panel);
36022         if(!panel){
36023             return null;
36024         }
36025         var e = {};
36026         this.fireEvent("beforeremove", this, panel, e);
36027         if(e.cancel === true){
36028             return null;
36029         }
36030         preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36031         var panelId = panel.getId();
36032         this.panels.removeKey(panelId);
36033         if(preservePanel){
36034             document.body.appendChild(panel.getEl().dom);
36035         }
36036         if(this.tabs){
36037             this.tabs.removeTab(panel.getEl().id);
36038         }else if (!preservePanel){
36039             this.bodyEl.dom.removeChild(panel.getEl().dom);
36040         }
36041         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36042             var p = this.panels.first();
36043             var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36044             tempEl.appendChild(p.getEl().dom);
36045             this.bodyEl.update("");
36046             this.bodyEl.dom.appendChild(p.getEl().dom);
36047             tempEl = null;
36048             this.updateTitle(p.getTitle());
36049             this.tabs = null;
36050             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36051             this.setActivePanel(p);
36052         }
36053         panel.setRegion(null);
36054         if(this.activePanel == panel){
36055             this.activePanel = null;
36056         }
36057         if(this.config.autoDestroy !== false && preservePanel !== true){
36058             try{panel.destroy();}catch(e){}
36059         }
36060         this.fireEvent("panelremoved", this, panel);
36061         return panel;
36062     },
36063
36064     /**
36065      * Returns the TabPanel component used by this region
36066      * @return {Roo.TabPanel}
36067      */
36068     getTabs : function(){
36069         return this.tabs;
36070     },
36071
36072     createTool : function(parentEl, className){
36073         var btn = Roo.DomHelper.append(parentEl, {
36074             tag: "div",
36075             cls: "x-layout-tools-button",
36076             children: [ {
36077                 tag: "div",
36078                 cls: "roo-layout-tools-button-inner " + className,
36079                 html: "&#160;"
36080             }]
36081         }, true);
36082         btn.addClassOnOver("roo-layout-tools-button-over");
36083         return btn;
36084     }
36085 });/*
36086  * Based on:
36087  * Ext JS Library 1.1.1
36088  * Copyright(c) 2006-2007, Ext JS, LLC.
36089  *
36090  * Originally Released Under LGPL - original licence link has changed is not relivant.
36091  *
36092  * Fork - LGPL
36093  * <script type="text/javascript">
36094  */
36095  
36096
36097
36098 /**
36099  * @class Roo.SplitLayoutRegion
36100  * @extends Roo.LayoutRegion
36101  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36102  */
36103 Roo.bootstrap.layout.Split = function(config){
36104     this.cursor = config.cursor;
36105     Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36106 };
36107
36108 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36109 {
36110     splitTip : "Drag to resize.",
36111     collapsibleSplitTip : "Drag to resize. Double click to hide.",
36112     useSplitTips : false,
36113
36114     applyConfig : function(config){
36115         Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36116     },
36117     
36118     onRender : function(ctr,pos) {
36119         
36120         Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36121         if(!this.config.split){
36122             return;
36123         }
36124         if(!this.split){
36125             
36126             var splitEl = Roo.DomHelper.append(ctr.dom,  {
36127                             tag: "div",
36128                             id: this.el.id + "-split",
36129                             cls: "roo-layout-split roo-layout-split-"+this.position,
36130                             html: "&#160;"
36131             });
36132             /** The SplitBar for this region 
36133             * @type Roo.SplitBar */
36134             // does not exist yet...
36135             Roo.log([this.position, this.orientation]);
36136             
36137             this.split = new Roo.bootstrap.SplitBar({
36138                 dragElement : splitEl,
36139                 resizingElement: this.el,
36140                 orientation : this.orientation
36141             });
36142             
36143             this.split.on("moved", this.onSplitMove, this);
36144             this.split.useShim = this.config.useShim === true;
36145             this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36146             if(this.useSplitTips){
36147                 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36148             }
36149             //if(config.collapsible){
36150             //    this.split.el.on("dblclick", this.collapse,  this);
36151             //}
36152         }
36153         if(typeof this.config.minSize != "undefined"){
36154             this.split.minSize = this.config.minSize;
36155         }
36156         if(typeof this.config.maxSize != "undefined"){
36157             this.split.maxSize = this.config.maxSize;
36158         }
36159         if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36160             this.hideSplitter();
36161         }
36162         
36163     },
36164
36165     getHMaxSize : function(){
36166          var cmax = this.config.maxSize || 10000;
36167          var center = this.mgr.getRegion("center");
36168          return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36169     },
36170
36171     getVMaxSize : function(){
36172          var cmax = this.config.maxSize || 10000;
36173          var center = this.mgr.getRegion("center");
36174          return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36175     },
36176
36177     onSplitMove : function(split, newSize){
36178         this.fireEvent("resized", this, newSize);
36179     },
36180     
36181     /** 
36182      * Returns the {@link Roo.SplitBar} for this region.
36183      * @return {Roo.SplitBar}
36184      */
36185     getSplitBar : function(){
36186         return this.split;
36187     },
36188     
36189     hide : function(){
36190         this.hideSplitter();
36191         Roo.bootstrap.layout.Split.superclass.hide.call(this);
36192     },
36193
36194     hideSplitter : function(){
36195         if(this.split){
36196             this.split.el.setLocation(-2000,-2000);
36197             this.split.el.hide();
36198         }
36199     },
36200
36201     show : function(){
36202         if(this.split){
36203             this.split.el.show();
36204         }
36205         Roo.bootstrap.layout.Split.superclass.show.call(this);
36206     },
36207     
36208     beforeSlide: function(){
36209         if(Roo.isGecko){// firefox overflow auto bug workaround
36210             this.bodyEl.clip();
36211             if(this.tabs) {
36212                 this.tabs.bodyEl.clip();
36213             }
36214             if(this.activePanel){
36215                 this.activePanel.getEl().clip();
36216                 
36217                 if(this.activePanel.beforeSlide){
36218                     this.activePanel.beforeSlide();
36219                 }
36220             }
36221         }
36222     },
36223     
36224     afterSlide : function(){
36225         if(Roo.isGecko){// firefox overflow auto bug workaround
36226             this.bodyEl.unclip();
36227             if(this.tabs) {
36228                 this.tabs.bodyEl.unclip();
36229             }
36230             if(this.activePanel){
36231                 this.activePanel.getEl().unclip();
36232                 if(this.activePanel.afterSlide){
36233                     this.activePanel.afterSlide();
36234                 }
36235             }
36236         }
36237     },
36238
36239     initAutoHide : function(){
36240         if(this.autoHide !== false){
36241             if(!this.autoHideHd){
36242                 var st = new Roo.util.DelayedTask(this.slideIn, this);
36243                 this.autoHideHd = {
36244                     "mouseout": function(e){
36245                         if(!e.within(this.el, true)){
36246                             st.delay(500);
36247                         }
36248                     },
36249                     "mouseover" : function(e){
36250                         st.cancel();
36251                     },
36252                     scope : this
36253                 };
36254             }
36255             this.el.on(this.autoHideHd);
36256         }
36257     },
36258
36259     clearAutoHide : function(){
36260         if(this.autoHide !== false){
36261             this.el.un("mouseout", this.autoHideHd.mouseout);
36262             this.el.un("mouseover", this.autoHideHd.mouseover);
36263         }
36264     },
36265
36266     clearMonitor : function(){
36267         Roo.get(document).un("click", this.slideInIf, this);
36268     },
36269
36270     // these names are backwards but not changed for compat
36271     slideOut : function(){
36272         if(this.isSlid || this.el.hasActiveFx()){
36273             return;
36274         }
36275         this.isSlid = true;
36276         if(this.collapseBtn){
36277             this.collapseBtn.hide();
36278         }
36279         this.closeBtnState = this.closeBtn.getStyle('display');
36280         this.closeBtn.hide();
36281         if(this.stickBtn){
36282             this.stickBtn.show();
36283         }
36284         this.el.show();
36285         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36286         this.beforeSlide();
36287         this.el.setStyle("z-index", 10001);
36288         this.el.slideIn(this.getSlideAnchor(), {
36289             callback: function(){
36290                 this.afterSlide();
36291                 this.initAutoHide();
36292                 Roo.get(document).on("click", this.slideInIf, this);
36293                 this.fireEvent("slideshow", this);
36294             },
36295             scope: this,
36296             block: true
36297         });
36298     },
36299
36300     afterSlideIn : function(){
36301         this.clearAutoHide();
36302         this.isSlid = false;
36303         this.clearMonitor();
36304         this.el.setStyle("z-index", "");
36305         if(this.collapseBtn){
36306             this.collapseBtn.show();
36307         }
36308         this.closeBtn.setStyle('display', this.closeBtnState);
36309         if(this.stickBtn){
36310             this.stickBtn.hide();
36311         }
36312         this.fireEvent("slidehide", this);
36313     },
36314
36315     slideIn : function(cb){
36316         if(!this.isSlid || this.el.hasActiveFx()){
36317             Roo.callback(cb);
36318             return;
36319         }
36320         this.isSlid = false;
36321         this.beforeSlide();
36322         this.el.slideOut(this.getSlideAnchor(), {
36323             callback: function(){
36324                 this.el.setLeftTop(-10000, -10000);
36325                 this.afterSlide();
36326                 this.afterSlideIn();
36327                 Roo.callback(cb);
36328             },
36329             scope: this,
36330             block: true
36331         });
36332     },
36333     
36334     slideInIf : function(e){
36335         if(!e.within(this.el)){
36336             this.slideIn();
36337         }
36338     },
36339
36340     animateCollapse : function(){
36341         this.beforeSlide();
36342         this.el.setStyle("z-index", 20000);
36343         var anchor = this.getSlideAnchor();
36344         this.el.slideOut(anchor, {
36345             callback : function(){
36346                 this.el.setStyle("z-index", "");
36347                 this.collapsedEl.slideIn(anchor, {duration:.3});
36348                 this.afterSlide();
36349                 this.el.setLocation(-10000,-10000);
36350                 this.el.hide();
36351                 this.fireEvent("collapsed", this);
36352             },
36353             scope: this,
36354             block: true
36355         });
36356     },
36357
36358     animateExpand : function(){
36359         this.beforeSlide();
36360         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36361         this.el.setStyle("z-index", 20000);
36362         this.collapsedEl.hide({
36363             duration:.1
36364         });
36365         this.el.slideIn(this.getSlideAnchor(), {
36366             callback : function(){
36367                 this.el.setStyle("z-index", "");
36368                 this.afterSlide();
36369                 if(this.split){
36370                     this.split.el.show();
36371                 }
36372                 this.fireEvent("invalidated", this);
36373                 this.fireEvent("expanded", this);
36374             },
36375             scope: this,
36376             block: true
36377         });
36378     },
36379
36380     anchors : {
36381         "west" : "left",
36382         "east" : "right",
36383         "north" : "top",
36384         "south" : "bottom"
36385     },
36386
36387     sanchors : {
36388         "west" : "l",
36389         "east" : "r",
36390         "north" : "t",
36391         "south" : "b"
36392     },
36393
36394     canchors : {
36395         "west" : "tl-tr",
36396         "east" : "tr-tl",
36397         "north" : "tl-bl",
36398         "south" : "bl-tl"
36399     },
36400
36401     getAnchor : function(){
36402         return this.anchors[this.position];
36403     },
36404
36405     getCollapseAnchor : function(){
36406         return this.canchors[this.position];
36407     },
36408
36409     getSlideAnchor : function(){
36410         return this.sanchors[this.position];
36411     },
36412
36413     getAlignAdj : function(){
36414         var cm = this.cmargins;
36415         switch(this.position){
36416             case "west":
36417                 return [0, 0];
36418             break;
36419             case "east":
36420                 return [0, 0];
36421             break;
36422             case "north":
36423                 return [0, 0];
36424             break;
36425             case "south":
36426                 return [0, 0];
36427             break;
36428         }
36429     },
36430
36431     getExpandAdj : function(){
36432         var c = this.collapsedEl, cm = this.cmargins;
36433         switch(this.position){
36434             case "west":
36435                 return [-(cm.right+c.getWidth()+cm.left), 0];
36436             break;
36437             case "east":
36438                 return [cm.right+c.getWidth()+cm.left, 0];
36439             break;
36440             case "north":
36441                 return [0, -(cm.top+cm.bottom+c.getHeight())];
36442             break;
36443             case "south":
36444                 return [0, cm.top+cm.bottom+c.getHeight()];
36445             break;
36446         }
36447     }
36448 });/*
36449  * Based on:
36450  * Ext JS Library 1.1.1
36451  * Copyright(c) 2006-2007, Ext JS, LLC.
36452  *
36453  * Originally Released Under LGPL - original licence link has changed is not relivant.
36454  *
36455  * Fork - LGPL
36456  * <script type="text/javascript">
36457  */
36458 /*
36459  * These classes are private internal classes
36460  */
36461 Roo.bootstrap.layout.Center = function(config){
36462     config.region = "center";
36463     Roo.bootstrap.layout.Region.call(this, config);
36464     this.visible = true;
36465     this.minWidth = config.minWidth || 20;
36466     this.minHeight = config.minHeight || 20;
36467 };
36468
36469 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36470     hide : function(){
36471         // center panel can't be hidden
36472     },
36473     
36474     show : function(){
36475         // center panel can't be hidden
36476     },
36477     
36478     getMinWidth: function(){
36479         return this.minWidth;
36480     },
36481     
36482     getMinHeight: function(){
36483         return this.minHeight;
36484     }
36485 });
36486
36487
36488
36489
36490  
36491
36492
36493
36494
36495
36496 Roo.bootstrap.layout.North = function(config)
36497 {
36498     config.region = 'north';
36499     config.cursor = 'n-resize';
36500     
36501     Roo.bootstrap.layout.Split.call(this, config);
36502     
36503     
36504     if(this.split){
36505         this.split.placement = Roo.bootstrap.SplitBar.TOP;
36506         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36507         this.split.el.addClass("roo-layout-split-v");
36508     }
36509     var size = config.initialSize || config.height;
36510     if(typeof size != "undefined"){
36511         this.el.setHeight(size);
36512     }
36513 };
36514 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36515 {
36516     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36517     
36518     
36519     
36520     getBox : function(){
36521         if(this.collapsed){
36522             return this.collapsedEl.getBox();
36523         }
36524         var box = this.el.getBox();
36525         if(this.split){
36526             box.height += this.split.el.getHeight();
36527         }
36528         return box;
36529     },
36530     
36531     updateBox : function(box){
36532         if(this.split && !this.collapsed){
36533             box.height -= this.split.el.getHeight();
36534             this.split.el.setLeft(box.x);
36535             this.split.el.setTop(box.y+box.height);
36536             this.split.el.setWidth(box.width);
36537         }
36538         if(this.collapsed){
36539             this.updateBody(box.width, null);
36540         }
36541         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36542     }
36543 });
36544
36545
36546
36547
36548
36549 Roo.bootstrap.layout.South = function(config){
36550     config.region = 'south';
36551     config.cursor = 's-resize';
36552     Roo.bootstrap.layout.Split.call(this, config);
36553     if(this.split){
36554         this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36555         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36556         this.split.el.addClass("roo-layout-split-v");
36557     }
36558     var size = config.initialSize || config.height;
36559     if(typeof size != "undefined"){
36560         this.el.setHeight(size);
36561     }
36562 };
36563
36564 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36565     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36566     getBox : function(){
36567         if(this.collapsed){
36568             return this.collapsedEl.getBox();
36569         }
36570         var box = this.el.getBox();
36571         if(this.split){
36572             var sh = this.split.el.getHeight();
36573             box.height += sh;
36574             box.y -= sh;
36575         }
36576         return box;
36577     },
36578     
36579     updateBox : function(box){
36580         if(this.split && !this.collapsed){
36581             var sh = this.split.el.getHeight();
36582             box.height -= sh;
36583             box.y += sh;
36584             this.split.el.setLeft(box.x);
36585             this.split.el.setTop(box.y-sh);
36586             this.split.el.setWidth(box.width);
36587         }
36588         if(this.collapsed){
36589             this.updateBody(box.width, null);
36590         }
36591         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36592     }
36593 });
36594
36595 Roo.bootstrap.layout.East = function(config){
36596     config.region = "east";
36597     config.cursor = "e-resize";
36598     Roo.bootstrap.layout.Split.call(this, config);
36599     if(this.split){
36600         this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36601         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36602         this.split.el.addClass("roo-layout-split-h");
36603     }
36604     var size = config.initialSize || config.width;
36605     if(typeof size != "undefined"){
36606         this.el.setWidth(size);
36607     }
36608 };
36609 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36610     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36611     getBox : function(){
36612         if(this.collapsed){
36613             return this.collapsedEl.getBox();
36614         }
36615         var box = this.el.getBox();
36616         if(this.split){
36617             var sw = this.split.el.getWidth();
36618             box.width += sw;
36619             box.x -= sw;
36620         }
36621         return box;
36622     },
36623
36624     updateBox : function(box){
36625         if(this.split && !this.collapsed){
36626             var sw = this.split.el.getWidth();
36627             box.width -= sw;
36628             this.split.el.setLeft(box.x);
36629             this.split.el.setTop(box.y);
36630             this.split.el.setHeight(box.height);
36631             box.x += sw;
36632         }
36633         if(this.collapsed){
36634             this.updateBody(null, box.height);
36635         }
36636         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36637     }
36638 });
36639
36640 Roo.bootstrap.layout.West = function(config){
36641     config.region = "west";
36642     config.cursor = "w-resize";
36643     
36644     Roo.bootstrap.layout.Split.call(this, config);
36645     if(this.split){
36646         this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36647         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36648         this.split.el.addClass("roo-layout-split-h");
36649     }
36650     
36651 };
36652 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36653     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36654     
36655     onRender: function(ctr, pos)
36656     {
36657         Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36658         var size = this.config.initialSize || this.config.width;
36659         if(typeof size != "undefined"){
36660             this.el.setWidth(size);
36661         }
36662     },
36663     
36664     getBox : function(){
36665         if(this.collapsed){
36666             return this.collapsedEl.getBox();
36667         }
36668         var box = this.el.getBox();
36669         if(this.split){
36670             box.width += this.split.el.getWidth();
36671         }
36672         return box;
36673     },
36674     
36675     updateBox : function(box){
36676         if(this.split && !this.collapsed){
36677             var sw = this.split.el.getWidth();
36678             box.width -= sw;
36679             this.split.el.setLeft(box.x+box.width);
36680             this.split.el.setTop(box.y);
36681             this.split.el.setHeight(box.height);
36682         }
36683         if(this.collapsed){
36684             this.updateBody(null, box.height);
36685         }
36686         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36687     }
36688 });
36689 Roo.namespace("Roo.bootstrap.panel");/*
36690  * Based on:
36691  * Ext JS Library 1.1.1
36692  * Copyright(c) 2006-2007, Ext JS, LLC.
36693  *
36694  * Originally Released Under LGPL - original licence link has changed is not relivant.
36695  *
36696  * Fork - LGPL
36697  * <script type="text/javascript">
36698  */
36699 /**
36700  * @class Roo.ContentPanel
36701  * @extends Roo.util.Observable
36702  * A basic ContentPanel element.
36703  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
36704  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
36705  * @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
36706  * @cfg {Boolean}   closable      True if the panel can be closed/removed
36707  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
36708  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36709  * @cfg {Toolbar}   toolbar       A toolbar for this panel
36710  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
36711  * @cfg {String} title          The title for this panel
36712  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36713  * @cfg {String} url            Calls {@link #setUrl} with this value
36714  * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36715  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
36716  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
36717  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
36718  * @cfg {Boolean} badges render the badges
36719
36720  * @constructor
36721  * Create a new ContentPanel.
36722  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36723  * @param {String/Object} config A string to set only the title or a config object
36724  * @param {String} content (optional) Set the HTML content for this panel
36725  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36726  */
36727 Roo.bootstrap.panel.Content = function( config){
36728     
36729     this.tpl = config.tpl || false;
36730     
36731     var el = config.el;
36732     var content = config.content;
36733
36734     if(config.autoCreate){ // xtype is available if this is called from factory
36735         el = Roo.id();
36736     }
36737     this.el = Roo.get(el);
36738     if(!this.el && config && config.autoCreate){
36739         if(typeof config.autoCreate == "object"){
36740             if(!config.autoCreate.id){
36741                 config.autoCreate.id = config.id||el;
36742             }
36743             this.el = Roo.DomHelper.append(document.body,
36744                         config.autoCreate, true);
36745         }else{
36746             var elcfg =  {   tag: "div",
36747                             cls: "roo-layout-inactive-content",
36748                             id: config.id||el
36749                             };
36750             if (config.html) {
36751                 elcfg.html = config.html;
36752                 
36753             }
36754                         
36755             this.el = Roo.DomHelper.append(document.body, elcfg , true);
36756         }
36757     } 
36758     this.closable = false;
36759     this.loaded = false;
36760     this.active = false;
36761    
36762       
36763     if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36764         
36765         this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36766         
36767         this.wrapEl = this.el; //this.el.wrap();
36768         var ti = [];
36769         if (config.toolbar.items) {
36770             ti = config.toolbar.items ;
36771             delete config.toolbar.items ;
36772         }
36773         
36774         var nitems = [];
36775         this.toolbar.render(this.wrapEl, 'before');
36776         for(var i =0;i < ti.length;i++) {
36777           //  Roo.log(['add child', items[i]]);
36778             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36779         }
36780         this.toolbar.items = nitems;
36781         this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36782         delete config.toolbar;
36783         
36784     }
36785     /*
36786     // xtype created footer. - not sure if will work as we normally have to render first..
36787     if (this.footer && !this.footer.el && this.footer.xtype) {
36788         if (!this.wrapEl) {
36789             this.wrapEl = this.el.wrap();
36790         }
36791     
36792         this.footer.container = this.wrapEl.createChild();
36793          
36794         this.footer = Roo.factory(this.footer, Roo);
36795         
36796     }
36797     */
36798     
36799      if(typeof config == "string"){
36800         this.title = config;
36801     }else{
36802         Roo.apply(this, config);
36803     }
36804     
36805     if(this.resizeEl){
36806         this.resizeEl = Roo.get(this.resizeEl, true);
36807     }else{
36808         this.resizeEl = this.el;
36809     }
36810     // handle view.xtype
36811     
36812  
36813     
36814     
36815     this.addEvents({
36816         /**
36817          * @event activate
36818          * Fires when this panel is activated. 
36819          * @param {Roo.ContentPanel} this
36820          */
36821         "activate" : true,
36822         /**
36823          * @event deactivate
36824          * Fires when this panel is activated. 
36825          * @param {Roo.ContentPanel} this
36826          */
36827         "deactivate" : true,
36828
36829         /**
36830          * @event resize
36831          * Fires when this panel is resized if fitToFrame is true.
36832          * @param {Roo.ContentPanel} this
36833          * @param {Number} width The width after any component adjustments
36834          * @param {Number} height The height after any component adjustments
36835          */
36836         "resize" : true,
36837         
36838          /**
36839          * @event render
36840          * Fires when this tab is created
36841          * @param {Roo.ContentPanel} this
36842          */
36843         "render" : true
36844         
36845         
36846         
36847     });
36848     
36849
36850     
36851     
36852     if(this.autoScroll){
36853         this.resizeEl.setStyle("overflow", "auto");
36854     } else {
36855         // fix randome scrolling
36856         //this.el.on('scroll', function() {
36857         //    Roo.log('fix random scolling');
36858         //    this.scrollTo('top',0); 
36859         //});
36860     }
36861     content = content || this.content;
36862     if(content){
36863         this.setContent(content);
36864     }
36865     if(config && config.url){
36866         this.setUrl(this.url, this.params, this.loadOnce);
36867     }
36868     
36869     
36870     
36871     Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36872     
36873     if (this.view && typeof(this.view.xtype) != 'undefined') {
36874         this.view.el = this.el.appendChild(document.createElement("div"));
36875         this.view = Roo.factory(this.view); 
36876         this.view.render  &&  this.view.render(false, '');  
36877     }
36878     
36879     
36880     this.fireEvent('render', this);
36881 };
36882
36883 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36884     
36885     tabTip : '',
36886     
36887     setRegion : function(region){
36888         this.region = region;
36889         this.setActiveClass(region && !this.background);
36890     },
36891     
36892     
36893     setActiveClass: function(state)
36894     {
36895         if(state){
36896            this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36897            this.el.setStyle('position','relative');
36898         }else{
36899            this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36900            this.el.setStyle('position', 'absolute');
36901         } 
36902     },
36903     
36904     /**
36905      * Returns the toolbar for this Panel if one was configured. 
36906      * @return {Roo.Toolbar} 
36907      */
36908     getToolbar : function(){
36909         return this.toolbar;
36910     },
36911     
36912     setActiveState : function(active)
36913     {
36914         this.active = active;
36915         this.setActiveClass(active);
36916         if(!active){
36917             if(this.fireEvent("deactivate", this) === false){
36918                 return false;
36919             }
36920             return true;
36921         }
36922         this.fireEvent("activate", this);
36923         return true;
36924     },
36925     /**
36926      * Updates this panel's element
36927      * @param {String} content The new content
36928      * @param {Boolean} loadScripts (optional) true to look for and process scripts
36929     */
36930     setContent : function(content, loadScripts){
36931         this.el.update(content, loadScripts);
36932     },
36933
36934     ignoreResize : function(w, h){
36935         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36936             return true;
36937         }else{
36938             this.lastSize = {width: w, height: h};
36939             return false;
36940         }
36941     },
36942     /**
36943      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36944      * @return {Roo.UpdateManager} The UpdateManager
36945      */
36946     getUpdateManager : function(){
36947         return this.el.getUpdateManager();
36948     },
36949      /**
36950      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36951      * @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:
36952 <pre><code>
36953 panel.load({
36954     url: "your-url.php",
36955     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36956     callback: yourFunction,
36957     scope: yourObject, //(optional scope)
36958     discardUrl: false,
36959     nocache: false,
36960     text: "Loading...",
36961     timeout: 30,
36962     scripts: false
36963 });
36964 </code></pre>
36965      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36966      * 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.
36967      * @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}
36968      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36969      * @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.
36970      * @return {Roo.ContentPanel} this
36971      */
36972     load : function(){
36973         var um = this.el.getUpdateManager();
36974         um.update.apply(um, arguments);
36975         return this;
36976     },
36977
36978
36979     /**
36980      * 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.
36981      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36982      * @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)
36983      * @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)
36984      * @return {Roo.UpdateManager} The UpdateManager
36985      */
36986     setUrl : function(url, params, loadOnce){
36987         if(this.refreshDelegate){
36988             this.removeListener("activate", this.refreshDelegate);
36989         }
36990         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36991         this.on("activate", this.refreshDelegate);
36992         return this.el.getUpdateManager();
36993     },
36994     
36995     _handleRefresh : function(url, params, loadOnce){
36996         if(!loadOnce || !this.loaded){
36997             var updater = this.el.getUpdateManager();
36998             updater.update(url, params, this._setLoaded.createDelegate(this));
36999         }
37000     },
37001     
37002     _setLoaded : function(){
37003         this.loaded = true;
37004     }, 
37005     
37006     /**
37007      * Returns this panel's id
37008      * @return {String} 
37009      */
37010     getId : function(){
37011         return this.el.id;
37012     },
37013     
37014     /** 
37015      * Returns this panel's element - used by regiosn to add.
37016      * @return {Roo.Element} 
37017      */
37018     getEl : function(){
37019         return this.wrapEl || this.el;
37020     },
37021     
37022    
37023     
37024     adjustForComponents : function(width, height)
37025     {
37026         //Roo.log('adjustForComponents ');
37027         if(this.resizeEl != this.el){
37028             width -= this.el.getFrameWidth('lr');
37029             height -= this.el.getFrameWidth('tb');
37030         }
37031         if(this.toolbar){
37032             var te = this.toolbar.getEl();
37033             te.setWidth(width);
37034             height -= te.getHeight();
37035         }
37036         if(this.footer){
37037             var te = this.footer.getEl();
37038             te.setWidth(width);
37039             height -= te.getHeight();
37040         }
37041         
37042         
37043         if(this.adjustments){
37044             width += this.adjustments[0];
37045             height += this.adjustments[1];
37046         }
37047         return {"width": width, "height": height};
37048     },
37049     
37050     setSize : function(width, height){
37051         if(this.fitToFrame && !this.ignoreResize(width, height)){
37052             if(this.fitContainer && this.resizeEl != this.el){
37053                 this.el.setSize(width, height);
37054             }
37055             var size = this.adjustForComponents(width, height);
37056             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37057             this.fireEvent('resize', this, size.width, size.height);
37058         }
37059     },
37060     
37061     /**
37062      * Returns this panel's title
37063      * @return {String} 
37064      */
37065     getTitle : function(){
37066         
37067         if (typeof(this.title) != 'object') {
37068             return this.title;
37069         }
37070         
37071         var t = '';
37072         for (var k in this.title) {
37073             if (!this.title.hasOwnProperty(k)) {
37074                 continue;
37075             }
37076             
37077             if (k.indexOf('-') >= 0) {
37078                 var s = k.split('-');
37079                 for (var i = 0; i<s.length; i++) {
37080                     t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37081                 }
37082             } else {
37083                 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37084             }
37085         }
37086         return t;
37087     },
37088     
37089     /**
37090      * Set this panel's title
37091      * @param {String} title
37092      */
37093     setTitle : function(title){
37094         this.title = title;
37095         if(this.region){
37096             this.region.updatePanelTitle(this, title);
37097         }
37098     },
37099     
37100     /**
37101      * Returns true is this panel was configured to be closable
37102      * @return {Boolean} 
37103      */
37104     isClosable : function(){
37105         return this.closable;
37106     },
37107     
37108     beforeSlide : function(){
37109         this.el.clip();
37110         this.resizeEl.clip();
37111     },
37112     
37113     afterSlide : function(){
37114         this.el.unclip();
37115         this.resizeEl.unclip();
37116     },
37117     
37118     /**
37119      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
37120      *   Will fail silently if the {@link #setUrl} method has not been called.
37121      *   This does not activate the panel, just updates its content.
37122      */
37123     refresh : function(){
37124         if(this.refreshDelegate){
37125            this.loaded = false;
37126            this.refreshDelegate();
37127         }
37128     },
37129     
37130     /**
37131      * Destroys this panel
37132      */
37133     destroy : function(){
37134         this.el.removeAllListeners();
37135         var tempEl = document.createElement("span");
37136         tempEl.appendChild(this.el.dom);
37137         tempEl.innerHTML = "";
37138         this.el.remove();
37139         this.el = null;
37140     },
37141     
37142     /**
37143      * form - if the content panel contains a form - this is a reference to it.
37144      * @type {Roo.form.Form}
37145      */
37146     form : false,
37147     /**
37148      * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37149      *    This contains a reference to it.
37150      * @type {Roo.View}
37151      */
37152     view : false,
37153     
37154       /**
37155      * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37156      * <pre><code>
37157
37158 layout.addxtype({
37159        xtype : 'Form',
37160        items: [ .... ]
37161    }
37162 );
37163
37164 </code></pre>
37165      * @param {Object} cfg Xtype definition of item to add.
37166      */
37167     
37168     
37169     getChildContainer: function () {
37170         return this.getEl();
37171     }
37172     
37173     
37174     /*
37175         var  ret = new Roo.factory(cfg);
37176         return ret;
37177         
37178         
37179         // add form..
37180         if (cfg.xtype.match(/^Form$/)) {
37181             
37182             var el;
37183             //if (this.footer) {
37184             //    el = this.footer.container.insertSibling(false, 'before');
37185             //} else {
37186                 el = this.el.createChild();
37187             //}
37188
37189             this.form = new  Roo.form.Form(cfg);
37190             
37191             
37192             if ( this.form.allItems.length) {
37193                 this.form.render(el.dom);
37194             }
37195             return this.form;
37196         }
37197         // should only have one of theses..
37198         if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37199             // views.. should not be just added - used named prop 'view''
37200             
37201             cfg.el = this.el.appendChild(document.createElement("div"));
37202             // factory?
37203             
37204             var ret = new Roo.factory(cfg);
37205              
37206              ret.render && ret.render(false, ''); // render blank..
37207             this.view = ret;
37208             return ret;
37209         }
37210         return false;
37211     }
37212     \*/
37213 });
37214  
37215 /**
37216  * @class Roo.bootstrap.panel.Grid
37217  * @extends Roo.bootstrap.panel.Content
37218  * @constructor
37219  * Create a new GridPanel.
37220  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37221  * @param {Object} config A the config object
37222   
37223  */
37224
37225
37226
37227 Roo.bootstrap.panel.Grid = function(config)
37228 {
37229     
37230       
37231     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37232         {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37233
37234     config.el = this.wrapper;
37235     //this.el = this.wrapper;
37236     
37237       if (config.container) {
37238         // ctor'ed from a Border/panel.grid
37239         
37240         
37241         this.wrapper.setStyle("overflow", "hidden");
37242         this.wrapper.addClass('roo-grid-container');
37243
37244     }
37245     
37246     
37247     if(config.toolbar){
37248         var tool_el = this.wrapper.createChild();    
37249         this.toolbar = Roo.factory(config.toolbar);
37250         var ti = [];
37251         if (config.toolbar.items) {
37252             ti = config.toolbar.items ;
37253             delete config.toolbar.items ;
37254         }
37255         
37256         var nitems = [];
37257         this.toolbar.render(tool_el);
37258         for(var i =0;i < ti.length;i++) {
37259           //  Roo.log(['add child', items[i]]);
37260             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37261         }
37262         this.toolbar.items = nitems;
37263         
37264         delete config.toolbar;
37265     }
37266     
37267     Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37268     config.grid.scrollBody = true;;
37269     config.grid.monitorWindowResize = false; // turn off autosizing
37270     config.grid.autoHeight = false;
37271     config.grid.autoWidth = false;
37272     
37273     this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37274     
37275     if (config.background) {
37276         // render grid on panel activation (if panel background)
37277         this.on('activate', function(gp) {
37278             if (!gp.grid.rendered) {
37279                 gp.grid.render(this.wrapper);
37280                 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");   
37281             }
37282         });
37283             
37284     } else {
37285         this.grid.render(this.wrapper);
37286         this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");               
37287
37288     }
37289     //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37290     // ??? needed ??? config.el = this.wrapper;
37291     
37292     
37293     
37294   
37295     // xtype created footer. - not sure if will work as we normally have to render first..
37296     if (this.footer && !this.footer.el && this.footer.xtype) {
37297         
37298         var ctr = this.grid.getView().getFooterPanel(true);
37299         this.footer.dataSource = this.grid.dataSource;
37300         this.footer = Roo.factory(this.footer, Roo);
37301         this.footer.render(ctr);
37302         
37303     }
37304     
37305     
37306     
37307     
37308      
37309 };
37310
37311 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37312     getId : function(){
37313         return this.grid.id;
37314     },
37315     
37316     /**
37317      * Returns the grid for this panel
37318      * @return {Roo.bootstrap.Table} 
37319      */
37320     getGrid : function(){
37321         return this.grid;    
37322     },
37323     
37324     setSize : function(width, height){
37325         if(!this.ignoreResize(width, height)){
37326             var grid = this.grid;
37327             var size = this.adjustForComponents(width, height);
37328             var gridel = grid.getGridEl();
37329             gridel.setSize(size.width, size.height);
37330             /*
37331             var thd = grid.getGridEl().select('thead',true).first();
37332             var tbd = grid.getGridEl().select('tbody', true).first();
37333             if (tbd) {
37334                 tbd.setSize(width, height - thd.getHeight());
37335             }
37336             */
37337             grid.autoSize();
37338         }
37339     },
37340      
37341     
37342     
37343     beforeSlide : function(){
37344         this.grid.getView().scroller.clip();
37345     },
37346     
37347     afterSlide : function(){
37348         this.grid.getView().scroller.unclip();
37349     },
37350     
37351     destroy : function(){
37352         this.grid.destroy();
37353         delete this.grid;
37354         Roo.bootstrap.panel.Grid.superclass.destroy.call(this); 
37355     }
37356 });
37357
37358 /**
37359  * @class Roo.bootstrap.panel.Nest
37360  * @extends Roo.bootstrap.panel.Content
37361  * @constructor
37362  * Create a new Panel, that can contain a layout.Border.
37363  * 
37364  * 
37365  * @param {Roo.BorderLayout} layout The layout for this panel
37366  * @param {String/Object} config A string to set only the title or a config object
37367  */
37368 Roo.bootstrap.panel.Nest = function(config)
37369 {
37370     // construct with only one argument..
37371     /* FIXME - implement nicer consturctors
37372     if (layout.layout) {
37373         config = layout;
37374         layout = config.layout;
37375         delete config.layout;
37376     }
37377     if (layout.xtype && !layout.getEl) {
37378         // then layout needs constructing..
37379         layout = Roo.factory(layout, Roo);
37380     }
37381     */
37382     
37383     config.el =  config.layout.getEl();
37384     
37385     Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37386     
37387     config.layout.monitorWindowResize = false; // turn off autosizing
37388     this.layout = config.layout;
37389     this.layout.getEl().addClass("roo-layout-nested-layout");
37390     
37391     
37392     
37393     
37394 };
37395
37396 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37397
37398     setSize : function(width, height){
37399         if(!this.ignoreResize(width, height)){
37400             var size = this.adjustForComponents(width, height);
37401             var el = this.layout.getEl();
37402             if (size.height < 1) {
37403                 el.setWidth(size.width);   
37404             } else {
37405                 el.setSize(size.width, size.height);
37406             }
37407             var touch = el.dom.offsetWidth;
37408             this.layout.layout();
37409             // ie requires a double layout on the first pass
37410             if(Roo.isIE && !this.initialized){
37411                 this.initialized = true;
37412                 this.layout.layout();
37413             }
37414         }
37415     },
37416     
37417     // activate all subpanels if not currently active..
37418     
37419     setActiveState : function(active){
37420         this.active = active;
37421         this.setActiveClass(active);
37422         
37423         if(!active){
37424             this.fireEvent("deactivate", this);
37425             return;
37426         }
37427         
37428         this.fireEvent("activate", this);
37429         // not sure if this should happen before or after..
37430         if (!this.layout) {
37431             return; // should not happen..
37432         }
37433         var reg = false;
37434         for (var r in this.layout.regions) {
37435             reg = this.layout.getRegion(r);
37436             if (reg.getActivePanel()) {
37437                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
37438                 reg.setActivePanel(reg.getActivePanel());
37439                 continue;
37440             }
37441             if (!reg.panels.length) {
37442                 continue;
37443             }
37444             reg.showPanel(reg.getPanel(0));
37445         }
37446         
37447         
37448         
37449         
37450     },
37451     
37452     /**
37453      * Returns the nested BorderLayout for this panel
37454      * @return {Roo.BorderLayout} 
37455      */
37456     getLayout : function(){
37457         return this.layout;
37458     },
37459     
37460      /**
37461      * Adds a xtype elements to the layout of the nested panel
37462      * <pre><code>
37463
37464 panel.addxtype({
37465        xtype : 'ContentPanel',
37466        region: 'west',
37467        items: [ .... ]
37468    }
37469 );
37470
37471 panel.addxtype({
37472         xtype : 'NestedLayoutPanel',
37473         region: 'west',
37474         layout: {
37475            center: { },
37476            west: { }   
37477         },
37478         items : [ ... list of content panels or nested layout panels.. ]
37479    }
37480 );
37481 </code></pre>
37482      * @param {Object} cfg Xtype definition of item to add.
37483      */
37484     addxtype : function(cfg) {
37485         return this.layout.addxtype(cfg);
37486     
37487     }
37488 });        /*
37489  * Based on:
37490  * Ext JS Library 1.1.1
37491  * Copyright(c) 2006-2007, Ext JS, LLC.
37492  *
37493  * Originally Released Under LGPL - original licence link has changed is not relivant.
37494  *
37495  * Fork - LGPL
37496  * <script type="text/javascript">
37497  */
37498 /**
37499  * @class Roo.TabPanel
37500  * @extends Roo.util.Observable
37501  * A lightweight tab container.
37502  * <br><br>
37503  * Usage:
37504  * <pre><code>
37505 // basic tabs 1, built from existing content
37506 var tabs = new Roo.TabPanel("tabs1");
37507 tabs.addTab("script", "View Script");
37508 tabs.addTab("markup", "View Markup");
37509 tabs.activate("script");
37510
37511 // more advanced tabs, built from javascript
37512 var jtabs = new Roo.TabPanel("jtabs");
37513 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37514
37515 // set up the UpdateManager
37516 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37517 var updater = tab2.getUpdateManager();
37518 updater.setDefaultUrl("ajax1.htm");
37519 tab2.on('activate', updater.refresh, updater, true);
37520
37521 // Use setUrl for Ajax loading
37522 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37523 tab3.setUrl("ajax2.htm", null, true);
37524
37525 // Disabled tab
37526 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37527 tab4.disable();
37528
37529 jtabs.activate("jtabs-1");
37530  * </code></pre>
37531  * @constructor
37532  * Create a new TabPanel.
37533  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37534  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37535  */
37536 Roo.bootstrap.panel.Tabs = function(config){
37537     /**
37538     * The container element for this TabPanel.
37539     * @type Roo.Element
37540     */
37541     this.el = Roo.get(config.el);
37542     delete config.el;
37543     if(config){
37544         if(typeof config == "boolean"){
37545             this.tabPosition = config ? "bottom" : "top";
37546         }else{
37547             Roo.apply(this, config);
37548         }
37549     }
37550     
37551     if(this.tabPosition == "bottom"){
37552         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37553         this.el.addClass("roo-tabs-bottom");
37554     }
37555     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37556     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37557     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37558     if(Roo.isIE){
37559         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37560     }
37561     if(this.tabPosition != "bottom"){
37562         /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37563          * @type Roo.Element
37564          */
37565         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37566         this.el.addClass("roo-tabs-top");
37567     }
37568     this.items = [];
37569
37570     this.bodyEl.setStyle("position", "relative");
37571
37572     this.active = null;
37573     this.activateDelegate = this.activate.createDelegate(this);
37574
37575     this.addEvents({
37576         /**
37577          * @event tabchange
37578          * Fires when the active tab changes
37579          * @param {Roo.TabPanel} this
37580          * @param {Roo.TabPanelItem} activePanel The new active tab
37581          */
37582         "tabchange": true,
37583         /**
37584          * @event beforetabchange
37585          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37586          * @param {Roo.TabPanel} this
37587          * @param {Object} e Set cancel to true on this object to cancel the tab change
37588          * @param {Roo.TabPanelItem} tab The tab being changed to
37589          */
37590         "beforetabchange" : true
37591     });
37592
37593     Roo.EventManager.onWindowResize(this.onResize, this);
37594     this.cpad = this.el.getPadding("lr");
37595     this.hiddenCount = 0;
37596
37597
37598     // toolbar on the tabbar support...
37599     if (this.toolbar) {
37600         alert("no toolbar support yet");
37601         this.toolbar  = false;
37602         /*
37603         var tcfg = this.toolbar;
37604         tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
37605         this.toolbar = new Roo.Toolbar(tcfg);
37606         if (Roo.isSafari) {
37607             var tbl = tcfg.container.child('table', true);
37608             tbl.setAttribute('width', '100%');
37609         }
37610         */
37611         
37612     }
37613    
37614
37615
37616     Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37617 };
37618
37619 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37620     /*
37621      *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37622      */
37623     tabPosition : "top",
37624     /*
37625      *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37626      */
37627     currentTabWidth : 0,
37628     /*
37629      *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37630      */
37631     minTabWidth : 40,
37632     /*
37633      *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37634      */
37635     maxTabWidth : 250,
37636     /*
37637      *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37638      */
37639     preferredTabWidth : 175,
37640     /*
37641      *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37642      */
37643     resizeTabs : false,
37644     /*
37645      *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37646      */
37647     monitorResize : true,
37648     /*
37649      *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
37650      */
37651     toolbar : false,
37652
37653     /**
37654      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37655      * @param {String} id The id of the div to use <b>or create</b>
37656      * @param {String} text The text for the tab
37657      * @param {String} content (optional) Content to put in the TabPanelItem body
37658      * @param {Boolean} closable (optional) True to create a close icon on the tab
37659      * @return {Roo.TabPanelItem} The created TabPanelItem
37660      */
37661     addTab : function(id, text, content, closable, tpl)
37662     {
37663         var item = new Roo.bootstrap.panel.TabItem({
37664             panel: this,
37665             id : id,
37666             text : text,
37667             closable : closable,
37668             tpl : tpl
37669         });
37670         this.addTabItem(item);
37671         if(content){
37672             item.setContent(content);
37673         }
37674         return item;
37675     },
37676
37677     /**
37678      * Returns the {@link Roo.TabPanelItem} with the specified id/index
37679      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37680      * @return {Roo.TabPanelItem}
37681      */
37682     getTab : function(id){
37683         return this.items[id];
37684     },
37685
37686     /**
37687      * Hides the {@link Roo.TabPanelItem} with the specified id/index
37688      * @param {String/Number} id The id or index of the TabPanelItem to hide.
37689      */
37690     hideTab : function(id){
37691         var t = this.items[id];
37692         if(!t.isHidden()){
37693            t.setHidden(true);
37694            this.hiddenCount++;
37695            this.autoSizeTabs();
37696         }
37697     },
37698
37699     /**
37700      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37701      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37702      */
37703     unhideTab : function(id){
37704         var t = this.items[id];
37705         if(t.isHidden()){
37706            t.setHidden(false);
37707            this.hiddenCount--;
37708            this.autoSizeTabs();
37709         }
37710     },
37711
37712     /**
37713      * Adds an existing {@link Roo.TabPanelItem}.
37714      * @param {Roo.TabPanelItem} item The TabPanelItem to add
37715      */
37716     addTabItem : function(item){
37717         this.items[item.id] = item;
37718         this.items.push(item);
37719       //  if(this.resizeTabs){
37720     //       item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37721   //         this.autoSizeTabs();
37722 //        }else{
37723 //            item.autoSize();
37724        // }
37725     },
37726
37727     /**
37728      * Removes a {@link Roo.TabPanelItem}.
37729      * @param {String/Number} id The id or index of the TabPanelItem to remove.
37730      */
37731     removeTab : function(id){
37732         var items = this.items;
37733         var tab = items[id];
37734         if(!tab) { return; }
37735         var index = items.indexOf(tab);
37736         if(this.active == tab && items.length > 1){
37737             var newTab = this.getNextAvailable(index);
37738             if(newTab) {
37739                 newTab.activate();
37740             }
37741         }
37742         this.stripEl.dom.removeChild(tab.pnode.dom);
37743         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37744             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37745         }
37746         items.splice(index, 1);
37747         delete this.items[tab.id];
37748         tab.fireEvent("close", tab);
37749         tab.purgeListeners();
37750         this.autoSizeTabs();
37751     },
37752
37753     getNextAvailable : function(start){
37754         var items = this.items;
37755         var index = start;
37756         // look for a next tab that will slide over to
37757         // replace the one being removed
37758         while(index < items.length){
37759             var item = items[++index];
37760             if(item && !item.isHidden()){
37761                 return item;
37762             }
37763         }
37764         // if one isn't found select the previous tab (on the left)
37765         index = start;
37766         while(index >= 0){
37767             var item = items[--index];
37768             if(item && !item.isHidden()){
37769                 return item;
37770             }
37771         }
37772         return null;
37773     },
37774
37775     /**
37776      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37777      * @param {String/Number} id The id or index of the TabPanelItem to disable.
37778      */
37779     disableTab : function(id){
37780         var tab = this.items[id];
37781         if(tab && this.active != tab){
37782             tab.disable();
37783         }
37784     },
37785
37786     /**
37787      * Enables a {@link Roo.TabPanelItem} that is disabled.
37788      * @param {String/Number} id The id or index of the TabPanelItem to enable.
37789      */
37790     enableTab : function(id){
37791         var tab = this.items[id];
37792         tab.enable();
37793     },
37794
37795     /**
37796      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37797      * @param {String/Number} id The id or index of the TabPanelItem to activate.
37798      * @return {Roo.TabPanelItem} The TabPanelItem.
37799      */
37800     activate : function(id){
37801         var tab = this.items[id];
37802         if(!tab){
37803             return null;
37804         }
37805         if(tab == this.active || tab.disabled){
37806             return tab;
37807         }
37808         var e = {};
37809         this.fireEvent("beforetabchange", this, e, tab);
37810         if(e.cancel !== true && !tab.disabled){
37811             if(this.active){
37812                 this.active.hide();
37813             }
37814             this.active = this.items[id];
37815             this.active.show();
37816             this.fireEvent("tabchange", this, this.active);
37817         }
37818         return tab;
37819     },
37820
37821     /**
37822      * Gets the active {@link Roo.TabPanelItem}.
37823      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37824      */
37825     getActiveTab : function(){
37826         return this.active;
37827     },
37828
37829     /**
37830      * Updates the tab body element to fit the height of the container element
37831      * for overflow scrolling
37832      * @param {Number} targetHeight (optional) Override the starting height from the elements height
37833      */
37834     syncHeight : function(targetHeight){
37835         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37836         var bm = this.bodyEl.getMargins();
37837         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37838         this.bodyEl.setHeight(newHeight);
37839         return newHeight;
37840     },
37841
37842     onResize : function(){
37843         if(this.monitorResize){
37844             this.autoSizeTabs();
37845         }
37846     },
37847
37848     /**
37849      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37850      */
37851     beginUpdate : function(){
37852         this.updating = true;
37853     },
37854
37855     /**
37856      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37857      */
37858     endUpdate : function(){
37859         this.updating = false;
37860         this.autoSizeTabs();
37861     },
37862
37863     /**
37864      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37865      */
37866     autoSizeTabs : function(){
37867         var count = this.items.length;
37868         var vcount = count - this.hiddenCount;
37869         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37870             return;
37871         }
37872         var w = Math.max(this.el.getWidth() - this.cpad, 10);
37873         var availWidth = Math.floor(w / vcount);
37874         var b = this.stripBody;
37875         if(b.getWidth() > w){
37876             var tabs = this.items;
37877             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37878             if(availWidth < this.minTabWidth){
37879                 /*if(!this.sleft){    // incomplete scrolling code
37880                     this.createScrollButtons();
37881                 }
37882                 this.showScroll();
37883                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37884             }
37885         }else{
37886             if(this.currentTabWidth < this.preferredTabWidth){
37887                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37888             }
37889         }
37890     },
37891
37892     /**
37893      * Returns the number of tabs in this TabPanel.
37894      * @return {Number}
37895      */
37896      getCount : function(){
37897          return this.items.length;
37898      },
37899
37900     /**
37901      * Resizes all the tabs to the passed width
37902      * @param {Number} The new width
37903      */
37904     setTabWidth : function(width){
37905         this.currentTabWidth = width;
37906         for(var i = 0, len = this.items.length; i < len; i++) {
37907                 if(!this.items[i].isHidden()) {
37908                 this.items[i].setWidth(width);
37909             }
37910         }
37911     },
37912
37913     /**
37914      * Destroys this TabPanel
37915      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37916      */
37917     destroy : function(removeEl){
37918         Roo.EventManager.removeResizeListener(this.onResize, this);
37919         for(var i = 0, len = this.items.length; i < len; i++){
37920             this.items[i].purgeListeners();
37921         }
37922         if(removeEl === true){
37923             this.el.update("");
37924             this.el.remove();
37925         }
37926     },
37927     
37928     createStrip : function(container)
37929     {
37930         var strip = document.createElement("nav");
37931         strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37932         container.appendChild(strip);
37933         return strip;
37934     },
37935     
37936     createStripList : function(strip)
37937     {
37938         // div wrapper for retard IE
37939         // returns the "tr" element.
37940         strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37941         //'<div class="x-tabs-strip-wrap">'+
37942           //  '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37943           //  '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37944         return strip.firstChild; //.firstChild.firstChild.firstChild;
37945     },
37946     createBody : function(container)
37947     {
37948         var body = document.createElement("div");
37949         Roo.id(body, "tab-body");
37950         //Roo.fly(body).addClass("x-tabs-body");
37951         Roo.fly(body).addClass("tab-content");
37952         container.appendChild(body);
37953         return body;
37954     },
37955     createItemBody :function(bodyEl, id){
37956         var body = Roo.getDom(id);
37957         if(!body){
37958             body = document.createElement("div");
37959             body.id = id;
37960         }
37961         //Roo.fly(body).addClass("x-tabs-item-body");
37962         Roo.fly(body).addClass("tab-pane");
37963          bodyEl.insertBefore(body, bodyEl.firstChild);
37964         return body;
37965     },
37966     /** @private */
37967     createStripElements :  function(stripEl, text, closable, tpl)
37968     {
37969         var td = document.createElement("li"); // was td..
37970         
37971         
37972         //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37973         
37974         
37975         stripEl.appendChild(td);
37976         /*if(closable){
37977             td.className = "x-tabs-closable";
37978             if(!this.closeTpl){
37979                 this.closeTpl = new Roo.Template(
37980                    '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37981                    '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37982                    '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
37983                 );
37984             }
37985             var el = this.closeTpl.overwrite(td, {"text": text});
37986             var close = el.getElementsByTagName("div")[0];
37987             var inner = el.getElementsByTagName("em")[0];
37988             return {"el": el, "close": close, "inner": inner};
37989         } else {
37990         */
37991         // not sure what this is..
37992 //            if(!this.tabTpl){
37993                 //this.tabTpl = new Roo.Template(
37994                 //   '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37995                 //   '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37996                 //);
37997 //                this.tabTpl = new Roo.Template(
37998 //                   '<a href="#">' +
37999 //                   '<span unselectable="on"' +
38000 //                            (this.disableTooltips ? '' : ' title="{text}"') +
38001 //                            ' >{text}</span></a>'
38002 //                );
38003 //                
38004 //            }
38005
38006
38007             var template = tpl || this.tabTpl || false;
38008             
38009             if(!template){
38010                 
38011                 template = new Roo.Template(
38012                    '<a href="#">' +
38013                    '<span unselectable="on"' +
38014                             (this.disableTooltips ? '' : ' title="{text}"') +
38015                             ' >{text}</span></a>'
38016                 );
38017             }
38018             
38019             switch (typeof(template)) {
38020                 case 'object' :
38021                     break;
38022                 case 'string' :
38023                     template = new Roo.Template(template);
38024                     break;
38025                 default :
38026                     break;
38027             }
38028             
38029             var el = template.overwrite(td, {"text": text});
38030             
38031             var inner = el.getElementsByTagName("span")[0];
38032             
38033             return {"el": el, "inner": inner};
38034             
38035     }
38036         
38037     
38038 });
38039
38040 /**
38041  * @class Roo.TabPanelItem
38042  * @extends Roo.util.Observable
38043  * Represents an individual item (tab plus body) in a TabPanel.
38044  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38045  * @param {String} id The id of this TabPanelItem
38046  * @param {String} text The text for the tab of this TabPanelItem
38047  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38048  */
38049 Roo.bootstrap.panel.TabItem = function(config){
38050     /**
38051      * The {@link Roo.TabPanel} this TabPanelItem belongs to
38052      * @type Roo.TabPanel
38053      */
38054     this.tabPanel = config.panel;
38055     /**
38056      * The id for this TabPanelItem
38057      * @type String
38058      */
38059     this.id = config.id;
38060     /** @private */
38061     this.disabled = false;
38062     /** @private */
38063     this.text = config.text;
38064     /** @private */
38065     this.loaded = false;
38066     this.closable = config.closable;
38067
38068     /**
38069      * The body element for this TabPanelItem.
38070      * @type Roo.Element
38071      */
38072     this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38073     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38074     this.bodyEl.setStyle("display", "block");
38075     this.bodyEl.setStyle("zoom", "1");
38076     //this.hideAction();
38077
38078     var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38079     /** @private */
38080     this.el = Roo.get(els.el);
38081     this.inner = Roo.get(els.inner, true);
38082     this.textEl = Roo.get(this.el.dom.firstChild, true);
38083     this.pnode = Roo.get(els.el.parentNode, true);
38084 //    this.el.on("mousedown", this.onTabMouseDown, this);
38085     this.el.on("click", this.onTabClick, this);
38086     /** @private */
38087     if(config.closable){
38088         var c = Roo.get(els.close, true);
38089         c.dom.title = this.closeText;
38090         c.addClassOnOver("close-over");
38091         c.on("click", this.closeClick, this);
38092      }
38093
38094     this.addEvents({
38095          /**
38096          * @event activate
38097          * Fires when this tab becomes the active tab.
38098          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38099          * @param {Roo.TabPanelItem} this
38100          */
38101         "activate": true,
38102         /**
38103          * @event beforeclose
38104          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38105          * @param {Roo.TabPanelItem} this
38106          * @param {Object} e Set cancel to true on this object to cancel the close.
38107          */
38108         "beforeclose": true,
38109         /**
38110          * @event close
38111          * Fires when this tab is closed.
38112          * @param {Roo.TabPanelItem} this
38113          */
38114          "close": true,
38115         /**
38116          * @event deactivate
38117          * Fires when this tab is no longer the active tab.
38118          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38119          * @param {Roo.TabPanelItem} this
38120          */
38121          "deactivate" : true
38122     });
38123     this.hidden = false;
38124
38125     Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38126 };
38127
38128 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38129            {
38130     purgeListeners : function(){
38131        Roo.util.Observable.prototype.purgeListeners.call(this);
38132        this.el.removeAllListeners();
38133     },
38134     /**
38135      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38136      */
38137     show : function(){
38138         this.pnode.addClass("active");
38139         this.showAction();
38140         if(Roo.isOpera){
38141             this.tabPanel.stripWrap.repaint();
38142         }
38143         this.fireEvent("activate", this.tabPanel, this);
38144     },
38145
38146     /**
38147      * Returns true if this tab is the active tab.
38148      * @return {Boolean}
38149      */
38150     isActive : function(){
38151         return this.tabPanel.getActiveTab() == this;
38152     },
38153
38154     /**
38155      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38156      */
38157     hide : function(){
38158         this.pnode.removeClass("active");
38159         this.hideAction();
38160         this.fireEvent("deactivate", this.tabPanel, this);
38161     },
38162
38163     hideAction : function(){
38164         this.bodyEl.hide();
38165         this.bodyEl.setStyle("position", "absolute");
38166         this.bodyEl.setLeft("-20000px");
38167         this.bodyEl.setTop("-20000px");
38168     },
38169
38170     showAction : function(){
38171         this.bodyEl.setStyle("position", "relative");
38172         this.bodyEl.setTop("");
38173         this.bodyEl.setLeft("");
38174         this.bodyEl.show();
38175     },
38176
38177     /**
38178      * Set the tooltip for the tab.
38179      * @param {String} tooltip The tab's tooltip
38180      */
38181     setTooltip : function(text){
38182         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38183             this.textEl.dom.qtip = text;
38184             this.textEl.dom.removeAttribute('title');
38185         }else{
38186             this.textEl.dom.title = text;
38187         }
38188     },
38189
38190     onTabClick : function(e){
38191         e.preventDefault();
38192         this.tabPanel.activate(this.id);
38193     },
38194
38195     onTabMouseDown : function(e){
38196         e.preventDefault();
38197         this.tabPanel.activate(this.id);
38198     },
38199 /*
38200     getWidth : function(){
38201         return this.inner.getWidth();
38202     },
38203
38204     setWidth : function(width){
38205         var iwidth = width - this.pnode.getPadding("lr");
38206         this.inner.setWidth(iwidth);
38207         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38208         this.pnode.setWidth(width);
38209     },
38210 */
38211     /**
38212      * Show or hide the tab
38213      * @param {Boolean} hidden True to hide or false to show.
38214      */
38215     setHidden : function(hidden){
38216         this.hidden = hidden;
38217         this.pnode.setStyle("display", hidden ? "none" : "");
38218     },
38219
38220     /**
38221      * Returns true if this tab is "hidden"
38222      * @return {Boolean}
38223      */
38224     isHidden : function(){
38225         return this.hidden;
38226     },
38227
38228     /**
38229      * Returns the text for this tab
38230      * @return {String}
38231      */
38232     getText : function(){
38233         return this.text;
38234     },
38235     /*
38236     autoSize : function(){
38237         //this.el.beginMeasure();
38238         this.textEl.setWidth(1);
38239         /*
38240          *  #2804 [new] Tabs in Roojs
38241          *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38242          */
38243         //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38244         //this.el.endMeasure();
38245     //},
38246
38247     /**
38248      * Sets the text for the tab (Note: this also sets the tooltip text)
38249      * @param {String} text The tab's text and tooltip
38250      */
38251     setText : function(text){
38252         this.text = text;
38253         this.textEl.update(text);
38254         this.setTooltip(text);
38255         //if(!this.tabPanel.resizeTabs){
38256         //    this.autoSize();
38257         //}
38258     },
38259     /**
38260      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38261      */
38262     activate : function(){
38263         this.tabPanel.activate(this.id);
38264     },
38265
38266     /**
38267      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38268      */
38269     disable : function(){
38270         if(this.tabPanel.active != this){
38271             this.disabled = true;
38272             this.pnode.addClass("disabled");
38273         }
38274     },
38275
38276     /**
38277      * Enables this TabPanelItem if it was previously disabled.
38278      */
38279     enable : function(){
38280         this.disabled = false;
38281         this.pnode.removeClass("disabled");
38282     },
38283
38284     /**
38285      * Sets the content for this TabPanelItem.
38286      * @param {String} content The content
38287      * @param {Boolean} loadScripts true to look for and load scripts
38288      */
38289     setContent : function(content, loadScripts){
38290         this.bodyEl.update(content, loadScripts);
38291     },
38292
38293     /**
38294      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38295      * @return {Roo.UpdateManager} The UpdateManager
38296      */
38297     getUpdateManager : function(){
38298         return this.bodyEl.getUpdateManager();
38299     },
38300
38301     /**
38302      * Set a URL to be used to load the content for this TabPanelItem.
38303      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38304      * @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)
38305      * @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)
38306      * @return {Roo.UpdateManager} The UpdateManager
38307      */
38308     setUrl : function(url, params, loadOnce){
38309         if(this.refreshDelegate){
38310             this.un('activate', this.refreshDelegate);
38311         }
38312         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38313         this.on("activate", this.refreshDelegate);
38314         return this.bodyEl.getUpdateManager();
38315     },
38316
38317     /** @private */
38318     _handleRefresh : function(url, params, loadOnce){
38319         if(!loadOnce || !this.loaded){
38320             var updater = this.bodyEl.getUpdateManager();
38321             updater.update(url, params, this._setLoaded.createDelegate(this));
38322         }
38323     },
38324
38325     /**
38326      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
38327      *   Will fail silently if the setUrl method has not been called.
38328      *   This does not activate the panel, just updates its content.
38329      */
38330     refresh : function(){
38331         if(this.refreshDelegate){
38332            this.loaded = false;
38333            this.refreshDelegate();
38334         }
38335     },
38336
38337     /** @private */
38338     _setLoaded : function(){
38339         this.loaded = true;
38340     },
38341
38342     /** @private */
38343     closeClick : function(e){
38344         var o = {};
38345         e.stopEvent();
38346         this.fireEvent("beforeclose", this, o);
38347         if(o.cancel !== true){
38348             this.tabPanel.removeTab(this.id);
38349         }
38350     },
38351     /**
38352      * The text displayed in the tooltip for the close icon.
38353      * @type String
38354      */
38355     closeText : "Close this tab"
38356 });
38357 /**
38358 *    This script refer to:
38359 *    Title: International Telephone Input
38360 *    Author: Jack O'Connor
38361 *    Code version:  v12.1.12
38362 *    Availability: https://github.com/jackocnr/intl-tel-input.git
38363 **/
38364
38365 Roo.bootstrap.PhoneInputData = function() {
38366     var d = [
38367       [
38368         "Afghanistan (‫افغانستان‬‎)",
38369         "af",
38370         "93"
38371       ],
38372       [
38373         "Albania (Shqipëri)",
38374         "al",
38375         "355"
38376       ],
38377       [
38378         "Algeria (‫الجزائر‬‎)",
38379         "dz",
38380         "213"
38381       ],
38382       [
38383         "American Samoa",
38384         "as",
38385         "1684"
38386       ],
38387       [
38388         "Andorra",
38389         "ad",
38390         "376"
38391       ],
38392       [
38393         "Angola",
38394         "ao",
38395         "244"
38396       ],
38397       [
38398         "Anguilla",
38399         "ai",
38400         "1264"
38401       ],
38402       [
38403         "Antigua and Barbuda",
38404         "ag",
38405         "1268"
38406       ],
38407       [
38408         "Argentina",
38409         "ar",
38410         "54"
38411       ],
38412       [
38413         "Armenia (Հայաստան)",
38414         "am",
38415         "374"
38416       ],
38417       [
38418         "Aruba",
38419         "aw",
38420         "297"
38421       ],
38422       [
38423         "Australia",
38424         "au",
38425         "61",
38426         0
38427       ],
38428       [
38429         "Austria (Österreich)",
38430         "at",
38431         "43"
38432       ],
38433       [
38434         "Azerbaijan (Azərbaycan)",
38435         "az",
38436         "994"
38437       ],
38438       [
38439         "Bahamas",
38440         "bs",
38441         "1242"
38442       ],
38443       [
38444         "Bahrain (‫البحرين‬‎)",
38445         "bh",
38446         "973"
38447       ],
38448       [
38449         "Bangladesh (বাংলাদেশ)",
38450         "bd",
38451         "880"
38452       ],
38453       [
38454         "Barbados",
38455         "bb",
38456         "1246"
38457       ],
38458       [
38459         "Belarus (Беларусь)",
38460         "by",
38461         "375"
38462       ],
38463       [
38464         "Belgium (België)",
38465         "be",
38466         "32"
38467       ],
38468       [
38469         "Belize",
38470         "bz",
38471         "501"
38472       ],
38473       [
38474         "Benin (Bénin)",
38475         "bj",
38476         "229"
38477       ],
38478       [
38479         "Bermuda",
38480         "bm",
38481         "1441"
38482       ],
38483       [
38484         "Bhutan (འབྲུག)",
38485         "bt",
38486         "975"
38487       ],
38488       [
38489         "Bolivia",
38490         "bo",
38491         "591"
38492       ],
38493       [
38494         "Bosnia and Herzegovina (Босна и Херцеговина)",
38495         "ba",
38496         "387"
38497       ],
38498       [
38499         "Botswana",
38500         "bw",
38501         "267"
38502       ],
38503       [
38504         "Brazil (Brasil)",
38505         "br",
38506         "55"
38507       ],
38508       [
38509         "British Indian Ocean Territory",
38510         "io",
38511         "246"
38512       ],
38513       [
38514         "British Virgin Islands",
38515         "vg",
38516         "1284"
38517       ],
38518       [
38519         "Brunei",
38520         "bn",
38521         "673"
38522       ],
38523       [
38524         "Bulgaria (България)",
38525         "bg",
38526         "359"
38527       ],
38528       [
38529         "Burkina Faso",
38530         "bf",
38531         "226"
38532       ],
38533       [
38534         "Burundi (Uburundi)",
38535         "bi",
38536         "257"
38537       ],
38538       [
38539         "Cambodia (កម្ពុជា)",
38540         "kh",
38541         "855"
38542       ],
38543       [
38544         "Cameroon (Cameroun)",
38545         "cm",
38546         "237"
38547       ],
38548       [
38549         "Canada",
38550         "ca",
38551         "1",
38552         1,
38553         ["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"]
38554       ],
38555       [
38556         "Cape Verde (Kabu Verdi)",
38557         "cv",
38558         "238"
38559       ],
38560       [
38561         "Caribbean Netherlands",
38562         "bq",
38563         "599",
38564         1
38565       ],
38566       [
38567         "Cayman Islands",
38568         "ky",
38569         "1345"
38570       ],
38571       [
38572         "Central African Republic (République centrafricaine)",
38573         "cf",
38574         "236"
38575       ],
38576       [
38577         "Chad (Tchad)",
38578         "td",
38579         "235"
38580       ],
38581       [
38582         "Chile",
38583         "cl",
38584         "56"
38585       ],
38586       [
38587         "China (中国)",
38588         "cn",
38589         "86"
38590       ],
38591       [
38592         "Christmas Island",
38593         "cx",
38594         "61",
38595         2
38596       ],
38597       [
38598         "Cocos (Keeling) Islands",
38599         "cc",
38600         "61",
38601         1
38602       ],
38603       [
38604         "Colombia",
38605         "co",
38606         "57"
38607       ],
38608       [
38609         "Comoros (‫جزر القمر‬‎)",
38610         "km",
38611         "269"
38612       ],
38613       [
38614         "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38615         "cd",
38616         "243"
38617       ],
38618       [
38619         "Congo (Republic) (Congo-Brazzaville)",
38620         "cg",
38621         "242"
38622       ],
38623       [
38624         "Cook Islands",
38625         "ck",
38626         "682"
38627       ],
38628       [
38629         "Costa Rica",
38630         "cr",
38631         "506"
38632       ],
38633       [
38634         "Côte d’Ivoire",
38635         "ci",
38636         "225"
38637       ],
38638       [
38639         "Croatia (Hrvatska)",
38640         "hr",
38641         "385"
38642       ],
38643       [
38644         "Cuba",
38645         "cu",
38646         "53"
38647       ],
38648       [
38649         "Curaçao",
38650         "cw",
38651         "599",
38652         0
38653       ],
38654       [
38655         "Cyprus (Κύπρος)",
38656         "cy",
38657         "357"
38658       ],
38659       [
38660         "Czech Republic (Česká republika)",
38661         "cz",
38662         "420"
38663       ],
38664       [
38665         "Denmark (Danmark)",
38666         "dk",
38667         "45"
38668       ],
38669       [
38670         "Djibouti",
38671         "dj",
38672         "253"
38673       ],
38674       [
38675         "Dominica",
38676         "dm",
38677         "1767"
38678       ],
38679       [
38680         "Dominican Republic (República Dominicana)",
38681         "do",
38682         "1",
38683         2,
38684         ["809", "829", "849"]
38685       ],
38686       [
38687         "Ecuador",
38688         "ec",
38689         "593"
38690       ],
38691       [
38692         "Egypt (‫مصر‬‎)",
38693         "eg",
38694         "20"
38695       ],
38696       [
38697         "El Salvador",
38698         "sv",
38699         "503"
38700       ],
38701       [
38702         "Equatorial Guinea (Guinea Ecuatorial)",
38703         "gq",
38704         "240"
38705       ],
38706       [
38707         "Eritrea",
38708         "er",
38709         "291"
38710       ],
38711       [
38712         "Estonia (Eesti)",
38713         "ee",
38714         "372"
38715       ],
38716       [
38717         "Ethiopia",
38718         "et",
38719         "251"
38720       ],
38721       [
38722         "Falkland Islands (Islas Malvinas)",
38723         "fk",
38724         "500"
38725       ],
38726       [
38727         "Faroe Islands (Føroyar)",
38728         "fo",
38729         "298"
38730       ],
38731       [
38732         "Fiji",
38733         "fj",
38734         "679"
38735       ],
38736       [
38737         "Finland (Suomi)",
38738         "fi",
38739         "358",
38740         0
38741       ],
38742       [
38743         "France",
38744         "fr",
38745         "33"
38746       ],
38747       [
38748         "French Guiana (Guyane française)",
38749         "gf",
38750         "594"
38751       ],
38752       [
38753         "French Polynesia (Polynésie française)",
38754         "pf",
38755         "689"
38756       ],
38757       [
38758         "Gabon",
38759         "ga",
38760         "241"
38761       ],
38762       [
38763         "Gambia",
38764         "gm",
38765         "220"
38766       ],
38767       [
38768         "Georgia (საქართველო)",
38769         "ge",
38770         "995"
38771       ],
38772       [
38773         "Germany (Deutschland)",
38774         "de",
38775         "49"
38776       ],
38777       [
38778         "Ghana (Gaana)",
38779         "gh",
38780         "233"
38781       ],
38782       [
38783         "Gibraltar",
38784         "gi",
38785         "350"
38786       ],
38787       [
38788         "Greece (Ελλάδα)",
38789         "gr",
38790         "30"
38791       ],
38792       [
38793         "Greenland (Kalaallit Nunaat)",
38794         "gl",
38795         "299"
38796       ],
38797       [
38798         "Grenada",
38799         "gd",
38800         "1473"
38801       ],
38802       [
38803         "Guadeloupe",
38804         "gp",
38805         "590",
38806         0
38807       ],
38808       [
38809         "Guam",
38810         "gu",
38811         "1671"
38812       ],
38813       [
38814         "Guatemala",
38815         "gt",
38816         "502"
38817       ],
38818       [
38819         "Guernsey",
38820         "gg",
38821         "44",
38822         1
38823       ],
38824       [
38825         "Guinea (Guinée)",
38826         "gn",
38827         "224"
38828       ],
38829       [
38830         "Guinea-Bissau (Guiné Bissau)",
38831         "gw",
38832         "245"
38833       ],
38834       [
38835         "Guyana",
38836         "gy",
38837         "592"
38838       ],
38839       [
38840         "Haiti",
38841         "ht",
38842         "509"
38843       ],
38844       [
38845         "Honduras",
38846         "hn",
38847         "504"
38848       ],
38849       [
38850         "Hong Kong (香港)",
38851         "hk",
38852         "852"
38853       ],
38854       [
38855         "Hungary (Magyarország)",
38856         "hu",
38857         "36"
38858       ],
38859       [
38860         "Iceland (Ísland)",
38861         "is",
38862         "354"
38863       ],
38864       [
38865         "India (भारत)",
38866         "in",
38867         "91"
38868       ],
38869       [
38870         "Indonesia",
38871         "id",
38872         "62"
38873       ],
38874       [
38875         "Iran (‫ایران‬‎)",
38876         "ir",
38877         "98"
38878       ],
38879       [
38880         "Iraq (‫العراق‬‎)",
38881         "iq",
38882         "964"
38883       ],
38884       [
38885         "Ireland",
38886         "ie",
38887         "353"
38888       ],
38889       [
38890         "Isle of Man",
38891         "im",
38892         "44",
38893         2
38894       ],
38895       [
38896         "Israel (‫ישראל‬‎)",
38897         "il",
38898         "972"
38899       ],
38900       [
38901         "Italy (Italia)",
38902         "it",
38903         "39",
38904         0
38905       ],
38906       [
38907         "Jamaica",
38908         "jm",
38909         "1876"
38910       ],
38911       [
38912         "Japan (日本)",
38913         "jp",
38914         "81"
38915       ],
38916       [
38917         "Jersey",
38918         "je",
38919         "44",
38920         3
38921       ],
38922       [
38923         "Jordan (‫الأردن‬‎)",
38924         "jo",
38925         "962"
38926       ],
38927       [
38928         "Kazakhstan (Казахстан)",
38929         "kz",
38930         "7",
38931         1
38932       ],
38933       [
38934         "Kenya",
38935         "ke",
38936         "254"
38937       ],
38938       [
38939         "Kiribati",
38940         "ki",
38941         "686"
38942       ],
38943       [
38944         "Kosovo",
38945         "xk",
38946         "383"
38947       ],
38948       [
38949         "Kuwait (‫الكويت‬‎)",
38950         "kw",
38951         "965"
38952       ],
38953       [
38954         "Kyrgyzstan (Кыргызстан)",
38955         "kg",
38956         "996"
38957       ],
38958       [
38959         "Laos (ລາວ)",
38960         "la",
38961         "856"
38962       ],
38963       [
38964         "Latvia (Latvija)",
38965         "lv",
38966         "371"
38967       ],
38968       [
38969         "Lebanon (‫لبنان‬‎)",
38970         "lb",
38971         "961"
38972       ],
38973       [
38974         "Lesotho",
38975         "ls",
38976         "266"
38977       ],
38978       [
38979         "Liberia",
38980         "lr",
38981         "231"
38982       ],
38983       [
38984         "Libya (‫ليبيا‬‎)",
38985         "ly",
38986         "218"
38987       ],
38988       [
38989         "Liechtenstein",
38990         "li",
38991         "423"
38992       ],
38993       [
38994         "Lithuania (Lietuva)",
38995         "lt",
38996         "370"
38997       ],
38998       [
38999         "Luxembourg",
39000         "lu",
39001         "352"
39002       ],
39003       [
39004         "Macau (澳門)",
39005         "mo",
39006         "853"
39007       ],
39008       [
39009         "Macedonia (FYROM) (Македонија)",
39010         "mk",
39011         "389"
39012       ],
39013       [
39014         "Madagascar (Madagasikara)",
39015         "mg",
39016         "261"
39017       ],
39018       [
39019         "Malawi",
39020         "mw",
39021         "265"
39022       ],
39023       [
39024         "Malaysia",
39025         "my",
39026         "60"
39027       ],
39028       [
39029         "Maldives",
39030         "mv",
39031         "960"
39032       ],
39033       [
39034         "Mali",
39035         "ml",
39036         "223"
39037       ],
39038       [
39039         "Malta",
39040         "mt",
39041         "356"
39042       ],
39043       [
39044         "Marshall Islands",
39045         "mh",
39046         "692"
39047       ],
39048       [
39049         "Martinique",
39050         "mq",
39051         "596"
39052       ],
39053       [
39054         "Mauritania (‫موريتانيا‬‎)",
39055         "mr",
39056         "222"
39057       ],
39058       [
39059         "Mauritius (Moris)",
39060         "mu",
39061         "230"
39062       ],
39063       [
39064         "Mayotte",
39065         "yt",
39066         "262",
39067         1
39068       ],
39069       [
39070         "Mexico (México)",
39071         "mx",
39072         "52"
39073       ],
39074       [
39075         "Micronesia",
39076         "fm",
39077         "691"
39078       ],
39079       [
39080         "Moldova (Republica Moldova)",
39081         "md",
39082         "373"
39083       ],
39084       [
39085         "Monaco",
39086         "mc",
39087         "377"
39088       ],
39089       [
39090         "Mongolia (Монгол)",
39091         "mn",
39092         "976"
39093       ],
39094       [
39095         "Montenegro (Crna Gora)",
39096         "me",
39097         "382"
39098       ],
39099       [
39100         "Montserrat",
39101         "ms",
39102         "1664"
39103       ],
39104       [
39105         "Morocco (‫المغرب‬‎)",
39106         "ma",
39107         "212",
39108         0
39109       ],
39110       [
39111         "Mozambique (Moçambique)",
39112         "mz",
39113         "258"
39114       ],
39115       [
39116         "Myanmar (Burma) (မြန်မာ)",
39117         "mm",
39118         "95"
39119       ],
39120       [
39121         "Namibia (Namibië)",
39122         "na",
39123         "264"
39124       ],
39125       [
39126         "Nauru",
39127         "nr",
39128         "674"
39129       ],
39130       [
39131         "Nepal (नेपाल)",
39132         "np",
39133         "977"
39134       ],
39135       [
39136         "Netherlands (Nederland)",
39137         "nl",
39138         "31"
39139       ],
39140       [
39141         "New Caledonia (Nouvelle-Calédonie)",
39142         "nc",
39143         "687"
39144       ],
39145       [
39146         "New Zealand",
39147         "nz",
39148         "64"
39149       ],
39150       [
39151         "Nicaragua",
39152         "ni",
39153         "505"
39154       ],
39155       [
39156         "Niger (Nijar)",
39157         "ne",
39158         "227"
39159       ],
39160       [
39161         "Nigeria",
39162         "ng",
39163         "234"
39164       ],
39165       [
39166         "Niue",
39167         "nu",
39168         "683"
39169       ],
39170       [
39171         "Norfolk Island",
39172         "nf",
39173         "672"
39174       ],
39175       [
39176         "North Korea (조선 민주주의 인민 공화국)",
39177         "kp",
39178         "850"
39179       ],
39180       [
39181         "Northern Mariana Islands",
39182         "mp",
39183         "1670"
39184       ],
39185       [
39186         "Norway (Norge)",
39187         "no",
39188         "47",
39189         0
39190       ],
39191       [
39192         "Oman (‫عُمان‬‎)",
39193         "om",
39194         "968"
39195       ],
39196       [
39197         "Pakistan (‫پاکستان‬‎)",
39198         "pk",
39199         "92"
39200       ],
39201       [
39202         "Palau",
39203         "pw",
39204         "680"
39205       ],
39206       [
39207         "Palestine (‫فلسطين‬‎)",
39208         "ps",
39209         "970"
39210       ],
39211       [
39212         "Panama (Panamá)",
39213         "pa",
39214         "507"
39215       ],
39216       [
39217         "Papua New Guinea",
39218         "pg",
39219         "675"
39220       ],
39221       [
39222         "Paraguay",
39223         "py",
39224         "595"
39225       ],
39226       [
39227         "Peru (Perú)",
39228         "pe",
39229         "51"
39230       ],
39231       [
39232         "Philippines",
39233         "ph",
39234         "63"
39235       ],
39236       [
39237         "Poland (Polska)",
39238         "pl",
39239         "48"
39240       ],
39241       [
39242         "Portugal",
39243         "pt",
39244         "351"
39245       ],
39246       [
39247         "Puerto Rico",
39248         "pr",
39249         "1",
39250         3,
39251         ["787", "939"]
39252       ],
39253       [
39254         "Qatar (‫قطر‬‎)",
39255         "qa",
39256         "974"
39257       ],
39258       [
39259         "Réunion (La Réunion)",
39260         "re",
39261         "262",
39262         0
39263       ],
39264       [
39265         "Romania (România)",
39266         "ro",
39267         "40"
39268       ],
39269       [
39270         "Russia (Россия)",
39271         "ru",
39272         "7",
39273         0
39274       ],
39275       [
39276         "Rwanda",
39277         "rw",
39278         "250"
39279       ],
39280       [
39281         "Saint Barthélemy",
39282         "bl",
39283         "590",
39284         1
39285       ],
39286       [
39287         "Saint Helena",
39288         "sh",
39289         "290"
39290       ],
39291       [
39292         "Saint Kitts and Nevis",
39293         "kn",
39294         "1869"
39295       ],
39296       [
39297         "Saint Lucia",
39298         "lc",
39299         "1758"
39300       ],
39301       [
39302         "Saint Martin (Saint-Martin (partie française))",
39303         "mf",
39304         "590",
39305         2
39306       ],
39307       [
39308         "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39309         "pm",
39310         "508"
39311       ],
39312       [
39313         "Saint Vincent and the Grenadines",
39314         "vc",
39315         "1784"
39316       ],
39317       [
39318         "Samoa",
39319         "ws",
39320         "685"
39321       ],
39322       [
39323         "San Marino",
39324         "sm",
39325         "378"
39326       ],
39327       [
39328         "São Tomé and Príncipe (São Tomé e Príncipe)",
39329         "st",
39330         "239"
39331       ],
39332       [
39333         "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
39334         "sa",
39335         "966"
39336       ],
39337       [
39338         "Senegal (Sénégal)",
39339         "sn",
39340         "221"
39341       ],
39342       [
39343         "Serbia (Србија)",
39344         "rs",
39345         "381"
39346       ],
39347       [
39348         "Seychelles",
39349         "sc",
39350         "248"
39351       ],
39352       [
39353         "Sierra Leone",
39354         "sl",
39355         "232"
39356       ],
39357       [
39358         "Singapore",
39359         "sg",
39360         "65"
39361       ],
39362       [
39363         "Sint Maarten",
39364         "sx",
39365         "1721"
39366       ],
39367       [
39368         "Slovakia (Slovensko)",
39369         "sk",
39370         "421"
39371       ],
39372       [
39373         "Slovenia (Slovenija)",
39374         "si",
39375         "386"
39376       ],
39377       [
39378         "Solomon Islands",
39379         "sb",
39380         "677"
39381       ],
39382       [
39383         "Somalia (Soomaaliya)",
39384         "so",
39385         "252"
39386       ],
39387       [
39388         "South Africa",
39389         "za",
39390         "27"
39391       ],
39392       [
39393         "South Korea (대한민국)",
39394         "kr",
39395         "82"
39396       ],
39397       [
39398         "South Sudan (‫جنوب السودان‬‎)",
39399         "ss",
39400         "211"
39401       ],
39402       [
39403         "Spain (España)",
39404         "es",
39405         "34"
39406       ],
39407       [
39408         "Sri Lanka (ශ්‍රී ලංකාව)",
39409         "lk",
39410         "94"
39411       ],
39412       [
39413         "Sudan (‫السودان‬‎)",
39414         "sd",
39415         "249"
39416       ],
39417       [
39418         "Suriname",
39419         "sr",
39420         "597"
39421       ],
39422       [
39423         "Svalbard and Jan Mayen",
39424         "sj",
39425         "47",
39426         1
39427       ],
39428       [
39429         "Swaziland",
39430         "sz",
39431         "268"
39432       ],
39433       [
39434         "Sweden (Sverige)",
39435         "se",
39436         "46"
39437       ],
39438       [
39439         "Switzerland (Schweiz)",
39440         "ch",
39441         "41"
39442       ],
39443       [
39444         "Syria (‫سوريا‬‎)",
39445         "sy",
39446         "963"
39447       ],
39448       [
39449         "Taiwan (台灣)",
39450         "tw",
39451         "886"
39452       ],
39453       [
39454         "Tajikistan",
39455         "tj",
39456         "992"
39457       ],
39458       [
39459         "Tanzania",
39460         "tz",
39461         "255"
39462       ],
39463       [
39464         "Thailand (ไทย)",
39465         "th",
39466         "66"
39467       ],
39468       [
39469         "Timor-Leste",
39470         "tl",
39471         "670"
39472       ],
39473       [
39474         "Togo",
39475         "tg",
39476         "228"
39477       ],
39478       [
39479         "Tokelau",
39480         "tk",
39481         "690"
39482       ],
39483       [
39484         "Tonga",
39485         "to",
39486         "676"
39487       ],
39488       [
39489         "Trinidad and Tobago",
39490         "tt",
39491         "1868"
39492       ],
39493       [
39494         "Tunisia (‫تونس‬‎)",
39495         "tn",
39496         "216"
39497       ],
39498       [
39499         "Turkey (Türkiye)",
39500         "tr",
39501         "90"
39502       ],
39503       [
39504         "Turkmenistan",
39505         "tm",
39506         "993"
39507       ],
39508       [
39509         "Turks and Caicos Islands",
39510         "tc",
39511         "1649"
39512       ],
39513       [
39514         "Tuvalu",
39515         "tv",
39516         "688"
39517       ],
39518       [
39519         "U.S. Virgin Islands",
39520         "vi",
39521         "1340"
39522       ],
39523       [
39524         "Uganda",
39525         "ug",
39526         "256"
39527       ],
39528       [
39529         "Ukraine (Україна)",
39530         "ua",
39531         "380"
39532       ],
39533       [
39534         "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
39535         "ae",
39536         "971"
39537       ],
39538       [
39539         "United Kingdom",
39540         "gb",
39541         "44",
39542         0
39543       ],
39544       [
39545         "United States",
39546         "us",
39547         "1",
39548         0
39549       ],
39550       [
39551         "Uruguay",
39552         "uy",
39553         "598"
39554       ],
39555       [
39556         "Uzbekistan (Oʻzbekiston)",
39557         "uz",
39558         "998"
39559       ],
39560       [
39561         "Vanuatu",
39562         "vu",
39563         "678"
39564       ],
39565       [
39566         "Vatican City (Città del Vaticano)",
39567         "va",
39568         "39",
39569         1
39570       ],
39571       [
39572         "Venezuela",
39573         "ve",
39574         "58"
39575       ],
39576       [
39577         "Vietnam (Việt Nam)",
39578         "vn",
39579         "84"
39580       ],
39581       [
39582         "Wallis and Futuna (Wallis-et-Futuna)",
39583         "wf",
39584         "681"
39585       ],
39586       [
39587         "Western Sahara (‫الصحراء الغربية‬‎)",
39588         "eh",
39589         "212",
39590         1
39591       ],
39592       [
39593         "Yemen (‫اليمن‬‎)",
39594         "ye",
39595         "967"
39596       ],
39597       [
39598         "Zambia",
39599         "zm",
39600         "260"
39601       ],
39602       [
39603         "Zimbabwe",
39604         "zw",
39605         "263"
39606       ],
39607       [
39608         "Åland Islands",
39609         "ax",
39610         "358",
39611         1
39612       ]
39613   ];
39614   
39615   return d;
39616 }/**
39617 *    This script refer to:
39618 *    Title: International Telephone Input
39619 *    Author: Jack O'Connor
39620 *    Code version:  v12.1.12
39621 *    Availability: https://github.com/jackocnr/intl-tel-input.git
39622 **/
39623
39624 /**
39625  * @class Roo.bootstrap.PhoneInput
39626  * @extends Roo.bootstrap.TriggerField
39627  * An input with International dial-code selection
39628  
39629  * @cfg {String} defaultDialCode default '+852'
39630  * @cfg {Array} preferedCountries default []
39631   
39632  * @constructor
39633  * Create a new PhoneInput.
39634  * @param {Object} config Configuration options
39635  */
39636
39637 Roo.bootstrap.PhoneInput = function(config) {
39638     Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39639 };
39640
39641 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39642         
39643         listWidth: undefined,
39644         
39645         selectedClass: 'active',
39646         
39647         invalidClass : "has-warning",
39648         
39649         validClass: 'has-success',
39650         
39651         allowed: '0123456789',
39652         
39653         /**
39654          * @cfg {String} defaultDialCode The default dial code when initializing the input
39655          */
39656         defaultDialCode: '+852',
39657         
39658         /**
39659          * @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
39660          */
39661         preferedCountries: false,
39662         
39663         getAutoCreate : function()
39664         {
39665             var data = Roo.bootstrap.PhoneInputData();
39666             var align = this.labelAlign || this.parentLabelAlign();
39667             var id = Roo.id();
39668             
39669             this.allCountries = [];
39670             this.dialCodeMapping = [];
39671             
39672             for (var i = 0; i < data.length; i++) {
39673               var c = data[i];
39674               this.allCountries[i] = {
39675                 name: c[0],
39676                 iso2: c[1],
39677                 dialCode: c[2],
39678                 priority: c[3] || 0,
39679                 areaCodes: c[4] || null
39680               };
39681               this.dialCodeMapping[c[2]] = {
39682                   name: c[0],
39683                   iso2: c[1],
39684                   priority: c[3] || 0,
39685                   areaCodes: c[4] || null
39686               };
39687             }
39688             
39689             var cfg = {
39690                 cls: 'form-group',
39691                 cn: []
39692             };
39693             
39694             var input =  {
39695                 tag: 'input',
39696                 id : id,
39697                 cls : 'form-control tel-input',
39698                 autocomplete: 'new-password'
39699             };
39700             
39701             var hiddenInput = {
39702                 tag: 'input',
39703                 type: 'hidden',
39704                 cls: 'hidden-tel-input'
39705             };
39706             
39707             if (this.name) {
39708                 hiddenInput.name = this.name;
39709             }
39710             
39711             if (this.disabled) {
39712                 input.disabled = true;
39713             }
39714             
39715             var flag_container = {
39716                 tag: 'div',
39717                 cls: 'flag-box',
39718                 cn: [
39719                     {
39720                         tag: 'div',
39721                         cls: 'flag'
39722                     },
39723                     {
39724                         tag: 'div',
39725                         cls: 'caret'
39726                     }
39727                 ]
39728             };
39729             
39730             var box = {
39731                 tag: 'div',
39732                 cls: this.hasFeedback ? 'has-feedback' : '',
39733                 cn: [
39734                     hiddenInput,
39735                     input,
39736                     {
39737                         tag: 'input',
39738                         cls: 'dial-code-holder',
39739                         disabled: true
39740                     }
39741                 ]
39742             };
39743             
39744             var container = {
39745                 cls: 'roo-select2-container input-group',
39746                 cn: [
39747                     flag_container,
39748                     box
39749                 ]
39750             };
39751             
39752             if (this.fieldLabel.length) {
39753                 var indicator = {
39754                     tag: 'i',
39755                     tooltip: 'This field is required'
39756                 };
39757                 
39758                 var label = {
39759                     tag: 'label',
39760                     'for':  id,
39761                     cls: 'control-label',
39762                     cn: []
39763                 };
39764                 
39765                 var label_text = {
39766                     tag: 'span',
39767                     html: this.fieldLabel
39768                 };
39769                 
39770                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39771                 label.cn = [
39772                     indicator,
39773                     label_text
39774                 ];
39775                 
39776                 if(this.indicatorpos == 'right') {
39777                     indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39778                     label.cn = [
39779                         label_text,
39780                         indicator
39781                     ];
39782                 }
39783                 
39784                 if(align == 'left') {
39785                     container = {
39786                         tag: 'div',
39787                         cn: [
39788                             container
39789                         ]
39790                     };
39791                     
39792                     if(this.labelWidth > 12){
39793                         label.style = "width: " + this.labelWidth + 'px';
39794                     }
39795                     if(this.labelWidth < 13 && this.labelmd == 0){
39796                         this.labelmd = this.labelWidth;
39797                     }
39798                     if(this.labellg > 0){
39799                         label.cls += ' col-lg-' + this.labellg;
39800                         input.cls += ' col-lg-' + (12 - this.labellg);
39801                     }
39802                     if(this.labelmd > 0){
39803                         label.cls += ' col-md-' + this.labelmd;
39804                         container.cls += ' col-md-' + (12 - this.labelmd);
39805                     }
39806                     if(this.labelsm > 0){
39807                         label.cls += ' col-sm-' + this.labelsm;
39808                         container.cls += ' col-sm-' + (12 - this.labelsm);
39809                     }
39810                     if(this.labelxs > 0){
39811                         label.cls += ' col-xs-' + this.labelxs;
39812                         container.cls += ' col-xs-' + (12 - this.labelxs);
39813                     }
39814                 }
39815             }
39816             
39817             cfg.cn = [
39818                 label,
39819                 container
39820             ];
39821             
39822             var settings = this;
39823             
39824             ['xs','sm','md','lg'].map(function(size){
39825                 if (settings[size]) {
39826                     cfg.cls += ' col-' + size + '-' + settings[size];
39827                 }
39828             });
39829             
39830             this.store = new Roo.data.Store({
39831                 proxy : new Roo.data.MemoryProxy({}),
39832                 reader : new Roo.data.JsonReader({
39833                     fields : [
39834                         {
39835                             'name' : 'name',
39836                             'type' : 'string'
39837                         },
39838                         {
39839                             'name' : 'iso2',
39840                             'type' : 'string'
39841                         },
39842                         {
39843                             'name' : 'dialCode',
39844                             'type' : 'string'
39845                         },
39846                         {
39847                             'name' : 'priority',
39848                             'type' : 'string'
39849                         },
39850                         {
39851                             'name' : 'areaCodes',
39852                             'type' : 'string'
39853                         }
39854                     ]
39855                 })
39856             });
39857             
39858             if(!this.preferedCountries) {
39859                 this.preferedCountries = [
39860                     'hk',
39861                     'gb',
39862                     'us'
39863                 ];
39864             }
39865             
39866             var p = this.preferedCountries.reverse();
39867             
39868             if(p) {
39869                 for (var i = 0; i < p.length; i++) {
39870                     for (var j = 0; j < this.allCountries.length; j++) {
39871                         if(this.allCountries[j].iso2 == p[i]) {
39872                             var t = this.allCountries[j];
39873                             this.allCountries.splice(j,1);
39874                             this.allCountries.unshift(t);
39875                         }
39876                     } 
39877                 }
39878             }
39879             
39880             this.store.proxy.data = {
39881                 success: true,
39882                 data: this.allCountries
39883             };
39884             
39885             return cfg;
39886         },
39887         
39888         initEvents : function()
39889         {
39890             this.createList();
39891             Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39892             
39893             this.indicator = this.indicatorEl();
39894             this.flag = this.flagEl();
39895             this.dialCodeHolder = this.dialCodeHolderEl();
39896             
39897             this.trigger = this.el.select('div.flag-box',true).first();
39898             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39899             
39900             var _this = this;
39901             
39902             (function(){
39903                 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39904                 _this.list.setWidth(lw);
39905             }).defer(100);
39906             
39907             this.list.on('mouseover', this.onViewOver, this);
39908             this.list.on('mousemove', this.onViewMove, this);
39909             this.inputEl().on("keyup", this.onKeyUp, this);
39910             
39911             this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39912
39913             this.view = new Roo.View(this.list, this.tpl, {
39914                 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39915             });
39916             
39917             this.view.on('click', this.onViewClick, this);
39918             this.setValue(this.defaultDialCode);
39919         },
39920         
39921         onTriggerClick : function(e)
39922         {
39923             Roo.log('trigger click');
39924             if(this.disabled){
39925                 return;
39926             }
39927             
39928             if(this.isExpanded()){
39929                 this.collapse();
39930                 this.hasFocus = false;
39931             }else {
39932                 this.store.load({});
39933                 this.hasFocus = true;
39934                 this.expand();
39935             }
39936         },
39937         
39938         isExpanded : function()
39939         {
39940             return this.list.isVisible();
39941         },
39942         
39943         collapse : function()
39944         {
39945             if(!this.isExpanded()){
39946                 return;
39947             }
39948             this.list.hide();
39949             Roo.get(document).un('mousedown', this.collapseIf, this);
39950             Roo.get(document).un('mousewheel', this.collapseIf, this);
39951             this.fireEvent('collapse', this);
39952             this.validate();
39953         },
39954         
39955         expand : function()
39956         {
39957             Roo.log('expand');
39958
39959             if(this.isExpanded() || !this.hasFocus){
39960                 return;
39961             }
39962             
39963             var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39964             this.list.setWidth(lw);
39965             
39966             this.list.show();
39967             this.restrictHeight();
39968             
39969             Roo.get(document).on('mousedown', this.collapseIf, this);
39970             Roo.get(document).on('mousewheel', this.collapseIf, this);
39971             
39972             this.fireEvent('expand', this);
39973         },
39974         
39975         restrictHeight : function()
39976         {
39977             this.list.alignTo(this.inputEl(), this.listAlign);
39978             this.list.alignTo(this.inputEl(), this.listAlign);
39979         },
39980         
39981         onViewOver : function(e, t)
39982         {
39983             if(this.inKeyMode){
39984                 return;
39985             }
39986             var item = this.view.findItemFromChild(t);
39987             
39988             if(item){
39989                 var index = this.view.indexOf(item);
39990                 this.select(index, false);
39991             }
39992         },
39993
39994         // private
39995         onViewClick : function(view, doFocus, el, e)
39996         {
39997             var index = this.view.getSelectedIndexes()[0];
39998             
39999             var r = this.store.getAt(index);
40000             
40001             if(r){
40002                 this.onSelect(r, index);
40003             }
40004             if(doFocus !== false && !this.blockFocus){
40005                 this.inputEl().focus();
40006             }
40007         },
40008         
40009         onViewMove : function(e, t)
40010         {
40011             this.inKeyMode = false;
40012         },
40013         
40014         select : function(index, scrollIntoView)
40015         {
40016             this.selectedIndex = index;
40017             this.view.select(index);
40018             if(scrollIntoView !== false){
40019                 var el = this.view.getNode(index);
40020                 if(el){
40021                     this.list.scrollChildIntoView(el, false);
40022                 }
40023             }
40024         },
40025         
40026         createList : function()
40027         {
40028             this.list = Roo.get(document.body).createChild({
40029                 tag: 'ul',
40030                 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40031                 style: 'display:none'
40032             });
40033             this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
40034         },
40035         
40036         collapseIf : function(e)
40037         {
40038             var in_combo  = e.within(this.el);
40039             var in_list =  e.within(this.list);
40040             var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40041             
40042             if (in_combo || in_list || is_list) {
40043                 return;
40044             }
40045             this.collapse();
40046         },
40047         
40048         onSelect : function(record, index)
40049         {
40050             if(this.fireEvent('beforeselect', this, record, index) !== false){
40051                 
40052                 this.setFlagClass(record.data.iso2);
40053                 this.setDialCode(record.data.dialCode);
40054                 this.hasFocus = false;
40055                 this.collapse();
40056                 this.fireEvent('select', this, record, index);
40057             }
40058         },
40059         
40060         flagEl : function()
40061         {
40062             var flag = this.el.select('div.flag',true).first();
40063             if(!flag){
40064                 return false;
40065             }
40066             return flag;
40067         },
40068         
40069         dialCodeHolderEl : function()
40070         {
40071             var d = this.el.select('input.dial-code-holder',true).first();
40072             if(!d){
40073                 return false;
40074             }
40075             return d;
40076         },
40077         
40078         setDialCode : function(v)
40079         {
40080             this.dialCodeHolder.dom.value = '+'+v;
40081         },
40082         
40083         setFlagClass : function(n)
40084         {
40085             this.flag.dom.className = 'flag '+n;
40086         },
40087         
40088         getValue : function()
40089         {
40090             var v = this.inputEl().getValue();
40091             if(this.dialCodeHolder) {
40092                 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40093             }
40094             return v;
40095         },
40096         
40097         setValue : function(v)
40098         {
40099             var d = this.getDialCode(v);
40100             
40101             //invalid dial code
40102             if(v.length == 0 || !d || d.length == 0) {
40103                 if(this.rendered){
40104                     this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40105                     this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40106                 }
40107                 return;
40108             }
40109             
40110             //valid dial code
40111             this.setFlagClass(this.dialCodeMapping[d].iso2);
40112             this.setDialCode(d);
40113             this.inputEl().dom.value = v.replace('+'+d,'');
40114             this.hiddenEl().dom.value = this.getValue();
40115             
40116             this.validate();
40117         },
40118         
40119         getDialCode : function(v = '')
40120         {
40121             if (v.length == 0) {
40122                 return this.dialCodeHolder.dom.value;
40123             }
40124             
40125             var dialCode = "";
40126             if (v.charAt(0) != "+") {
40127                 return false;
40128             }
40129             var numericChars = "";
40130             for (var i = 1; i < v.length; i++) {
40131               var c = v.charAt(i);
40132               if (!isNaN(c)) {
40133                 numericChars += c;
40134                 if (this.dialCodeMapping[numericChars]) {
40135                   dialCode = v.substr(1, i);
40136                 }
40137                 if (numericChars.length == 4) {
40138                   break;
40139                 }
40140               }
40141             }
40142             return dialCode;
40143         },
40144         
40145         reset : function()
40146         {
40147             this.setValue(this.defaultDialCode);
40148             this.validate();
40149         },
40150         
40151         hiddenEl : function()
40152         {
40153             return this.el.select('input.hidden-tel-input',true).first();
40154         },
40155         
40156         onKeyUp : function(e){
40157             
40158             var k = e.getKey();
40159             var c = e.getCharCode();
40160             
40161             if(
40162                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40163                     this.allowed.indexOf(String.fromCharCode(c)) === -1
40164             ){
40165                 e.stopEvent();
40166             }
40167             
40168             // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40169             //     return;
40170             // }
40171             if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40172                 e.stopEvent();
40173             }
40174             
40175             this.setValue(this.getValue());
40176         }
40177         
40178 });
40179 /**
40180  * @class Roo.bootstrap.MoneyField
40181  * @extends Roo.bootstrap.ComboBox
40182  * Bootstrap MoneyField class
40183  * 
40184  * @constructor
40185  * Create a new MoneyField.
40186  * @param {Object} config Configuration options
40187  */
40188
40189 Roo.bootstrap.MoneyField = function(config) {
40190     
40191     Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40192     
40193 };
40194
40195 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40196     
40197     /**
40198      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40199      */
40200     allowDecimals : true,
40201     /**
40202      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40203      */
40204     decimalSeparator : ".",
40205     /**
40206      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40207      */
40208     decimalPrecision : 0,
40209     /**
40210      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40211      */
40212     allowNegative : true,
40213     /**
40214      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40215      */
40216     minValue : Number.NEGATIVE_INFINITY,
40217     /**
40218      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40219      */
40220     maxValue : Number.MAX_VALUE,
40221     /**
40222      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40223      */
40224     minText : "The minimum value for this field is {0}",
40225     /**
40226      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40227      */
40228     maxText : "The maximum value for this field is {0}",
40229     /**
40230      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
40231      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40232      */
40233     nanText : "{0} is not a valid number",
40234     /**
40235      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40236      */
40237     castInt : true,
40238     /**
40239      * @cfg {String} defaults currency of the MoneyField
40240      * value should be in lkey
40241      */
40242     defaultCurrency : false,
40243     /**
40244      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40245      */
40246     thousandsDelimiter : false,
40247     
40248     
40249     inputlg : 9,
40250     inputmd : 9,
40251     inputsm : 9,
40252     inputxs : 6,
40253     
40254     store : false,
40255     
40256     getAutoCreate : function()
40257     {
40258         var align = this.labelAlign || this.parentLabelAlign();
40259         
40260         var id = Roo.id();
40261
40262         var cfg = {
40263             cls: 'form-group',
40264             cn: []
40265         };
40266
40267         var input =  {
40268             tag: 'input',
40269             id : id,
40270             cls : 'form-control roo-money-amount-input',
40271             autocomplete: 'new-password'
40272         };
40273         
40274         var hiddenInput = {
40275             tag: 'input',
40276             type: 'hidden',
40277             id: Roo.id(),
40278             cls: 'hidden-number-input'
40279         };
40280         
40281         if (this.name) {
40282             hiddenInput.name = this.name;
40283         }
40284
40285         if (this.disabled) {
40286             input.disabled = true;
40287         }
40288
40289         var clg = 12 - this.inputlg;
40290         var cmd = 12 - this.inputmd;
40291         var csm = 12 - this.inputsm;
40292         var cxs = 12 - this.inputxs;
40293         
40294         var container = {
40295             tag : 'div',
40296             cls : 'row roo-money-field',
40297             cn : [
40298                 {
40299                     tag : 'div',
40300                     cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40301                     cn : [
40302                         {
40303                             tag : 'div',
40304                             cls: 'roo-select2-container input-group',
40305                             cn: [
40306                                 {
40307                                     tag : 'input',
40308                                     cls : 'form-control roo-money-currency-input',
40309                                     autocomplete: 'new-password',
40310                                     readOnly : 1,
40311                                     name : this.currencyName
40312                                 },
40313                                 {
40314                                     tag :'span',
40315                                     cls : 'input-group-addon',
40316                                     cn : [
40317                                         {
40318                                             tag: 'span',
40319                                             cls: 'caret'
40320                                         }
40321                                     ]
40322                                 }
40323                             ]
40324                         }
40325                     ]
40326                 },
40327                 {
40328                     tag : 'div',
40329                     cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40330                     cn : [
40331                         {
40332                             tag: 'div',
40333                             cls: this.hasFeedback ? 'has-feedback' : '',
40334                             cn: [
40335                                 input
40336                             ]
40337                         }
40338                     ]
40339                 }
40340             ]
40341             
40342         };
40343         
40344         if (this.fieldLabel.length) {
40345             var indicator = {
40346                 tag: 'i',
40347                 tooltip: 'This field is required'
40348             };
40349
40350             var label = {
40351                 tag: 'label',
40352                 'for':  id,
40353                 cls: 'control-label',
40354                 cn: []
40355             };
40356
40357             var label_text = {
40358                 tag: 'span',
40359                 html: this.fieldLabel
40360             };
40361
40362             indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40363             label.cn = [
40364                 indicator,
40365                 label_text
40366             ];
40367
40368             if(this.indicatorpos == 'right') {
40369                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40370                 label.cn = [
40371                     label_text,
40372                     indicator
40373                 ];
40374             }
40375
40376             if(align == 'left') {
40377                 container = {
40378                     tag: 'div',
40379                     cn: [
40380                         container
40381                     ]
40382                 };
40383
40384                 if(this.labelWidth > 12){
40385                     label.style = "width: " + this.labelWidth + 'px';
40386                 }
40387                 if(this.labelWidth < 13 && this.labelmd == 0){
40388                     this.labelmd = this.labelWidth;
40389                 }
40390                 if(this.labellg > 0){
40391                     label.cls += ' col-lg-' + this.labellg;
40392                     input.cls += ' col-lg-' + (12 - this.labellg);
40393                 }
40394                 if(this.labelmd > 0){
40395                     label.cls += ' col-md-' + this.labelmd;
40396                     container.cls += ' col-md-' + (12 - this.labelmd);
40397                 }
40398                 if(this.labelsm > 0){
40399                     label.cls += ' col-sm-' + this.labelsm;
40400                     container.cls += ' col-sm-' + (12 - this.labelsm);
40401                 }
40402                 if(this.labelxs > 0){
40403                     label.cls += ' col-xs-' + this.labelxs;
40404                     container.cls += ' col-xs-' + (12 - this.labelxs);
40405                 }
40406             }
40407         }
40408
40409         cfg.cn = [
40410             label,
40411             container,
40412             hiddenInput
40413         ];
40414         
40415         var settings = this;
40416
40417         ['xs','sm','md','lg'].map(function(size){
40418             if (settings[size]) {
40419                 cfg.cls += ' col-' + size + '-' + settings[size];
40420             }
40421         });
40422         
40423         return cfg;
40424     },
40425     
40426     initEvents : function()
40427     {
40428         this.indicator = this.indicatorEl();
40429         
40430         this.initCurrencyEvent();
40431         
40432         this.initNumberEvent();
40433     },
40434     
40435     initCurrencyEvent : function()
40436     {
40437         if (!this.store) {
40438             throw "can not find store for combo";
40439         }
40440         
40441         this.store = Roo.factory(this.store, Roo.data);
40442         this.store.parent = this;
40443         
40444         this.createList();
40445         
40446         this.triggerEl = this.el.select('.input-group-addon', true).first();
40447         
40448         this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40449         
40450         var _this = this;
40451         
40452         (function(){
40453             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40454             _this.list.setWidth(lw);
40455         }).defer(100);
40456         
40457         this.list.on('mouseover', this.onViewOver, this);
40458         this.list.on('mousemove', this.onViewMove, this);
40459         this.list.on('scroll', this.onViewScroll, this);
40460         
40461         if(!this.tpl){
40462             this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40463         }
40464         
40465         this.view = new Roo.View(this.list, this.tpl, {
40466             singleSelect:true, store: this.store, selectedClass: this.selectedClass
40467         });
40468         
40469         this.view.on('click', this.onViewClick, this);
40470         
40471         this.store.on('beforeload', this.onBeforeLoad, this);
40472         this.store.on('load', this.onLoad, this);
40473         this.store.on('loadexception', this.onLoadException, this);
40474         
40475         this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40476             "up" : function(e){
40477                 this.inKeyMode = true;
40478                 this.selectPrev();
40479             },
40480
40481             "down" : function(e){
40482                 if(!this.isExpanded()){
40483                     this.onTriggerClick();
40484                 }else{
40485                     this.inKeyMode = true;
40486                     this.selectNext();
40487                 }
40488             },
40489
40490             "enter" : function(e){
40491                 this.collapse();
40492                 
40493                 if(this.fireEvent("specialkey", this, e)){
40494                     this.onViewClick(false);
40495                 }
40496                 
40497                 return true;
40498             },
40499
40500             "esc" : function(e){
40501                 this.collapse();
40502             },
40503
40504             "tab" : function(e){
40505                 this.collapse();
40506                 
40507                 if(this.fireEvent("specialkey", this, e)){
40508                     this.onViewClick(false);
40509                 }
40510                 
40511                 return true;
40512             },
40513
40514             scope : this,
40515
40516             doRelay : function(foo, bar, hname){
40517                 if(hname == 'down' || this.scope.isExpanded()){
40518                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40519                 }
40520                 return true;
40521             },
40522
40523             forceKeyDown: true
40524         });
40525         
40526         this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40527         
40528     },
40529     
40530     initNumberEvent : function(e)
40531     {
40532         this.inputEl().on("keydown" , this.fireKey,  this);
40533         this.inputEl().on("focus", this.onFocus,  this);
40534         this.inputEl().on("blur", this.onBlur,  this);
40535         
40536         this.inputEl().relayEvent('keyup', this);
40537         
40538         if(this.indicator){
40539             this.indicator.addClass('invisible');
40540         }
40541  
40542         this.originalValue = this.getValue();
40543         
40544         if(this.validationEvent == 'keyup'){
40545             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40546             this.inputEl().on('keyup', this.filterValidation, this);
40547         }
40548         else if(this.validationEvent !== false){
40549             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40550         }
40551         
40552         if(this.selectOnFocus){
40553             this.on("focus", this.preFocus, this);
40554             
40555         }
40556         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40557             this.inputEl().on("keypress", this.filterKeys, this);
40558         } else {
40559             this.inputEl().relayEvent('keypress', this);
40560         }
40561         
40562         var allowed = "0123456789";
40563         
40564         if(this.allowDecimals){
40565             allowed += this.decimalSeparator;
40566         }
40567         
40568         if(this.allowNegative){
40569             allowed += "-";
40570         }
40571         
40572         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40573         
40574         var keyPress = function(e){
40575             
40576             var k = e.getKey();
40577             
40578             var c = e.getCharCode();
40579             
40580             if(
40581                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40582                     allowed.indexOf(String.fromCharCode(c)) === -1
40583             ){
40584                 e.stopEvent();
40585                 return;
40586             }
40587             
40588             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40589                 return;
40590             }
40591             
40592             if(allowed.indexOf(String.fromCharCode(c)) === -1){
40593                 e.stopEvent();
40594             }
40595         };
40596         
40597         this.inputEl().on("keypress", keyPress, this);
40598         
40599     },
40600     
40601     onTriggerClick : function(e)
40602     {   
40603         if(this.disabled){
40604             return;
40605         }
40606         
40607         this.page = 0;
40608         this.loadNext = false;
40609         
40610         if(this.isExpanded()){
40611             this.collapse();
40612             return;
40613         }
40614         
40615         this.hasFocus = true;
40616         
40617         if(this.triggerAction == 'all') {
40618             this.doQuery(this.allQuery, true);
40619             return;
40620         }
40621         
40622         this.doQuery(this.getRawValue());
40623     },
40624     
40625     getCurrency : function()
40626     {   
40627         var v = this.currencyEl().getValue();
40628         
40629         return v;
40630     },
40631     
40632     restrictHeight : function()
40633     {
40634         this.list.alignTo(this.currencyEl(), this.listAlign);
40635         this.list.alignTo(this.currencyEl(), this.listAlign);
40636     },
40637     
40638     onViewClick : function(view, doFocus, el, e)
40639     {
40640         var index = this.view.getSelectedIndexes()[0];
40641         
40642         var r = this.store.getAt(index);
40643         
40644         if(r){
40645             this.onSelect(r, index);
40646         }
40647     },
40648     
40649     onSelect : function(record, index){
40650         
40651         if(this.fireEvent('beforeselect', this, record, index) !== false){
40652         
40653             this.setFromCurrencyData(index > -1 ? record.data : false);
40654             
40655             this.collapse();
40656             
40657             this.fireEvent('select', this, record, index);
40658         }
40659     },
40660     
40661     setFromCurrencyData : function(o)
40662     {
40663         var currency = '';
40664         
40665         this.lastCurrency = o;
40666         
40667         if (this.currencyField) {
40668             currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40669         } else {
40670             Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
40671         }
40672         
40673         this.lastSelectionText = currency;
40674         
40675         //setting default currency
40676         if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40677             this.setCurrency(this.defaultCurrency);
40678             return;
40679         }
40680         
40681         this.setCurrency(currency);
40682     },
40683     
40684     setFromData : function(o)
40685     {
40686         var c = {};
40687         
40688         c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40689         
40690         this.setFromCurrencyData(c);
40691         
40692         var value = '';
40693         
40694         if (this.name) {
40695             value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40696         } else {
40697             Roo.log('no value set for '+ (this.name ? this.name : this.id));
40698         }
40699         
40700         this.setValue(value);
40701         
40702     },
40703     
40704     setCurrency : function(v)
40705     {   
40706         this.currencyValue = v;
40707         
40708         if(this.rendered){
40709             this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40710             this.validate();
40711         }
40712     },
40713     
40714     setValue : function(v)
40715     {
40716         v = this.fixPrecision(v);
40717         
40718         v = String(v).replace(".", this.decimalSeparator);
40719         
40720         this.value = v;
40721         
40722         if(this.rendered){
40723             
40724             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40725             
40726             this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision, 
40727                 this.thousandsDelimiter || ','
40728             );
40729             
40730             if(this.allowBlank && !v) {
40731                 this.inputEl().dom.value = '';
40732             }
40733             
40734             this.validate();
40735         }
40736     },
40737     
40738     getRawValue : function()
40739     {
40740         var v = this.inputEl().getValue();
40741         
40742         return v;
40743     },
40744     
40745     getValue : function()
40746     {
40747         return this.fixPrecision(this.parseValue(this.getRawValue()));
40748     },
40749     
40750     parseValue : function(value)
40751     {
40752         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40753         return isNaN(value) ? '' : value;
40754     },
40755     
40756     fixPrecision : function(value)
40757     {
40758         var nan = isNaN(value);
40759         
40760         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40761             return nan ? '' : value;
40762         }
40763         
40764         return parseFloat(value).toFixed(this.decimalPrecision);
40765     },
40766     
40767     decimalPrecisionFcn : function(v)
40768     {
40769         return Math.floor(v);
40770     },
40771     
40772     validateValue : function(value)
40773     {
40774         if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40775             return false;
40776         }
40777         
40778         var num = this.parseValue(value);
40779         
40780         if(isNaN(num)){
40781             this.markInvalid(String.format(this.nanText, value));
40782             return false;
40783         }
40784         
40785         if(num < this.minValue){
40786             this.markInvalid(String.format(this.minText, this.minValue));
40787             return false;
40788         }
40789         
40790         if(num > this.maxValue){
40791             this.markInvalid(String.format(this.maxText, this.maxValue));
40792             return false;
40793         }
40794         
40795         return true;
40796     },
40797     
40798     validate : function()
40799     {
40800         if(this.disabled || this.allowBlank){
40801             this.markValid();
40802             return true;
40803         }
40804         
40805         var currency = this.getCurrency();
40806         
40807         if(this.validateValue(this.getRawValue()) && currency.length){
40808             this.markValid();
40809             return true;
40810         }
40811         
40812         this.markInvalid();
40813         return false;
40814     },
40815     
40816     getName: function()
40817     {
40818         return this.name;
40819     },
40820     
40821     beforeBlur : function()
40822     {
40823         if(!this.castInt){
40824             return;
40825         }
40826         
40827         var v = this.parseValue(this.getRawValue());
40828         
40829         if(v || v == 0){
40830             this.setValue(v);
40831         }
40832     },
40833     
40834     onBlur : function()
40835     {
40836         this.beforeBlur();
40837         
40838         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40839             //this.el.removeClass(this.focusClass);
40840         }
40841         
40842         this.hasFocus = false;
40843         
40844         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40845             this.validate();
40846         }
40847         
40848         var v = this.getValue();
40849         
40850         if(String(v) !== String(this.startValue)){
40851             this.fireEvent('change', this, v, this.startValue);
40852         }
40853         
40854         this.fireEvent("blur", this);
40855     },
40856     
40857     inputEl : function()
40858     {
40859         return this.el.select('.roo-money-amount-input', true).first();
40860     },
40861     
40862     currencyEl : function()
40863     {
40864         return this.el.select('.roo-money-currency-input', true).first();
40865     },
40866     
40867     hiddenEl : function()
40868     {
40869         return this.el.select('input.hidden-number-input',true).first();
40870     }
40871     
40872 });